blob: a7a23c2133cb4d1a62e39468e05c82fd0ae2fbad [file] [log] [blame]
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001/* assemble.c code generation for the Netwide Assembler
2 *
3 * The Netwide Assembler is copyright (C) 1996 Simon Tatham and
4 * Julian Hall. All rights reserved. The software is
Beroset095e6a22007-12-29 09:44:23 -05005 * redistributable under the license given in the file "LICENSE"
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00006 * distributed in the NASM archive.
7 *
8 * the actual codes (C syntax, i.e. octal):
9 * \0 - terminates the code. (Unless it's a literal of course.)
10 * \1, \2, \3 - that many literal bytes follow in the code stream
11 * \4, \6 - the POP/PUSH (respectively) codes for CS, DS, ES, SS
12 * (POP is never used for CS) depending on operand 0
13 * \5, \7 - the second byte of POP/PUSH codes for FS, GS, depending
14 * on operand 0
H. Peter Anvin7eb4a382007-09-17 15:49:30 -070015 * \10..\13 - a literal byte follows in the code stream, to be added
16 * to the register value of operand 0..3
17 * \14..\17 - a signed byte immediate operand, from operand 0..3
18 * \20..\23 - a byte immediate operand, from operand 0..3
19 * \24..\27 - an unsigned byte immediate operand, from operand 0..3
20 * \30..\33 - a word immediate operand, from operand 0..3
21 * \34..\37 - select between \3[0-3] and \4[0-3] depending on 16/32 bit
H. Peter Anvin3ba46772002-05-27 23:19:35 +000022 * assembly mode or the operand-size override on the operand
H. Peter Anvin7eb4a382007-09-17 15:49:30 -070023 * \40..\43 - a long immediate operand, from operand 0..3
24 * \44..\47 - select between \3[0-3], \4[0-3] and \5[4-7]
H. Peter Anvinde4b89b2007-10-01 15:41:25 -070025 * depending on the address size of the instruction.
H. Peter Anvin7eb4a382007-09-17 15:49:30 -070026 * \50..\53 - a byte relative operand, from operand 0..3
27 * \54..\57 - a qword immediate operand, from operand 0..3
28 * \60..\63 - a word relative operand, from operand 0..3
29 * \64..\67 - select between \6[0-3] and \7[0-3] depending on 16/32 bit
H. Peter Anvin17799b42002-05-21 03:31:21 +000030 * assembly mode or the operand-size override on the operand
H. Peter Anvin7eb4a382007-09-17 15:49:30 -070031 * \70..\73 - a long relative operand, from operand 0..3
H. Peter Anvinc1377e92008-10-06 23:40:31 -070032 * \74..\77 - a word constant, from the _segment_ part of operand 0..3
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000033 * \1ab - a ModRM, calculated on EA in operand a, with the spare
34 * field the register value of operand b.
H. Peter Anvin7eb4a382007-09-17 15:49:30 -070035 * \140..\143 - an immediate word or signed byte for operand 0..3
H. Peter Anvina30cc072007-11-18 21:55:26 -080036 * \144..\147 - or 2 (s-field) into opcode byte if operand 0..3
37 * is a signed byte rather than a word. Opcode byte follows.
H. Peter Anvinc1377e92008-10-06 23:40:31 -070038 * \150..\153 - an immediate dword or signed byte for operand 0..3
H. Peter Anvina30cc072007-11-18 21:55:26 -080039 * \154..\157 - or 2 (s-field) into opcode byte if operand 0..3
H. Peter Anvin32cd4c22008-04-04 13:34:53 -070040 * is a signed byte rather than a dword. Opcode byte follows.
H. Peter Anvin401c07e2007-09-17 16:55:04 -070041 * \160..\163 - this instruction uses DREX rather than REX, with the
42 * OC0 field set to 0, and the dest field taken from
43 * operand 0..3.
44 * \164..\167 - this instruction uses DREX rather than REX, with the
45 * OC0 field set to 1, and the dest field taken from
46 * operand 0..3.
H. Peter Anvin401c07e2007-09-17 16:55:04 -070047 * \171 - placement of DREX suffix in the absence of an EA
H. Peter Anvind85d2502008-05-04 17:53:31 -070048 * \172\ab - the register number from operand a in bits 7..4, with
H. Peter Anvin52dc3532008-05-20 19:29:04 -070049 * the 4-bit immediate from operand b in bits 3..0.
H. Peter Anvind58656f2008-05-06 20:11:14 -070050 * \173\xab - the register number from operand a in bits 7..4, with
H. Peter Anvin52dc3532008-05-20 19:29:04 -070051 * the value b in bits 3..0.
52 * \174\a - the register number from operand a in bits 7..4, and
53 * an arbitrary value in bits 3..0 (assembled as zero.)
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000054 * \2ab - a ModRM, calculated on EA in operand a, with the spare
55 * field equal to digit b.
H. Peter Anvin32cd4c22008-04-04 13:34:53 -070056 * \250..\253 - same as \150..\153, except warn if the 64-bit operand
57 * is not equal to the truncated and sign-extended 32-bit
58 * operand; used for 32-bit immediates in 64-bit mode.
H. Peter Anvind85d2502008-05-04 17:53:31 -070059 * \260..\263 - this instruction uses VEX rather than REX, with the
60 * V field taken from operand 0..3.
61 * \270 - this instruction uses VEX rather than REX, with the
62 * V field set to 1111b.
63 *
64 * VEX prefixes are followed by the sequence:
H. Peter Anvinaaa088f2008-05-12 11:13:41 -070065 * \mm\wlp where mm is the M field; and wlp is:
66 * 00 0ww lpp
H. Peter Anvinbd420c72008-05-22 11:24:35 -070067 * [w0] ww = 0 for W = 0
68 * [w1] ww = 1 for W = 1
69 * [wx] ww = 2 for W don't care (always assembled as 0)
70 * [ww] ww = 3 for W used as REX.W
71 *
H. Peter Anvind85d2502008-05-04 17:53:31 -070072 *
H. Peter 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 Anvinfff5a472008-05-20 09:46:24 -0700103 * \360 - no SSE prefix (== \364\331)
104 * \361 - 66 SSE prefix (== \366\331)
105 * \362 - F2 SSE prefix (== \364\332)
106 * \363 - F3 SSE prefix (== \364\333)
H. Peter Anvin62cb6062007-09-11 22:44:03 +0000107 * \364 - operand-size prefix (0x66) not permitted
108 * \365 - address-size prefix (0x67) not permitted
109 * \366 - operand-size prefix (0x66) used as opcode extension
110 * \367 - address-size prefix (0x67) used as opcode extension
H. Peter Anvin788e6c12002-04-30 21:02:01 +0000111 * \370,\371,\372 - match only if operand 0 meets byte jump criteria.
112 * 370 is used for Jcc, 371 is used for JMP.
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000113 * \373 - assemble 0x03 if bits==16, 0x05 if bits==32;
114 * used for conditional jump over longer jump
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000115 */
116
H. Peter Anvinfe501952007-10-02 21:53:51 -0700117#include "compiler.h"
118
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000119#include <stdio.h>
120#include <string.h>
Keith Kaniosb7a89542007-04-12 02:40:54 +0000121#include <inttypes.h>
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000122
123#include "nasm.h"
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000124#include "nasmlib.h"
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000125#include "assemble.h"
126#include "insns.h"
H. Peter Anvina4835d42008-05-20 14:21:29 -0700127#include "tables.h"
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000128
H. Peter Anvindfb91802008-05-20 11:43:53 -0700129/* Initialized to zero by the C standard */
130static const uint8_t const_zero_buf[256];
131
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000132typedef struct {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000133 int sib_present; /* is a SIB byte necessary? */
134 int bytes; /* # of bytes of offset needed */
135 int size; /* lazy - this is sib+bytes+1 */
136 uint8_t modrm, sib, rex, rip; /* the bytes themselves */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000137} ea;
138
Keith Kaniosb7a89542007-04-12 02:40:54 +0000139static uint32_t cpu; /* cpu level received from nasm.c */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000140static efunc errfunc;
141static struct ofmt *outfmt;
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000142static ListGen *list;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000143
H. Peter Anvin3720f7b2008-05-12 11:00:50 -0700144static int64_t calcsize(int32_t, int64_t, int, insn *, const uint8_t *);
H. Peter Anvin833caea2008-10-04 19:02:30 -0700145static void gencode(int32_t segment, int64_t offset, int bits,
146 insn * ins, const struct itemplate *temp,
147 int64_t insn_end);
H. Peter Anvin3360d792007-09-11 04:16:57 +0000148static int matches(const struct itemplate *, insn *, int bits);
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000149static int32_t regflag(const operand *);
150static int32_t regval(const operand *);
151static int rexflags(int, int32_t, int);
152static int op_rexflags(const operand *, int);
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700153static ea *process_ea(operand *, ea *, int, int, int, int32_t);
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700154static void add_asp(insn *, int);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000155
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700156static int has_prefix(insn * ins, enum prefix_pos pos, enum prefixes prefix)
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000157{
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700158 return ins->prefixes[pos] == prefix;
159}
160
161static void assert_no_prefix(insn * ins, enum prefix_pos pos)
162{
163 if (ins->prefixes[pos])
164 errfunc(ERR_NONFATAL, "invalid %s prefix",
165 prefix_name(ins->prefixes[pos]));
166}
167
168static const char *size_name(int size)
169{
170 switch (size) {
171 case 1:
172 return "byte";
173 case 2:
174 return "word";
175 case 4:
176 return "dword";
177 case 8:
178 return "qword";
179 case 10:
180 return "tword";
181 case 16:
182 return "oword";
H. Peter Anvindfb91802008-05-20 11:43:53 -0700183 case 32:
184 return "yword";
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700185 default:
186 return "???";
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000187 }
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700188}
189
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -0700190static void warn_overflow(int size, const struct operand *o)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700191{
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -0700192 if (size < 8 && o->wrt == NO_SEG && o->segment == NO_SEG) {
Charles Craynedd462c82007-11-04 15:28:30 -0800193 int64_t lim = ((int64_t)1 << (size*8))-1;
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -0700194 int64_t data = o->offset;
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000195
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700196 if (data < ~lim || data > lim)
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -0700197 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700198 "%s data exceeds bounds", size_name(size));
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700199 }
200}
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000201/*
202 * This routine wrappers the real output format's output routine,
203 * in order to pass a copy of the data off to the listing file
204 * generator at the same time.
205 */
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800206static void out(int64_t offset, int32_t segto, const void *data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800207 enum out_type type, uint64_t size,
208 int32_t segment, int32_t wrt)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000209{
Keith Kaniosb7a89542007-04-12 02:40:54 +0000210 static int32_t lineno = 0; /* static!!! */
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000211 static char *lnfname = NULL;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800212 uint8_t p[8];
H. Peter Anvineba20a72002-04-30 20:53:55 +0000213
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800214 if (type == OUT_ADDRESS && segment == NO_SEG && wrt == NO_SEG) {
215 /*
216 * This is a non-relocated address, and we're going to
217 * convert it into RAWDATA format.
218 */
219 uint8_t *q = p;
H. Peter Anvind1fb15c2007-11-13 09:37:59 -0800220
221 if (size > 8) {
222 errfunc(ERR_PANIC, "OUT_ADDRESS with size > 8");
223 return;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800224 }
H. Peter Anvind85d2502008-05-04 17:53:31 -0700225
H. Peter Anvind1fb15c2007-11-13 09:37:59 -0800226 WRITEADDR(q, *(int64_t *)data, size);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800227 data = p;
228 type = OUT_RAWDATA;
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000229 }
230
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800231 list->output(offset, data, type, size);
232
Frank Kotlerabebb082003-09-06 04:45:37 +0000233 /*
234 * this call to src_get determines when we call the
235 * debug-format-specific "linenum" function
236 * it updates lineno and lnfname to the current values
237 * returning 0 if "same as last time", -2 if lnfname
238 * changed, and the amount by which lineno changed,
239 * if it did. thus, these variables must be static
240 */
241
H. Peter Anvine2c80182005-01-15 22:15:51 +0000242 if (src_get(&lineno, &lnfname)) {
243 outfmt->current_dfmt->linenum(lnfname, lineno, segto);
H. Peter Anvince616072002-04-30 21:02:23 +0000244 }
H. Peter Anvineba20a72002-04-30 20:53:55 +0000245
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800246 outfmt->output(segto, data, type, size, segment, wrt);
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000247}
248
H. Peter Anvin2d5baaa2008-09-30 16:31:06 -0700249static bool jmp_match(int32_t segment, int64_t offset, int bits,
H. Peter Anvin3720f7b2008-05-12 11:00:50 -0700250 insn * ins, const uint8_t *code)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000251{
Charles Crayne5fbbc8c2007-11-07 19:03:46 -0800252 int64_t isize;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000253 uint8_t c = code[0];
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000254
Charles Craynef1aefd82008-09-30 16:11:32 -0700255 if ((c != 0370 && c != 0371) || (ins->oprs[0].type & STRICT))
H. Peter Anvin2d5baaa2008-09-30 16:31:06 -0700256 return false;
257 if (!optimizing)
258 return false;
259 if (optimizing < 0 && c == 0371)
260 return false;
261
H. Peter Anvine2c80182005-01-15 22:15:51 +0000262 isize = calcsize(segment, offset, bits, ins, code);
263 if (ins->oprs[0].segment != segment)
H. Peter Anvin2d5baaa2008-09-30 16:31:06 -0700264 return false;
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000265
H. Peter Anvin2d5baaa2008-09-30 16:31:06 -0700266 isize = ins->oprs[0].offset - offset - isize; /* isize is delta */
267 return (isize >= -128 && isize <= 127); /* is it byte size? */
H. Peter Anvine2c80182005-01-15 22:15:51 +0000268}
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000269
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800270int64_t assemble(int32_t segment, int64_t offset, int bits, uint32_t cp,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000271 insn * instruction, struct ofmt *output, efunc error,
272 ListGen * listgen)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000273{
H. Peter Anvin3360d792007-09-11 04:16:57 +0000274 const struct itemplate *temp;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000275 int j;
276 int size_prob;
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800277 int64_t insn_end;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000278 int32_t itimes;
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800279 int64_t start = offset;
280 int64_t wsize = 0; /* size for DB etc. */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000281
H. Peter Anvine2c80182005-01-15 22:15:51 +0000282 errfunc = error; /* to pass to other functions */
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000283 cpu = cp;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000284 outfmt = output; /* likewise */
285 list = listgen; /* and again */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000286
H. Peter Anvine2c80182005-01-15 22:15:51 +0000287 switch (instruction->opcode) {
288 case -1:
289 return 0;
290 case I_DB:
291 wsize = 1;
292 break;
293 case I_DW:
294 wsize = 2;
295 break;
296 case I_DD:
297 wsize = 4;
298 break;
299 case I_DQ:
300 wsize = 8;
301 break;
302 case I_DT:
303 wsize = 10;
304 break;
H. Peter Anvincfbe7c32007-09-18 17:49:09 -0700305 case I_DO:
306 wsize = 16;
307 break;
H. Peter Anvindfb91802008-05-20 11:43:53 -0700308 case I_DY:
309 wsize = 32;
310 break;
H. Peter Anvin16b0a332007-09-12 20:27:41 -0700311 default:
312 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000313 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000314
H. Peter Anvineba20a72002-04-30 20:53:55 +0000315 if (wsize) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000316 extop *e;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000317 int32_t t = instruction->times;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000318 if (t < 0)
319 errfunc(ERR_PANIC,
320 "instruction->times < 0 (%ld) in assemble()", t);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000321
H. Peter Anvine2c80182005-01-15 22:15:51 +0000322 while (t--) { /* repeat TIMES times */
323 for (e = instruction->eops; e; e = e->next) {
324 if (e->type == EOT_DB_NUMBER) {
325 if (wsize == 1) {
326 if (e->segment != NO_SEG)
327 errfunc(ERR_NONFATAL,
328 "one-byte relocation attempted");
329 else {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000330 uint8_t out_byte = e->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000331 out(offset, segment, &out_byte,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800332 OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000333 }
Keith Kanios61ff53c2007-04-14 18:54:52 +0000334 } else if (wsize > 8) {
H. Peter Anvin3be5d852008-05-20 14:49:32 -0700335 errfunc(ERR_NONFATAL,
336 "integer supplied to a DT, DO or DY"
Keith Kanios61ff53c2007-04-14 18:54:52 +0000337 " instruction");
H. Peter Anvine2c80182005-01-15 22:15:51 +0000338 } else
339 out(offset, segment, &e->offset,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800340 OUT_ADDRESS, wsize, e->segment, e->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000341 offset += wsize;
H. Peter Anvin518df302008-06-14 16:53:48 -0700342 } else if (e->type == EOT_DB_STRING ||
343 e->type == EOT_DB_STRING_FREE) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000344 int align;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000345
H. Peter Anvine2c80182005-01-15 22:15:51 +0000346 out(offset, segment, e->stringval,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800347 OUT_RAWDATA, e->stringlen, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000348 align = e->stringlen % wsize;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000349
H. Peter Anvine2c80182005-01-15 22:15:51 +0000350 if (align) {
351 align = wsize - align;
H. Peter Anvindfb91802008-05-20 11:43:53 -0700352 out(offset, segment, const_zero_buf,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800353 OUT_RAWDATA, align, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000354 }
355 offset += e->stringlen + align;
356 }
357 }
358 if (t > 0 && t == instruction->times - 1) {
359 /*
360 * Dummy call to list->output to give the offset to the
361 * listing module.
362 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800363 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000364 list->uplevel(LIST_TIMES);
365 }
366 }
367 if (instruction->times > 1)
368 list->downlevel(LIST_TIMES);
369 return offset - start;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000370 }
371
H. Peter Anvine2c80182005-01-15 22:15:51 +0000372 if (instruction->opcode == I_INCBIN) {
H. Peter Anvin518df302008-06-14 16:53:48 -0700373 const char *fname = instruction->eops->stringval;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000374 FILE *fp;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000375
H. Peter Anvin418ca702008-05-30 10:42:30 -0700376 fp = fopen(fname, "rb");
377 if (!fp) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000378 error(ERR_NONFATAL, "`incbin': unable to open file `%s'",
379 fname);
H. Peter Anvin418ca702008-05-30 10:42:30 -0700380 } else if (fseek(fp, 0L, SEEK_END) < 0) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000381 error(ERR_NONFATAL, "`incbin': unable to seek on file `%s'",
382 fname);
H. Peter Anvin418ca702008-05-30 10:42:30 -0700383 } else {
H. Peter Anvin518df302008-06-14 16:53:48 -0700384 static char buf[4096];
385 size_t t = instruction->times;
386 size_t base = 0;
387 size_t len;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000388
H. Peter Anvine2c80182005-01-15 22:15:51 +0000389 len = ftell(fp);
390 if (instruction->eops->next) {
391 base = instruction->eops->next->offset;
392 len -= base;
393 if (instruction->eops->next->next &&
H. Peter Anvin518df302008-06-14 16:53:48 -0700394 len > (size_t)instruction->eops->next->next->offset)
395 len = (size_t)instruction->eops->next->next->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000396 }
397 /*
398 * Dummy call to list->output to give the offset to the
399 * listing module.
400 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800401 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000402 list->uplevel(LIST_INCBIN);
403 while (t--) {
H. Peter Anvin518df302008-06-14 16:53:48 -0700404 size_t l;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000405
H. Peter Anvine2c80182005-01-15 22:15:51 +0000406 fseek(fp, base, SEEK_SET);
407 l = len;
408 while (l > 0) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000409 int32_t m =
Charles Crayne192d5b52007-10-18 19:02:42 -0700410 fread(buf, 1, (l > (int32_t) sizeof(buf) ? (int32_t) sizeof(buf) : l),
H. Peter Anvine2c80182005-01-15 22:15:51 +0000411 fp);
412 if (!m) {
413 /*
414 * This shouldn't happen unless the file
415 * actually changes while we are reading
416 * it.
417 */
418 error(ERR_NONFATAL,
419 "`incbin': unexpected EOF while"
420 " reading file `%s'", fname);
421 t = 0; /* Try to exit cleanly */
422 break;
423 }
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800424 out(offset, segment, buf, OUT_RAWDATA, m,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000425 NO_SEG, NO_SEG);
426 l -= m;
427 }
428 }
429 list->downlevel(LIST_INCBIN);
430 if (instruction->times > 1) {
431 /*
432 * Dummy call to list->output to give the offset to the
433 * listing module.
434 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800435 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000436 list->uplevel(LIST_TIMES);
437 list->downlevel(LIST_TIMES);
438 }
439 fclose(fp);
440 return instruction->times * len;
441 }
442 return 0; /* if we're here, there's an error */
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000443 }
444
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700445 /* Check to see if we need an address-size prefix */
446 add_asp(instruction, bits);
447
H. Peter Anvin6867acc2007-10-10 14:58:45 -0700448 size_prob = false;
H. Peter Anvin70653092007-10-19 14:42:29 -0700449
450 for (temp = nasm_instructions[instruction->opcode]; temp->opcode != -1; temp++){
Keith Kaniosb7a89542007-04-12 02:40:54 +0000451 int m = matches(temp, instruction, bits);
H. Peter Anvin2d5baaa2008-09-30 16:31:06 -0700452 if (m == 100 ||
453 (m == 99 && jmp_match(segment, offset, bits,
454 instruction, temp->code))) {
455 /* Matches! */
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800456 int64_t insn_size = calcsize(segment, offset, bits,
H. Peter Anvin833caea2008-10-04 19:02:30 -0700457 instruction, temp->code);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000458 itimes = instruction->times;
459 if (insn_size < 0) /* shouldn't be, on pass two */
460 error(ERR_PANIC, "errors made it through from pass one");
461 else
462 while (itimes--) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700463 for (j = 0; j < MAXPREFIX; j++) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000464 uint8_t c = 0;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000465 switch (instruction->prefixes[j]) {
466 case P_LOCK:
467 c = 0xF0;
468 break;
469 case P_REPNE:
470 case P_REPNZ:
471 c = 0xF2;
472 break;
473 case P_REPE:
474 case P_REPZ:
475 case P_REP:
476 c = 0xF3;
477 break;
478 case R_CS:
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000479 if (bits == 64) {
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -0700480 error(ERR_WARNING | ERR_PASS2,
Charles Crayne1b851dc2007-11-05 21:49:49 -0800481 "cs segment base generated, but will be ignored in 64-bit mode");
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000482 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000483 c = 0x2E;
484 break;
485 case R_DS:
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000486 if (bits == 64) {
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -0700487 error(ERR_WARNING | ERR_PASS2,
Charles Crayne1b851dc2007-11-05 21:49:49 -0800488 "ds segment base generated, but will be ignored in 64-bit mode");
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000489 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000490 c = 0x3E;
491 break;
492 case R_ES:
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000493 if (bits == 64) {
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -0700494 error(ERR_WARNING | ERR_PASS2,
Charles Crayne1b851dc2007-11-05 21:49:49 -0800495 "es segment base generated, but will be ignored in 64-bit mode");
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000496 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000497 c = 0x26;
498 break;
499 case R_FS:
500 c = 0x64;
501 break;
502 case R_GS:
503 c = 0x65;
504 break;
505 case R_SS:
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000506 if (bits == 64) {
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -0700507 error(ERR_WARNING | ERR_PASS2,
Charles Crayne1b851dc2007-11-05 21:49:49 -0800508 "ss segment base generated, but will be ignored in 64-bit mode");
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000509 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000510 c = 0x36;
511 break;
512 case R_SEGR6:
513 case R_SEGR7:
514 error(ERR_NONFATAL,
515 "segr6 and segr7 cannot be used as prefixes");
516 break;
517 case P_A16:
Keith Kaniosb7a89542007-04-12 02:40:54 +0000518 if (bits == 64) {
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000519 error(ERR_NONFATAL,
520 "16-bit addressing is not supported "
521 "in 64-bit mode");
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700522 } else if (bits != 16)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000523 c = 0x67;
524 break;
525 case P_A32:
526 if (bits != 32)
527 c = 0x67;
528 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700529 case P_A64:
530 if (bits != 64) {
531 error(ERR_NONFATAL,
532 "64-bit addressing is only supported "
533 "in 64-bit mode");
534 }
535 break;
536 case P_ASP:
537 c = 0x67;
538 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000539 case P_O16:
540 if (bits != 16)
541 c = 0x66;
542 break;
543 case P_O32:
Keith Kaniosb7a89542007-04-12 02:40:54 +0000544 if (bits == 16)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000545 c = 0x66;
546 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700547 case P_O64:
548 /* REX.W */
549 break;
550 case P_OSP:
551 c = 0x66;
552 break;
553 case P_none:
554 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000555 default:
556 error(ERR_PANIC, "invalid instruction prefix");
557 }
558 if (c != 0) {
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800559 out(offset, segment, &c, OUT_RAWDATA, 1,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000560 NO_SEG, NO_SEG);
561 offset++;
562 }
H. Peter Anvin70653092007-10-19 14:42:29 -0700563 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000564 insn_end = offset + insn_size;
H. Peter Anvin833caea2008-10-04 19:02:30 -0700565 gencode(segment, offset, bits, instruction,
566 temp, insn_end);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000567 offset += insn_size;
568 if (itimes > 0 && itimes == instruction->times - 1) {
569 /*
570 * Dummy call to list->output to give the offset to the
571 * listing module.
572 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800573 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000574 list->uplevel(LIST_TIMES);
575 }
576 }
577 if (instruction->times > 1)
578 list->downlevel(LIST_TIMES);
579 return offset - start;
580 } else if (m > 0 && m > size_prob) {
581 size_prob = m;
582 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000583 }
H. Peter Anvineba20a72002-04-30 20:53:55 +0000584
H. Peter Anvine2c80182005-01-15 22:15:51 +0000585 if (temp->opcode == -1) { /* didn't match any instruction */
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000586 switch (size_prob) {
587 case 1:
588 error(ERR_NONFATAL, "operation size not specified");
589 break;
590 case 2:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000591 error(ERR_NONFATAL, "mismatch in operand sizes");
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000592 break;
593 case 3:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000594 error(ERR_NONFATAL, "no instruction for this cpu level");
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000595 break;
596 case 4:
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000597 error(ERR_NONFATAL, "instruction not supported in 64-bit mode");
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000598 break;
599 default:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000600 error(ERR_NONFATAL,
601 "invalid combination of opcode and operands");
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000602 break;
603 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000604 }
605 return 0;
606}
607
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800608int64_t insn_size(int32_t segment, int64_t offset, int bits, uint32_t cp,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000609 insn * instruction, efunc error)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000610{
H. Peter Anvin3360d792007-09-11 04:16:57 +0000611 const struct itemplate *temp;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000612
H. Peter Anvine2c80182005-01-15 22:15:51 +0000613 errfunc = error; /* to pass to other functions */
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000614 cpu = cp;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000615
616 if (instruction->opcode == -1)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000617 return 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000618
H. Peter Anvincfbe7c32007-09-18 17:49:09 -0700619 if (instruction->opcode == I_DB || instruction->opcode == I_DW ||
620 instruction->opcode == I_DD || instruction->opcode == I_DQ ||
H. Peter Anvindfb91802008-05-20 11:43:53 -0700621 instruction->opcode == I_DT || instruction->opcode == I_DO ||
622 instruction->opcode == I_DY) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000623 extop *e;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000624 int32_t isize, osize, wsize = 0; /* placate gcc */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000625
H. Peter Anvine2c80182005-01-15 22:15:51 +0000626 isize = 0;
627 switch (instruction->opcode) {
628 case I_DB:
629 wsize = 1;
630 break;
631 case I_DW:
632 wsize = 2;
633 break;
634 case I_DD:
635 wsize = 4;
636 break;
637 case I_DQ:
638 wsize = 8;
639 break;
640 case I_DT:
641 wsize = 10;
642 break;
H. Peter Anvincfbe7c32007-09-18 17:49:09 -0700643 case I_DO:
644 wsize = 16;
645 break;
H. Peter Anvindfb91802008-05-20 11:43:53 -0700646 case I_DY:
647 wsize = 32;
648 break;
H. Peter Anvin16b0a332007-09-12 20:27:41 -0700649 default:
650 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000651 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000652
H. Peter Anvine2c80182005-01-15 22:15:51 +0000653 for (e = instruction->eops; e; e = e->next) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000654 int32_t align;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000655
H. Peter Anvine2c80182005-01-15 22:15:51 +0000656 osize = 0;
657 if (e->type == EOT_DB_NUMBER)
658 osize = 1;
H. Peter Anvin518df302008-06-14 16:53:48 -0700659 else if (e->type == EOT_DB_STRING ||
660 e->type == EOT_DB_STRING_FREE)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000661 osize = e->stringlen;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000662
H. Peter Anvine2c80182005-01-15 22:15:51 +0000663 align = (-osize) % wsize;
664 if (align < 0)
665 align += wsize;
666 isize += osize + align;
667 }
668 return isize * instruction->times;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000669 }
670
H. Peter Anvine2c80182005-01-15 22:15:51 +0000671 if (instruction->opcode == I_INCBIN) {
H. Peter Anvin518df302008-06-14 16:53:48 -0700672 const char *fname = instruction->eops->stringval;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000673 FILE *fp;
H. Peter Anvin518df302008-06-14 16:53:48 -0700674 size_t len;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000675
H. Peter Anvin418ca702008-05-30 10:42:30 -0700676 fp = fopen(fname, "rb");
677 if (!fp)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000678 error(ERR_NONFATAL, "`incbin': unable to open file `%s'",
679 fname);
680 else if (fseek(fp, 0L, SEEK_END) < 0)
681 error(ERR_NONFATAL, "`incbin': unable to seek on file `%s'",
682 fname);
683 else {
684 len = ftell(fp);
685 fclose(fp);
686 if (instruction->eops->next) {
687 len -= instruction->eops->next->offset;
688 if (instruction->eops->next->next &&
H. Peter Anvin518df302008-06-14 16:53:48 -0700689 len > (size_t)instruction->eops->next->next->offset) {
690 len = (size_t)instruction->eops->next->next->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000691 }
692 }
693 return instruction->times * len;
694 }
695 return 0; /* if we're here, there's an error */
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000696 }
697
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700698 /* Check to see if we need an address-size prefix */
699 add_asp(instruction, bits);
700
Keith Kaniosb7a89542007-04-12 02:40:54 +0000701 for (temp = nasm_instructions[instruction->opcode]; temp->opcode != -1; temp++) {
702 int m = matches(temp, instruction, bits);
H. Peter Anvin2d5baaa2008-09-30 16:31:06 -0700703 if (m == 100 ||
704 (m == 99 && jmp_match(segment, offset, bits,
705 instruction, temp->code))) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000706 /* we've matched an instruction. */
Charles Crayne5fbbc8c2007-11-07 19:03:46 -0800707 int64_t isize;
H. Peter Anvin3720f7b2008-05-12 11:00:50 -0700708 const uint8_t *codes = temp->code;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000709 int j;
710
711 isize = calcsize(segment, offset, bits, instruction, codes);
712 if (isize < 0)
713 return -1;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700714 for (j = 0; j < MAXPREFIX; j++) {
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700715 switch (instruction->prefixes[j]) {
716 case P_A16:
717 if (bits != 16)
718 isize++;
719 break;
720 case P_A32:
721 if (bits != 32)
722 isize++;
723 break;
724 case P_O16:
725 if (bits != 16)
726 isize++;
727 break;
728 case P_O32:
729 if (bits == 16)
730 isize++;
731 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700732 case P_A64:
733 case P_O64:
734 case P_none:
735 break;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700736 default:
737 isize++;
738 break;
739 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000740 }
741 return isize * instruction->times;
742 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000743 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000744 return -1; /* didn't match any instruction */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000745}
746
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700747static bool possible_sbyte(operand *o)
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000748{
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700749 return !(o->opflags & OPFLAG_FORWARD) &&
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -0700750 optimizing >= 0 && !(o->type & STRICT);
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000751}
752
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700753/* check that opn[op] is a signed byte of size 16 or 32 */
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700754static bool is_sbyte16(operand *o)
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700755{
756 int16_t v;
757
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700758 if (!possible_sbyte(o))
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700759 return false;
760
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700761 v = o->offset;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700762 return v >= -128 && v <= 127;
763}
764
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700765static bool is_sbyte32(operand *o)
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700766{
767 int32_t v;
768
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700769 if (!possible_sbyte(o))
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700770 return false;
771
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700772 v = o->offset;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700773 return v >= -128 && v <= 127;
774}
775
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -0700776/* check that opn[op] is a signed byte of size 32; warn if this is not
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700777 the original value when extended to 64 bits */
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700778static bool is_sbyte64(operand *o)
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700779{
780 int64_t v64;
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -0700781 int32_t v;
782
783 if (!(o->wrt == NO_SEG && o->segment == NO_SEG))
784 return false; /* Not a pure immediate */
785
786 v64 = o->offset;
787 v = (int32_t)v64;
788
789 if (v64 != v)
790 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
791 "signed dword immediate exceeds bounds");
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700792
793 /* dead in the water on forward reference or External */
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700794 if (!possible_sbyte(o))
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700795 return false;
796
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -0700797 v = o->offset;
798 return v >= -128 && v <= 127;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700799}
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800800static int64_t calcsize(int32_t segment, int64_t offset, int bits,
H. Peter Anvin9f817132008-10-06 19:11:07 -0700801 insn * ins, const uint8_t *codes)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000802{
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800803 int64_t length = 0;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000804 uint8_t c;
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000805 int rex_mask = ~0;
H. Peter Anvin839eca22007-10-29 23:12:47 -0700806 struct operand *opx;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000807
H. Peter Anvine3917fc2007-11-01 14:53:32 -0700808 ins->rex = 0; /* Ensure REX is reset */
809
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700810 if (ins->prefixes[PPS_OSIZE] == P_O64)
811 ins->rex |= REX_W;
812
H. Peter Anvine2c80182005-01-15 22:15:51 +0000813 (void)segment; /* Don't warn that this parameter is unused */
814 (void)offset; /* Don't warn that this parameter is unused */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000815
H. Peter Anvin839eca22007-10-29 23:12:47 -0700816 while (*codes) {
817 c = *codes++;
818 opx = &ins->oprs[c & 3];
819 switch (c) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000820 case 01:
821 case 02:
822 case 03:
823 codes += c, length += c;
824 break;
825 case 04:
826 case 05:
827 case 06:
828 case 07:
829 length++;
830 break;
831 case 010:
832 case 011:
833 case 012:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700834 case 013:
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000835 ins->rex |=
H. Peter Anvin839eca22007-10-29 23:12:47 -0700836 op_rexflags(opx, REX_B|REX_H|REX_P|REX_W);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000837 codes++, length++;
838 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000839 case 014:
840 case 015:
841 case 016:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700842 case 017:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000843 length++;
844 break;
845 case 020:
846 case 021:
847 case 022:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700848 case 023:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000849 length++;
850 break;
851 case 024:
852 case 025:
853 case 026:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700854 case 027:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000855 length++;
856 break;
857 case 030:
858 case 031:
859 case 032:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700860 case 033:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000861 length += 2;
862 break;
863 case 034:
864 case 035:
865 case 036:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700866 case 037:
H. Peter Anvin839eca22007-10-29 23:12:47 -0700867 if (opx->type & (BITS16 | BITS32 | BITS64))
868 length += (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000869 else
870 length += (bits == 16) ? 2 : 4;
871 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000872 case 040:
873 case 041:
874 case 042:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700875 case 043:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000876 length += 4;
877 break;
878 case 044:
879 case 045:
880 case 046:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700881 case 047:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700882 length += ins->addr_size >> 3;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000883 break;
884 case 050:
885 case 051:
886 case 052:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700887 case 053:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000888 length++;
889 break;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000890 case 054:
891 case 055:
892 case 056:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700893 case 057:
Keith Kaniosb7a89542007-04-12 02:40:54 +0000894 length += 8; /* MOV reg64/imm */
895 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000896 case 060:
897 case 061:
898 case 062:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700899 case 063:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000900 length += 2;
901 break;
902 case 064:
903 case 065:
904 case 066:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700905 case 067:
H. Peter Anvin839eca22007-10-29 23:12:47 -0700906 if (opx->type & (BITS16 | BITS32 | BITS64))
907 length += (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000908 else
909 length += (bits == 16) ? 2 : 4;
910 break;
911 case 070:
912 case 071:
913 case 072:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700914 case 073:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000915 length += 4;
916 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700917 case 074:
918 case 075:
919 case 076:
920 case 077:
921 length += 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000922 break;
923 case 0140:
924 case 0141:
925 case 0142:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700926 case 0143:
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700927 length += is_sbyte16(opx) ? 1 : 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000928 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000929 case 0144:
930 case 0145:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700931 case 0146:
932 case 0147:
H. Peter Anvina30cc072007-11-18 21:55:26 -0800933 codes++;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000934 length++;
935 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700936 case 0150:
937 case 0151:
938 case 0152:
939 case 0153:
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700940 length += is_sbyte32(opx) ? 1 : 4;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700941 break;
942 case 0154:
943 case 0155:
944 case 0156:
945 case 0157:
H. Peter Anvina30cc072007-11-18 21:55:26 -0800946 codes++;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700947 length++;
948 break;
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700949 case 0160:
950 case 0161:
951 case 0162:
952 case 0163:
953 length++;
954 ins->rex |= REX_D;
H. Peter Anvind85d2502008-05-04 17:53:31 -0700955 ins->drexdst = regval(opx);
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700956 break;
957 case 0164:
958 case 0165:
959 case 0166:
960 case 0167:
961 length++;
962 ins->rex |= REX_D|REX_OC;
H. Peter Anvind85d2502008-05-04 17:53:31 -0700963 ins->drexdst = regval(opx);
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700964 break;
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700965 case 0171:
966 break;
H. Peter Anvind85d2502008-05-04 17:53:31 -0700967 case 0172:
H. Peter Anvind58656f2008-05-06 20:11:14 -0700968 case 0173:
H. Peter Anvin52dc3532008-05-20 19:29:04 -0700969 case 0174:
H. Peter Anvind85d2502008-05-04 17:53:31 -0700970 codes++;
971 length++;
972 break;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700973 case 0250:
974 case 0251:
975 case 0252:
976 case 0253:
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700977 length += is_sbyte64(opx) ? 1 : 4;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700978 break;
H. Peter Anvind85d2502008-05-04 17:53:31 -0700979 case 0260:
980 case 0261:
981 case 0262:
982 case 0263:
H. Peter Anvind85d2502008-05-04 17:53:31 -0700983 ins->rex |= REX_V;
984 ins->drexdst = regval(opx);
985 ins->vex_m = *codes++;
986 ins->vex_wlp = *codes++;
987 break;
988 case 0270:
H. Peter Anvind85d2502008-05-04 17:53:31 -0700989 ins->rex |= REX_V;
990 ins->drexdst = 0;
991 ins->vex_m = *codes++;
992 ins->vex_wlp = *codes++;
993 break;
H. Peter Anvinc1377e92008-10-06 23:40:31 -0700994 case 0274:
995 case 0275:
996 case 0276:
997 case 0277:
998 length++;
999 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001000 case 0300:
1001 case 0301:
H. Peter Anvin70653092007-10-19 14:42:29 -07001002 case 0302:
1003 case 0303:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001004 break;
1005 case 0310:
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07001006 if (bits == 64)
1007 return -1;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001008 length += (bits != 16) && !has_prefix(ins, PPS_ASIZE, P_A16);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001009 break;
1010 case 0311:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001011 length += (bits != 32) && !has_prefix(ins, PPS_ASIZE, P_A32);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001012 break;
1013 case 0312:
H. Peter Anvin70653092007-10-19 14:42:29 -07001014 break;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001015 case 0313:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001016 if (bits != 64 || has_prefix(ins, PPS_ASIZE, P_A16) ||
1017 has_prefix(ins, PPS_ASIZE, P_A32))
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07001018 return -1;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001019 break;
H. Peter Anvin23440102007-11-12 21:02:33 -08001020 case 0314:
1021 case 0315:
1022 case 0316:
1023 case 0317:
1024 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001025 case 0320:
Keith Kaniosb7a89542007-04-12 02:40:54 +00001026 length += (bits != 16);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001027 break;
1028 case 0321:
1029 length += (bits == 16);
1030 break;
1031 case 0322:
1032 break;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001033 case 0323:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001034 rex_mask &= ~REX_W;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001035 break;
1036 case 0324:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001037 ins->rex |= REX_W;
H. Peter Anvin8d7316a2007-04-18 02:27:18 +00001038 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001039 case 0330:
1040 codes++, length++;
1041 break;
1042 case 0331:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001043 break;
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001044 case 0332:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001045 case 0333:
1046 length++;
1047 break;
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001048 case 0334:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001049 ins->rex |= REX_L;
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001050 break;
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001051 case 0335:
1052 break;
H. Peter Anvin962e3052008-08-28 17:47:16 -07001053 case 0336:
1054 if (!ins->prefixes[PPS_LREP])
1055 ins->prefixes[PPS_LREP] = P_REP;
1056 break;
1057 case 0337:
1058 if (!ins->prefixes[PPS_LREP])
1059 ins->prefixes[PPS_LREP] = P_REPNE;
1060 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001061 case 0340:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001062 if (ins->oprs[0].segment != NO_SEG)
1063 errfunc(ERR_NONFATAL, "attempt to reserve non-constant"
1064 " quantity of BSS space");
1065 else
H. Peter Anvin428fd672007-11-15 10:25:52 -08001066 length += ins->oprs[0].offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001067 break;
H. Peter Anvinfff5a472008-05-20 09:46:24 -07001068 case 0360:
1069 break;
1070 case 0361:
1071 case 0362:
1072 case 0363:
1073 length++;
1074 break;
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001075 case 0364:
1076 case 0365:
1077 break;
Keith Kanios48af1772007-08-17 07:37:52 +00001078 case 0366:
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001079 case 0367:
1080 length++;
1081 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001082 case 0370:
1083 case 0371:
1084 case 0372:
1085 break;
1086 case 0373:
1087 length++;
1088 break;
1089 default: /* can't do it by 'case' statements */
1090 if (c >= 0100 && c <= 0277) { /* it's an EA */
1091 ea ea_data;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001092 int rfield;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001093 int32_t rflags;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001094 ea_data.rex = 0; /* Ensure ea.REX is initially 0 */
H. Peter Anvin70653092007-10-19 14:42:29 -07001095
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001096 if (c <= 0177) {
1097 /* pick rfield from operand b */
1098 rflags = regflag(&ins->oprs[c & 7]);
H. Peter Anvina4835d42008-05-20 14:21:29 -07001099 rfield = nasm_regvals[ins->oprs[c & 7].basereg];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001100 } else {
1101 rflags = 0;
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001102 rfield = c & 7;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001103 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00001104
H. Peter Anvine2c80182005-01-15 22:15:51 +00001105 if (!process_ea
Keith Kaniosb7a89542007-04-12 02:40:54 +00001106 (&ins->oprs[(c >> 3) & 7], &ea_data, bits,
H. Peter Anvin1c3277b2008-07-19 21:38:56 -07001107 ins->addr_size, rfield, rflags)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001108 errfunc(ERR_NONFATAL, "invalid effective address");
1109 return -1;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001110 } else {
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001111 ins->rex |= ea_data.rex;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001112 length += ea_data.size;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001113 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001114 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001115 errfunc(ERR_PANIC, "internal instruction table corrupt"
1116 ": instruction code 0x%02X given", c);
H. Peter Anvin839eca22007-10-29 23:12:47 -07001117 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001118 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001119 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001120
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001121 ins->rex &= rex_mask;
H. Peter Anvin70653092007-10-19 14:42:29 -07001122
H. Peter Anvind85d2502008-05-04 17:53:31 -07001123 if (ins->rex & REX_V) {
1124 int bad32 = REX_R|REX_W|REX_X|REX_B;
1125
1126 if (ins->rex & REX_H) {
1127 errfunc(ERR_NONFATAL, "cannot use high register in vex instruction");
1128 return -1;
1129 }
1130 switch (ins->vex_wlp & 030) {
1131 case 000:
H. Peter Anvinbd420c72008-05-22 11:24:35 -07001132 case 020:
H. Peter Anvind85d2502008-05-04 17:53:31 -07001133 ins->rex &= ~REX_W;
1134 break;
1135 case 010:
1136 ins->rex |= REX_W;
1137 bad32 &= ~REX_W;
1138 break;
H. Peter Anvinbd420c72008-05-22 11:24:35 -07001139 case 030:
H. Peter Anvind85d2502008-05-04 17:53:31 -07001140 /* Follow REX_W */
1141 break;
1142 }
1143
1144 if (bits != 64 && ((ins->rex & bad32) || ins->drexdst > 7)) {
1145 errfunc(ERR_NONFATAL, "invalid operands in non-64-bit mode");
1146 return -1;
1147 }
1148 if (ins->vex_m != 1 || (ins->rex & (REX_W|REX_R|REX_B)))
1149 length += 3;
1150 else
1151 length += 2;
1152 } else if (ins->rex & REX_D) {
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001153 if (ins->rex & REX_H) {
1154 errfunc(ERR_NONFATAL, "cannot use high register in drex instruction");
1155 return -1;
1156 }
H. Peter Anvind85d2502008-05-04 17:53:31 -07001157 if (bits != 64 && ((ins->rex & (REX_R|REX_W|REX_X|REX_B)) ||
H. Peter Anvincf5180a2007-09-17 17:25:27 -07001158 ins->drexdst > 7)) {
1159 errfunc(ERR_NONFATAL, "invalid operands in non-64-bit mode");
1160 return -1;
1161 }
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001162 length++;
1163 } else if (ins->rex & REX_REAL) {
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001164 if (ins->rex & REX_H) {
1165 errfunc(ERR_NONFATAL, "cannot use high register in rex instruction");
1166 return -1;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001167 } else if (bits == 64) {
1168 length++;
1169 } else if ((ins->rex & REX_L) &&
1170 !(ins->rex & (REX_P|REX_W|REX_X|REX_B)) &&
1171 cpu >= IF_X86_64) {
1172 /* LOCK-as-REX.R */
1173 assert_no_prefix(ins, PPS_LREP);
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001174 length++;
H. Peter Anvin8d7316a2007-04-18 02:27:18 +00001175 } else {
H. Peter Anvincf5180a2007-09-17 17:25:27 -07001176 errfunc(ERR_NONFATAL, "invalid operands in non-64-bit mode");
1177 return -1;
H. Peter Anvin8d7316a2007-04-18 02:27:18 +00001178 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00001179 }
1180
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001181 return length;
1182}
Keith Kaniosb7a89542007-04-12 02:40:54 +00001183
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001184#define EMIT_REX() \
H. Peter Anvind85d2502008-05-04 17:53:31 -07001185 if (!(ins->rex & (REX_D|REX_V)) && (ins->rex & REX_REAL) && (bits == 64)) { \
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001186 ins->rex = (ins->rex & REX_REAL)|REX_P; \
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001187 out(offset, segment, &ins->rex, OUT_RAWDATA, 1, NO_SEG, NO_SEG); \
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001188 ins->rex = 0; \
1189 offset += 1; \
1190 }
1191
Charles Crayne1f8bc4c2007-11-06 18:27:23 -08001192static void gencode(int32_t segment, int64_t offset, int bits,
H. Peter Anvin833caea2008-10-04 19:02:30 -07001193 insn * ins, const struct itemplate *temp,
1194 int64_t insn_end)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001195{
Keith Kaniosa6dfa782007-04-13 16:47:53 +00001196 static char condval[] = { /* conditional opcodes */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001197 0x7, 0x3, 0x2, 0x6, 0x2, 0x4, 0xF, 0xD, 0xC, 0xE, 0x6, 0x2,
1198 0x3, 0x7, 0x3, 0x5, 0xE, 0xC, 0xD, 0xF, 0x1, 0xB, 0x9, 0x5,
1199 0x0, 0xA, 0xA, 0xB, 0x8, 0x4
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001200 };
Keith Kaniosb7a89542007-04-12 02:40:54 +00001201 uint8_t c;
1202 uint8_t bytes[4];
Charles Crayne1f8bc4c2007-11-06 18:27:23 -08001203 int64_t size;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001204 int64_t data;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001205 struct operand *opx;
H. Peter Anvin833caea2008-10-04 19:02:30 -07001206 const uint8_t *codes = temp->code;
H. Peter Anvin70653092007-10-19 14:42:29 -07001207
H. Peter Anvin839eca22007-10-29 23:12:47 -07001208 while (*codes) {
1209 c = *codes++;
1210 opx = &ins->oprs[c & 3];
1211 switch (c) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001212 case 01:
1213 case 02:
1214 case 03:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001215 EMIT_REX();
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001216 out(offset, segment, codes, OUT_RAWDATA, c, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001217 codes += c;
1218 offset += c;
1219 break;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001220
H. Peter Anvine2c80182005-01-15 22:15:51 +00001221 case 04:
1222 case 06:
1223 switch (ins->oprs[0].basereg) {
1224 case R_CS:
1225 bytes[0] = 0x0E + (c == 0x04 ? 1 : 0);
1226 break;
1227 case R_DS:
1228 bytes[0] = 0x1E + (c == 0x04 ? 1 : 0);
1229 break;
1230 case R_ES:
1231 bytes[0] = 0x06 + (c == 0x04 ? 1 : 0);
1232 break;
1233 case R_SS:
1234 bytes[0] = 0x16 + (c == 0x04 ? 1 : 0);
1235 break;
1236 default:
1237 errfunc(ERR_PANIC,
1238 "bizarre 8086 segment register received");
1239 }
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001240 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001241 offset++;
1242 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001243
H. Peter Anvine2c80182005-01-15 22:15:51 +00001244 case 05:
1245 case 07:
1246 switch (ins->oprs[0].basereg) {
1247 case R_FS:
1248 bytes[0] = 0xA0 + (c == 0x05 ? 1 : 0);
1249 break;
1250 case R_GS:
1251 bytes[0] = 0xA8 + (c == 0x05 ? 1 : 0);
1252 break;
1253 default:
1254 errfunc(ERR_PANIC,
1255 "bizarre 386 segment register received");
1256 }
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001257 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001258 offset++;
1259 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001260
H. Peter Anvine2c80182005-01-15 22:15:51 +00001261 case 010:
1262 case 011:
1263 case 012:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001264 case 013:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001265 EMIT_REX();
H. Peter Anvin839eca22007-10-29 23:12:47 -07001266 bytes[0] = *codes++ + ((regval(opx)) & 7);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001267 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001268 offset += 1;
1269 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001270
H. Peter Anvine2c80182005-01-15 22:15:51 +00001271 case 014:
1272 case 015:
1273 case 016:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001274 case 017:
H. Peter Anvin6c80ab62008-10-04 18:50:47 -07001275 /* The test for BITS8 and SBYTE here is intended to avoid
1276 warning on optimizer actions due to SBYTE, while still
1277 warn on explicit BYTE directives. Also warn, obviously,
1278 if the optimizer isn't enabled. */
1279 if (((opx->type & BITS8) ||
H. Peter Anvin833caea2008-10-04 19:02:30 -07001280 !(opx->type & temp->opd[c & 3] & BYTENESS)) &&
H. Peter Anvin6c80ab62008-10-04 18:50:47 -07001281 (opx->offset < -128 || opx->offset > 127)) {
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -07001282 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
H. Peter Anvin72c64372008-01-08 22:13:48 -08001283 "signed byte value exceeds bounds");
H. Peter Anvin6c80ab62008-10-04 18:50:47 -07001284 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001285 if (opx->segment != NO_SEG) {
1286 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001287 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001288 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001289 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001290 bytes[0] = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001291 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001292 NO_SEG);
1293 }
1294 offset += 1;
1295 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001296
H. Peter Anvine2c80182005-01-15 22:15:51 +00001297 case 020:
1298 case 021:
1299 case 022:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001300 case 023:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001301 if (opx->offset < -256 || opx->offset > 255) {
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -07001302 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
H. Peter Anvin72c64372008-01-08 22:13:48 -08001303 "byte value exceeds bounds");
H. Peter Anvine2c80182005-01-15 22:15:51 +00001304 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001305 if (opx->segment != NO_SEG) {
1306 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001307 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001308 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001309 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001310 bytes[0] = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001311 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001312 NO_SEG);
1313 }
1314 offset += 1;
1315 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001316
H. Peter Anvine2c80182005-01-15 22:15:51 +00001317 case 024:
1318 case 025:
1319 case 026:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001320 case 027:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001321 if (opx->offset < 0 || opx->offset > 255)
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -07001322 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
H. Peter Anvin72c64372008-01-08 22:13:48 -08001323 "unsigned byte value exceeds bounds");
H. Peter Anvin839eca22007-10-29 23:12:47 -07001324 if (opx->segment != NO_SEG) {
1325 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001326 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001327 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001328 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001329 bytes[0] = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001330 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001331 NO_SEG);
1332 }
1333 offset += 1;
1334 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001335
H. Peter Anvine2c80182005-01-15 22:15:51 +00001336 case 030:
1337 case 031:
1338 case 032:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001339 case 033:
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -07001340 warn_overflow(2, opx);
H. Peter Anvin839eca22007-10-29 23:12:47 -07001341 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001342 out(offset, segment, &data, OUT_ADDRESS, 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001343 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001344 offset += 2;
1345 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001346
H. Peter Anvine2c80182005-01-15 22:15:51 +00001347 case 034:
1348 case 035:
1349 case 036:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001350 case 037:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001351 if (opx->type & (BITS16 | BITS32))
1352 size = (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001353 else
1354 size = (bits == 16) ? 2 : 4;
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -07001355 warn_overflow(size, opx);
H. Peter Anvin839eca22007-10-29 23:12:47 -07001356 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001357 out(offset, segment, &data, OUT_ADDRESS, size,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001358 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001359 offset += size;
1360 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001361
H. Peter Anvine2c80182005-01-15 22:15:51 +00001362 case 040:
1363 case 041:
1364 case 042:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001365 case 043:
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -07001366 warn_overflow(4, opx);
H. Peter Anvin839eca22007-10-29 23:12:47 -07001367 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001368 out(offset, segment, &data, OUT_ADDRESS, 4,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001369 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001370 offset += 4;
1371 break;
H. Peter Anvin3ba46772002-05-27 23:19:35 +00001372
H. Peter Anvine2c80182005-01-15 22:15:51 +00001373 case 044:
1374 case 045:
1375 case 046:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001376 case 047:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001377 data = opx->offset;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001378 size = ins->addr_size >> 3;
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -07001379 warn_overflow(size, opx);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001380 out(offset, segment, &data, OUT_ADDRESS, size,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001381 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001382 offset += size;
1383 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001384
H. Peter Anvine2c80182005-01-15 22:15:51 +00001385 case 050:
1386 case 051:
1387 case 052:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001388 case 053:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001389 if (opx->segment != segment)
H. Peter Anvine2c80182005-01-15 22:15:51 +00001390 errfunc(ERR_NONFATAL,
1391 "short relative jump outside segment");
H. Peter Anvin839eca22007-10-29 23:12:47 -07001392 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001393 if (data > 127 || data < -128)
1394 errfunc(ERR_NONFATAL, "short jump is out of range");
1395 bytes[0] = data;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001396 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001397 offset += 1;
1398 break;
H. Peter Anvin70653092007-10-19 14:42:29 -07001399
Keith Kaniosb7a89542007-04-12 02:40:54 +00001400 case 054:
1401 case 055:
1402 case 056:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001403 case 057:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001404 data = (int64_t)opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001405 out(offset, segment, &data, OUT_ADDRESS, 8,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001406 opx->segment, opx->wrt);
Keith Kaniosb7a89542007-04-12 02:40:54 +00001407 offset += 8;
1408 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001409
H. Peter Anvine2c80182005-01-15 22:15:51 +00001410 case 060:
1411 case 061:
1412 case 062:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001413 case 063:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001414 if (opx->segment != segment) {
1415 data = opx->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001416 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001417 OUT_REL2ADR, insn_end - offset,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001418 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001419 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001420 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001421 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001422 OUT_ADDRESS, 2, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001423 }
1424 offset += 2;
1425 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001426
H. Peter Anvine2c80182005-01-15 22:15:51 +00001427 case 064:
1428 case 065:
1429 case 066:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001430 case 067:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001431 if (opx->type & (BITS16 | BITS32 | BITS64))
1432 size = (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001433 else
1434 size = (bits == 16) ? 2 : 4;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001435 if (opx->segment != segment) {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001436 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001437 out(offset, segment, &data,
1438 size == 2 ? OUT_REL2ADR : OUT_REL4ADR,
1439 insn_end - offset, opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001440 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001441 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001442 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001443 OUT_ADDRESS, size, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001444 }
1445 offset += size;
1446 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001447
H. Peter Anvine2c80182005-01-15 22:15:51 +00001448 case 070:
1449 case 071:
1450 case 072:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001451 case 073:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001452 if (opx->segment != segment) {
1453 data = opx->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001454 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001455 OUT_REL4ADR, insn_end - offset,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001456 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001457 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001458 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001459 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001460 OUT_ADDRESS, 4, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001461 }
1462 offset += 4;
1463 break;
H. Peter Anvinaf535c12002-04-30 20:59:21 +00001464
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001465 case 074:
1466 case 075:
1467 case 076:
1468 case 077:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001469 if (opx->segment == NO_SEG)
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001470 errfunc(ERR_NONFATAL, "value referenced by FAR is not"
1471 " relocatable");
H. Peter Anvindfb91802008-05-20 11:43:53 -07001472 data = 0;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001473 out(offset, segment, &data, OUT_ADDRESS, 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001474 outfmt->segbase(1 + opx->segment),
1475 opx->wrt);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001476 offset += 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001477 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001478
H. Peter Anvine2c80182005-01-15 22:15:51 +00001479 case 0140:
1480 case 0141:
1481 case 0142:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001482 case 0143:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001483 data = opx->offset;
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -07001484 warn_overflow(2, opx);
H. Peter Anvin1c3277b2008-07-19 21:38:56 -07001485 if (is_sbyte16(opx)) {
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001486 bytes[0] = data;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001487 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001488 NO_SEG);
1489 offset++;
1490 } else {
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001491 out(offset, segment, &data, OUT_ADDRESS, 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001492 opx->segment, opx->wrt);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001493 offset += 2;
1494 }
1495 break;
1496
1497 case 0144:
1498 case 0145:
1499 case 0146:
1500 case 0147:
1501 EMIT_REX();
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001502 bytes[0] = *codes++;
H. Peter Anvin1c3277b2008-07-19 21:38:56 -07001503 if (is_sbyte16(opx))
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001504 bytes[0] |= 2; /* s-bit */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001505 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001506 offset++;
1507 break;
1508
1509 case 0150:
1510 case 0151:
1511 case 0152:
1512 case 0153:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001513 data = opx->offset;
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -07001514 warn_overflow(4, opx);
H. Peter Anvin1c3277b2008-07-19 21:38:56 -07001515 if (is_sbyte32(opx)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001516 bytes[0] = data;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001517 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001518 NO_SEG);
1519 offset++;
1520 } else {
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001521 out(offset, segment, &data, OUT_ADDRESS, 4,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001522 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001523 offset += 4;
1524 }
1525 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001526
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001527 case 0154:
1528 case 0155:
1529 case 0156:
1530 case 0157:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001531 EMIT_REX();
H. Peter Anvine2c80182005-01-15 22:15:51 +00001532 bytes[0] = *codes++;
H. Peter Anvin1c3277b2008-07-19 21:38:56 -07001533 if (is_sbyte32(opx))
H. Peter Anvine2c80182005-01-15 22:15:51 +00001534 bytes[0] |= 2; /* s-bit */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001535 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001536 offset++;
1537 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001538
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001539 case 0160:
1540 case 0161:
1541 case 0162:
1542 case 0163:
1543 case 0164:
1544 case 0165:
1545 case 0166:
1546 case 0167:
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001547 break;
1548
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001549 case 0171:
1550 bytes[0] =
1551 (ins->drexdst << 4) |
1552 (ins->rex & REX_OC ? 0x08 : 0) |
1553 (ins->rex & (REX_R|REX_X|REX_B));
1554 ins->rex = 0;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001555 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001556 offset++;
1557 break;
1558
H. Peter Anvind85d2502008-05-04 17:53:31 -07001559 case 0172:
1560 c = *codes++;
1561 opx = &ins->oprs[c >> 3];
H. Peter Anvina4835d42008-05-20 14:21:29 -07001562 bytes[0] = nasm_regvals[opx->basereg] << 4;
H. Peter Anvind85d2502008-05-04 17:53:31 -07001563 opx = &ins->oprs[c & 7];
1564 if (opx->segment != NO_SEG || opx->wrt != NO_SEG) {
1565 errfunc(ERR_NONFATAL,
1566 "non-absolute expression not permitted as argument %d",
1567 c & 7);
1568 } else {
1569 if (opx->offset & ~15) {
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -07001570 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
H. Peter Anvind85d2502008-05-04 17:53:31 -07001571 "four-bit argument exceeds bounds");
1572 }
1573 bytes[0] |= opx->offset & 15;
1574 }
1575 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1576 offset++;
1577 break;
1578
H. Peter Anvind58656f2008-05-06 20:11:14 -07001579 case 0173:
1580 c = *codes++;
1581 opx = &ins->oprs[c >> 4];
H. Peter Anvina4835d42008-05-20 14:21:29 -07001582 bytes[0] = nasm_regvals[opx->basereg] << 4;
H. Peter Anvind58656f2008-05-06 20:11:14 -07001583 bytes[0] |= c & 15;
1584 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1585 offset++;
1586 break;
1587
H. Peter Anvin52dc3532008-05-20 19:29:04 -07001588 case 0174:
1589 c = *codes++;
1590 opx = &ins->oprs[c];
1591 bytes[0] = nasm_regvals[opx->basereg] << 4;
1592 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1593 offset++;
1594 break;
1595
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001596 case 0250:
1597 case 0251:
1598 case 0252:
1599 case 0253:
1600 data = opx->offset;
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -07001601 warn_overflow(4, opx);
1602 if (is_sbyte64(opx)) {
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001603 bytes[0] = data;
1604 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
1605 NO_SEG);
1606 offset++;
1607 } else {
1608 out(offset, segment, &data, OUT_ADDRESS, 4,
1609 opx->segment, opx->wrt);
1610 offset += 4;
1611 }
1612 break;
1613
H. Peter Anvind85d2502008-05-04 17:53:31 -07001614 case 0260:
1615 case 0261:
1616 case 0262:
1617 case 0263:
1618 case 0270:
1619 codes += 2;
1620 if (ins->vex_m != 1 || (ins->rex & (REX_W|REX_X|REX_B))) {
1621 bytes[0] = 0xc4;
H. Peter Anvin4d2c38c2008-05-04 23:15:13 -07001622 bytes[1] = ins->vex_m | ((~ins->rex & 7) << 5);
H. Peter Anvind85d2502008-05-04 17:53:31 -07001623 bytes[2] = ((ins->rex & REX_W) << (7-3)) |
H. Peter Anvin4d2c38c2008-05-04 23:15:13 -07001624 ((~ins->drexdst & 15)<< 3) | (ins->vex_wlp & 07);
H. Peter Anvind85d2502008-05-04 17:53:31 -07001625 out(offset, segment, &bytes, OUT_RAWDATA, 3, NO_SEG, NO_SEG);
1626 offset += 3;
1627 } else {
1628 bytes[0] = 0xc5;
H. Peter Anvin4d2c38c2008-05-04 23:15:13 -07001629 bytes[1] = ((~ins->rex & REX_R) << (7-2)) |
1630 ((~ins->drexdst & 15) << 3) | (ins->vex_wlp & 07);
H. Peter Anvind85d2502008-05-04 17:53:31 -07001631 out(offset, segment, &bytes, OUT_RAWDATA, 2, NO_SEG, NO_SEG);
1632 offset += 2;
1633 }
1634 break;
1635
H. Peter Anvinc1377e92008-10-06 23:40:31 -07001636 case 0274:
1637 case 0275:
1638 case 0276:
1639 case 0277:
1640 {
1641 uint64_t uv, um;
1642 int s;
1643
1644 if (ins->rex & REX_W)
1645 s = 64;
1646 else if (ins->prefixes[PPS_OSIZE] == P_O16)
1647 s = 16;
1648 else if (ins->prefixes[PPS_OSIZE] == P_O32)
1649 s = 32;
1650 else
1651 s = bits;
1652
1653 um = (uint64_t)2 << (s-1);
1654 uv = opx->offset;
1655
1656 if (uv > 127 && uv < (uint64_t)-128 &&
1657 (uv < um-128 || uv > um-1)) {
1658 errfunc(ERR_WARNING | ERR_PASS2 | ERR_WARN_NOV,
1659 "signed byte value exceeds bounds");
1660 }
1661 if (opx->segment != NO_SEG) {
1662 data = um;
1663 out(offset, segment, &data, OUT_ADDRESS, 1,
1664 opx->segment, opx->wrt);
1665 } else {
1666 bytes[0] = um;
1667 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
1668 NO_SEG);
1669 }
1670 offset += 1;
1671 break;
1672 }
1673
H. Peter Anvine2c80182005-01-15 22:15:51 +00001674 case 0300:
1675 case 0301:
1676 case 0302:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001677 case 0303:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001678 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001679
H. Peter Anvine2c80182005-01-15 22:15:51 +00001680 case 0310:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001681 if (bits == 32 && !has_prefix(ins, PPS_ASIZE, P_A16)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001682 *bytes = 0x67;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001683 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001684 offset += 1;
1685 } else
1686 offset += 0;
1687 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001688
H. Peter Anvine2c80182005-01-15 22:15:51 +00001689 case 0311:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001690 if (bits != 32 && !has_prefix(ins, PPS_ASIZE, P_A32)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001691 *bytes = 0x67;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001692 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001693 offset += 1;
1694 } else
1695 offset += 0;
1696 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001697
H. Peter Anvine2c80182005-01-15 22:15:51 +00001698 case 0312:
1699 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001700
Keith Kaniosb7a89542007-04-12 02:40:54 +00001701 case 0313:
1702 ins->rex = 0;
1703 break;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07001704
H. Peter Anvin23440102007-11-12 21:02:33 -08001705 case 0314:
1706 case 0315:
1707 case 0316:
1708 case 0317:
1709 break;
1710
H. Peter Anvine2c80182005-01-15 22:15:51 +00001711 case 0320:
Keith Kaniosb7a89542007-04-12 02:40:54 +00001712 if (bits != 16) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001713 *bytes = 0x66;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001714 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001715 offset += 1;
1716 } else
1717 offset += 0;
1718 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001719
H. Peter Anvine2c80182005-01-15 22:15:51 +00001720 case 0321:
1721 if (bits == 16) {
1722 *bytes = 0x66;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001723 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001724 offset += 1;
1725 } else
1726 offset += 0;
1727 break;
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001728
H. Peter Anvine2c80182005-01-15 22:15:51 +00001729 case 0322:
H. Peter Anvin70653092007-10-19 14:42:29 -07001730 case 0323:
1731 break;
1732
Keith Kaniosb7a89542007-04-12 02:40:54 +00001733 case 0324:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001734 ins->rex |= REX_W;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001735 break;
H. Peter Anvin70653092007-10-19 14:42:29 -07001736
H. Peter Anvine2c80182005-01-15 22:15:51 +00001737 case 0330:
1738 *bytes = *codes++ ^ condval[ins->condition];
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001739 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001740 offset += 1;
1741 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001742
H. Peter Anvine2c80182005-01-15 22:15:51 +00001743 case 0331:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001744 break;
H. Peter Anvinaf535c12002-04-30 20:59:21 +00001745
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001746 case 0332:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001747 case 0333:
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001748 *bytes = c - 0332 + 0xF2;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001749 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001750 offset += 1;
1751 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001752
Keith Kanios48af1772007-08-17 07:37:52 +00001753 case 0334:
1754 if (ins->rex & REX_R) {
1755 *bytes = 0xF0;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001756 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
Keith Kanios48af1772007-08-17 07:37:52 +00001757 offset += 1;
1758 }
1759 ins->rex &= ~(REX_L|REX_R);
1760 break;
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001761
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001762 case 0335:
1763 break;
1764
H. Peter Anvin962e3052008-08-28 17:47:16 -07001765 case 0336:
1766 case 0337:
1767 break;
1768
H. Peter Anvine2c80182005-01-15 22:15:51 +00001769 case 0340:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001770 if (ins->oprs[0].segment != NO_SEG)
1771 errfunc(ERR_PANIC, "non-constant BSS size in pass two");
1772 else {
H. Peter Anvin428fd672007-11-15 10:25:52 -08001773 int64_t size = ins->oprs[0].offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001774 if (size > 0)
1775 out(offset, segment, NULL,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001776 OUT_RESERVE, size, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001777 offset += size;
1778 }
1779 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001780
H. Peter Anvinfff5a472008-05-20 09:46:24 -07001781 case 0360:
1782 break;
1783
1784 case 0361:
1785 bytes[0] = 0x66;
1786 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1787 offset += 1;
1788 break;
1789
1790 case 0362:
1791 case 0363:
1792 bytes[0] = c - 0362 + 0xf2;
1793 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1794 offset += 1;
1795 break;
1796
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001797 case 0364:
1798 case 0365:
1799 break;
1800
Keith Kanios48af1772007-08-17 07:37:52 +00001801 case 0366:
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001802 case 0367:
1803 *bytes = c - 0366 + 0x66;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001804 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
Keith Kanios48af1772007-08-17 07:37:52 +00001805 offset += 1;
1806 break;
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001807
H. Peter Anvine2c80182005-01-15 22:15:51 +00001808 case 0370:
1809 case 0371:
1810 case 0372:
1811 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001812
H. Peter Anvine2c80182005-01-15 22:15:51 +00001813 case 0373:
1814 *bytes = bits == 16 ? 3 : 5;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001815 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001816 offset += 1;
1817 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001818
H. Peter Anvine2c80182005-01-15 22:15:51 +00001819 default: /* can't do it by 'case' statements */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001820 if (c >= 0100 && c <= 0277) { /* it's an EA */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001821 ea ea_data;
1822 int rfield;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001823 int32_t rflags;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001824 uint8_t *p;
1825 int32_t s;
H. Peter Anvin9f817132008-10-06 19:11:07 -07001826 enum out_type type;
H. Peter Anvin70653092007-10-19 14:42:29 -07001827
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001828 if (c <= 0177) {
1829 /* pick rfield from operand b */
1830 rflags = regflag(&ins->oprs[c & 7]);
H. Peter Anvina4835d42008-05-20 14:21:29 -07001831 rfield = nasm_regvals[ins->oprs[c & 7].basereg];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001832 } else {
1833 /* rfield is constant */
1834 rflags = 0;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001835 rfield = c & 7;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001836 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001837
1838 if (!process_ea
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001839 (&ins->oprs[(c >> 3) & 7], &ea_data, bits,
H. Peter Anvin1c3277b2008-07-19 21:38:56 -07001840 ins->addr_size, rfield, rflags)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001841 errfunc(ERR_NONFATAL, "invalid effective address");
1842 }
H. Peter Anvin70653092007-10-19 14:42:29 -07001843
Charles Crayne7e975552007-11-03 22:06:13 -07001844
H. Peter Anvine2c80182005-01-15 22:15:51 +00001845 p = bytes;
1846 *p++ = ea_data.modrm;
1847 if (ea_data.sib_present)
1848 *p++ = ea_data.sib;
1849
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001850 /* DREX suffixes come between the SIB and the displacement */
1851 if (ins->rex & REX_D) {
1852 *p++ =
1853 (ins->drexdst << 4) |
1854 (ins->rex & REX_OC ? 0x08 : 0) |
1855 (ins->rex & (REX_R|REX_X|REX_B));
1856 ins->rex = 0;
1857 }
1858
H. Peter Anvine2c80182005-01-15 22:15:51 +00001859 s = p - bytes;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001860 out(offset, segment, bytes, OUT_RAWDATA, s, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001861
Victor van den Elzencf9332c2008-10-01 12:18:28 +02001862 /*
1863 * Make sure the address gets the right offset in case
1864 * the line breaks in the .lst file (BR 1197827)
1865 */
1866 offset += s;
1867 s = 0;
1868
H. Peter Anvine2c80182005-01-15 22:15:51 +00001869 switch (ea_data.bytes) {
1870 case 0:
1871 break;
1872 case 1:
1873 if (ins->oprs[(c >> 3) & 7].segment != NO_SEG) {
1874 data = ins->oprs[(c >> 3) & 7].offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001875 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001876 ins->oprs[(c >> 3) & 7].segment,
1877 ins->oprs[(c >> 3) & 7].wrt);
1878 } else {
1879 *bytes = ins->oprs[(c >> 3) & 7].offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001880 out(offset, segment, bytes, OUT_RAWDATA, 1,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001881 NO_SEG, NO_SEG);
1882 }
1883 s++;
1884 break;
H. Peter Anvin70653092007-10-19 14:42:29 -07001885 case 8:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001886 case 2:
1887 case 4:
1888 data = ins->oprs[(c >> 3) & 7].offset;
H. Peter Anvine9d7f1a2008-10-05 19:42:55 -07001889 warn_overflow(ea_data.bytes, opx);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001890 s += ea_data.bytes;
H. Peter Anvin9f817132008-10-06 19:11:07 -07001891 if (ea_data.rip) {
1892 data -= insn_end - (offset+ea_data.bytes);
1893 type = OUT_REL4ADR;
1894 } else {
1895 type = OUT_ADDRESS;
1896 }
1897 out(offset, segment, &data, type, ea_data.bytes,
1898 ins->oprs[(c >> 3) & 7].segment,
1899 ins->oprs[(c >> 3) & 7].wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001900 break;
1901 }
1902 offset += s;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001903 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001904 errfunc(ERR_PANIC, "internal instruction table corrupt"
1905 ": instruction code 0x%02X given", c);
H. Peter Anvin839eca22007-10-29 23:12:47 -07001906 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001907 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001908 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001909}
1910
H. Peter Anvin0ec60e62007-07-07 01:59:52 +00001911static int32_t regflag(const operand * o)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001912{
1913 if (o->basereg < EXPR_REG_START || o->basereg >= REG_ENUM_LIMIT) {
1914 errfunc(ERR_PANIC, "invalid operand passed to regflag()");
1915 }
H. Peter Anvina4835d42008-05-20 14:21:29 -07001916 return nasm_reg_flags[o->basereg];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001917}
1918
H. Peter Anvin5b0e3ec2007-07-07 02:01:08 +00001919static int32_t regval(const operand * o)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001920{
H. Peter Anvine2c80182005-01-15 22:15:51 +00001921 if (o->basereg < EXPR_REG_START || o->basereg >= REG_ENUM_LIMIT) {
1922 errfunc(ERR_PANIC, "invalid operand passed to regval()");
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001923 }
H. Peter Anvina4835d42008-05-20 14:21:29 -07001924 return nasm_regvals[o->basereg];
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001925}
1926
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001927static int op_rexflags(const operand * o, int mask)
1928{
1929 int32_t flags;
1930 int val;
1931
1932 if (o->basereg < EXPR_REG_START || o->basereg >= REG_ENUM_LIMIT) {
1933 errfunc(ERR_PANIC, "invalid operand passed to op_rexflags()");
1934 }
1935
H. Peter Anvina4835d42008-05-20 14:21:29 -07001936 flags = nasm_reg_flags[o->basereg];
1937 val = nasm_regvals[o->basereg];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001938
1939 return rexflags(val, flags, mask);
1940}
1941
1942static int rexflags(int val, int32_t flags, int mask)
1943{
1944 int rex = 0;
1945
1946 if (val >= 8)
1947 rex |= REX_B|REX_X|REX_R;
1948 if (flags & BITS64)
1949 rex |= REX_W;
1950 if (!(REG_HIGH & ~flags)) /* AH, CH, DH, BH */
1951 rex |= REX_H;
1952 else if (!(REG8 & ~flags) && val >= 4) /* SPL, BPL, SIL, DIL */
1953 rex |= REX_P;
1954
1955 return rex & mask;
1956}
1957
H. Peter Anvin3360d792007-09-11 04:16:57 +00001958static int matches(const struct itemplate *itemp, insn * instruction, int bits)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001959{
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001960 int i, size[MAX_OPERANDS], asize, oprs, ret;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001961
1962 ret = 100;
1963
1964 /*
1965 * Check the opcode
1966 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001967 if (itemp->opcode != instruction->opcode)
1968 return 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001969
1970 /*
1971 * Count the operands
1972 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001973 if (itemp->operands != instruction->operands)
1974 return 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001975
1976 /*
1977 * Check that no spurious colons or TOs are present
1978 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001979 for (i = 0; i < itemp->operands; i++)
1980 if (instruction->oprs[i].type & ~itemp->opd[i] & (COLON | TO))
1981 return 0;
H. Peter Anvin70653092007-10-19 14:42:29 -07001982
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001983 /*
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001984 * Process size flags
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001985 */
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001986 if (itemp->flags & IF_ARMASK) {
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001987 memset(size, 0, sizeof size);
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001988
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001989 i = ((itemp->flags & IF_ARMASK) >> IF_ARSHFT) - 1;
1990
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001991 switch (itemp->flags & IF_SMASK) {
1992 case IF_SB:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001993 size[i] = BITS8;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001994 break;
1995 case IF_SW:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001996 size[i] = BITS16;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001997 break;
1998 case IF_SD:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001999 size[i] = BITS32;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07002000 break;
2001 case IF_SQ:
Keith Kaniosb7a89542007-04-12 02:40:54 +00002002 size[i] = BITS64;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07002003 break;
H. Peter Anvin41c9f6f2007-09-18 13:01:32 -07002004 case IF_SO:
2005 size[i] = BITS128;
2006 break;
H. Peter Anvindfb91802008-05-20 11:43:53 -07002007 case IF_SY:
2008 size[i] = BITS256;
2009 break;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002010 case IF_SZ:
2011 switch (bits) {
2012 case 16:
2013 size[i] = BITS16;
2014 break;
2015 case 32:
2016 size[i] = BITS32;
2017 break;
2018 case 64:
2019 size[i] = BITS64;
2020 break;
2021 }
2022 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07002023 default:
2024 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002025 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002026 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002027 asize = 0;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07002028 switch (itemp->flags & IF_SMASK) {
2029 case IF_SB:
H. Peter Anvine2c80182005-01-15 22:15:51 +00002030 asize = BITS8;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07002031 break;
2032 case IF_SW:
H. Peter Anvine2c80182005-01-15 22:15:51 +00002033 asize = BITS16;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07002034 break;
2035 case IF_SD:
H. Peter Anvine2c80182005-01-15 22:15:51 +00002036 asize = BITS32;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07002037 break;
2038 case IF_SQ:
Keith Kaniosb7a89542007-04-12 02:40:54 +00002039 asize = BITS64;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07002040 break;
H. Peter Anvin41c9f6f2007-09-18 13:01:32 -07002041 case IF_SO:
2042 asize = BITS128;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002043 break;
H. Peter Anvindfb91802008-05-20 11:43:53 -07002044 case IF_SY:
2045 asize = BITS256;
2046 break;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002047 case IF_SZ:
2048 switch (bits) {
2049 case 16:
2050 asize = BITS16;
2051 break;
2052 case 32:
2053 asize = BITS32;
2054 break;
2055 case 64:
2056 asize = BITS64;
2057 break;
2058 }
H. Peter Anvin41c9f6f2007-09-18 13:01:32 -07002059 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07002060 default:
2061 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002062 }
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07002063 for (i = 0; i < MAX_OPERANDS; i++)
2064 size[i] = asize;
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002065 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002066
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002067 /*
2068 * Check that the operand flags all match up
2069 */
2070 for (i = 0; i < itemp->operands; i++) {
2071 int32_t type = instruction->oprs[i].type;
2072 if (!(type & SIZE_MASK))
2073 type |= size[i];
H. Peter Anvind85d2502008-05-04 17:53:31 -07002074
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002075 if (itemp->opd[i] & SAME_AS) {
2076 int j = itemp->opd[i] & ~SAME_AS;
2077 if (type != instruction->oprs[j].type ||
2078 instruction->oprs[i].basereg != instruction->oprs[j].basereg)
2079 return 0;
2080 } else if (itemp->opd[i] & ~type ||
2081 ((itemp->opd[i] & SIZE_MASK) &&
2082 ((itemp->opd[i] ^ type) & SIZE_MASK))) {
2083 if ((itemp->opd[i] & ~type & ~SIZE_MASK) ||
2084 (type & SIZE_MASK))
2085 return 0;
2086 else
2087 return 1;
2088 }
2089 }
2090
2091 /*
2092 * Check operand sizes
2093 */
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002094 if (itemp->flags & (IF_SM | IF_SM2)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002095 oprs = (itemp->flags & IF_SM2 ? 2 : itemp->operands);
2096 asize = 0;
2097 for (i = 0; i < oprs; i++) {
2098 if ((asize = itemp->opd[i] & SIZE_MASK) != 0) {
2099 int j;
2100 for (j = 0; j < oprs; j++)
2101 size[j] = asize;
2102 break;
2103 }
2104 }
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002105 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002106 oprs = itemp->operands;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002107 }
2108
Keith Kaniosb7a89542007-04-12 02:40:54 +00002109 for (i = 0; i < itemp->operands; i++) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002110 if (!(itemp->opd[i] & SIZE_MASK) &&
2111 (instruction->oprs[i].type & SIZE_MASK & ~size[i]))
H. Peter Anvine2c80182005-01-15 22:15:51 +00002112 return 2;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002113 }
2114
H. Peter Anvinaf535c12002-04-30 20:59:21 +00002115 /*
2116 * Check template is okay at the set cpu level
2117 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002118 if (((itemp->flags & IF_PLEVEL) > cpu))
H. Peter Anvine2c80182005-01-15 22:15:51 +00002119 return 3;
H. Peter Anvin70653092007-10-19 14:42:29 -07002120
Keith Kaniosb7a89542007-04-12 02:40:54 +00002121 /*
2122 * Check if instruction is available in long mode
2123 */
2124 if ((itemp->flags & IF_NOLONG) && (bits == 64))
2125 return 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002126
H. Peter Anvinaf535c12002-04-30 20:59:21 +00002127 /*
2128 * Check if special handling needed for Jumps
2129 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002130 if ((uint8_t)(itemp->code[0]) >= 0370)
H. Peter Anvine2c80182005-01-15 22:15:51 +00002131 return 99;
2132
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002133 return ret;
2134}
2135
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002136static ea *process_ea(operand * input, ea * output, int bits,
H. Peter Anvin1c3277b2008-07-19 21:38:56 -07002137 int addrbits, int rfield, int32_t rflags)
H. Peter Anvineba20a72002-04-30 20:53:55 +00002138{
H. Peter Anvin1c3277b2008-07-19 21:38:56 -07002139 bool forw_ref = !!(input->opflags & OPFLAG_FORWARD);
2140
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002141 output->rip = false;
H. Peter Anvin99c4ecd2007-08-28 23:06:00 +00002142
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002143 /* REX flags for the rfield operand */
2144 output->rex |= rexflags(rfield, rflags, REX_R|REX_P|REX_W|REX_H);
2145
Keith Kaniosb7a89542007-04-12 02:40:54 +00002146 if (!(REGISTER & ~input->type)) { /* register direct */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002147 int i;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002148 int32_t f;
2149
2150 if (input->basereg < EXPR_REG_START /* Verify as Register */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002151 || input->basereg >= REG_ENUM_LIMIT)
H. Peter Anvine2c80182005-01-15 22:15:51 +00002152 return NULL;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002153 f = regflag(input);
H. Peter Anvina4835d42008-05-20 14:21:29 -07002154 i = nasm_regvals[input->basereg];
Keith Kaniosb7a89542007-04-12 02:40:54 +00002155
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002156 if (REG_EA & ~f)
2157 return NULL; /* Invalid EA register */
H. Peter Anvin70653092007-10-19 14:42:29 -07002158
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002159 output->rex |= op_rexflags(input, REX_B|REX_P|REX_W|REX_H);
2160
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002161 output->sib_present = false; /* no SIB necessary */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002162 output->bytes = 0; /* no offset necessary either */
2163 output->modrm = 0xC0 | ((rfield & 7) << 3) | (i & 7);
H. Peter Anvine2c80182005-01-15 22:15:51 +00002164 } else { /* it's a memory reference */
2165 if (input->basereg == -1
2166 && (input->indexreg == -1 || input->scale == 0)) {
2167 /* it's a pure offset */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002168 if (bits == 64 && (~input->type & IP_REL)) {
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002169 int scale, index, base;
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002170 output->sib_present = true;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002171 scale = 0;
2172 index = 4;
2173 base = 5;
2174 output->sib = (scale << 6) | (index << 3) | base;
2175 output->bytes = 4;
2176 output->modrm = 4 | ((rfield & 7) << 3);
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002177 output->rip = false;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002178 } else {
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002179 output->sib_present = false;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002180 output->bytes = (addrbits != 16 ? 4 : 2);
2181 output->modrm = (addrbits != 16 ? 5 : 6) | ((rfield & 7) << 3);
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002182 output->rip = bits == 64;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002183 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00002184 } else { /* it's an indirection */
2185 int i = input->indexreg, b = input->basereg, s = input->scale;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002186 int32_t o = input->offset, seg = input->segment;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002187 int hb = input->hintbase, ht = input->hinttype;
2188 int t;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002189 int it, bt;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002190 int32_t ix, bx; /* register flags */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002191
H. Peter Anvine2c80182005-01-15 22:15:51 +00002192 if (s == 0)
2193 i = -1; /* make this easy, at least */
H. Peter Anvin70653092007-10-19 14:42:29 -07002194
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002195 if (i >= EXPR_REG_START && i < REG_ENUM_LIMIT) {
H. Peter Anvina4835d42008-05-20 14:21:29 -07002196 it = nasm_regvals[i];
2197 ix = nasm_reg_flags[i];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002198 } else {
Keith Kaniosb7a89542007-04-12 02:40:54 +00002199 it = -1;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002200 ix = 0;
2201 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002202
H. Peter Anvinb0c54622007-10-28 23:21:46 -07002203 if (b >= EXPR_REG_START && b < REG_ENUM_LIMIT) {
H. Peter Anvina4835d42008-05-20 14:21:29 -07002204 bt = nasm_regvals[b];
2205 bx = nasm_reg_flags[b];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002206 } else {
Keith Kaniosb7a89542007-04-12 02:40:54 +00002207 bt = -1;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002208 bx = 0;
2209 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002210
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002211 /* check for a 32/64-bit memory reference... */
2212 if ((ix|bx) & (BITS32|BITS64)) {
Keith Kaniosb7a89542007-04-12 02:40:54 +00002213 /* it must be a 32/64-bit memory reference. Firstly we have
2214 * to check that all registers involved are type E/Rxx. */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002215 int32_t sok = BITS32|BITS64;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002216
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002217 if (it != -1) {
2218 if (!(REG64 & ~ix) || !(REG32 & ~ix))
2219 sok &= ix;
2220 else
2221 return NULL;
2222 }
2223
2224 if (bt != -1) {
H. Peter Anvin99c4ecd2007-08-28 23:06:00 +00002225 if (REG_GPR & ~bx)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002226 return NULL; /* Invalid register */
H. Peter Anvina57e8d42007-05-30 03:44:02 +00002227 if (~sok & bx & SIZE_MASK)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002228 return NULL; /* Invalid size */
H. Peter Anvinb0c54622007-10-28 23:21:46 -07002229 sok &= bx;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002230 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002231
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002232 /* While we're here, ensure the user didn't specify
2233 WORD or QWORD. */
2234 if (input->disp_size == 16 || input->disp_size == 64)
2235 return NULL;
2236
2237 if (addrbits == 16 ||
2238 (addrbits == 32 && !(sok & BITS32)) ||
2239 (addrbits == 64 && !(sok & BITS64)))
2240 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002241
Keith Kaniosb7a89542007-04-12 02:40:54 +00002242 /* now reorganize base/index */
2243 if (s == 1 && bt != it && bt != -1 && it != -1 &&
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002244 ((hb == b && ht == EAH_NOTBASE)
2245 || (hb == i && ht == EAH_MAKEBASE))) {
2246 /* swap if hints say so */
2247 t = bt, bt = it, it = t;
2248 t = bx, bx = ix, ix = t;
2249 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00002250 if (bt == it) /* convert EAX+2*EAX to 3*EAX */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002251 bt = -1, bx = 0, s++;
2252 if (bt == -1 && s == 1 && !(hb == it && ht == EAH_NOTBASE)) {
2253 /* make single reg base, unless hint */
2254 bt = it, bx = ix, it = -1, ix = 0;
2255 }
H. Peter Anvinf5843c62007-09-10 18:59:26 +00002256 if (((s == 2 && it != REG_NUM_ESP
H. Peter Anvine2c80182005-01-15 22:15:51 +00002257 && !(input->eaflags & EAF_TIMESTWO)) || s == 3
Keith Kaniosb7a89542007-04-12 02:40:54 +00002258 || s == 5 || s == 9) && bt == -1)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002259 bt = it, bx = ix, s--; /* convert 3*EAX to EAX+2*EAX */
Keith Kanios48af1772007-08-17 07:37:52 +00002260 if (it == -1 && (bt & 7) != REG_NUM_ESP
H. Peter Anvine2c80182005-01-15 22:15:51 +00002261 && (input->eaflags & EAF_TIMESTWO))
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002262 it = bt, ix = bx, bt = -1, bx = 0, s = 1;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002263 /* convert [NOSPLIT EAX] to sib format with 0x0 displacement */
Keith Kanios48af1772007-08-17 07:37:52 +00002264 if (s == 1 && it == REG_NUM_ESP) {
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002265 /* swap ESP into base if scale is 1 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002266 t = it, it = bt, bt = t;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002267 t = ix, ix = bx, bx = t;
2268 }
Keith Kanios48af1772007-08-17 07:37:52 +00002269 if (it == REG_NUM_ESP
Keith Kaniosb7a89542007-04-12 02:40:54 +00002270 || (s != 1 && s != 2 && s != 4 && s != 8 && it != -1))
H. Peter Anvine2c80182005-01-15 22:15:51 +00002271 return NULL; /* wrong, for various reasons */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002272
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002273 output->rex |= rexflags(it, ix, REX_X);
2274 output->rex |= rexflags(bt, bx, REX_B);
Keith Kaniosb7a89542007-04-12 02:40:54 +00002275
Keith Kanios48af1772007-08-17 07:37:52 +00002276 if (it == -1 && (bt & 7) != REG_NUM_ESP) {
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002277 /* no SIB needed */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002278 int mod, rm;
H. Peter Anvin70653092007-10-19 14:42:29 -07002279
Keith Kaniosb7a89542007-04-12 02:40:54 +00002280 if (bt == -1) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002281 rm = 5;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002282 mod = 0;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002283 } else {
2284 rm = (bt & 7);
Keith Kanios48af1772007-08-17 07:37:52 +00002285 if (rm != REG_NUM_EBP && o == 0 &&
Keith Kaniosb7a89542007-04-12 02:40:54 +00002286 seg == NO_SEG && !forw_ref &&
2287 !(input->eaflags &
2288 (EAF_BYTEOFFS | EAF_WORDOFFS)))
2289 mod = 0;
2290 else if (input->eaflags & EAF_BYTEOFFS ||
2291 (o >= -128 && o <= 127 && seg == NO_SEG
2292 && !forw_ref
2293 && !(input->eaflags & EAF_WORDOFFS)))
2294 mod = 1;
2295 else
2296 mod = 2;
2297 }
H. Peter Anvinea838272002-04-30 20:51:53 +00002298
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002299 output->sib_present = false;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002300 output->bytes = (bt == -1 || mod == 2 ? 4 : mod);
2301 output->modrm = (mod << 6) | ((rfield & 7) << 3) | rm;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002302 } else {
2303 /* we need a SIB */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002304 int mod, scale, index, base;
H. Peter Anvin70653092007-10-19 14:42:29 -07002305
Keith Kaniosb7a89542007-04-12 02:40:54 +00002306 if (it == -1)
2307 index = 4, s = 1;
2308 else
2309 index = (it & 7);
H. Peter Anvin70653092007-10-19 14:42:29 -07002310
H. Peter Anvine2c80182005-01-15 22:15:51 +00002311 switch (s) {
2312 case 1:
2313 scale = 0;
2314 break;
2315 case 2:
2316 scale = 1;
2317 break;
2318 case 4:
2319 scale = 2;
2320 break;
2321 case 8:
2322 scale = 3;
2323 break;
2324 default: /* then what the smeg is it? */
2325 return NULL; /* panic */
2326 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002327
Keith Kaniosb7a89542007-04-12 02:40:54 +00002328 if (bt == -1) {
2329 base = 5;
2330 mod = 0;
2331 } else {
2332 base = (bt & 7);
Keith Kanios48af1772007-08-17 07:37:52 +00002333 if (base != REG_NUM_EBP && o == 0 &&
H. Peter Anvine2c80182005-01-15 22:15:51 +00002334 seg == NO_SEG && !forw_ref &&
2335 !(input->eaflags &
Keith Kaniosb7a89542007-04-12 02:40:54 +00002336 (EAF_BYTEOFFS | EAF_WORDOFFS)))
2337 mod = 0;
2338 else if (input->eaflags & EAF_BYTEOFFS ||
2339 (o >= -128 && o <= 127 && seg == NO_SEG
2340 && !forw_ref
2341 && !(input->eaflags & EAF_WORDOFFS)))
2342 mod = 1;
2343 else
2344 mod = 2;
2345 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002346
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002347 output->sib_present = true;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002348 output->bytes = (bt == -1 || mod == 2 ? 4 : mod);
2349 output->modrm = (mod << 6) | ((rfield & 7) << 3) | 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002350 output->sib = (scale << 6) | (index << 3) | base;
2351 }
2352 } else { /* it's 16-bit */
2353 int mod, rm;
H. Peter Anvin70653092007-10-19 14:42:29 -07002354
Keith Kaniosb7a89542007-04-12 02:40:54 +00002355 /* check for 64-bit long mode */
2356 if (addrbits == 64)
2357 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002358
H. Peter Anvine2c80182005-01-15 22:15:51 +00002359 /* check all registers are BX, BP, SI or DI */
2360 if ((b != -1 && b != R_BP && b != R_BX && b != R_SI
2361 && b != R_DI) || (i != -1 && i != R_BP && i != R_BX
2362 && i != R_SI && i != R_DI))
2363 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002364
Keith Kaniosb7a89542007-04-12 02:40:54 +00002365 /* ensure the user didn't specify DWORD/QWORD */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002366 if (input->disp_size == 32 || input->disp_size == 64)
H. Peter Anvine2c80182005-01-15 22:15:51 +00002367 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002368
H. Peter Anvine2c80182005-01-15 22:15:51 +00002369 if (s != 1 && i != -1)
2370 return NULL; /* no can do, in 16-bit EA */
2371 if (b == -1 && i != -1) {
2372 int tmp = b;
2373 b = i;
2374 i = tmp;
2375 } /* swap */
2376 if ((b == R_SI || b == R_DI) && i != -1) {
2377 int tmp = b;
2378 b = i;
2379 i = tmp;
2380 }
2381 /* have BX/BP as base, SI/DI index */
2382 if (b == i)
2383 return NULL; /* shouldn't ever happen, in theory */
2384 if (i != -1 && b != -1 &&
2385 (i == R_BP || i == R_BX || b == R_SI || b == R_DI))
2386 return NULL; /* invalid combinations */
2387 if (b == -1) /* pure offset: handled above */
2388 return NULL; /* so if it gets to here, panic! */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002389
H. Peter Anvine2c80182005-01-15 22:15:51 +00002390 rm = -1;
2391 if (i != -1)
2392 switch (i * 256 + b) {
2393 case R_SI * 256 + R_BX:
2394 rm = 0;
2395 break;
2396 case R_DI * 256 + R_BX:
2397 rm = 1;
2398 break;
2399 case R_SI * 256 + R_BP:
2400 rm = 2;
2401 break;
2402 case R_DI * 256 + R_BP:
2403 rm = 3;
2404 break;
2405 } else
2406 switch (b) {
2407 case R_SI:
2408 rm = 4;
2409 break;
2410 case R_DI:
2411 rm = 5;
2412 break;
2413 case R_BP:
2414 rm = 6;
2415 break;
2416 case R_BX:
2417 rm = 7;
2418 break;
2419 }
2420 if (rm == -1) /* can't happen, in theory */
2421 return NULL; /* so panic if it does */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002422
H. Peter Anvine2c80182005-01-15 22:15:51 +00002423 if (o == 0 && seg == NO_SEG && !forw_ref && rm != 6 &&
2424 !(input->eaflags & (EAF_BYTEOFFS | EAF_WORDOFFS)))
2425 mod = 0;
2426 else if (input->eaflags & EAF_BYTEOFFS ||
2427 (o >= -128 && o <= 127 && seg == NO_SEG
2428 && !forw_ref
2429 && !(input->eaflags & EAF_WORDOFFS)))
2430 mod = 1;
2431 else
2432 mod = 2;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002433
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002434 output->sib_present = false; /* no SIB - it's 16-bit */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002435 output->bytes = mod; /* bytes of offset needed */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002436 output->modrm = (mod << 6) | ((rfield & 7) << 3) | rm;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002437 }
2438 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002439 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002440
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002441 output->size = 1 + output->sib_present + output->bytes;
2442 return output;
2443}
2444
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002445static void add_asp(insn *ins, int addrbits)
H. Peter Anvineba20a72002-04-30 20:53:55 +00002446{
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002447 int j, valid;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002448 int defdisp;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002449
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002450 valid = (addrbits == 64) ? 64|32 : 32|16;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002451
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002452 switch (ins->prefixes[PPS_ASIZE]) {
2453 case P_A16:
2454 valid &= 16;
2455 break;
2456 case P_A32:
2457 valid &= 32;
2458 break;
2459 case P_A64:
2460 valid &= 64;
2461 break;
2462 case P_ASP:
2463 valid &= (addrbits == 32) ? 16 : 32;
2464 break;
2465 default:
2466 break;
2467 }
2468
2469 for (j = 0; j < ins->operands; j++) {
2470 if (!(MEMORY & ~ins->oprs[j].type)) {
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002471 int32_t i, b;
H. Peter Anvin70653092007-10-19 14:42:29 -07002472
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002473 /* Verify as Register */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002474 if (ins->oprs[j].indexreg < EXPR_REG_START
2475 || ins->oprs[j].indexreg >= REG_ENUM_LIMIT)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002476 i = 0;
2477 else
H. Peter Anvina4835d42008-05-20 14:21:29 -07002478 i = nasm_reg_flags[ins->oprs[j].indexreg];
H. Peter Anvin70653092007-10-19 14:42:29 -07002479
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002480 /* Verify as Register */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002481 if (ins->oprs[j].basereg < EXPR_REG_START
2482 || ins->oprs[j].basereg >= REG_ENUM_LIMIT)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002483 b = 0;
2484 else
H. Peter Anvina4835d42008-05-20 14:21:29 -07002485 b = nasm_reg_flags[ins->oprs[j].basereg];
H. Peter Anvin70653092007-10-19 14:42:29 -07002486
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002487 if (ins->oprs[j].scale == 0)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002488 i = 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002489
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002490 if (!i && !b) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002491 int ds = ins->oprs[j].disp_size;
2492 if ((addrbits != 64 && ds > 8) ||
2493 (addrbits == 64 && ds == 16))
2494 valid &= ds;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002495 } else {
2496 if (!(REG16 & ~b))
2497 valid &= 16;
2498 if (!(REG32 & ~b))
2499 valid &= 32;
2500 if (!(REG64 & ~b))
2501 valid &= 64;
H. Peter Anvin70653092007-10-19 14:42:29 -07002502
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002503 if (!(REG16 & ~i))
2504 valid &= 16;
2505 if (!(REG32 & ~i))
2506 valid &= 32;
2507 if (!(REG64 & ~i))
2508 valid &= 64;
2509 }
2510 }
2511 }
2512
2513 if (valid & addrbits) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002514 ins->addr_size = addrbits;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002515 } else if (valid & ((addrbits == 32) ? 16 : 32)) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002516 /* Add an address size prefix */
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002517 enum prefixes pref = (addrbits == 32) ? P_A16 : P_A32;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002518 ins->prefixes[PPS_ASIZE] = pref;
2519 ins->addr_size = (addrbits == 32) ? 16 : 32;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002520 } else {
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002521 /* Impossible... */
2522 errfunc(ERR_NONFATAL, "impossible combination of address sizes");
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002523 ins->addr_size = addrbits; /* Error recovery */
2524 }
2525
2526 defdisp = ins->addr_size == 16 ? 16 : 32;
2527
2528 for (j = 0; j < ins->operands; j++) {
2529 if (!(MEM_OFFS & ~ins->oprs[j].type) &&
2530 (ins->oprs[j].disp_size ? ins->oprs[j].disp_size : defdisp)
2531 != ins->addr_size) {
2532 /* mem_offs sizes must match the address size; if not,
2533 strip the MEM_OFFS bit and match only EA instructions */
2534 ins->oprs[j].type &= ~(MEM_OFFS & ~MEMORY);
2535 }
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002536 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002537}