blob: c5f8172e4701a2a227d41ee12fd2c99a89ef93f0 [file] [log] [blame]
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001/* assemble.c code generation for the Netwide Assembler
2 *
3 * The Netwide Assembler is copyright (C) 1996 Simon Tatham and
4 * Julian Hall. All rights reserved. The software is
Beroset095e6a22007-12-29 09:44:23 -05005 * redistributable under the license given in the file "LICENSE"
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00006 * distributed in the NASM archive.
7 *
8 * the actual codes (C syntax, i.e. octal):
9 * \0 - terminates the code. (Unless it's a literal of course.)
10 * \1, \2, \3 - that many literal bytes follow in the code stream
11 * \4, \6 - the POP/PUSH (respectively) codes for CS, DS, ES, SS
12 * (POP is never used for CS) depending on operand 0
13 * \5, \7 - the second byte of POP/PUSH codes for FS, GS, depending
14 * on operand 0
H. Peter Anvin7eb4a382007-09-17 15:49:30 -070015 * \10..\13 - a literal byte follows in the code stream, to be added
16 * to the register value of operand 0..3
17 * \14..\17 - a signed byte immediate operand, from operand 0..3
18 * \20..\23 - a byte immediate operand, from operand 0..3
19 * \24..\27 - an unsigned byte immediate operand, from operand 0..3
20 * \30..\33 - a word immediate operand, from operand 0..3
21 * \34..\37 - select between \3[0-3] and \4[0-3] depending on 16/32 bit
H. Peter Anvin3ba46772002-05-27 23:19:35 +000022 * assembly mode or the operand-size override on the operand
H. Peter Anvin7eb4a382007-09-17 15:49:30 -070023 * \40..\43 - a long immediate operand, from operand 0..3
24 * \44..\47 - select between \3[0-3], \4[0-3] and \5[4-7]
H. Peter Anvinde4b89b2007-10-01 15:41:25 -070025 * depending on the address size of the instruction.
H. Peter Anvin7eb4a382007-09-17 15:49:30 -070026 * \50..\53 - a byte relative operand, from operand 0..3
27 * \54..\57 - a qword immediate operand, from operand 0..3
28 * \60..\63 - a word relative operand, from operand 0..3
29 * \64..\67 - select between \6[0-3] and \7[0-3] depending on 16/32 bit
H. Peter Anvin17799b42002-05-21 03:31:21 +000030 * assembly mode or the operand-size override on the operand
H. Peter Anvin7eb4a382007-09-17 15:49:30 -070031 * \70..\73 - a long relative operand, from operand 0..3
32 * \74..\77 - a word constant, from the _segment_ part of operand 0..3
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000033 * \1ab - a ModRM, calculated on EA in operand a, with the spare
34 * field the register value of operand b.
H. Peter Anvin7eb4a382007-09-17 15:49:30 -070035 * \140..\143 - an immediate word or signed byte for operand 0..3
H. Peter Anvina30cc072007-11-18 21:55:26 -080036 * \144..\147 - or 2 (s-field) into opcode byte if operand 0..3
37 * is a signed byte rather than a word. Opcode byte follows.
H. Peter Anvin7eb4a382007-09-17 15:49:30 -070038 * \150..\153 - an immediate dword or signed byte for operand 0..3
H. Peter Anvina30cc072007-11-18 21:55:26 -080039 * \154..\157 - or 2 (s-field) into opcode byte if operand 0..3
H. Peter Anvin32cd4c22008-04-04 13:34:53 -070040 * is a signed byte rather than a dword. Opcode byte follows.
H. Peter Anvin401c07e2007-09-17 16:55:04 -070041 * \160..\163 - this instruction uses DREX rather than REX, with the
42 * OC0 field set to 0, and the dest field taken from
43 * operand 0..3.
44 * \164..\167 - this instruction uses DREX rather than REX, with the
45 * OC0 field set to 1, and the dest field taken from
46 * operand 0..3.
H. Peter Anvin401c07e2007-09-17 16:55:04 -070047 * \171 - placement of DREX suffix in the absence of an EA
H. Peter Anvind85d2502008-05-04 17:53:31 -070048 * \172\ab - the register number from operand a in bits 7..4, with
H. Peter Anvin52dc3532008-05-20 19:29:04 -070049 * the 4-bit immediate from operand b in bits 3..0.
H. Peter Anvind58656f2008-05-06 20:11:14 -070050 * \173\xab - the register number from operand a in bits 7..4, with
H. Peter Anvin52dc3532008-05-20 19:29:04 -070051 * the value b in bits 3..0.
52 * \174\a - the register number from operand a in bits 7..4, and
53 * an arbitrary value in bits 3..0 (assembled as zero.)
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000054 * \2ab - a ModRM, calculated on EA in operand a, with the spare
55 * field equal to digit b.
H. Peter Anvin32cd4c22008-04-04 13:34:53 -070056 * \250..\253 - same as \150..\153, except warn if the 64-bit operand
57 * is not equal to the truncated and sign-extended 32-bit
58 * operand; used for 32-bit immediates in 64-bit mode.
H. Peter Anvind85d2502008-05-04 17:53:31 -070059 * \260..\263 - this instruction uses VEX rather than REX, with the
60 * V field taken from operand 0..3.
61 * \270 - this instruction uses VEX rather than REX, with the
62 * V field set to 1111b.
63 *
64 * VEX prefixes are followed by the sequence:
H. Peter Anvinaaa088f2008-05-12 11:13:41 -070065 * \mm\wlp where mm is the M field; and wlp is:
66 * 00 0ww lpp
H. Peter Anvind85d2502008-05-04 17:53:31 -070067 * ww = 0 for W = 0
68 * ww = 1 for W = 1
69 * ww = 2 for W used as REX.W
70 *
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000071 * \310 - indicates fixed 16-bit address size, i.e. optional 0x67.
72 * \311 - indicates fixed 32-bit address size, i.e. optional 0x67.
Keith Kanios48af1772007-08-17 07:37:52 +000073 * \312 - (disassembler only) marker on LOOP, LOOPxx instructions.
H. Peter Anvince2b3972007-05-30 22:21:11 +000074 * \313 - indicates fixed 64-bit address size, 0x67 invalid.
H. Peter Anvin23440102007-11-12 21:02:33 -080075 * \314 - (disassembler only) invalid with REX.B
76 * \315 - (disassembler only) invalid with REX.X
77 * \316 - (disassembler only) invalid with REX.R
78 * \317 - (disassembler only) invalid with REX.W
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000079 * \320 - indicates fixed 16-bit operand size, i.e. optional 0x66.
80 * \321 - indicates fixed 32-bit operand size, i.e. optional 0x66.
81 * \322 - indicates that this instruction is only valid when the
82 * operand size is the default (instruction to disassembler,
83 * generates no code in the assembler)
H. Peter Anvince2b3972007-05-30 22:21:11 +000084 * \323 - indicates fixed 64-bit operand size, REX on extensions only.
Keith Kaniosb7a89542007-04-12 02:40:54 +000085 * \324 - indicates 64-bit operand size requiring REX prefix.
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000086 * \330 - a literal byte follows in the code stream, to be added
87 * to the condition code value of the instruction.
Keith Kanios48af1772007-08-17 07:37:52 +000088 * \331 - instruction not valid with REP prefix. Hint for
H. Peter Anvinef7468f2002-04-30 20:57:59 +000089 * disassembler only; for SSE instructions.
H. Peter Anvincb9b6902007-09-12 21:58:51 -070090 * \332 - REP prefix (0xF2 byte) used as opcode extension.
91 * \333 - REP prefix (0xF3 byte) used as opcode extension.
Keith Kanios48af1772007-08-17 07:37:52 +000092 * \334 - LOCK prefix used instead of REX.R
H. Peter Anvincb9b6902007-09-12 21:58:51 -070093 * \335 - disassemble a rep (0xF3 byte) prefix as repe not rep.
Keith Kaniosb7a89542007-04-12 02:40:54 +000094 * \340 - reserve <operand 0> bytes of uninitialized storage.
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000095 * Operand 0 had better be a segmentless constant.
H. Peter Anvinfff5a472008-05-20 09:46:24 -070096 * \360 - no SSE prefix (== \364\331)
97 * \361 - 66 SSE prefix (== \366\331)
98 * \362 - F2 SSE prefix (== \364\332)
99 * \363 - F3 SSE prefix (== \364\333)
H. Peter Anvin62cb6062007-09-11 22:44:03 +0000100 * \364 - operand-size prefix (0x66) not permitted
101 * \365 - address-size prefix (0x67) not permitted
102 * \366 - operand-size prefix (0x66) used as opcode extension
103 * \367 - address-size prefix (0x67) used as opcode extension
H. Peter Anvin788e6c12002-04-30 21:02:01 +0000104 * \370,\371,\372 - match only if operand 0 meets byte jump criteria.
105 * 370 is used for Jcc, 371 is used for JMP.
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000106 * \373 - assemble 0x03 if bits==16, 0x05 if bits==32;
107 * used for conditional jump over longer jump
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000108 */
109
H. Peter Anvinfe501952007-10-02 21:53:51 -0700110#include "compiler.h"
111
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000112#include <stdio.h>
113#include <string.h>
Keith Kaniosb7a89542007-04-12 02:40:54 +0000114#include <inttypes.h>
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000115
116#include "nasm.h"
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000117#include "nasmlib.h"
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000118#include "assemble.h"
119#include "insns.h"
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000120#include "preproc.h"
H. Peter Anvina4835d42008-05-20 14:21:29 -0700121#include "tables.h"
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000122
H. Peter Anvindfb91802008-05-20 11:43:53 -0700123/* Initialized to zero by the C standard */
124static const uint8_t const_zero_buf[256];
125
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000126typedef struct {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000127 int sib_present; /* is a SIB byte necessary? */
128 int bytes; /* # of bytes of offset needed */
129 int size; /* lazy - this is sib+bytes+1 */
130 uint8_t modrm, sib, rex, rip; /* the bytes themselves */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000131} ea;
132
Keith Kaniosb7a89542007-04-12 02:40:54 +0000133static uint32_t cpu; /* cpu level received from nasm.c */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000134static efunc errfunc;
135static struct ofmt *outfmt;
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000136static ListGen *list;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000137
H. Peter Anvin3720f7b2008-05-12 11:00:50 -0700138static int64_t calcsize(int32_t, int64_t, int, insn *, const uint8_t *);
139static void gencode(int32_t, int64_t, int, insn *, const uint8_t *, int64_t);
H. Peter Anvin3360d792007-09-11 04:16:57 +0000140static int matches(const struct itemplate *, insn *, int bits);
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000141static int32_t regflag(const operand *);
142static int32_t regval(const operand *);
143static int rexflags(int, int32_t, int);
144static int op_rexflags(const operand *, int);
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700145static ea *process_ea(operand *, ea *, int, int, int, int32_t, int);
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700146static void add_asp(insn *, int);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000147
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700148static int has_prefix(insn * ins, enum prefix_pos pos, enum prefixes prefix)
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000149{
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700150 return ins->prefixes[pos] == prefix;
151}
152
153static void assert_no_prefix(insn * ins, enum prefix_pos pos)
154{
155 if (ins->prefixes[pos])
156 errfunc(ERR_NONFATAL, "invalid %s prefix",
157 prefix_name(ins->prefixes[pos]));
158}
159
160static const char *size_name(int size)
161{
162 switch (size) {
163 case 1:
164 return "byte";
165 case 2:
166 return "word";
167 case 4:
168 return "dword";
169 case 8:
170 return "qword";
171 case 10:
172 return "tword";
173 case 16:
174 return "oword";
H. Peter Anvindfb91802008-05-20 11:43:53 -0700175 case 32:
176 return "yword";
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700177 default:
178 return "???";
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000179 }
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700180}
181
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700182static void warn_overflow(int size, int64_t data)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700183{
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700184 if (size < 8) {
Charles Craynedd462c82007-11-04 15:28:30 -0800185 int64_t lim = ((int64_t)1 << (size*8))-1;
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000186
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700187 if (data < ~lim || data > lim)
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700188 errfunc(ERR_WARNING | ERR_WARN_NOV,
189 "%s data exceeds bounds", size_name(size));
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700190 }
191}
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000192/*
193 * This routine wrappers the real output format's output routine,
194 * in order to pass a copy of the data off to the listing file
195 * generator at the same time.
196 */
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800197static void out(int64_t offset, int32_t segto, const void *data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800198 enum out_type type, uint64_t size,
199 int32_t segment, int32_t wrt)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000200{
Keith Kaniosb7a89542007-04-12 02:40:54 +0000201 static int32_t lineno = 0; /* static!!! */
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000202 static char *lnfname = NULL;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800203 uint8_t p[8];
H. Peter Anvineba20a72002-04-30 20:53:55 +0000204
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800205 if (type == OUT_ADDRESS && segment == NO_SEG && wrt == NO_SEG) {
206 /*
207 * This is a non-relocated address, and we're going to
208 * convert it into RAWDATA format.
209 */
210 uint8_t *q = p;
H. Peter Anvind1fb15c2007-11-13 09:37:59 -0800211
212 if (size > 8) {
213 errfunc(ERR_PANIC, "OUT_ADDRESS with size > 8");
214 return;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800215 }
H. Peter Anvind85d2502008-05-04 17:53:31 -0700216
H. Peter Anvind1fb15c2007-11-13 09:37:59 -0800217 WRITEADDR(q, *(int64_t *)data, size);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800218 data = p;
219 type = OUT_RAWDATA;
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000220 }
221
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800222 list->output(offset, data, type, size);
223
Frank Kotlerabebb082003-09-06 04:45:37 +0000224 /*
225 * this call to src_get determines when we call the
226 * debug-format-specific "linenum" function
227 * it updates lineno and lnfname to the current values
228 * returning 0 if "same as last time", -2 if lnfname
229 * changed, and the amount by which lineno changed,
230 * if it did. thus, these variables must be static
231 */
232
H. Peter Anvine2c80182005-01-15 22:15:51 +0000233 if (src_get(&lineno, &lnfname)) {
234 outfmt->current_dfmt->linenum(lnfname, lineno, segto);
H. Peter Anvince616072002-04-30 21:02:23 +0000235 }
H. Peter Anvineba20a72002-04-30 20:53:55 +0000236
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800237 outfmt->output(segto, data, type, size, segment, wrt);
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000238}
239
Charles Crayne5fbbc8c2007-11-07 19:03:46 -0800240static int jmp_match(int32_t segment, int64_t offset, int bits,
H. Peter Anvin3720f7b2008-05-12 11:00:50 -0700241 insn * ins, const uint8_t *code)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000242{
Charles Crayne5fbbc8c2007-11-07 19:03:46 -0800243 int64_t isize;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000244 uint8_t c = code[0];
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000245
H. Peter Anvine2c80182005-01-15 22:15:51 +0000246 if (c != 0370 && c != 0371)
247 return 0;
H. Peter Anvin788e6c12002-04-30 21:02:01 +0000248 if (ins->oprs[0].opflags & OPFLAG_FORWARD) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000249 if ((optimizing < 0 || (ins->oprs[0].type & STRICT))
250 && c == 0370)
251 return 1;
252 else
253 return (pass0 == 0); /* match a forward reference */
H. Peter Anvin788e6c12002-04-30 21:02:01 +0000254 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000255 isize = calcsize(segment, offset, bits, ins, code);
256 if (ins->oprs[0].segment != segment)
257 return 0;
258 isize = ins->oprs[0].offset - offset - isize; /* isize is now the delta */
259 if (isize >= -128L && isize <= 127L)
260 return 1; /* it is byte size */
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000261
262 return 0;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000263}
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000264
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800265int64_t assemble(int32_t segment, int64_t offset, int bits, uint32_t cp,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000266 insn * instruction, struct ofmt *output, efunc error,
267 ListGen * listgen)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000268{
H. Peter Anvin3360d792007-09-11 04:16:57 +0000269 const struct itemplate *temp;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000270 int j;
271 int size_prob;
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800272 int64_t insn_end;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000273 int32_t itimes;
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800274 int64_t start = offset;
275 int64_t wsize = 0; /* size for DB etc. */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000276
H. Peter Anvine2c80182005-01-15 22:15:51 +0000277 errfunc = error; /* to pass to other functions */
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000278 cpu = cp;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000279 outfmt = output; /* likewise */
280 list = listgen; /* and again */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000281
H. Peter Anvine2c80182005-01-15 22:15:51 +0000282 switch (instruction->opcode) {
283 case -1:
284 return 0;
285 case I_DB:
286 wsize = 1;
287 break;
288 case I_DW:
289 wsize = 2;
290 break;
291 case I_DD:
292 wsize = 4;
293 break;
294 case I_DQ:
295 wsize = 8;
296 break;
297 case I_DT:
298 wsize = 10;
299 break;
H. Peter Anvincfbe7c32007-09-18 17:49:09 -0700300 case I_DO:
301 wsize = 16;
302 break;
H. Peter Anvindfb91802008-05-20 11:43:53 -0700303 case I_DY:
304 wsize = 32;
305 break;
H. Peter Anvin16b0a332007-09-12 20:27:41 -0700306 default:
307 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000308 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000309
H. Peter Anvineba20a72002-04-30 20:53:55 +0000310 if (wsize) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000311 extop *e;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000312 int32_t t = instruction->times;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000313 if (t < 0)
314 errfunc(ERR_PANIC,
315 "instruction->times < 0 (%ld) in assemble()", t);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000316
H. Peter Anvine2c80182005-01-15 22:15:51 +0000317 while (t--) { /* repeat TIMES times */
318 for (e = instruction->eops; e; e = e->next) {
319 if (e->type == EOT_DB_NUMBER) {
320 if (wsize == 1) {
321 if (e->segment != NO_SEG)
322 errfunc(ERR_NONFATAL,
323 "one-byte relocation attempted");
324 else {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000325 uint8_t out_byte = e->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000326 out(offset, segment, &out_byte,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800327 OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000328 }
Keith Kanios61ff53c2007-04-14 18:54:52 +0000329 } else if (wsize > 8) {
H. Peter Anvin3be5d852008-05-20 14:49:32 -0700330 errfunc(ERR_NONFATAL,
331 "integer supplied to a DT, DO or DY"
Keith Kanios61ff53c2007-04-14 18:54:52 +0000332 " instruction");
H. Peter Anvine2c80182005-01-15 22:15:51 +0000333 } else
334 out(offset, segment, &e->offset,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800335 OUT_ADDRESS, wsize, e->segment, e->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000336 offset += wsize;
337 } else if (e->type == EOT_DB_STRING) {
338 int align;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000339
H. Peter Anvine2c80182005-01-15 22:15:51 +0000340 out(offset, segment, e->stringval,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800341 OUT_RAWDATA, e->stringlen, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000342 align = e->stringlen % wsize;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000343
H. Peter Anvine2c80182005-01-15 22:15:51 +0000344 if (align) {
345 align = wsize - align;
H. Peter Anvindfb91802008-05-20 11:43:53 -0700346 out(offset, segment, const_zero_buf,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800347 OUT_RAWDATA, align, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000348 }
349 offset += e->stringlen + align;
350 }
351 }
352 if (t > 0 && t == instruction->times - 1) {
353 /*
354 * Dummy call to list->output to give the offset to the
355 * listing module.
356 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800357 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000358 list->uplevel(LIST_TIMES);
359 }
360 }
361 if (instruction->times > 1)
362 list->downlevel(LIST_TIMES);
363 return offset - start;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000364 }
365
H. Peter Anvine2c80182005-01-15 22:15:51 +0000366 if (instruction->opcode == I_INCBIN) {
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000367 static char fname[FILENAME_MAX];
H. Peter Anvine2c80182005-01-15 22:15:51 +0000368 FILE *fp;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000369 int32_t len;
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000370 char *prefix = "", *combine;
371 char **pPrevPath = NULL;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000372
H. Peter Anvine2c80182005-01-15 22:15:51 +0000373 len = FILENAME_MAX - 1;
374 if (len > instruction->eops->stringlen)
375 len = instruction->eops->stringlen;
376 strncpy(fname, instruction->eops->stringval, len);
377 fname[len] = '\0';
H. Peter Anvineba20a72002-04-30 20:53:55 +0000378
Keith Kaniosb7a89542007-04-12 02:40:54 +0000379 while (1) { /* added by alexfru: 'incbin' uses include paths */
H. Peter Anvine2c80182005-01-15 22:15:51 +0000380 combine = nasm_malloc(strlen(prefix) + len + 1);
381 strcpy(combine, prefix);
382 strcat(combine, fname);
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000383
H. Peter Anvine2c80182005-01-15 22:15:51 +0000384 if ((fp = fopen(combine, "rb")) != NULL) {
385 nasm_free(combine);
386 break;
387 }
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000388
H. Peter Anvine2c80182005-01-15 22:15:51 +0000389 nasm_free(combine);
390 pPrevPath = pp_get_include_path_ptr(pPrevPath);
391 if (pPrevPath == NULL)
392 break;
393 prefix = *pPrevPath;
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000394 }
395
396 if (fp == NULL)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000397 error(ERR_NONFATAL, "`incbin': unable to open file `%s'",
398 fname);
399 else if (fseek(fp, 0L, SEEK_END) < 0)
400 error(ERR_NONFATAL, "`incbin': unable to seek on file `%s'",
401 fname);
402 else {
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000403 static char buf[2048];
Keith Kaniosb7a89542007-04-12 02:40:54 +0000404 int32_t t = instruction->times;
405 int32_t base = 0;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000406
H. Peter Anvine2c80182005-01-15 22:15:51 +0000407 len = ftell(fp);
408 if (instruction->eops->next) {
409 base = instruction->eops->next->offset;
410 len -= base;
411 if (instruction->eops->next->next &&
412 len > instruction->eops->next->next->offset)
413 len = instruction->eops->next->next->offset;
414 }
415 /*
416 * Dummy call to list->output to give the offset to the
417 * listing module.
418 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800419 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000420 list->uplevel(LIST_INCBIN);
421 while (t--) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000422 int32_t l;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000423
H. Peter Anvine2c80182005-01-15 22:15:51 +0000424 fseek(fp, base, SEEK_SET);
425 l = len;
426 while (l > 0) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000427 int32_t m =
Charles Crayne192d5b52007-10-18 19:02:42 -0700428 fread(buf, 1, (l > (int32_t) sizeof(buf) ? (int32_t) sizeof(buf) : l),
H. Peter Anvine2c80182005-01-15 22:15:51 +0000429 fp);
430 if (!m) {
431 /*
432 * This shouldn't happen unless the file
433 * actually changes while we are reading
434 * it.
435 */
436 error(ERR_NONFATAL,
437 "`incbin': unexpected EOF while"
438 " reading file `%s'", fname);
439 t = 0; /* Try to exit cleanly */
440 break;
441 }
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800442 out(offset, segment, buf, OUT_RAWDATA, m,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000443 NO_SEG, NO_SEG);
444 l -= m;
445 }
446 }
447 list->downlevel(LIST_INCBIN);
448 if (instruction->times > 1) {
449 /*
450 * Dummy call to list->output to give the offset to the
451 * listing module.
452 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800453 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000454 list->uplevel(LIST_TIMES);
455 list->downlevel(LIST_TIMES);
456 }
457 fclose(fp);
458 return instruction->times * len;
459 }
460 return 0; /* if we're here, there's an error */
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000461 }
462
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700463 /* Check to see if we need an address-size prefix */
464 add_asp(instruction, bits);
465
H. Peter Anvin6867acc2007-10-10 14:58:45 -0700466 size_prob = false;
H. Peter Anvin70653092007-10-19 14:42:29 -0700467
468 for (temp = nasm_instructions[instruction->opcode]; temp->opcode != -1; temp++){
Keith Kaniosb7a89542007-04-12 02:40:54 +0000469 int m = matches(temp, instruction, bits);
H. Peter Anvin70653092007-10-19 14:42:29 -0700470
H. Peter Anvine2c80182005-01-15 22:15:51 +0000471 if (m == 99)
472 m += jmp_match(segment, offset, bits, instruction, temp->code);
H. Peter Anvineba20a72002-04-30 20:53:55 +0000473
H. Peter Anvine2c80182005-01-15 22:15:51 +0000474 if (m == 100) { /* matches! */
H. Peter Anvin3720f7b2008-05-12 11:00:50 -0700475 const uint8_t *codes = temp->code;
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800476 int64_t insn_size = calcsize(segment, offset, bits,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000477 instruction, codes);
478 itimes = instruction->times;
479 if (insn_size < 0) /* shouldn't be, on pass two */
480 error(ERR_PANIC, "errors made it through from pass one");
481 else
482 while (itimes--) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700483 for (j = 0; j < MAXPREFIX; j++) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000484 uint8_t c = 0;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000485 switch (instruction->prefixes[j]) {
486 case P_LOCK:
487 c = 0xF0;
488 break;
489 case P_REPNE:
490 case P_REPNZ:
491 c = 0xF2;
492 break;
493 case P_REPE:
494 case P_REPZ:
495 case P_REP:
496 c = 0xF3;
497 break;
498 case R_CS:
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000499 if (bits == 64) {
500 error(ERR_WARNING,
Charles Crayne1b851dc2007-11-05 21:49:49 -0800501 "cs segment base generated, but will be ignored in 64-bit mode");
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000502 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000503 c = 0x2E;
504 break;
505 case R_DS:
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000506 if (bits == 64) {
507 error(ERR_WARNING,
Charles Crayne1b851dc2007-11-05 21:49:49 -0800508 "ds 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 = 0x3E;
511 break;
512 case R_ES:
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000513 if (bits == 64) {
514 error(ERR_WARNING,
Charles Crayne1b851dc2007-11-05 21:49:49 -0800515 "es segment base generated, but will be ignored in 64-bit mode");
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000516 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000517 c = 0x26;
518 break;
519 case R_FS:
520 c = 0x64;
521 break;
522 case R_GS:
523 c = 0x65;
524 break;
525 case R_SS:
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000526 if (bits == 64) {
527 error(ERR_WARNING,
Charles Crayne1b851dc2007-11-05 21:49:49 -0800528 "ss segment base generated, but will be ignored in 64-bit mode");
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000529 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000530 c = 0x36;
531 break;
532 case R_SEGR6:
533 case R_SEGR7:
534 error(ERR_NONFATAL,
535 "segr6 and segr7 cannot be used as prefixes");
536 break;
537 case P_A16:
Keith Kaniosb7a89542007-04-12 02:40:54 +0000538 if (bits == 64) {
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000539 error(ERR_NONFATAL,
540 "16-bit addressing is not supported "
541 "in 64-bit mode");
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700542 } else if (bits != 16)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000543 c = 0x67;
544 break;
545 case P_A32:
546 if (bits != 32)
547 c = 0x67;
548 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700549 case P_A64:
550 if (bits != 64) {
551 error(ERR_NONFATAL,
552 "64-bit addressing is only supported "
553 "in 64-bit mode");
554 }
555 break;
556 case P_ASP:
557 c = 0x67;
558 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000559 case P_O16:
560 if (bits != 16)
561 c = 0x66;
562 break;
563 case P_O32:
Keith Kaniosb7a89542007-04-12 02:40:54 +0000564 if (bits == 16)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000565 c = 0x66;
566 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700567 case P_O64:
568 /* REX.W */
569 break;
570 case P_OSP:
571 c = 0x66;
572 break;
573 case P_none:
574 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000575 default:
576 error(ERR_PANIC, "invalid instruction prefix");
577 }
578 if (c != 0) {
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800579 out(offset, segment, &c, OUT_RAWDATA, 1,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000580 NO_SEG, NO_SEG);
581 offset++;
582 }
H. Peter Anvin70653092007-10-19 14:42:29 -0700583 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000584 insn_end = offset + insn_size;
585 gencode(segment, offset, bits, instruction, codes,
586 insn_end);
587 offset += insn_size;
588 if (itimes > 0 && itimes == instruction->times - 1) {
589 /*
590 * Dummy call to list->output to give the offset to the
591 * listing module.
592 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800593 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000594 list->uplevel(LIST_TIMES);
595 }
596 }
597 if (instruction->times > 1)
598 list->downlevel(LIST_TIMES);
599 return offset - start;
600 } else if (m > 0 && m > size_prob) {
601 size_prob = m;
602 }
Keith Kaniosb7a89542007-04-12 02:40:54 +0000603// temp++;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000604 }
H. Peter Anvineba20a72002-04-30 20:53:55 +0000605
H. Peter Anvine2c80182005-01-15 22:15:51 +0000606 if (temp->opcode == -1) { /* didn't match any instruction */
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000607 switch (size_prob) {
608 case 1:
609 error(ERR_NONFATAL, "operation size not specified");
610 break;
611 case 2:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000612 error(ERR_NONFATAL, "mismatch in operand sizes");
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000613 break;
614 case 3:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000615 error(ERR_NONFATAL, "no instruction for this cpu level");
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000616 break;
617 case 4:
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000618 error(ERR_NONFATAL, "instruction not supported in 64-bit mode");
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000619 break;
620 default:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000621 error(ERR_NONFATAL,
622 "invalid combination of opcode and operands");
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000623 break;
624 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000625 }
626 return 0;
627}
628
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800629int64_t insn_size(int32_t segment, int64_t offset, int bits, uint32_t cp,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000630 insn * instruction, efunc error)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000631{
H. Peter Anvin3360d792007-09-11 04:16:57 +0000632 const struct itemplate *temp;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000633
H. Peter Anvine2c80182005-01-15 22:15:51 +0000634 errfunc = error; /* to pass to other functions */
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000635 cpu = cp;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000636
637 if (instruction->opcode == -1)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000638 return 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000639
H. Peter Anvincfbe7c32007-09-18 17:49:09 -0700640 if (instruction->opcode == I_DB || instruction->opcode == I_DW ||
641 instruction->opcode == I_DD || instruction->opcode == I_DQ ||
H. Peter Anvindfb91802008-05-20 11:43:53 -0700642 instruction->opcode == I_DT || instruction->opcode == I_DO ||
643 instruction->opcode == I_DY) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000644 extop *e;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000645 int32_t isize, osize, wsize = 0; /* placate gcc */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000646
H. Peter Anvine2c80182005-01-15 22:15:51 +0000647 isize = 0;
648 switch (instruction->opcode) {
649 case I_DB:
650 wsize = 1;
651 break;
652 case I_DW:
653 wsize = 2;
654 break;
655 case I_DD:
656 wsize = 4;
657 break;
658 case I_DQ:
659 wsize = 8;
660 break;
661 case I_DT:
662 wsize = 10;
663 break;
H. Peter Anvincfbe7c32007-09-18 17:49:09 -0700664 case I_DO:
665 wsize = 16;
666 break;
H. Peter Anvindfb91802008-05-20 11:43:53 -0700667 case I_DY:
668 wsize = 32;
669 break;
H. Peter Anvin16b0a332007-09-12 20:27:41 -0700670 default:
671 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000672 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000673
H. Peter Anvine2c80182005-01-15 22:15:51 +0000674 for (e = instruction->eops; e; e = e->next) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000675 int32_t align;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000676
H. Peter Anvine2c80182005-01-15 22:15:51 +0000677 osize = 0;
678 if (e->type == EOT_DB_NUMBER)
679 osize = 1;
680 else if (e->type == EOT_DB_STRING)
681 osize = e->stringlen;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000682
H. Peter Anvine2c80182005-01-15 22:15:51 +0000683 align = (-osize) % wsize;
684 if (align < 0)
685 align += wsize;
686 isize += osize + align;
687 }
688 return isize * instruction->times;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000689 }
690
H. Peter Anvine2c80182005-01-15 22:15:51 +0000691 if (instruction->opcode == I_INCBIN) {
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000692 char fname[FILENAME_MAX];
H. Peter Anvine2c80182005-01-15 22:15:51 +0000693 FILE *fp;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000694 int32_t len;
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000695 char *prefix = "", *combine;
696 char **pPrevPath = NULL;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000697
H. Peter Anvine2c80182005-01-15 22:15:51 +0000698 len = FILENAME_MAX - 1;
699 if (len > instruction->eops->stringlen)
700 len = instruction->eops->stringlen;
701 strncpy(fname, instruction->eops->stringval, len);
702 fname[len] = '\0';
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000703
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700704 /* added by alexfru: 'incbin' uses include paths */
705 while (1) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000706 combine = nasm_malloc(strlen(prefix) + len + 1);
707 strcpy(combine, prefix);
708 strcat(combine, fname);
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000709
H. Peter Anvine2c80182005-01-15 22:15:51 +0000710 if ((fp = fopen(combine, "rb")) != NULL) {
711 nasm_free(combine);
712 break;
713 }
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000714
H. Peter Anvine2c80182005-01-15 22:15:51 +0000715 nasm_free(combine);
716 pPrevPath = pp_get_include_path_ptr(pPrevPath);
717 if (pPrevPath == NULL)
718 break;
719 prefix = *pPrevPath;
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000720 }
721
722 if (fp == NULL)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000723 error(ERR_NONFATAL, "`incbin': unable to open file `%s'",
724 fname);
725 else if (fseek(fp, 0L, SEEK_END) < 0)
726 error(ERR_NONFATAL, "`incbin': unable to seek on file `%s'",
727 fname);
728 else {
729 len = ftell(fp);
730 fclose(fp);
731 if (instruction->eops->next) {
732 len -= instruction->eops->next->offset;
733 if (instruction->eops->next->next &&
734 len > instruction->eops->next->next->offset) {
735 len = instruction->eops->next->next->offset;
736 }
737 }
738 return instruction->times * len;
739 }
740 return 0; /* if we're here, there's an error */
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000741 }
742
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700743 /* Check to see if we need an address-size prefix */
744 add_asp(instruction, bits);
745
Keith Kaniosb7a89542007-04-12 02:40:54 +0000746 for (temp = nasm_instructions[instruction->opcode]; temp->opcode != -1; temp++) {
747 int m = matches(temp, instruction, bits);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000748 if (m == 99)
749 m += jmp_match(segment, offset, bits, instruction, temp->code);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000750
H. Peter Anvine2c80182005-01-15 22:15:51 +0000751 if (m == 100) {
752 /* we've matched an instruction. */
Charles Crayne5fbbc8c2007-11-07 19:03:46 -0800753 int64_t isize;
H. Peter Anvin3720f7b2008-05-12 11:00:50 -0700754 const uint8_t *codes = temp->code;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000755 int j;
756
757 isize = calcsize(segment, offset, bits, instruction, codes);
758 if (isize < 0)
759 return -1;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700760 for (j = 0; j < MAXPREFIX; j++) {
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700761 switch (instruction->prefixes[j]) {
762 case P_A16:
763 if (bits != 16)
764 isize++;
765 break;
766 case P_A32:
767 if (bits != 32)
768 isize++;
769 break;
770 case P_O16:
771 if (bits != 16)
772 isize++;
773 break;
774 case P_O32:
775 if (bits == 16)
776 isize++;
777 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700778 case P_A64:
779 case P_O64:
780 case P_none:
781 break;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700782 default:
783 isize++;
784 break;
785 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000786 }
787 return isize * instruction->times;
788 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000789 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000790 return -1; /* didn't match any instruction */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000791}
792
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700793static bool possible_sbyte(insn * ins, int op)
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000794{
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700795 return !(ins->forw_ref && ins->oprs[op].opflags) &&
H. Peter Anvine2c80182005-01-15 22:15:51 +0000796 optimizing >= 0 &&
797 !(ins->oprs[op].type & STRICT) &&
798 ins->oprs[op].wrt == NO_SEG && ins->oprs[op].segment == NO_SEG;
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000799}
800
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700801/* check that opn[op] is a signed byte of size 16 or 32 */
802static bool is_sbyte16(insn * ins, int op)
803{
804 int16_t v;
805
806 if (!possible_sbyte(ins, op))
807 return false;
808
809 v = ins->oprs[op].offset;
810 return v >= -128 && v <= 127;
811}
812
813static bool is_sbyte32(insn * ins, int op)
814{
815 int32_t v;
816
817 if (!possible_sbyte(ins, op))
818 return false;
819
820 v = ins->oprs[op].offset;
821 return v >= -128 && v <= 127;
822}
823
824/* check that opn[op] is a signed byte of size 32; warn if this is not
825 the original value when extended to 64 bits */
826static bool is_sbyte64(insn * ins, int op)
827{
828 int64_t v64;
829 int32_t v32;
830
831 /* dead in the water on forward reference or External */
832 if (!possible_sbyte(ins, op))
833 return false;
834
835 v64 = ins->oprs[op].offset;
836 v32 = (int32_t)v64;
837
838 warn_overflow(32, v64);
839
840 return v32 >= -128 && v32 <= 127;
841}
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800842static int64_t calcsize(int32_t segment, int64_t offset, int bits,
H. Peter Anvin3720f7b2008-05-12 11:00:50 -0700843 insn * ins, const uint8_t *codes)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000844{
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800845 int64_t length = 0;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000846 uint8_t c;
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000847 int rex_mask = ~0;
H. Peter Anvin839eca22007-10-29 23:12:47 -0700848 struct operand *opx;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000849
H. Peter Anvine3917fc2007-11-01 14:53:32 -0700850 ins->rex = 0; /* Ensure REX is reset */
851
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700852 if (ins->prefixes[PPS_OSIZE] == P_O64)
853 ins->rex |= REX_W;
854
H. Peter Anvine2c80182005-01-15 22:15:51 +0000855 (void)segment; /* Don't warn that this parameter is unused */
856 (void)offset; /* Don't warn that this parameter is unused */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000857
H. Peter Anvin839eca22007-10-29 23:12:47 -0700858 while (*codes) {
859 c = *codes++;
860 opx = &ins->oprs[c & 3];
861 switch (c) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000862 case 01:
863 case 02:
864 case 03:
865 codes += c, length += c;
866 break;
867 case 04:
868 case 05:
869 case 06:
870 case 07:
871 length++;
872 break;
873 case 010:
874 case 011:
875 case 012:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700876 case 013:
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000877 ins->rex |=
H. Peter Anvin839eca22007-10-29 23:12:47 -0700878 op_rexflags(opx, REX_B|REX_H|REX_P|REX_W);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000879 codes++, length++;
880 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000881 case 014:
882 case 015:
883 case 016:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700884 case 017:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000885 length++;
886 break;
887 case 020:
888 case 021:
889 case 022:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700890 case 023:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000891 length++;
892 break;
893 case 024:
894 case 025:
895 case 026:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700896 case 027:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000897 length++;
898 break;
899 case 030:
900 case 031:
901 case 032:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700902 case 033:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000903 length += 2;
904 break;
905 case 034:
906 case 035:
907 case 036:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700908 case 037:
H. Peter Anvin839eca22007-10-29 23:12:47 -0700909 if (opx->type & (BITS16 | BITS32 | BITS64))
910 length += (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000911 else
912 length += (bits == 16) ? 2 : 4;
913 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000914 case 040:
915 case 041:
916 case 042:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700917 case 043:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000918 length += 4;
919 break;
920 case 044:
921 case 045:
922 case 046:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700923 case 047:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700924 length += ins->addr_size >> 3;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000925 break;
926 case 050:
927 case 051:
928 case 052:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700929 case 053:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000930 length++;
931 break;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000932 case 054:
933 case 055:
934 case 056:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700935 case 057:
Keith Kaniosb7a89542007-04-12 02:40:54 +0000936 length += 8; /* MOV reg64/imm */
937 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000938 case 060:
939 case 061:
940 case 062:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700941 case 063:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000942 length += 2;
943 break;
944 case 064:
945 case 065:
946 case 066:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700947 case 067:
H. Peter Anvin839eca22007-10-29 23:12:47 -0700948 if (opx->type & (BITS16 | BITS32 | BITS64))
949 length += (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000950 else
951 length += (bits == 16) ? 2 : 4;
952 break;
953 case 070:
954 case 071:
955 case 072:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700956 case 073:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000957 length += 4;
958 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700959 case 074:
960 case 075:
961 case 076:
962 case 077:
963 length += 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000964 break;
965 case 0140:
966 case 0141:
967 case 0142:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700968 case 0143:
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700969 length += is_sbyte16(ins, c & 3) ? 1 : 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000970 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000971 case 0144:
972 case 0145:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700973 case 0146:
974 case 0147:
H. Peter Anvina30cc072007-11-18 21:55:26 -0800975 codes++;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000976 length++;
977 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700978 case 0150:
979 case 0151:
980 case 0152:
981 case 0153:
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700982 length += is_sbyte32(ins, c & 3) ? 1 : 4;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700983 break;
984 case 0154:
985 case 0155:
986 case 0156:
987 case 0157:
H. Peter Anvina30cc072007-11-18 21:55:26 -0800988 codes++;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700989 length++;
990 break;
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700991 case 0160:
992 case 0161:
993 case 0162:
994 case 0163:
995 length++;
996 ins->rex |= REX_D;
H. Peter Anvind85d2502008-05-04 17:53:31 -0700997 ins->drexdst = regval(opx);
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700998 break;
999 case 0164:
1000 case 0165:
1001 case 0166:
1002 case 0167:
1003 length++;
1004 ins->rex |= REX_D|REX_OC;
H. Peter Anvind85d2502008-05-04 17:53:31 -07001005 ins->drexdst = regval(opx);
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001006 break;
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001007 case 0171:
1008 break;
H. Peter Anvind85d2502008-05-04 17:53:31 -07001009 case 0172:
H. Peter Anvind58656f2008-05-06 20:11:14 -07001010 case 0173:
H. Peter Anvin52dc3532008-05-20 19:29:04 -07001011 case 0174:
H. Peter Anvind85d2502008-05-04 17:53:31 -07001012 codes++;
1013 length++;
1014 break;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001015 case 0250:
1016 case 0251:
1017 case 0252:
1018 case 0253:
1019 length += is_sbyte64(ins, c & 3) ? 1 : 4;
1020 break;
H. Peter Anvind85d2502008-05-04 17:53:31 -07001021 case 0260:
1022 case 0261:
1023 case 0262:
1024 case 0263:
1025 length += 2;
1026 ins->rex |= REX_V;
1027 ins->drexdst = regval(opx);
1028 ins->vex_m = *codes++;
1029 ins->vex_wlp = *codes++;
1030 break;
1031 case 0270:
1032 length += 2;
1033 ins->rex |= REX_V;
1034 ins->drexdst = 0;
1035 ins->vex_m = *codes++;
1036 ins->vex_wlp = *codes++;
1037 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001038 case 0300:
1039 case 0301:
H. Peter Anvin70653092007-10-19 14:42:29 -07001040 case 0302:
1041 case 0303:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001042 break;
1043 case 0310:
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07001044 if (bits == 64)
1045 return -1;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001046 length += (bits != 16) && !has_prefix(ins, PPS_ASIZE, P_A16);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001047 break;
1048 case 0311:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001049 length += (bits != 32) && !has_prefix(ins, PPS_ASIZE, P_A32);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001050 break;
1051 case 0312:
H. Peter Anvin70653092007-10-19 14:42:29 -07001052 break;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001053 case 0313:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001054 if (bits != 64 || has_prefix(ins, PPS_ASIZE, P_A16) ||
1055 has_prefix(ins, PPS_ASIZE, P_A32))
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07001056 return -1;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001057 break;
H. Peter Anvin23440102007-11-12 21:02:33 -08001058 case 0314:
1059 case 0315:
1060 case 0316:
1061 case 0317:
1062 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001063 case 0320:
Keith Kaniosb7a89542007-04-12 02:40:54 +00001064 length += (bits != 16);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001065 break;
1066 case 0321:
1067 length += (bits == 16);
1068 break;
1069 case 0322:
1070 break;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001071 case 0323:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001072 rex_mask &= ~REX_W;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001073 break;
1074 case 0324:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001075 ins->rex |= REX_W;
H. Peter Anvin8d7316a2007-04-18 02:27:18 +00001076 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001077 case 0330:
1078 codes++, length++;
1079 break;
1080 case 0331:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001081 break;
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001082 case 0332:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001083 case 0333:
1084 length++;
1085 break;
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001086 case 0334:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001087 ins->rex |= REX_L;
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001088 break;
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001089 case 0335:
1090 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001091 case 0340:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001092 if (ins->oprs[0].segment != NO_SEG)
1093 errfunc(ERR_NONFATAL, "attempt to reserve non-constant"
1094 " quantity of BSS space");
1095 else
H. Peter Anvin428fd672007-11-15 10:25:52 -08001096 length += ins->oprs[0].offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001097 break;
H. Peter Anvinfff5a472008-05-20 09:46:24 -07001098 case 0360:
1099 break;
1100 case 0361:
1101 case 0362:
1102 case 0363:
1103 length++;
1104 break;
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001105 case 0364:
1106 case 0365:
1107 break;
Keith Kanios48af1772007-08-17 07:37:52 +00001108 case 0366:
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001109 case 0367:
1110 length++;
1111 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001112 case 0370:
1113 case 0371:
1114 case 0372:
1115 break;
1116 case 0373:
1117 length++;
1118 break;
1119 default: /* can't do it by 'case' statements */
1120 if (c >= 0100 && c <= 0277) { /* it's an EA */
1121 ea ea_data;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001122 int rfield;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001123 int32_t rflags;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001124 ea_data.rex = 0; /* Ensure ea.REX is initially 0 */
H. Peter Anvin70653092007-10-19 14:42:29 -07001125
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001126 if (c <= 0177) {
1127 /* pick rfield from operand b */
1128 rflags = regflag(&ins->oprs[c & 7]);
H. Peter Anvina4835d42008-05-20 14:21:29 -07001129 rfield = nasm_regvals[ins->oprs[c & 7].basereg];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001130 } else {
1131 rflags = 0;
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001132 rfield = c & 7;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001133 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00001134
H. Peter Anvine2c80182005-01-15 22:15:51 +00001135 if (!process_ea
Keith Kaniosb7a89542007-04-12 02:40:54 +00001136 (&ins->oprs[(c >> 3) & 7], &ea_data, bits,
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001137 ins->addr_size, rfield, rflags, ins->forw_ref)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001138 errfunc(ERR_NONFATAL, "invalid effective address");
1139 return -1;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001140 } else {
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001141 ins->rex |= ea_data.rex;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001142 length += ea_data.size;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001143 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001144 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001145 errfunc(ERR_PANIC, "internal instruction table corrupt"
1146 ": instruction code 0x%02X given", c);
H. Peter Anvin839eca22007-10-29 23:12:47 -07001147 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001148 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001149 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001150
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001151 ins->rex &= rex_mask;
H. Peter Anvin70653092007-10-19 14:42:29 -07001152
H. Peter Anvind85d2502008-05-04 17:53:31 -07001153 if (ins->rex & REX_V) {
1154 int bad32 = REX_R|REX_W|REX_X|REX_B;
1155
1156 if (ins->rex & REX_H) {
1157 errfunc(ERR_NONFATAL, "cannot use high register in vex instruction");
1158 return -1;
1159 }
1160 switch (ins->vex_wlp & 030) {
1161 case 000:
1162 ins->rex &= ~REX_W;
1163 break;
1164 case 010:
1165 ins->rex |= REX_W;
1166 bad32 &= ~REX_W;
1167 break;
1168 default:
1169 /* Follow REX_W */
1170 break;
1171 }
1172
1173 if (bits != 64 && ((ins->rex & bad32) || ins->drexdst > 7)) {
1174 errfunc(ERR_NONFATAL, "invalid operands in non-64-bit mode");
1175 return -1;
1176 }
1177 if (ins->vex_m != 1 || (ins->rex & (REX_W|REX_R|REX_B)))
1178 length += 3;
1179 else
1180 length += 2;
1181 } else if (ins->rex & REX_D) {
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001182 if (ins->rex & REX_H) {
1183 errfunc(ERR_NONFATAL, "cannot use high register in drex instruction");
1184 return -1;
1185 }
H. Peter Anvind85d2502008-05-04 17:53:31 -07001186 if (bits != 64 && ((ins->rex & (REX_R|REX_W|REX_X|REX_B)) ||
H. Peter Anvincf5180a2007-09-17 17:25:27 -07001187 ins->drexdst > 7)) {
1188 errfunc(ERR_NONFATAL, "invalid operands in non-64-bit mode");
1189 return -1;
1190 }
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001191 length++;
1192 } else if (ins->rex & REX_REAL) {
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001193 if (ins->rex & REX_H) {
1194 errfunc(ERR_NONFATAL, "cannot use high register in rex instruction");
1195 return -1;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001196 } else if (bits == 64) {
1197 length++;
1198 } else if ((ins->rex & REX_L) &&
1199 !(ins->rex & (REX_P|REX_W|REX_X|REX_B)) &&
1200 cpu >= IF_X86_64) {
1201 /* LOCK-as-REX.R */
1202 assert_no_prefix(ins, PPS_LREP);
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001203 length++;
H. Peter Anvin8d7316a2007-04-18 02:27:18 +00001204 } else {
H. Peter Anvincf5180a2007-09-17 17:25:27 -07001205 errfunc(ERR_NONFATAL, "invalid operands in non-64-bit mode");
1206 return -1;
H. Peter Anvin8d7316a2007-04-18 02:27:18 +00001207 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00001208 }
1209
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001210 return length;
1211}
Keith Kaniosb7a89542007-04-12 02:40:54 +00001212
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001213#define EMIT_REX() \
H. Peter Anvind85d2502008-05-04 17:53:31 -07001214 if (!(ins->rex & (REX_D|REX_V)) && (ins->rex & REX_REAL) && (bits == 64)) { \
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001215 ins->rex = (ins->rex & REX_REAL)|REX_P; \
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001216 out(offset, segment, &ins->rex, OUT_RAWDATA, 1, NO_SEG, NO_SEG); \
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001217 ins->rex = 0; \
1218 offset += 1; \
1219 }
1220
Charles Crayne1f8bc4c2007-11-06 18:27:23 -08001221static void gencode(int32_t segment, int64_t offset, int bits,
H. Peter Anvin3720f7b2008-05-12 11:00:50 -07001222 insn * ins, const uint8_t *codes, int64_t insn_end)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001223{
Keith Kaniosa6dfa782007-04-13 16:47:53 +00001224 static char condval[] = { /* conditional opcodes */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001225 0x7, 0x3, 0x2, 0x6, 0x2, 0x4, 0xF, 0xD, 0xC, 0xE, 0x6, 0x2,
1226 0x3, 0x7, 0x3, 0x5, 0xE, 0xC, 0xD, 0xF, 0x1, 0xB, 0x9, 0x5,
1227 0x0, 0xA, 0xA, 0xB, 0x8, 0x4
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001228 };
Keith Kaniosb7a89542007-04-12 02:40:54 +00001229 uint8_t c;
1230 uint8_t bytes[4];
Charles Crayne1f8bc4c2007-11-06 18:27:23 -08001231 int64_t size;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001232 int64_t data;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001233 struct operand *opx;
H. Peter Anvin70653092007-10-19 14:42:29 -07001234
H. Peter Anvin839eca22007-10-29 23:12:47 -07001235 while (*codes) {
1236 c = *codes++;
1237 opx = &ins->oprs[c & 3];
1238 switch (c) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001239 case 01:
1240 case 02:
1241 case 03:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001242 EMIT_REX();
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001243 out(offset, segment, codes, OUT_RAWDATA, c, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001244 codes += c;
1245 offset += c;
1246 break;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001247
H. Peter Anvine2c80182005-01-15 22:15:51 +00001248 case 04:
1249 case 06:
1250 switch (ins->oprs[0].basereg) {
1251 case R_CS:
1252 bytes[0] = 0x0E + (c == 0x04 ? 1 : 0);
1253 break;
1254 case R_DS:
1255 bytes[0] = 0x1E + (c == 0x04 ? 1 : 0);
1256 break;
1257 case R_ES:
1258 bytes[0] = 0x06 + (c == 0x04 ? 1 : 0);
1259 break;
1260 case R_SS:
1261 bytes[0] = 0x16 + (c == 0x04 ? 1 : 0);
1262 break;
1263 default:
1264 errfunc(ERR_PANIC,
1265 "bizarre 8086 segment register received");
1266 }
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++;
1269 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001270
H. Peter Anvine2c80182005-01-15 22:15:51 +00001271 case 05:
1272 case 07:
1273 switch (ins->oprs[0].basereg) {
1274 case R_FS:
1275 bytes[0] = 0xA0 + (c == 0x05 ? 1 : 0);
1276 break;
1277 case R_GS:
1278 bytes[0] = 0xA8 + (c == 0x05 ? 1 : 0);
1279 break;
1280 default:
1281 errfunc(ERR_PANIC,
1282 "bizarre 386 segment register received");
1283 }
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001284 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001285 offset++;
1286 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001287
H. Peter Anvine2c80182005-01-15 22:15:51 +00001288 case 010:
1289 case 011:
1290 case 012:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001291 case 013:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001292 EMIT_REX();
H. Peter Anvin839eca22007-10-29 23:12:47 -07001293 bytes[0] = *codes++ + ((regval(opx)) & 7);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001294 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001295 offset += 1;
1296 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001297
H. Peter Anvine2c80182005-01-15 22:15:51 +00001298 case 014:
1299 case 015:
1300 case 016:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001301 case 017:
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001302 /* XXX: warns for legitimate optimizer actions */
H. Peter Anvin839eca22007-10-29 23:12:47 -07001303 if (opx->offset < -128 || opx->offset > 127) {
H. Peter Anvin72c64372008-01-08 22:13:48 -08001304 errfunc(ERR_WARNING | ERR_WARN_NOV,
1305 "signed byte value exceeds bounds");
H. Peter Anvine2c80182005-01-15 22:15:51 +00001306 }
H. Peter Anvineba20a72002-04-30 20:53:55 +00001307
H. Peter Anvin839eca22007-10-29 23:12:47 -07001308 if (opx->segment != NO_SEG) {
1309 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001310 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001311 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001312 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001313 bytes[0] = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001314 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001315 NO_SEG);
1316 }
1317 offset += 1;
1318 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001319
H. Peter Anvine2c80182005-01-15 22:15:51 +00001320 case 020:
1321 case 021:
1322 case 022:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001323 case 023:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001324 if (opx->offset < -256 || opx->offset > 255) {
H. Peter Anvin72c64372008-01-08 22:13:48 -08001325 errfunc(ERR_WARNING | ERR_WARN_NOV,
1326 "byte value exceeds bounds");
H. Peter Anvine2c80182005-01-15 22:15:51 +00001327 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001328 if (opx->segment != NO_SEG) {
1329 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001330 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001331 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001332 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001333 bytes[0] = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001334 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001335 NO_SEG);
1336 }
1337 offset += 1;
1338 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001339
H. Peter Anvine2c80182005-01-15 22:15:51 +00001340 case 024:
1341 case 025:
1342 case 026:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001343 case 027:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001344 if (opx->offset < 0 || opx->offset > 255)
H. Peter Anvin72c64372008-01-08 22:13:48 -08001345 errfunc(ERR_WARNING | ERR_WARN_NOV,
1346 "unsigned byte value exceeds bounds");
H. Peter Anvin839eca22007-10-29 23:12:47 -07001347 if (opx->segment != NO_SEG) {
1348 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001349 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001350 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001351 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001352 bytes[0] = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001353 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001354 NO_SEG);
1355 }
1356 offset += 1;
1357 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001358
H. Peter Anvine2c80182005-01-15 22:15:51 +00001359 case 030:
1360 case 031:
1361 case 032:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001362 case 033:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001363 data = opx->offset;
1364 if (opx->segment == NO_SEG && opx->wrt == NO_SEG)
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001365 warn_overflow(2, data);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001366 out(offset, segment, &data, OUT_ADDRESS, 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001367 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001368 offset += 2;
1369 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001370
H. Peter Anvine2c80182005-01-15 22:15:51 +00001371 case 034:
1372 case 035:
1373 case 036:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001374 case 037:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001375 if (opx->type & (BITS16 | BITS32))
1376 size = (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001377 else
1378 size = (bits == 16) ? 2 : 4;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001379 data = opx->offset;
1380 if (opx->segment == NO_SEG && opx->wrt == NO_SEG)
H. Peter Anvin10e27272007-10-29 22:56:08 -07001381 warn_overflow(size, data);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001382 out(offset, segment, &data, OUT_ADDRESS, size,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001383 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001384 offset += size;
1385 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001386
H. Peter Anvine2c80182005-01-15 22:15:51 +00001387 case 040:
1388 case 041:
1389 case 042:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001390 case 043:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001391 data = opx->offset;
H. Peter Anvin72c64372008-01-08 22:13:48 -08001392 if (opx->segment == NO_SEG && opx->wrt == NO_SEG)
1393 warn_overflow(4, data);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001394 out(offset, segment, &data, OUT_ADDRESS, 4,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001395 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001396 offset += 4;
1397 break;
H. Peter Anvin3ba46772002-05-27 23:19:35 +00001398
H. Peter Anvine2c80182005-01-15 22:15:51 +00001399 case 044:
1400 case 045:
1401 case 046:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001402 case 047:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001403 data = opx->offset;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001404 size = ins->addr_size >> 3;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001405 if (opx->segment == NO_SEG &&
1406 opx->wrt == NO_SEG)
H. Peter Anvin10e27272007-10-29 22:56:08 -07001407 warn_overflow(size, data);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001408 out(offset, segment, &data, OUT_ADDRESS, size,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001409 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001410 offset += size;
1411 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001412
H. Peter Anvine2c80182005-01-15 22:15:51 +00001413 case 050:
1414 case 051:
1415 case 052:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001416 case 053:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001417 if (opx->segment != segment)
H. Peter Anvine2c80182005-01-15 22:15:51 +00001418 errfunc(ERR_NONFATAL,
1419 "short relative jump outside segment");
H. Peter Anvin839eca22007-10-29 23:12:47 -07001420 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001421 if (data > 127 || data < -128)
1422 errfunc(ERR_NONFATAL, "short jump is out of range");
1423 bytes[0] = data;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001424 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001425 offset += 1;
1426 break;
H. Peter Anvin70653092007-10-19 14:42:29 -07001427
Keith Kaniosb7a89542007-04-12 02:40:54 +00001428 case 054:
1429 case 055:
1430 case 056:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001431 case 057:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001432 data = (int64_t)opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001433 out(offset, segment, &data, OUT_ADDRESS, 8,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001434 opx->segment, opx->wrt);
Keith Kaniosb7a89542007-04-12 02:40:54 +00001435 offset += 8;
1436 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001437
H. Peter Anvine2c80182005-01-15 22:15:51 +00001438 case 060:
1439 case 061:
1440 case 062:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001441 case 063:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001442 if (opx->segment != segment) {
1443 data = opx->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001444 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001445 OUT_REL2ADR, insn_end - offset,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001446 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001447 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001448 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001449 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001450 OUT_ADDRESS, 2, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001451 }
1452 offset += 2;
1453 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001454
H. Peter Anvine2c80182005-01-15 22:15:51 +00001455 case 064:
1456 case 065:
1457 case 066:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001458 case 067:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001459 if (opx->type & (BITS16 | BITS32 | BITS64))
1460 size = (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001461 else
1462 size = (bits == 16) ? 2 : 4;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001463 if (opx->segment != segment) {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001464 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001465 out(offset, segment, &data,
1466 size == 2 ? OUT_REL2ADR : OUT_REL4ADR,
1467 insn_end - offset, opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001468 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001469 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001470 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001471 OUT_ADDRESS, size, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001472 }
1473 offset += size;
1474 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001475
H. Peter Anvine2c80182005-01-15 22:15:51 +00001476 case 070:
1477 case 071:
1478 case 072:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001479 case 073:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001480 if (opx->segment != segment) {
1481 data = opx->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001482 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001483 OUT_REL4ADR, insn_end - offset,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001484 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001485 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001486 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001487 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001488 OUT_ADDRESS, 4, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001489 }
1490 offset += 4;
1491 break;
H. Peter Anvinaf535c12002-04-30 20:59:21 +00001492
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001493 case 074:
1494 case 075:
1495 case 076:
1496 case 077:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001497 if (opx->segment == NO_SEG)
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001498 errfunc(ERR_NONFATAL, "value referenced by FAR is not"
1499 " relocatable");
H. Peter Anvindfb91802008-05-20 11:43:53 -07001500 data = 0;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001501 out(offset, segment, &data, OUT_ADDRESS, 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001502 outfmt->segbase(1 + opx->segment),
1503 opx->wrt);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001504 offset += 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001505 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001506
H. Peter Anvine2c80182005-01-15 22:15:51 +00001507 case 0140:
1508 case 0141:
1509 case 0142:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001510 case 0143:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001511 data = opx->offset;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001512 if (is_sbyte16(ins, c & 3)) {
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001513 bytes[0] = data;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001514 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001515 NO_SEG);
1516 offset++;
1517 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001518 if (opx->segment == NO_SEG &&
1519 opx->wrt == NO_SEG)
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001520 warn_overflow(2, data);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001521 out(offset, segment, &data, OUT_ADDRESS, 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001522 opx->segment, opx->wrt);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001523 offset += 2;
1524 }
1525 break;
1526
1527 case 0144:
1528 case 0145:
1529 case 0146:
1530 case 0147:
1531 EMIT_REX();
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001532 bytes[0] = *codes++;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001533 if (is_sbyte16(ins, c & 3))
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001534 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 Anvin7eb4a382007-09-17 15:49:30 -07001536 offset++;
1537 break;
1538
1539 case 0150:
1540 case 0151:
1541 case 0152:
1542 case 0153:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001543 data = opx->offset;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001544 if (is_sbyte32(ins, c & 3)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001545 bytes[0] = data;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001546 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001547 NO_SEG);
1548 offset++;
1549 } else {
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001550 out(offset, segment, &data, OUT_ADDRESS, 4,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001551 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001552 offset += 4;
1553 }
1554 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001555
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001556 case 0154:
1557 case 0155:
1558 case 0156:
1559 case 0157:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001560 EMIT_REX();
H. Peter Anvine2c80182005-01-15 22:15:51 +00001561 bytes[0] = *codes++;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001562 if (is_sbyte32(ins, c & 3))
H. Peter Anvine2c80182005-01-15 22:15:51 +00001563 bytes[0] |= 2; /* s-bit */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001564 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001565 offset++;
1566 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001567
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001568 case 0160:
1569 case 0161:
1570 case 0162:
1571 case 0163:
1572 case 0164:
1573 case 0165:
1574 case 0166:
1575 case 0167:
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001576 break;
1577
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001578 case 0171:
1579 bytes[0] =
1580 (ins->drexdst << 4) |
1581 (ins->rex & REX_OC ? 0x08 : 0) |
1582 (ins->rex & (REX_R|REX_X|REX_B));
1583 ins->rex = 0;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001584 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001585 offset++;
1586 break;
1587
H. Peter Anvind85d2502008-05-04 17:53:31 -07001588 case 0172:
1589 c = *codes++;
1590 opx = &ins->oprs[c >> 3];
H. Peter Anvina4835d42008-05-20 14:21:29 -07001591 bytes[0] = nasm_regvals[opx->basereg] << 4;
H. Peter Anvind85d2502008-05-04 17:53:31 -07001592 opx = &ins->oprs[c & 7];
1593 if (opx->segment != NO_SEG || opx->wrt != NO_SEG) {
1594 errfunc(ERR_NONFATAL,
1595 "non-absolute expression not permitted as argument %d",
1596 c & 7);
1597 } else {
1598 if (opx->offset & ~15) {
1599 errfunc(ERR_WARNING | ERR_WARN_NOV,
1600 "four-bit argument exceeds bounds");
1601 }
1602 bytes[0] |= opx->offset & 15;
1603 }
1604 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1605 offset++;
1606 break;
1607
H. Peter Anvind58656f2008-05-06 20:11:14 -07001608 case 0173:
1609 c = *codes++;
1610 opx = &ins->oprs[c >> 4];
H. Peter Anvina4835d42008-05-20 14:21:29 -07001611 bytes[0] = nasm_regvals[opx->basereg] << 4;
H. Peter Anvind58656f2008-05-06 20:11:14 -07001612 bytes[0] |= c & 15;
1613 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1614 offset++;
1615 break;
1616
H. Peter Anvin52dc3532008-05-20 19:29:04 -07001617 case 0174:
1618 c = *codes++;
1619 opx = &ins->oprs[c];
1620 bytes[0] = nasm_regvals[opx->basereg] << 4;
1621 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1622 offset++;
1623 break;
1624
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001625 case 0250:
1626 case 0251:
1627 case 0252:
1628 case 0253:
1629 data = opx->offset;
1630 /* is_sbyte32() is right here, we have already warned */
1631 if (is_sbyte32(ins, c & 3)) {
1632 bytes[0] = data;
1633 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
1634 NO_SEG);
1635 offset++;
1636 } else {
1637 out(offset, segment, &data, OUT_ADDRESS, 4,
1638 opx->segment, opx->wrt);
1639 offset += 4;
1640 }
1641 break;
1642
H. Peter Anvind85d2502008-05-04 17:53:31 -07001643 case 0260:
1644 case 0261:
1645 case 0262:
1646 case 0263:
1647 case 0270:
1648 codes += 2;
1649 if (ins->vex_m != 1 || (ins->rex & (REX_W|REX_X|REX_B))) {
1650 bytes[0] = 0xc4;
H. Peter Anvin4d2c38c2008-05-04 23:15:13 -07001651 bytes[1] = ins->vex_m | ((~ins->rex & 7) << 5);
H. Peter Anvind85d2502008-05-04 17:53:31 -07001652 bytes[2] = ((ins->rex & REX_W) << (7-3)) |
H. Peter Anvin4d2c38c2008-05-04 23:15:13 -07001653 ((~ins->drexdst & 15)<< 3) | (ins->vex_wlp & 07);
H. Peter Anvind85d2502008-05-04 17:53:31 -07001654 out(offset, segment, &bytes, OUT_RAWDATA, 3, NO_SEG, NO_SEG);
1655 offset += 3;
1656 } else {
1657 bytes[0] = 0xc5;
H. Peter Anvin4d2c38c2008-05-04 23:15:13 -07001658 bytes[1] = ((~ins->rex & REX_R) << (7-2)) |
1659 ((~ins->drexdst & 15) << 3) | (ins->vex_wlp & 07);
H. Peter Anvind85d2502008-05-04 17:53:31 -07001660 out(offset, segment, &bytes, OUT_RAWDATA, 2, NO_SEG, NO_SEG);
1661 offset += 2;
1662 }
1663 break;
1664
H. Peter Anvine2c80182005-01-15 22:15:51 +00001665 case 0300:
1666 case 0301:
1667 case 0302:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001668 case 0303:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001669 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001670
H. Peter Anvine2c80182005-01-15 22:15:51 +00001671 case 0310:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001672 if (bits == 32 && !has_prefix(ins, PPS_ASIZE, P_A16)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001673 *bytes = 0x67;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001674 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001675 offset += 1;
1676 } else
1677 offset += 0;
1678 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001679
H. Peter Anvine2c80182005-01-15 22:15:51 +00001680 case 0311:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001681 if (bits != 32 && !has_prefix(ins, PPS_ASIZE, P_A32)) {
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 0312:
1690 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001691
Keith Kaniosb7a89542007-04-12 02:40:54 +00001692 case 0313:
1693 ins->rex = 0;
1694 break;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07001695
H. Peter Anvin23440102007-11-12 21:02:33 -08001696 case 0314:
1697 case 0315:
1698 case 0316:
1699 case 0317:
1700 break;
1701
H. Peter Anvine2c80182005-01-15 22:15:51 +00001702 case 0320:
Keith Kaniosb7a89542007-04-12 02:40:54 +00001703 if (bits != 16) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001704 *bytes = 0x66;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001705 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001706 offset += 1;
1707 } else
1708 offset += 0;
1709 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001710
H. Peter Anvine2c80182005-01-15 22:15:51 +00001711 case 0321:
1712 if (bits == 16) {
1713 *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 Anvinef7468f2002-04-30 20:57:59 +00001719
H. Peter Anvine2c80182005-01-15 22:15:51 +00001720 case 0322:
H. Peter Anvin70653092007-10-19 14:42:29 -07001721 case 0323:
1722 break;
1723
Keith Kaniosb7a89542007-04-12 02:40:54 +00001724 case 0324:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001725 ins->rex |= REX_W;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001726 break;
H. Peter Anvin70653092007-10-19 14:42:29 -07001727
H. Peter Anvine2c80182005-01-15 22:15:51 +00001728 case 0330:
1729 *bytes = *codes++ ^ condval[ins->condition];
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001730 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001731 offset += 1;
1732 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001733
H. Peter Anvine2c80182005-01-15 22:15:51 +00001734 case 0331:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001735 break;
H. Peter Anvinaf535c12002-04-30 20:59:21 +00001736
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001737 case 0332:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001738 case 0333:
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001739 *bytes = c - 0332 + 0xF2;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001740 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001741 offset += 1;
1742 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001743
Keith Kanios48af1772007-08-17 07:37:52 +00001744 case 0334:
1745 if (ins->rex & REX_R) {
1746 *bytes = 0xF0;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001747 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
Keith Kanios48af1772007-08-17 07:37:52 +00001748 offset += 1;
1749 }
1750 ins->rex &= ~(REX_L|REX_R);
1751 break;
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001752
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001753 case 0335:
1754 break;
1755
H. Peter Anvine2c80182005-01-15 22:15:51 +00001756 case 0340:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001757 if (ins->oprs[0].segment != NO_SEG)
1758 errfunc(ERR_PANIC, "non-constant BSS size in pass two");
1759 else {
H. Peter Anvin428fd672007-11-15 10:25:52 -08001760 int64_t size = ins->oprs[0].offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001761 if (size > 0)
1762 out(offset, segment, NULL,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001763 OUT_RESERVE, size, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001764 offset += size;
1765 }
1766 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001767
H. Peter Anvinfff5a472008-05-20 09:46:24 -07001768 case 0360:
1769 break;
1770
1771 case 0361:
1772 bytes[0] = 0x66;
1773 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1774 offset += 1;
1775 break;
1776
1777 case 0362:
1778 case 0363:
1779 bytes[0] = c - 0362 + 0xf2;
1780 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1781 offset += 1;
1782 break;
1783
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001784 case 0364:
1785 case 0365:
1786 break;
1787
Keith Kanios48af1772007-08-17 07:37:52 +00001788 case 0366:
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001789 case 0367:
1790 *bytes = c - 0366 + 0x66;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001791 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
Keith Kanios48af1772007-08-17 07:37:52 +00001792 offset += 1;
1793 break;
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001794
H. Peter Anvine2c80182005-01-15 22:15:51 +00001795 case 0370:
1796 case 0371:
1797 case 0372:
1798 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001799
H. Peter Anvine2c80182005-01-15 22:15:51 +00001800 case 0373:
1801 *bytes = bits == 16 ? 3 : 5;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001802 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001803 offset += 1;
1804 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001805
H. Peter Anvine2c80182005-01-15 22:15:51 +00001806 default: /* can't do it by 'case' statements */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001807 if (c >= 0100 && c <= 0277) { /* it's an EA */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001808 ea ea_data;
1809 int rfield;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001810 int32_t rflags;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001811 uint8_t *p;
1812 int32_t s;
H. Peter Anvin70653092007-10-19 14:42:29 -07001813
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001814 if (c <= 0177) {
1815 /* pick rfield from operand b */
1816 rflags = regflag(&ins->oprs[c & 7]);
H. Peter Anvina4835d42008-05-20 14:21:29 -07001817 rfield = nasm_regvals[ins->oprs[c & 7].basereg];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001818 } else {
1819 /* rfield is constant */
1820 rflags = 0;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001821 rfield = c & 7;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001822 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001823
1824 if (!process_ea
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001825 (&ins->oprs[(c >> 3) & 7], &ea_data, bits,
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001826 ins->addr_size, rfield, rflags, ins->forw_ref)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001827 errfunc(ERR_NONFATAL, "invalid effective address");
1828 }
H. Peter Anvin70653092007-10-19 14:42:29 -07001829
Charles Crayne7e975552007-11-03 22:06:13 -07001830
H. Peter Anvine2c80182005-01-15 22:15:51 +00001831 p = bytes;
1832 *p++ = ea_data.modrm;
1833 if (ea_data.sib_present)
1834 *p++ = ea_data.sib;
1835
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001836 /* DREX suffixes come between the SIB and the displacement */
1837 if (ins->rex & REX_D) {
1838 *p++ =
1839 (ins->drexdst << 4) |
1840 (ins->rex & REX_OC ? 0x08 : 0) |
1841 (ins->rex & (REX_R|REX_X|REX_B));
1842 ins->rex = 0;
1843 }
1844
H. Peter Anvine2c80182005-01-15 22:15:51 +00001845 s = p - bytes;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001846 out(offset, segment, bytes, OUT_RAWDATA, s, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001847
1848 switch (ea_data.bytes) {
1849 case 0:
1850 break;
1851 case 1:
1852 if (ins->oprs[(c >> 3) & 7].segment != NO_SEG) {
1853 data = ins->oprs[(c >> 3) & 7].offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001854 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001855 ins->oprs[(c >> 3) & 7].segment,
1856 ins->oprs[(c >> 3) & 7].wrt);
1857 } else {
1858 *bytes = ins->oprs[(c >> 3) & 7].offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001859 out(offset, segment, bytes, OUT_RAWDATA, 1,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001860 NO_SEG, NO_SEG);
1861 }
1862 s++;
1863 break;
H. Peter Anvin70653092007-10-19 14:42:29 -07001864 case 8:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001865 case 2:
1866 case 4:
1867 data = ins->oprs[(c >> 3) & 7].offset;
Charles Crayne7e975552007-11-03 22:06:13 -07001868 warn_overflow(ea_data.bytes, data);
H. Peter Anvind0b0d282007-09-28 17:17:20 -07001869 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001870 ea_data.rip ? OUT_REL4ADR : OUT_ADDRESS,
1871 ea_data.bytes,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001872 ins->oprs[(c >> 3) & 7].segment,
1873 ins->oprs[(c >> 3) & 7].wrt);
1874 s += ea_data.bytes;
1875 break;
1876 }
1877 offset += s;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001878 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001879 errfunc(ERR_PANIC, "internal instruction table corrupt"
1880 ": instruction code 0x%02X given", c);
H. Peter Anvin839eca22007-10-29 23:12:47 -07001881 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001882 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001883 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001884}
1885
H. Peter Anvin0ec60e62007-07-07 01:59:52 +00001886static int32_t regflag(const operand * o)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001887{
1888 if (o->basereg < EXPR_REG_START || o->basereg >= REG_ENUM_LIMIT) {
1889 errfunc(ERR_PANIC, "invalid operand passed to regflag()");
1890 }
H. Peter Anvina4835d42008-05-20 14:21:29 -07001891 return nasm_reg_flags[o->basereg];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001892}
1893
H. Peter Anvin5b0e3ec2007-07-07 02:01:08 +00001894static int32_t regval(const operand * o)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001895{
H. Peter Anvine2c80182005-01-15 22:15:51 +00001896 if (o->basereg < EXPR_REG_START || o->basereg >= REG_ENUM_LIMIT) {
1897 errfunc(ERR_PANIC, "invalid operand passed to regval()");
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001898 }
H. Peter Anvina4835d42008-05-20 14:21:29 -07001899 return nasm_regvals[o->basereg];
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001900}
1901
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001902static int op_rexflags(const operand * o, int mask)
1903{
1904 int32_t flags;
1905 int val;
1906
1907 if (o->basereg < EXPR_REG_START || o->basereg >= REG_ENUM_LIMIT) {
1908 errfunc(ERR_PANIC, "invalid operand passed to op_rexflags()");
1909 }
1910
H. Peter Anvina4835d42008-05-20 14:21:29 -07001911 flags = nasm_reg_flags[o->basereg];
1912 val = nasm_regvals[o->basereg];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001913
1914 return rexflags(val, flags, mask);
1915}
1916
1917static int rexflags(int val, int32_t flags, int mask)
1918{
1919 int rex = 0;
1920
1921 if (val >= 8)
1922 rex |= REX_B|REX_X|REX_R;
1923 if (flags & BITS64)
1924 rex |= REX_W;
1925 if (!(REG_HIGH & ~flags)) /* AH, CH, DH, BH */
1926 rex |= REX_H;
1927 else if (!(REG8 & ~flags) && val >= 4) /* SPL, BPL, SIL, DIL */
1928 rex |= REX_P;
1929
1930 return rex & mask;
1931}
1932
H. Peter Anvin3360d792007-09-11 04:16:57 +00001933static int matches(const struct itemplate *itemp, insn * instruction, int bits)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001934{
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001935 int i, size[MAX_OPERANDS], asize, oprs, ret;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001936
1937 ret = 100;
1938
1939 /*
1940 * Check the opcode
1941 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001942 if (itemp->opcode != instruction->opcode)
1943 return 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001944
1945 /*
1946 * Count the operands
1947 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001948 if (itemp->operands != instruction->operands)
1949 return 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001950
1951 /*
1952 * Check that no spurious colons or TOs are present
1953 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001954 for (i = 0; i < itemp->operands; i++)
1955 if (instruction->oprs[i].type & ~itemp->opd[i] & (COLON | TO))
1956 return 0;
H. Peter Anvin70653092007-10-19 14:42:29 -07001957
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001958 /*
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001959 * Process size flags
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001960 */
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001961 if (itemp->flags & IF_ARMASK) {
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001962 memset(size, 0, sizeof size);
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001963
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001964 i = ((itemp->flags & IF_ARMASK) >> IF_ARSHFT) - 1;
1965
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001966 switch (itemp->flags & IF_SMASK) {
1967 case IF_SB:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001968 size[i] = BITS8;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001969 break;
1970 case IF_SW:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001971 size[i] = BITS16;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001972 break;
1973 case IF_SD:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001974 size[i] = BITS32;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001975 break;
1976 case IF_SQ:
Keith Kaniosb7a89542007-04-12 02:40:54 +00001977 size[i] = BITS64;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001978 break;
H. Peter Anvin41c9f6f2007-09-18 13:01:32 -07001979 case IF_SO:
1980 size[i] = BITS128;
1981 break;
H. Peter Anvindfb91802008-05-20 11:43:53 -07001982 case IF_SY:
1983 size[i] = BITS256;
1984 break;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001985 case IF_SZ:
1986 switch (bits) {
1987 case 16:
1988 size[i] = BITS16;
1989 break;
1990 case 32:
1991 size[i] = BITS32;
1992 break;
1993 case 64:
1994 size[i] = BITS64;
1995 break;
1996 }
1997 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001998 default:
1999 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002000 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002001 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002002 asize = 0;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07002003 switch (itemp->flags & IF_SMASK) {
2004 case IF_SB:
H. Peter Anvine2c80182005-01-15 22:15:51 +00002005 asize = BITS8;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07002006 break;
2007 case IF_SW:
H. Peter Anvine2c80182005-01-15 22:15:51 +00002008 asize = BITS16;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07002009 break;
2010 case IF_SD:
H. Peter Anvine2c80182005-01-15 22:15:51 +00002011 asize = BITS32;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07002012 break;
2013 case IF_SQ:
Keith Kaniosb7a89542007-04-12 02:40:54 +00002014 asize = BITS64;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07002015 break;
H. Peter Anvin41c9f6f2007-09-18 13:01:32 -07002016 case IF_SO:
2017 asize = BITS128;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002018 break;
H. Peter Anvindfb91802008-05-20 11:43:53 -07002019 case IF_SY:
2020 asize = BITS256;
2021 break;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002022 case IF_SZ:
2023 switch (bits) {
2024 case 16:
2025 asize = BITS16;
2026 break;
2027 case 32:
2028 asize = BITS32;
2029 break;
2030 case 64:
2031 asize = BITS64;
2032 break;
2033 }
H. Peter Anvin41c9f6f2007-09-18 13:01:32 -07002034 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07002035 default:
2036 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002037 }
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07002038 for (i = 0; i < MAX_OPERANDS; i++)
2039 size[i] = asize;
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002040 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002041
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002042 /*
2043 * Check that the operand flags all match up
2044 */
2045 for (i = 0; i < itemp->operands; i++) {
2046 int32_t type = instruction->oprs[i].type;
2047 if (!(type & SIZE_MASK))
2048 type |= size[i];
H. Peter Anvind85d2502008-05-04 17:53:31 -07002049
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002050 if (itemp->opd[i] & SAME_AS) {
2051 int j = itemp->opd[i] & ~SAME_AS;
2052 if (type != instruction->oprs[j].type ||
2053 instruction->oprs[i].basereg != instruction->oprs[j].basereg)
2054 return 0;
2055 } else if (itemp->opd[i] & ~type ||
2056 ((itemp->opd[i] & SIZE_MASK) &&
2057 ((itemp->opd[i] ^ type) & SIZE_MASK))) {
2058 if ((itemp->opd[i] & ~type & ~SIZE_MASK) ||
2059 (type & SIZE_MASK))
2060 return 0;
2061 else
2062 return 1;
2063 }
2064 }
2065
2066 /*
2067 * Check operand sizes
2068 */
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002069 if (itemp->flags & (IF_SM | IF_SM2)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002070 oprs = (itemp->flags & IF_SM2 ? 2 : itemp->operands);
2071 asize = 0;
2072 for (i = 0; i < oprs; i++) {
2073 if ((asize = itemp->opd[i] & SIZE_MASK) != 0) {
2074 int j;
2075 for (j = 0; j < oprs; j++)
2076 size[j] = asize;
2077 break;
2078 }
2079 }
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002080 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002081 oprs = itemp->operands;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002082 }
2083
Keith Kaniosb7a89542007-04-12 02:40:54 +00002084 for (i = 0; i < itemp->operands; i++) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002085 if (!(itemp->opd[i] & SIZE_MASK) &&
2086 (instruction->oprs[i].type & SIZE_MASK & ~size[i]))
H. Peter Anvine2c80182005-01-15 22:15:51 +00002087 return 2;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002088 }
2089
H. Peter Anvinaf535c12002-04-30 20:59:21 +00002090 /*
2091 * Check template is okay at the set cpu level
2092 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002093 if (((itemp->flags & IF_PLEVEL) > cpu))
H. Peter Anvine2c80182005-01-15 22:15:51 +00002094 return 3;
H. Peter Anvin70653092007-10-19 14:42:29 -07002095
Keith Kaniosb7a89542007-04-12 02:40:54 +00002096 /*
2097 * Check if instruction is available in long mode
2098 */
2099 if ((itemp->flags & IF_NOLONG) && (bits == 64))
2100 return 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002101
H. Peter Anvinaf535c12002-04-30 20:59:21 +00002102 /*
2103 * Check if special handling needed for Jumps
2104 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002105 if ((uint8_t)(itemp->code[0]) >= 0370)
H. Peter Anvine2c80182005-01-15 22:15:51 +00002106 return 99;
2107
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002108 return ret;
2109}
2110
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002111static ea *process_ea(operand * input, ea * output, int bits,
2112 int addrbits, int rfield, int32_t rflags, int forw_ref)
H. Peter Anvineba20a72002-04-30 20:53:55 +00002113{
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002114 output->rip = false;
H. Peter Anvin99c4ecd2007-08-28 23:06:00 +00002115
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002116 /* REX flags for the rfield operand */
2117 output->rex |= rexflags(rfield, rflags, REX_R|REX_P|REX_W|REX_H);
2118
Keith Kaniosb7a89542007-04-12 02:40:54 +00002119 if (!(REGISTER & ~input->type)) { /* register direct */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002120 int i;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002121 int32_t f;
2122
2123 if (input->basereg < EXPR_REG_START /* Verify as Register */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002124 || input->basereg >= REG_ENUM_LIMIT)
H. Peter Anvine2c80182005-01-15 22:15:51 +00002125 return NULL;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002126 f = regflag(input);
H. Peter Anvina4835d42008-05-20 14:21:29 -07002127 i = nasm_regvals[input->basereg];
Keith Kaniosb7a89542007-04-12 02:40:54 +00002128
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002129 if (REG_EA & ~f)
2130 return NULL; /* Invalid EA register */
H. Peter Anvin70653092007-10-19 14:42:29 -07002131
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002132 output->rex |= op_rexflags(input, REX_B|REX_P|REX_W|REX_H);
2133
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002134 output->sib_present = false; /* no SIB necessary */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002135 output->bytes = 0; /* no offset necessary either */
2136 output->modrm = 0xC0 | ((rfield & 7) << 3) | (i & 7);
H. Peter Anvine2c80182005-01-15 22:15:51 +00002137 } else { /* it's a memory reference */
2138 if (input->basereg == -1
2139 && (input->indexreg == -1 || input->scale == 0)) {
2140 /* it's a pure offset */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002141 if (bits == 64 && (~input->type & IP_REL)) {
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002142 int scale, index, base;
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002143 output->sib_present = true;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002144 scale = 0;
2145 index = 4;
2146 base = 5;
2147 output->sib = (scale << 6) | (index << 3) | base;
2148 output->bytes = 4;
2149 output->modrm = 4 | ((rfield & 7) << 3);
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002150 output->rip = false;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002151 } else {
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002152 output->sib_present = false;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002153 output->bytes = (addrbits != 16 ? 4 : 2);
2154 output->modrm = (addrbits != 16 ? 5 : 6) | ((rfield & 7) << 3);
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002155 output->rip = bits == 64;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002156 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00002157 } else { /* it's an indirection */
2158 int i = input->indexreg, b = input->basereg, s = input->scale;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002159 int32_t o = input->offset, seg = input->segment;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002160 int hb = input->hintbase, ht = input->hinttype;
2161 int t;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002162 int it, bt;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002163 int32_t ix, bx; /* register flags */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002164
H. Peter Anvine2c80182005-01-15 22:15:51 +00002165 if (s == 0)
2166 i = -1; /* make this easy, at least */
H. Peter Anvin70653092007-10-19 14:42:29 -07002167
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002168 if (i >= EXPR_REG_START && i < REG_ENUM_LIMIT) {
H. Peter Anvina4835d42008-05-20 14:21:29 -07002169 it = nasm_regvals[i];
2170 ix = nasm_reg_flags[i];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002171 } else {
Keith Kaniosb7a89542007-04-12 02:40:54 +00002172 it = -1;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002173 ix = 0;
2174 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002175
H. Peter Anvinb0c54622007-10-28 23:21:46 -07002176 if (b >= EXPR_REG_START && b < REG_ENUM_LIMIT) {
H. Peter Anvina4835d42008-05-20 14:21:29 -07002177 bt = nasm_regvals[b];
2178 bx = nasm_reg_flags[b];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002179 } else {
Keith Kaniosb7a89542007-04-12 02:40:54 +00002180 bt = -1;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002181 bx = 0;
2182 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002183
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002184 /* check for a 32/64-bit memory reference... */
2185 if ((ix|bx) & (BITS32|BITS64)) {
Keith Kaniosb7a89542007-04-12 02:40:54 +00002186 /* it must be a 32/64-bit memory reference. Firstly we have
2187 * to check that all registers involved are type E/Rxx. */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002188 int32_t sok = BITS32|BITS64;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002189
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002190 if (it != -1) {
2191 if (!(REG64 & ~ix) || !(REG32 & ~ix))
2192 sok &= ix;
2193 else
2194 return NULL;
2195 }
2196
2197 if (bt != -1) {
H. Peter Anvin99c4ecd2007-08-28 23:06:00 +00002198 if (REG_GPR & ~bx)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002199 return NULL; /* Invalid register */
H. Peter Anvina57e8d42007-05-30 03:44:02 +00002200 if (~sok & bx & SIZE_MASK)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002201 return NULL; /* Invalid size */
H. Peter Anvinb0c54622007-10-28 23:21:46 -07002202 sok &= bx;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002203 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002204
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002205 /* While we're here, ensure the user didn't specify
2206 WORD or QWORD. */
2207 if (input->disp_size == 16 || input->disp_size == 64)
2208 return NULL;
2209
2210 if (addrbits == 16 ||
2211 (addrbits == 32 && !(sok & BITS32)) ||
2212 (addrbits == 64 && !(sok & BITS64)))
2213 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002214
Keith Kaniosb7a89542007-04-12 02:40:54 +00002215 /* now reorganize base/index */
2216 if (s == 1 && bt != it && bt != -1 && it != -1 &&
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002217 ((hb == b && ht == EAH_NOTBASE)
2218 || (hb == i && ht == EAH_MAKEBASE))) {
2219 /* swap if hints say so */
2220 t = bt, bt = it, it = t;
2221 t = bx, bx = ix, ix = t;
2222 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00002223 if (bt == it) /* convert EAX+2*EAX to 3*EAX */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002224 bt = -1, bx = 0, s++;
2225 if (bt == -1 && s == 1 && !(hb == it && ht == EAH_NOTBASE)) {
2226 /* make single reg base, unless hint */
2227 bt = it, bx = ix, it = -1, ix = 0;
2228 }
H. Peter Anvinf5843c62007-09-10 18:59:26 +00002229 if (((s == 2 && it != REG_NUM_ESP
H. Peter Anvine2c80182005-01-15 22:15:51 +00002230 && !(input->eaflags & EAF_TIMESTWO)) || s == 3
Keith Kaniosb7a89542007-04-12 02:40:54 +00002231 || s == 5 || s == 9) && bt == -1)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002232 bt = it, bx = ix, s--; /* convert 3*EAX to EAX+2*EAX */
Keith Kanios48af1772007-08-17 07:37:52 +00002233 if (it == -1 && (bt & 7) != REG_NUM_ESP
H. Peter Anvine2c80182005-01-15 22:15:51 +00002234 && (input->eaflags & EAF_TIMESTWO))
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002235 it = bt, ix = bx, bt = -1, bx = 0, s = 1;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002236 /* convert [NOSPLIT EAX] to sib format with 0x0 displacement */
Keith Kanios48af1772007-08-17 07:37:52 +00002237 if (s == 1 && it == REG_NUM_ESP) {
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002238 /* swap ESP into base if scale is 1 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002239 t = it, it = bt, bt = t;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002240 t = ix, ix = bx, bx = t;
2241 }
Keith Kanios48af1772007-08-17 07:37:52 +00002242 if (it == REG_NUM_ESP
Keith Kaniosb7a89542007-04-12 02:40:54 +00002243 || (s != 1 && s != 2 && s != 4 && s != 8 && it != -1))
H. Peter Anvine2c80182005-01-15 22:15:51 +00002244 return NULL; /* wrong, for various reasons */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002245
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002246 output->rex |= rexflags(it, ix, REX_X);
2247 output->rex |= rexflags(bt, bx, REX_B);
Keith Kaniosb7a89542007-04-12 02:40:54 +00002248
Keith Kanios48af1772007-08-17 07:37:52 +00002249 if (it == -1 && (bt & 7) != REG_NUM_ESP) {
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002250 /* no SIB needed */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002251 int mod, rm;
H. Peter Anvin70653092007-10-19 14:42:29 -07002252
Keith Kaniosb7a89542007-04-12 02:40:54 +00002253 if (bt == -1) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002254 rm = 5;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002255 mod = 0;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002256 } else {
2257 rm = (bt & 7);
Keith Kanios48af1772007-08-17 07:37:52 +00002258 if (rm != REG_NUM_EBP && o == 0 &&
Keith Kaniosb7a89542007-04-12 02:40:54 +00002259 seg == NO_SEG && !forw_ref &&
2260 !(input->eaflags &
2261 (EAF_BYTEOFFS | EAF_WORDOFFS)))
2262 mod = 0;
2263 else if (input->eaflags & EAF_BYTEOFFS ||
2264 (o >= -128 && o <= 127 && seg == NO_SEG
2265 && !forw_ref
2266 && !(input->eaflags & EAF_WORDOFFS)))
2267 mod = 1;
2268 else
2269 mod = 2;
2270 }
H. Peter Anvinea838272002-04-30 20:51:53 +00002271
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002272 output->sib_present = false;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002273 output->bytes = (bt == -1 || mod == 2 ? 4 : mod);
2274 output->modrm = (mod << 6) | ((rfield & 7) << 3) | rm;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002275 } else {
2276 /* we need a SIB */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002277 int mod, scale, index, base;
H. Peter Anvin70653092007-10-19 14:42:29 -07002278
Keith Kaniosb7a89542007-04-12 02:40:54 +00002279 if (it == -1)
2280 index = 4, s = 1;
2281 else
2282 index = (it & 7);
H. Peter Anvin70653092007-10-19 14:42:29 -07002283
H. Peter Anvine2c80182005-01-15 22:15:51 +00002284 switch (s) {
2285 case 1:
2286 scale = 0;
2287 break;
2288 case 2:
2289 scale = 1;
2290 break;
2291 case 4:
2292 scale = 2;
2293 break;
2294 case 8:
2295 scale = 3;
2296 break;
2297 default: /* then what the smeg is it? */
2298 return NULL; /* panic */
2299 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002300
Keith Kaniosb7a89542007-04-12 02:40:54 +00002301 if (bt == -1) {
2302 base = 5;
2303 mod = 0;
2304 } else {
2305 base = (bt & 7);
Keith Kanios48af1772007-08-17 07:37:52 +00002306 if (base != REG_NUM_EBP && o == 0 &&
H. Peter Anvine2c80182005-01-15 22:15:51 +00002307 seg == NO_SEG && !forw_ref &&
2308 !(input->eaflags &
Keith Kaniosb7a89542007-04-12 02:40:54 +00002309 (EAF_BYTEOFFS | EAF_WORDOFFS)))
2310 mod = 0;
2311 else if (input->eaflags & EAF_BYTEOFFS ||
2312 (o >= -128 && o <= 127 && seg == NO_SEG
2313 && !forw_ref
2314 && !(input->eaflags & EAF_WORDOFFS)))
2315 mod = 1;
2316 else
2317 mod = 2;
2318 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002319
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002320 output->sib_present = true;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002321 output->bytes = (bt == -1 || mod == 2 ? 4 : mod);
2322 output->modrm = (mod << 6) | ((rfield & 7) << 3) | 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002323 output->sib = (scale << 6) | (index << 3) | base;
2324 }
2325 } else { /* it's 16-bit */
2326 int mod, rm;
H. Peter Anvin70653092007-10-19 14:42:29 -07002327
Keith Kaniosb7a89542007-04-12 02:40:54 +00002328 /* check for 64-bit long mode */
2329 if (addrbits == 64)
2330 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002331
H. Peter Anvine2c80182005-01-15 22:15:51 +00002332 /* check all registers are BX, BP, SI or DI */
2333 if ((b != -1 && b != R_BP && b != R_BX && b != R_SI
2334 && b != R_DI) || (i != -1 && i != R_BP && i != R_BX
2335 && i != R_SI && i != R_DI))
2336 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002337
Keith Kaniosb7a89542007-04-12 02:40:54 +00002338 /* ensure the user didn't specify DWORD/QWORD */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002339 if (input->disp_size == 32 || input->disp_size == 64)
H. Peter Anvine2c80182005-01-15 22:15:51 +00002340 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002341
H. Peter Anvine2c80182005-01-15 22:15:51 +00002342 if (s != 1 && i != -1)
2343 return NULL; /* no can do, in 16-bit EA */
2344 if (b == -1 && i != -1) {
2345 int tmp = b;
2346 b = i;
2347 i = tmp;
2348 } /* swap */
2349 if ((b == R_SI || b == R_DI) && i != -1) {
2350 int tmp = b;
2351 b = i;
2352 i = tmp;
2353 }
2354 /* have BX/BP as base, SI/DI index */
2355 if (b == i)
2356 return NULL; /* shouldn't ever happen, in theory */
2357 if (i != -1 && b != -1 &&
2358 (i == R_BP || i == R_BX || b == R_SI || b == R_DI))
2359 return NULL; /* invalid combinations */
2360 if (b == -1) /* pure offset: handled above */
2361 return NULL; /* so if it gets to here, panic! */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002362
H. Peter Anvine2c80182005-01-15 22:15:51 +00002363 rm = -1;
2364 if (i != -1)
2365 switch (i * 256 + b) {
2366 case R_SI * 256 + R_BX:
2367 rm = 0;
2368 break;
2369 case R_DI * 256 + R_BX:
2370 rm = 1;
2371 break;
2372 case R_SI * 256 + R_BP:
2373 rm = 2;
2374 break;
2375 case R_DI * 256 + R_BP:
2376 rm = 3;
2377 break;
2378 } else
2379 switch (b) {
2380 case R_SI:
2381 rm = 4;
2382 break;
2383 case R_DI:
2384 rm = 5;
2385 break;
2386 case R_BP:
2387 rm = 6;
2388 break;
2389 case R_BX:
2390 rm = 7;
2391 break;
2392 }
2393 if (rm == -1) /* can't happen, in theory */
2394 return NULL; /* so panic if it does */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002395
H. Peter Anvine2c80182005-01-15 22:15:51 +00002396 if (o == 0 && seg == NO_SEG && !forw_ref && rm != 6 &&
2397 !(input->eaflags & (EAF_BYTEOFFS | EAF_WORDOFFS)))
2398 mod = 0;
2399 else if (input->eaflags & EAF_BYTEOFFS ||
2400 (o >= -128 && o <= 127 && seg == NO_SEG
2401 && !forw_ref
2402 && !(input->eaflags & EAF_WORDOFFS)))
2403 mod = 1;
2404 else
2405 mod = 2;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002406
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002407 output->sib_present = false; /* no SIB - it's 16-bit */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002408 output->bytes = mod; /* bytes of offset needed */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002409 output->modrm = (mod << 6) | ((rfield & 7) << 3) | rm;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002410 }
2411 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002412 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002413
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002414 output->size = 1 + output->sib_present + output->bytes;
2415 return output;
2416}
2417
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002418static void add_asp(insn *ins, int addrbits)
H. Peter Anvineba20a72002-04-30 20:53:55 +00002419{
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002420 int j, valid;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002421 int defdisp;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002422
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002423 valid = (addrbits == 64) ? 64|32 : 32|16;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002424
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002425 switch (ins->prefixes[PPS_ASIZE]) {
2426 case P_A16:
2427 valid &= 16;
2428 break;
2429 case P_A32:
2430 valid &= 32;
2431 break;
2432 case P_A64:
2433 valid &= 64;
2434 break;
2435 case P_ASP:
2436 valid &= (addrbits == 32) ? 16 : 32;
2437 break;
2438 default:
2439 break;
2440 }
2441
2442 for (j = 0; j < ins->operands; j++) {
2443 if (!(MEMORY & ~ins->oprs[j].type)) {
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002444 int32_t i, b;
H. Peter Anvin70653092007-10-19 14:42:29 -07002445
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002446 /* Verify as Register */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002447 if (ins->oprs[j].indexreg < EXPR_REG_START
2448 || ins->oprs[j].indexreg >= REG_ENUM_LIMIT)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002449 i = 0;
2450 else
H. Peter Anvina4835d42008-05-20 14:21:29 -07002451 i = nasm_reg_flags[ins->oprs[j].indexreg];
H. Peter Anvin70653092007-10-19 14:42:29 -07002452
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002453 /* Verify as Register */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002454 if (ins->oprs[j].basereg < EXPR_REG_START
2455 || ins->oprs[j].basereg >= REG_ENUM_LIMIT)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002456 b = 0;
2457 else
H. Peter Anvina4835d42008-05-20 14:21:29 -07002458 b = nasm_reg_flags[ins->oprs[j].basereg];
H. Peter Anvin70653092007-10-19 14:42:29 -07002459
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002460 if (ins->oprs[j].scale == 0)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002461 i = 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002462
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002463 if (!i && !b) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002464 int ds = ins->oprs[j].disp_size;
2465 if ((addrbits != 64 && ds > 8) ||
2466 (addrbits == 64 && ds == 16))
2467 valid &= ds;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002468 } else {
2469 if (!(REG16 & ~b))
2470 valid &= 16;
2471 if (!(REG32 & ~b))
2472 valid &= 32;
2473 if (!(REG64 & ~b))
2474 valid &= 64;
H. Peter Anvin70653092007-10-19 14:42:29 -07002475
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002476 if (!(REG16 & ~i))
2477 valid &= 16;
2478 if (!(REG32 & ~i))
2479 valid &= 32;
2480 if (!(REG64 & ~i))
2481 valid &= 64;
2482 }
2483 }
2484 }
2485
2486 if (valid & addrbits) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002487 ins->addr_size = addrbits;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002488 } else if (valid & ((addrbits == 32) ? 16 : 32)) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002489 /* Add an address size prefix */
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002490 enum prefixes pref = (addrbits == 32) ? P_A16 : P_A32;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002491 ins->prefixes[PPS_ASIZE] = pref;
2492 ins->addr_size = (addrbits == 32) ? 16 : 32;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002493 } else {
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002494 /* Impossible... */
2495 errfunc(ERR_NONFATAL, "impossible combination of address sizes");
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002496 ins->addr_size = addrbits; /* Error recovery */
2497 }
2498
2499 defdisp = ins->addr_size == 16 ? 16 : 32;
2500
2501 for (j = 0; j < ins->operands; j++) {
2502 if (!(MEM_OFFS & ~ins->oprs[j].type) &&
2503 (ins->oprs[j].disp_size ? ins->oprs[j].disp_size : defdisp)
2504 != ins->addr_size) {
2505 /* mem_offs sizes must match the address size; if not,
2506 strip the MEM_OFFS bit and match only EA instructions */
2507 ins->oprs[j].type &= ~(MEM_OFFS & ~MEMORY);
2508 }
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002509 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002510}