blob: 73b5a3f165e57921aab45d494199828cdb131abb [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 Anvinbd420c72008-05-22 11:24:35 -070067 * [w0] ww = 0 for W = 0
68 * [w1] ww = 1 for W = 1
69 * [wx] ww = 2 for W don't care (always assembled as 0)
70 * [ww] ww = 3 for W used as REX.W
71 *
H. Peter Anvind85d2502008-05-04 17:53:31 -070072 *
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000073 * \310 - indicates fixed 16-bit address size, i.e. optional 0x67.
74 * \311 - indicates fixed 32-bit address size, i.e. optional 0x67.
Keith Kanios48af1772007-08-17 07:37:52 +000075 * \312 - (disassembler only) marker on LOOP, LOOPxx instructions.
H. Peter Anvince2b3972007-05-30 22:21:11 +000076 * \313 - indicates fixed 64-bit address size, 0x67 invalid.
H. Peter Anvin23440102007-11-12 21:02:33 -080077 * \314 - (disassembler only) invalid with REX.B
78 * \315 - (disassembler only) invalid with REX.X
79 * \316 - (disassembler only) invalid with REX.R
80 * \317 - (disassembler only) invalid with REX.W
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000081 * \320 - indicates fixed 16-bit operand size, i.e. optional 0x66.
82 * \321 - indicates fixed 32-bit operand size, i.e. optional 0x66.
83 * \322 - indicates that this instruction is only valid when the
84 * operand size is the default (instruction to disassembler,
85 * generates no code in the assembler)
H. Peter Anvince2b3972007-05-30 22:21:11 +000086 * \323 - indicates fixed 64-bit operand size, REX on extensions only.
Keith Kaniosb7a89542007-04-12 02:40:54 +000087 * \324 - indicates 64-bit operand size requiring REX prefix.
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000088 * \330 - a literal byte follows in the code stream, to be added
89 * to the condition code value of the instruction.
Keith Kanios48af1772007-08-17 07:37:52 +000090 * \331 - instruction not valid with REP prefix. Hint for
H. Peter Anvinef7468f2002-04-30 20:57:59 +000091 * disassembler only; for SSE instructions.
H. Peter Anvincb9b6902007-09-12 21:58:51 -070092 * \332 - REP prefix (0xF2 byte) used as opcode extension.
93 * \333 - REP prefix (0xF3 byte) used as opcode extension.
Keith Kanios48af1772007-08-17 07:37:52 +000094 * \334 - LOCK prefix used instead of REX.R
H. Peter Anvincb9b6902007-09-12 21:58:51 -070095 * \335 - disassemble a rep (0xF3 byte) prefix as repe not rep.
Keith Kaniosb7a89542007-04-12 02:40:54 +000096 * \340 - reserve <operand 0> bytes of uninitialized storage.
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000097 * Operand 0 had better be a segmentless constant.
H. Peter Anvinfff5a472008-05-20 09:46:24 -070098 * \360 - no SSE prefix (== \364\331)
99 * \361 - 66 SSE prefix (== \366\331)
100 * \362 - F2 SSE prefix (== \364\332)
101 * \363 - F3 SSE prefix (== \364\333)
H. Peter Anvin62cb6062007-09-11 22:44:03 +0000102 * \364 - operand-size prefix (0x66) not permitted
103 * \365 - address-size prefix (0x67) not permitted
104 * \366 - operand-size prefix (0x66) used as opcode extension
105 * \367 - address-size prefix (0x67) used as opcode extension
H. Peter Anvin788e6c12002-04-30 21:02:01 +0000106 * \370,\371,\372 - match only if operand 0 meets byte jump criteria.
107 * 370 is used for Jcc, 371 is used for JMP.
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000108 * \373 - assemble 0x03 if bits==16, 0x05 if bits==32;
109 * used for conditional jump over longer jump
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000110 */
111
H. Peter Anvinfe501952007-10-02 21:53:51 -0700112#include "compiler.h"
113
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000114#include <stdio.h>
115#include <string.h>
Keith Kaniosb7a89542007-04-12 02:40:54 +0000116#include <inttypes.h>
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000117
118#include "nasm.h"
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000119#include "nasmlib.h"
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000120#include "assemble.h"
121#include "insns.h"
H. Peter Anvina4835d42008-05-20 14:21:29 -0700122#include "tables.h"
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000123
H. Peter Anvindfb91802008-05-20 11:43:53 -0700124/* Initialized to zero by the C standard */
125static const uint8_t const_zero_buf[256];
126
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000127typedef struct {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000128 int sib_present; /* is a SIB byte necessary? */
129 int bytes; /* # of bytes of offset needed */
130 int size; /* lazy - this is sib+bytes+1 */
131 uint8_t modrm, sib, rex, rip; /* the bytes themselves */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000132} ea;
133
Keith Kaniosb7a89542007-04-12 02:40:54 +0000134static uint32_t cpu; /* cpu level received from nasm.c */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000135static efunc errfunc;
136static struct ofmt *outfmt;
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000137static ListGen *list;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000138
H. Peter Anvin3720f7b2008-05-12 11:00:50 -0700139static int64_t calcsize(int32_t, int64_t, int, insn *, const uint8_t *);
140static void gencode(int32_t, int64_t, int, insn *, const uint8_t *, int64_t);
H. Peter Anvin3360d792007-09-11 04:16:57 +0000141static int matches(const struct itemplate *, insn *, int bits);
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000142static int32_t regflag(const operand *);
143static int32_t regval(const operand *);
144static int rexflags(int, int32_t, int);
145static int op_rexflags(const operand *, int);
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700146static ea *process_ea(operand *, ea *, int, int, int, int32_t);
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700147static void add_asp(insn *, int);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000148
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700149static int has_prefix(insn * ins, enum prefix_pos pos, enum prefixes prefix)
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000150{
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700151 return ins->prefixes[pos] == prefix;
152}
153
154static void assert_no_prefix(insn * ins, enum prefix_pos pos)
155{
156 if (ins->prefixes[pos])
157 errfunc(ERR_NONFATAL, "invalid %s prefix",
158 prefix_name(ins->prefixes[pos]));
159}
160
161static const char *size_name(int size)
162{
163 switch (size) {
164 case 1:
165 return "byte";
166 case 2:
167 return "word";
168 case 4:
169 return "dword";
170 case 8:
171 return "qword";
172 case 10:
173 return "tword";
174 case 16:
175 return "oword";
H. Peter Anvindfb91802008-05-20 11:43:53 -0700176 case 32:
177 return "yword";
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700178 default:
179 return "???";
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000180 }
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700181}
182
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700183static void warn_overflow(int size, int64_t data)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700184{
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700185 if (size < 8) {
Charles Craynedd462c82007-11-04 15:28:30 -0800186 int64_t lim = ((int64_t)1 << (size*8))-1;
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000187
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700188 if (data < ~lim || data > lim)
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700189 errfunc(ERR_WARNING | ERR_WARN_NOV,
190 "%s data exceeds bounds", size_name(size));
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700191 }
192}
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000193/*
194 * This routine wrappers the real output format's output routine,
195 * in order to pass a copy of the data off to the listing file
196 * generator at the same time.
197 */
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800198static void out(int64_t offset, int32_t segto, const void *data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800199 enum out_type type, uint64_t size,
200 int32_t segment, int32_t wrt)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000201{
Keith Kaniosb7a89542007-04-12 02:40:54 +0000202 static int32_t lineno = 0; /* static!!! */
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000203 static char *lnfname = NULL;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800204 uint8_t p[8];
H. Peter Anvineba20a72002-04-30 20:53:55 +0000205
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800206 if (type == OUT_ADDRESS && segment == NO_SEG && wrt == NO_SEG) {
207 /*
208 * This is a non-relocated address, and we're going to
209 * convert it into RAWDATA format.
210 */
211 uint8_t *q = p;
H. Peter Anvind1fb15c2007-11-13 09:37:59 -0800212
213 if (size > 8) {
214 errfunc(ERR_PANIC, "OUT_ADDRESS with size > 8");
215 return;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800216 }
H. Peter Anvind85d2502008-05-04 17:53:31 -0700217
H. Peter Anvind1fb15c2007-11-13 09:37:59 -0800218 WRITEADDR(q, *(int64_t *)data, size);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800219 data = p;
220 type = OUT_RAWDATA;
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000221 }
222
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800223 list->output(offset, data, type, size);
224
Frank Kotlerabebb082003-09-06 04:45:37 +0000225 /*
226 * this call to src_get determines when we call the
227 * debug-format-specific "linenum" function
228 * it updates lineno and lnfname to the current values
229 * returning 0 if "same as last time", -2 if lnfname
230 * changed, and the amount by which lineno changed,
231 * if it did. thus, these variables must be static
232 */
233
H. Peter Anvine2c80182005-01-15 22:15:51 +0000234 if (src_get(&lineno, &lnfname)) {
235 outfmt->current_dfmt->linenum(lnfname, lineno, segto);
H. Peter Anvince616072002-04-30 21:02:23 +0000236 }
H. Peter Anvineba20a72002-04-30 20:53:55 +0000237
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800238 outfmt->output(segto, data, type, size, segment, wrt);
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000239}
240
Charles Crayne5fbbc8c2007-11-07 19:03:46 -0800241static int jmp_match(int32_t segment, int64_t offset, int bits,
H. Peter Anvin3720f7b2008-05-12 11:00:50 -0700242 insn * ins, const uint8_t *code)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000243{
Charles Crayne5fbbc8c2007-11-07 19:03:46 -0800244 int64_t isize;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000245 uint8_t c = code[0];
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000246
H. Peter Anvine2c80182005-01-15 22:15:51 +0000247 if (c != 0370 && c != 0371)
248 return 0;
H. Peter Anvin788e6c12002-04-30 21:02:01 +0000249 if (ins->oprs[0].opflags & OPFLAG_FORWARD) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000250 if ((optimizing < 0 || (ins->oprs[0].type & STRICT))
251 && c == 0370)
252 return 1;
253 else
254 return (pass0 == 0); /* match a forward reference */
H. Peter Anvin788e6c12002-04-30 21:02:01 +0000255 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000256 isize = calcsize(segment, offset, bits, ins, code);
257 if (ins->oprs[0].segment != segment)
258 return 0;
259 isize = ins->oprs[0].offset - offset - isize; /* isize is now the delta */
260 if (isize >= -128L && isize <= 127L)
261 return 1; /* it is byte size */
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000262
263 return 0;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000264}
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000265
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800266int64_t assemble(int32_t segment, int64_t offset, int bits, uint32_t cp,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000267 insn * instruction, struct ofmt *output, efunc error,
268 ListGen * listgen)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000269{
H. Peter Anvin3360d792007-09-11 04:16:57 +0000270 const struct itemplate *temp;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000271 int j;
272 int size_prob;
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800273 int64_t insn_end;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000274 int32_t itimes;
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800275 int64_t start = offset;
276 int64_t wsize = 0; /* size for DB etc. */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000277
H. Peter Anvine2c80182005-01-15 22:15:51 +0000278 errfunc = error; /* to pass to other functions */
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000279 cpu = cp;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000280 outfmt = output; /* likewise */
281 list = listgen; /* and again */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000282
H. Peter Anvine2c80182005-01-15 22:15:51 +0000283 switch (instruction->opcode) {
284 case -1:
285 return 0;
286 case I_DB:
287 wsize = 1;
288 break;
289 case I_DW:
290 wsize = 2;
291 break;
292 case I_DD:
293 wsize = 4;
294 break;
295 case I_DQ:
296 wsize = 8;
297 break;
298 case I_DT:
299 wsize = 10;
300 break;
H. Peter Anvincfbe7c32007-09-18 17:49:09 -0700301 case I_DO:
302 wsize = 16;
303 break;
H. Peter Anvindfb91802008-05-20 11:43:53 -0700304 case I_DY:
305 wsize = 32;
306 break;
H. Peter Anvin16b0a332007-09-12 20:27:41 -0700307 default:
308 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000309 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000310
H. Peter Anvineba20a72002-04-30 20:53:55 +0000311 if (wsize) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000312 extop *e;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000313 int32_t t = instruction->times;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000314 if (t < 0)
315 errfunc(ERR_PANIC,
316 "instruction->times < 0 (%ld) in assemble()", t);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000317
H. Peter Anvine2c80182005-01-15 22:15:51 +0000318 while (t--) { /* repeat TIMES times */
319 for (e = instruction->eops; e; e = e->next) {
320 if (e->type == EOT_DB_NUMBER) {
321 if (wsize == 1) {
322 if (e->segment != NO_SEG)
323 errfunc(ERR_NONFATAL,
324 "one-byte relocation attempted");
325 else {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000326 uint8_t out_byte = e->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000327 out(offset, segment, &out_byte,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800328 OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000329 }
Keith Kanios61ff53c2007-04-14 18:54:52 +0000330 } else if (wsize > 8) {
H. Peter Anvin3be5d852008-05-20 14:49:32 -0700331 errfunc(ERR_NONFATAL,
332 "integer supplied to a DT, DO or DY"
Keith Kanios61ff53c2007-04-14 18:54:52 +0000333 " instruction");
H. Peter Anvine2c80182005-01-15 22:15:51 +0000334 } else
335 out(offset, segment, &e->offset,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800336 OUT_ADDRESS, wsize, e->segment, e->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000337 offset += wsize;
H. Peter Anvin518df302008-06-14 16:53:48 -0700338 } else if (e->type == EOT_DB_STRING ||
339 e->type == EOT_DB_STRING_FREE) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000340 int align;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000341
H. Peter Anvine2c80182005-01-15 22:15:51 +0000342 out(offset, segment, e->stringval,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800343 OUT_RAWDATA, e->stringlen, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000344 align = e->stringlen % wsize;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000345
H. Peter Anvine2c80182005-01-15 22:15:51 +0000346 if (align) {
347 align = wsize - align;
H. Peter Anvindfb91802008-05-20 11:43:53 -0700348 out(offset, segment, const_zero_buf,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800349 OUT_RAWDATA, align, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000350 }
351 offset += e->stringlen + align;
352 }
353 }
354 if (t > 0 && t == instruction->times - 1) {
355 /*
356 * Dummy call to list->output to give the offset to the
357 * listing module.
358 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800359 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000360 list->uplevel(LIST_TIMES);
361 }
362 }
363 if (instruction->times > 1)
364 list->downlevel(LIST_TIMES);
365 return offset - start;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000366 }
367
H. Peter Anvine2c80182005-01-15 22:15:51 +0000368 if (instruction->opcode == I_INCBIN) {
H. Peter Anvin518df302008-06-14 16:53:48 -0700369 const char *fname = instruction->eops->stringval;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000370 FILE *fp;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000371
H. Peter Anvin418ca702008-05-30 10:42:30 -0700372 fp = fopen(fname, "rb");
373 if (!fp) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000374 error(ERR_NONFATAL, "`incbin': unable to open file `%s'",
375 fname);
H. Peter Anvin418ca702008-05-30 10:42:30 -0700376 } else if (fseek(fp, 0L, SEEK_END) < 0) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000377 error(ERR_NONFATAL, "`incbin': unable to seek on file `%s'",
378 fname);
H. Peter Anvin418ca702008-05-30 10:42:30 -0700379 } else {
H. Peter Anvin518df302008-06-14 16:53:48 -0700380 static char buf[4096];
381 size_t t = instruction->times;
382 size_t base = 0;
383 size_t len;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000384
H. Peter Anvine2c80182005-01-15 22:15:51 +0000385 len = ftell(fp);
386 if (instruction->eops->next) {
387 base = instruction->eops->next->offset;
388 len -= base;
389 if (instruction->eops->next->next &&
H. Peter Anvin518df302008-06-14 16:53:48 -0700390 len > (size_t)instruction->eops->next->next->offset)
391 len = (size_t)instruction->eops->next->next->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000392 }
393 /*
394 * Dummy call to list->output to give the offset to the
395 * listing module.
396 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800397 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000398 list->uplevel(LIST_INCBIN);
399 while (t--) {
H. Peter Anvin518df302008-06-14 16:53:48 -0700400 size_t l;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000401
H. Peter Anvine2c80182005-01-15 22:15:51 +0000402 fseek(fp, base, SEEK_SET);
403 l = len;
404 while (l > 0) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000405 int32_t m =
Charles Crayne192d5b52007-10-18 19:02:42 -0700406 fread(buf, 1, (l > (int32_t) sizeof(buf) ? (int32_t) sizeof(buf) : l),
H. Peter Anvine2c80182005-01-15 22:15:51 +0000407 fp);
408 if (!m) {
409 /*
410 * This shouldn't happen unless the file
411 * actually changes while we are reading
412 * it.
413 */
414 error(ERR_NONFATAL,
415 "`incbin': unexpected EOF while"
416 " reading file `%s'", fname);
417 t = 0; /* Try to exit cleanly */
418 break;
419 }
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800420 out(offset, segment, buf, OUT_RAWDATA, m,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000421 NO_SEG, NO_SEG);
422 l -= m;
423 }
424 }
425 list->downlevel(LIST_INCBIN);
426 if (instruction->times > 1) {
427 /*
428 * Dummy call to list->output to give the offset to the
429 * listing module.
430 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800431 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000432 list->uplevel(LIST_TIMES);
433 list->downlevel(LIST_TIMES);
434 }
435 fclose(fp);
436 return instruction->times * len;
437 }
438 return 0; /* if we're here, there's an error */
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000439 }
440
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700441 /* Check to see if we need an address-size prefix */
442 add_asp(instruction, bits);
443
H. Peter Anvin6867acc2007-10-10 14:58:45 -0700444 size_prob = false;
H. Peter Anvin70653092007-10-19 14:42:29 -0700445
446 for (temp = nasm_instructions[instruction->opcode]; temp->opcode != -1; temp++){
Keith Kaniosb7a89542007-04-12 02:40:54 +0000447 int m = matches(temp, instruction, bits);
H. Peter Anvin70653092007-10-19 14:42:29 -0700448
H. Peter Anvine2c80182005-01-15 22:15:51 +0000449 if (m == 99)
450 m += jmp_match(segment, offset, bits, instruction, temp->code);
H. Peter Anvineba20a72002-04-30 20:53:55 +0000451
H. Peter Anvine2c80182005-01-15 22:15:51 +0000452 if (m == 100) { /* matches! */
H. Peter Anvin3720f7b2008-05-12 11:00:50 -0700453 const uint8_t *codes = temp->code;
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800454 int64_t insn_size = calcsize(segment, offset, bits,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000455 instruction, codes);
456 itimes = instruction->times;
457 if (insn_size < 0) /* shouldn't be, on pass two */
458 error(ERR_PANIC, "errors made it through from pass one");
459 else
460 while (itimes--) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700461 for (j = 0; j < MAXPREFIX; j++) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000462 uint8_t c = 0;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000463 switch (instruction->prefixes[j]) {
464 case P_LOCK:
465 c = 0xF0;
466 break;
467 case P_REPNE:
468 case P_REPNZ:
469 c = 0xF2;
470 break;
471 case P_REPE:
472 case P_REPZ:
473 case P_REP:
474 c = 0xF3;
475 break;
476 case R_CS:
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000477 if (bits == 64) {
478 error(ERR_WARNING,
Charles Crayne1b851dc2007-11-05 21:49:49 -0800479 "cs segment base generated, but will be ignored in 64-bit mode");
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000480 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000481 c = 0x2E;
482 break;
483 case R_DS:
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000484 if (bits == 64) {
485 error(ERR_WARNING,
Charles Crayne1b851dc2007-11-05 21:49:49 -0800486 "ds segment base generated, but will be ignored in 64-bit mode");
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000487 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000488 c = 0x3E;
489 break;
490 case R_ES:
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000491 if (bits == 64) {
492 error(ERR_WARNING,
Charles Crayne1b851dc2007-11-05 21:49:49 -0800493 "es segment base generated, but will be ignored in 64-bit mode");
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000494 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000495 c = 0x26;
496 break;
497 case R_FS:
498 c = 0x64;
499 break;
500 case R_GS:
501 c = 0x65;
502 break;
503 case R_SS:
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000504 if (bits == 64) {
505 error(ERR_WARNING,
Charles Crayne1b851dc2007-11-05 21:49:49 -0800506 "ss segment base generated, but will be ignored in 64-bit mode");
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000507 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000508 c = 0x36;
509 break;
510 case R_SEGR6:
511 case R_SEGR7:
512 error(ERR_NONFATAL,
513 "segr6 and segr7 cannot be used as prefixes");
514 break;
515 case P_A16:
Keith Kaniosb7a89542007-04-12 02:40:54 +0000516 if (bits == 64) {
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000517 error(ERR_NONFATAL,
518 "16-bit addressing is not supported "
519 "in 64-bit mode");
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700520 } else if (bits != 16)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000521 c = 0x67;
522 break;
523 case P_A32:
524 if (bits != 32)
525 c = 0x67;
526 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700527 case P_A64:
528 if (bits != 64) {
529 error(ERR_NONFATAL,
530 "64-bit addressing is only supported "
531 "in 64-bit mode");
532 }
533 break;
534 case P_ASP:
535 c = 0x67;
536 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000537 case P_O16:
538 if (bits != 16)
539 c = 0x66;
540 break;
541 case P_O32:
Keith Kaniosb7a89542007-04-12 02:40:54 +0000542 if (bits == 16)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000543 c = 0x66;
544 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700545 case P_O64:
546 /* REX.W */
547 break;
548 case P_OSP:
549 c = 0x66;
550 break;
551 case P_none:
552 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000553 default:
554 error(ERR_PANIC, "invalid instruction prefix");
555 }
556 if (c != 0) {
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800557 out(offset, segment, &c, OUT_RAWDATA, 1,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000558 NO_SEG, NO_SEG);
559 offset++;
560 }
H. Peter Anvin70653092007-10-19 14:42:29 -0700561 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000562 insn_end = offset + insn_size;
563 gencode(segment, offset, bits, instruction, codes,
564 insn_end);
565 offset += insn_size;
566 if (itimes > 0 && itimes == instruction->times - 1) {
567 /*
568 * Dummy call to list->output to give the offset to the
569 * listing module.
570 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800571 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000572 list->uplevel(LIST_TIMES);
573 }
574 }
575 if (instruction->times > 1)
576 list->downlevel(LIST_TIMES);
577 return offset - start;
578 } else if (m > 0 && m > size_prob) {
579 size_prob = m;
580 }
Keith Kaniosb7a89542007-04-12 02:40:54 +0000581// temp++;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000582 }
H. Peter Anvineba20a72002-04-30 20:53:55 +0000583
H. Peter Anvine2c80182005-01-15 22:15:51 +0000584 if (temp->opcode == -1) { /* didn't match any instruction */
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000585 switch (size_prob) {
586 case 1:
587 error(ERR_NONFATAL, "operation size not specified");
588 break;
589 case 2:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000590 error(ERR_NONFATAL, "mismatch in operand sizes");
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000591 break;
592 case 3:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000593 error(ERR_NONFATAL, "no instruction for this cpu level");
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000594 break;
595 case 4:
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000596 error(ERR_NONFATAL, "instruction not supported in 64-bit mode");
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000597 break;
598 default:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000599 error(ERR_NONFATAL,
600 "invalid combination of opcode and operands");
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000601 break;
602 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000603 }
604 return 0;
605}
606
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800607int64_t insn_size(int32_t segment, int64_t offset, int bits, uint32_t cp,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000608 insn * instruction, efunc error)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000609{
H. Peter Anvin3360d792007-09-11 04:16:57 +0000610 const struct itemplate *temp;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000611
H. Peter Anvine2c80182005-01-15 22:15:51 +0000612 errfunc = error; /* to pass to other functions */
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000613 cpu = cp;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000614
615 if (instruction->opcode == -1)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000616 return 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000617
H. Peter Anvincfbe7c32007-09-18 17:49:09 -0700618 if (instruction->opcode == I_DB || instruction->opcode == I_DW ||
619 instruction->opcode == I_DD || instruction->opcode == I_DQ ||
H. Peter Anvindfb91802008-05-20 11:43:53 -0700620 instruction->opcode == I_DT || instruction->opcode == I_DO ||
621 instruction->opcode == I_DY) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000622 extop *e;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000623 int32_t isize, osize, wsize = 0; /* placate gcc */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000624
H. Peter Anvine2c80182005-01-15 22:15:51 +0000625 isize = 0;
626 switch (instruction->opcode) {
627 case I_DB:
628 wsize = 1;
629 break;
630 case I_DW:
631 wsize = 2;
632 break;
633 case I_DD:
634 wsize = 4;
635 break;
636 case I_DQ:
637 wsize = 8;
638 break;
639 case I_DT:
640 wsize = 10;
641 break;
H. Peter Anvincfbe7c32007-09-18 17:49:09 -0700642 case I_DO:
643 wsize = 16;
644 break;
H. Peter Anvindfb91802008-05-20 11:43:53 -0700645 case I_DY:
646 wsize = 32;
647 break;
H. Peter Anvin16b0a332007-09-12 20:27:41 -0700648 default:
649 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000650 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000651
H. Peter Anvine2c80182005-01-15 22:15:51 +0000652 for (e = instruction->eops; e; e = e->next) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000653 int32_t align;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000654
H. Peter Anvine2c80182005-01-15 22:15:51 +0000655 osize = 0;
656 if (e->type == EOT_DB_NUMBER)
657 osize = 1;
H. Peter Anvin518df302008-06-14 16:53:48 -0700658 else if (e->type == EOT_DB_STRING ||
659 e->type == EOT_DB_STRING_FREE)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000660 osize = e->stringlen;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000661
H. Peter Anvine2c80182005-01-15 22:15:51 +0000662 align = (-osize) % wsize;
663 if (align < 0)
664 align += wsize;
665 isize += osize + align;
666 }
667 return isize * instruction->times;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000668 }
669
H. Peter Anvine2c80182005-01-15 22:15:51 +0000670 if (instruction->opcode == I_INCBIN) {
H. Peter Anvin518df302008-06-14 16:53:48 -0700671 const char *fname = instruction->eops->stringval;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000672 FILE *fp;
H. Peter Anvin518df302008-06-14 16:53:48 -0700673 size_t len;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000674
H. Peter Anvin418ca702008-05-30 10:42:30 -0700675 fp = fopen(fname, "rb");
676 if (!fp)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000677 error(ERR_NONFATAL, "`incbin': unable to open file `%s'",
678 fname);
679 else if (fseek(fp, 0L, SEEK_END) < 0)
680 error(ERR_NONFATAL, "`incbin': unable to seek on file `%s'",
681 fname);
682 else {
683 len = ftell(fp);
684 fclose(fp);
685 if (instruction->eops->next) {
686 len -= instruction->eops->next->offset;
687 if (instruction->eops->next->next &&
H. Peter Anvin518df302008-06-14 16:53:48 -0700688 len > (size_t)instruction->eops->next->next->offset) {
689 len = (size_t)instruction->eops->next->next->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000690 }
691 }
692 return instruction->times * len;
693 }
694 return 0; /* if we're here, there's an error */
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000695 }
696
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700697 /* Check to see if we need an address-size prefix */
698 add_asp(instruction, bits);
699
Keith Kaniosb7a89542007-04-12 02:40:54 +0000700 for (temp = nasm_instructions[instruction->opcode]; temp->opcode != -1; temp++) {
701 int m = matches(temp, instruction, bits);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000702 if (m == 99)
703 m += jmp_match(segment, offset, bits, instruction, temp->code);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000704
H. Peter Anvine2c80182005-01-15 22:15:51 +0000705 if (m == 100) {
706 /* we've matched an instruction. */
Charles Crayne5fbbc8c2007-11-07 19:03:46 -0800707 int64_t isize;
H. Peter Anvin3720f7b2008-05-12 11:00:50 -0700708 const uint8_t *codes = temp->code;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000709 int j;
710
711 isize = calcsize(segment, offset, bits, instruction, codes);
712 if (isize < 0)
713 return -1;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700714 for (j = 0; j < MAXPREFIX; j++) {
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700715 switch (instruction->prefixes[j]) {
716 case P_A16:
717 if (bits != 16)
718 isize++;
719 break;
720 case P_A32:
721 if (bits != 32)
722 isize++;
723 break;
724 case P_O16:
725 if (bits != 16)
726 isize++;
727 break;
728 case P_O32:
729 if (bits == 16)
730 isize++;
731 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700732 case P_A64:
733 case P_O64:
734 case P_none:
735 break;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700736 default:
737 isize++;
738 break;
739 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000740 }
741 return isize * instruction->times;
742 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000743 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000744 return -1; /* didn't match any instruction */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000745}
746
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700747static bool possible_sbyte(operand *o)
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000748{
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700749 return !(o->opflags & OPFLAG_FORWARD) &&
750 optimizing >= 0 && !(o->type & STRICT) &&
751 o->wrt == NO_SEG && o->segment == NO_SEG;
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000752}
753
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700754/* check that opn[op] is a signed byte of size 16 or 32 */
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700755static bool is_sbyte16(operand *o)
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700756{
757 int16_t v;
758
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700759 if (!possible_sbyte(o))
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700760 return false;
761
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700762 v = o->offset;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700763 return v >= -128 && v <= 127;
764}
765
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700766static bool is_sbyte32(operand *o)
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700767{
768 int32_t v;
769
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700770 if (!possible_sbyte(o))
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700771 return false;
772
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700773 v = o->offset;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700774 return v >= -128 && v <= 127;
775}
776
777/* check that opn[op] is a signed byte of size 32; warn if this is not
778 the original value when extended to 64 bits */
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700779static bool is_sbyte64(operand *o)
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700780{
781 int64_t v64;
782 int32_t v32;
783
784 /* dead in the water on forward reference or External */
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700785 if (!possible_sbyte(o))
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700786 return false;
787
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700788 v64 = o->offset;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700789 v32 = (int32_t)v64;
790
791 warn_overflow(32, v64);
792
793 return v32 >= -128 && v32 <= 127;
794}
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800795static int64_t calcsize(int32_t segment, int64_t offset, int bits,
H. Peter Anvin3720f7b2008-05-12 11:00:50 -0700796 insn * ins, const uint8_t *codes)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000797{
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800798 int64_t length = 0;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000799 uint8_t c;
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000800 int rex_mask = ~0;
H. Peter Anvin839eca22007-10-29 23:12:47 -0700801 struct operand *opx;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000802
H. Peter Anvine3917fc2007-11-01 14:53:32 -0700803 ins->rex = 0; /* Ensure REX is reset */
804
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700805 if (ins->prefixes[PPS_OSIZE] == P_O64)
806 ins->rex |= REX_W;
807
H. Peter Anvine2c80182005-01-15 22:15:51 +0000808 (void)segment; /* Don't warn that this parameter is unused */
809 (void)offset; /* Don't warn that this parameter is unused */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000810
H. Peter Anvin839eca22007-10-29 23:12:47 -0700811 while (*codes) {
812 c = *codes++;
813 opx = &ins->oprs[c & 3];
814 switch (c) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000815 case 01:
816 case 02:
817 case 03:
818 codes += c, length += c;
819 break;
820 case 04:
821 case 05:
822 case 06:
823 case 07:
824 length++;
825 break;
826 case 010:
827 case 011:
828 case 012:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700829 case 013:
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000830 ins->rex |=
H. Peter Anvin839eca22007-10-29 23:12:47 -0700831 op_rexflags(opx, REX_B|REX_H|REX_P|REX_W);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000832 codes++, length++;
833 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000834 case 014:
835 case 015:
836 case 016:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700837 case 017:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000838 length++;
839 break;
840 case 020:
841 case 021:
842 case 022:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700843 case 023:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000844 length++;
845 break;
846 case 024:
847 case 025:
848 case 026:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700849 case 027:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000850 length++;
851 break;
852 case 030:
853 case 031:
854 case 032:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700855 case 033:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000856 length += 2;
857 break;
858 case 034:
859 case 035:
860 case 036:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700861 case 037:
H. Peter Anvin839eca22007-10-29 23:12:47 -0700862 if (opx->type & (BITS16 | BITS32 | BITS64))
863 length += (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000864 else
865 length += (bits == 16) ? 2 : 4;
866 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000867 case 040:
868 case 041:
869 case 042:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700870 case 043:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000871 length += 4;
872 break;
873 case 044:
874 case 045:
875 case 046:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700876 case 047:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700877 length += ins->addr_size >> 3;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000878 break;
879 case 050:
880 case 051:
881 case 052:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700882 case 053:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000883 length++;
884 break;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000885 case 054:
886 case 055:
887 case 056:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700888 case 057:
Keith Kaniosb7a89542007-04-12 02:40:54 +0000889 length += 8; /* MOV reg64/imm */
890 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000891 case 060:
892 case 061:
893 case 062:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700894 case 063:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000895 length += 2;
896 break;
897 case 064:
898 case 065:
899 case 066:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700900 case 067:
H. Peter Anvin839eca22007-10-29 23:12:47 -0700901 if (opx->type & (BITS16 | BITS32 | BITS64))
902 length += (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000903 else
904 length += (bits == 16) ? 2 : 4;
905 break;
906 case 070:
907 case 071:
908 case 072:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700909 case 073:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000910 length += 4;
911 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700912 case 074:
913 case 075:
914 case 076:
915 case 077:
916 length += 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000917 break;
918 case 0140:
919 case 0141:
920 case 0142:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700921 case 0143:
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700922 length += is_sbyte16(opx) ? 1 : 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000923 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000924 case 0144:
925 case 0145:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700926 case 0146:
927 case 0147:
H. Peter Anvina30cc072007-11-18 21:55:26 -0800928 codes++;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000929 length++;
930 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700931 case 0150:
932 case 0151:
933 case 0152:
934 case 0153:
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700935 length += is_sbyte32(opx) ? 1 : 4;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700936 break;
937 case 0154:
938 case 0155:
939 case 0156:
940 case 0157:
H. Peter Anvina30cc072007-11-18 21:55:26 -0800941 codes++;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700942 length++;
943 break;
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700944 case 0160:
945 case 0161:
946 case 0162:
947 case 0163:
948 length++;
949 ins->rex |= REX_D;
H. Peter Anvind85d2502008-05-04 17:53:31 -0700950 ins->drexdst = regval(opx);
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700951 break;
952 case 0164:
953 case 0165:
954 case 0166:
955 case 0167:
956 length++;
957 ins->rex |= REX_D|REX_OC;
H. Peter Anvind85d2502008-05-04 17:53:31 -0700958 ins->drexdst = regval(opx);
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700959 break;
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700960 case 0171:
961 break;
H. Peter Anvind85d2502008-05-04 17:53:31 -0700962 case 0172:
H. Peter Anvind58656f2008-05-06 20:11:14 -0700963 case 0173:
H. Peter Anvin52dc3532008-05-20 19:29:04 -0700964 case 0174:
H. Peter Anvind85d2502008-05-04 17:53:31 -0700965 codes++;
966 length++;
967 break;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700968 case 0250:
969 case 0251:
970 case 0252:
971 case 0253:
H. Peter Anvin1c3277b2008-07-19 21:38:56 -0700972 length += is_sbyte64(opx) ? 1 : 4;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700973 break;
H. Peter Anvind85d2502008-05-04 17:53:31 -0700974 case 0260:
975 case 0261:
976 case 0262:
977 case 0263:
978 length += 2;
979 ins->rex |= REX_V;
980 ins->drexdst = regval(opx);
981 ins->vex_m = *codes++;
982 ins->vex_wlp = *codes++;
983 break;
984 case 0270:
985 length += 2;
986 ins->rex |= REX_V;
987 ins->drexdst = 0;
988 ins->vex_m = *codes++;
989 ins->vex_wlp = *codes++;
990 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000991 case 0300:
992 case 0301:
H. Peter Anvin70653092007-10-19 14:42:29 -0700993 case 0302:
994 case 0303:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000995 break;
996 case 0310:
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700997 if (bits == 64)
998 return -1;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700999 length += (bits != 16) && !has_prefix(ins, PPS_ASIZE, P_A16);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001000 break;
1001 case 0311:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001002 length += (bits != 32) && !has_prefix(ins, PPS_ASIZE, P_A32);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001003 break;
1004 case 0312:
H. Peter Anvin70653092007-10-19 14:42:29 -07001005 break;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001006 case 0313:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001007 if (bits != 64 || has_prefix(ins, PPS_ASIZE, P_A16) ||
1008 has_prefix(ins, PPS_ASIZE, P_A32))
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07001009 return -1;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001010 break;
H. Peter Anvin23440102007-11-12 21:02:33 -08001011 case 0314:
1012 case 0315:
1013 case 0316:
1014 case 0317:
1015 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001016 case 0320:
Keith Kaniosb7a89542007-04-12 02:40:54 +00001017 length += (bits != 16);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001018 break;
1019 case 0321:
1020 length += (bits == 16);
1021 break;
1022 case 0322:
1023 break;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001024 case 0323:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001025 rex_mask &= ~REX_W;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001026 break;
1027 case 0324:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001028 ins->rex |= REX_W;
H. Peter Anvin8d7316a2007-04-18 02:27:18 +00001029 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001030 case 0330:
1031 codes++, length++;
1032 break;
1033 case 0331:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001034 break;
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001035 case 0332:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001036 case 0333:
1037 length++;
1038 break;
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001039 case 0334:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001040 ins->rex |= REX_L;
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001041 break;
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001042 case 0335:
1043 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001044 case 0340:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001045 if (ins->oprs[0].segment != NO_SEG)
1046 errfunc(ERR_NONFATAL, "attempt to reserve non-constant"
1047 " quantity of BSS space");
1048 else
H. Peter Anvin428fd672007-11-15 10:25:52 -08001049 length += ins->oprs[0].offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001050 break;
H. Peter Anvinfff5a472008-05-20 09:46:24 -07001051 case 0360:
1052 break;
1053 case 0361:
1054 case 0362:
1055 case 0363:
1056 length++;
1057 break;
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001058 case 0364:
1059 case 0365:
1060 break;
Keith Kanios48af1772007-08-17 07:37:52 +00001061 case 0366:
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001062 case 0367:
1063 length++;
1064 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001065 case 0370:
1066 case 0371:
1067 case 0372:
1068 break;
1069 case 0373:
1070 length++;
1071 break;
1072 default: /* can't do it by 'case' statements */
1073 if (c >= 0100 && c <= 0277) { /* it's an EA */
1074 ea ea_data;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001075 int rfield;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001076 int32_t rflags;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001077 ea_data.rex = 0; /* Ensure ea.REX is initially 0 */
H. Peter Anvin70653092007-10-19 14:42:29 -07001078
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001079 if (c <= 0177) {
1080 /* pick rfield from operand b */
1081 rflags = regflag(&ins->oprs[c & 7]);
H. Peter Anvina4835d42008-05-20 14:21:29 -07001082 rfield = nasm_regvals[ins->oprs[c & 7].basereg];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001083 } else {
1084 rflags = 0;
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001085 rfield = c & 7;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001086 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00001087
H. Peter Anvine2c80182005-01-15 22:15:51 +00001088 if (!process_ea
Keith Kaniosb7a89542007-04-12 02:40:54 +00001089 (&ins->oprs[(c >> 3) & 7], &ea_data, bits,
H. Peter Anvin1c3277b2008-07-19 21:38:56 -07001090 ins->addr_size, rfield, rflags)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001091 errfunc(ERR_NONFATAL, "invalid effective address");
1092 return -1;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001093 } else {
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001094 ins->rex |= ea_data.rex;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001095 length += ea_data.size;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001096 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001097 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001098 errfunc(ERR_PANIC, "internal instruction table corrupt"
1099 ": instruction code 0x%02X given", c);
H. Peter Anvin839eca22007-10-29 23:12:47 -07001100 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001101 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001102 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001103
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001104 ins->rex &= rex_mask;
H. Peter Anvin70653092007-10-19 14:42:29 -07001105
H. Peter Anvind85d2502008-05-04 17:53:31 -07001106 if (ins->rex & REX_V) {
1107 int bad32 = REX_R|REX_W|REX_X|REX_B;
1108
1109 if (ins->rex & REX_H) {
1110 errfunc(ERR_NONFATAL, "cannot use high register in vex instruction");
1111 return -1;
1112 }
1113 switch (ins->vex_wlp & 030) {
1114 case 000:
H. Peter Anvinbd420c72008-05-22 11:24:35 -07001115 case 020:
H. Peter Anvind85d2502008-05-04 17:53:31 -07001116 ins->rex &= ~REX_W;
1117 break;
1118 case 010:
1119 ins->rex |= REX_W;
1120 bad32 &= ~REX_W;
1121 break;
H. Peter Anvinbd420c72008-05-22 11:24:35 -07001122 case 030:
H. Peter Anvind85d2502008-05-04 17:53:31 -07001123 /* Follow REX_W */
1124 break;
1125 }
1126
1127 if (bits != 64 && ((ins->rex & bad32) || ins->drexdst > 7)) {
1128 errfunc(ERR_NONFATAL, "invalid operands in non-64-bit mode");
1129 return -1;
1130 }
1131 if (ins->vex_m != 1 || (ins->rex & (REX_W|REX_R|REX_B)))
1132 length += 3;
1133 else
1134 length += 2;
1135 } else if (ins->rex & REX_D) {
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001136 if (ins->rex & REX_H) {
1137 errfunc(ERR_NONFATAL, "cannot use high register in drex instruction");
1138 return -1;
1139 }
H. Peter Anvind85d2502008-05-04 17:53:31 -07001140 if (bits != 64 && ((ins->rex & (REX_R|REX_W|REX_X|REX_B)) ||
H. Peter Anvincf5180a2007-09-17 17:25:27 -07001141 ins->drexdst > 7)) {
1142 errfunc(ERR_NONFATAL, "invalid operands in non-64-bit mode");
1143 return -1;
1144 }
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001145 length++;
1146 } else if (ins->rex & REX_REAL) {
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001147 if (ins->rex & REX_H) {
1148 errfunc(ERR_NONFATAL, "cannot use high register in rex instruction");
1149 return -1;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001150 } else if (bits == 64) {
1151 length++;
1152 } else if ((ins->rex & REX_L) &&
1153 !(ins->rex & (REX_P|REX_W|REX_X|REX_B)) &&
1154 cpu >= IF_X86_64) {
1155 /* LOCK-as-REX.R */
1156 assert_no_prefix(ins, PPS_LREP);
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001157 length++;
H. Peter Anvin8d7316a2007-04-18 02:27:18 +00001158 } else {
H. Peter Anvincf5180a2007-09-17 17:25:27 -07001159 errfunc(ERR_NONFATAL, "invalid operands in non-64-bit mode");
1160 return -1;
H. Peter Anvin8d7316a2007-04-18 02:27:18 +00001161 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00001162 }
1163
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001164 return length;
1165}
Keith Kaniosb7a89542007-04-12 02:40:54 +00001166
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001167#define EMIT_REX() \
H. Peter Anvind85d2502008-05-04 17:53:31 -07001168 if (!(ins->rex & (REX_D|REX_V)) && (ins->rex & REX_REAL) && (bits == 64)) { \
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001169 ins->rex = (ins->rex & REX_REAL)|REX_P; \
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001170 out(offset, segment, &ins->rex, OUT_RAWDATA, 1, NO_SEG, NO_SEG); \
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001171 ins->rex = 0; \
1172 offset += 1; \
1173 }
1174
Charles Crayne1f8bc4c2007-11-06 18:27:23 -08001175static void gencode(int32_t segment, int64_t offset, int bits,
H. Peter Anvin3720f7b2008-05-12 11:00:50 -07001176 insn * ins, const uint8_t *codes, int64_t insn_end)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001177{
Keith Kaniosa6dfa782007-04-13 16:47:53 +00001178 static char condval[] = { /* conditional opcodes */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001179 0x7, 0x3, 0x2, 0x6, 0x2, 0x4, 0xF, 0xD, 0xC, 0xE, 0x6, 0x2,
1180 0x3, 0x7, 0x3, 0x5, 0xE, 0xC, 0xD, 0xF, 0x1, 0xB, 0x9, 0x5,
1181 0x0, 0xA, 0xA, 0xB, 0x8, 0x4
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001182 };
Keith Kaniosb7a89542007-04-12 02:40:54 +00001183 uint8_t c;
1184 uint8_t bytes[4];
Charles Crayne1f8bc4c2007-11-06 18:27:23 -08001185 int64_t size;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001186 int64_t data;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001187 struct operand *opx;
H. Peter Anvin70653092007-10-19 14:42:29 -07001188
H. Peter Anvin839eca22007-10-29 23:12:47 -07001189 while (*codes) {
1190 c = *codes++;
1191 opx = &ins->oprs[c & 3];
1192 switch (c) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001193 case 01:
1194 case 02:
1195 case 03:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001196 EMIT_REX();
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001197 out(offset, segment, codes, OUT_RAWDATA, c, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001198 codes += c;
1199 offset += c;
1200 break;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001201
H. Peter Anvine2c80182005-01-15 22:15:51 +00001202 case 04:
1203 case 06:
1204 switch (ins->oprs[0].basereg) {
1205 case R_CS:
1206 bytes[0] = 0x0E + (c == 0x04 ? 1 : 0);
1207 break;
1208 case R_DS:
1209 bytes[0] = 0x1E + (c == 0x04 ? 1 : 0);
1210 break;
1211 case R_ES:
1212 bytes[0] = 0x06 + (c == 0x04 ? 1 : 0);
1213 break;
1214 case R_SS:
1215 bytes[0] = 0x16 + (c == 0x04 ? 1 : 0);
1216 break;
1217 default:
1218 errfunc(ERR_PANIC,
1219 "bizarre 8086 segment register received");
1220 }
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001221 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001222 offset++;
1223 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001224
H. Peter Anvine2c80182005-01-15 22:15:51 +00001225 case 05:
1226 case 07:
1227 switch (ins->oprs[0].basereg) {
1228 case R_FS:
1229 bytes[0] = 0xA0 + (c == 0x05 ? 1 : 0);
1230 break;
1231 case R_GS:
1232 bytes[0] = 0xA8 + (c == 0x05 ? 1 : 0);
1233 break;
1234 default:
1235 errfunc(ERR_PANIC,
1236 "bizarre 386 segment register received");
1237 }
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001238 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001239 offset++;
1240 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001241
H. Peter Anvine2c80182005-01-15 22:15:51 +00001242 case 010:
1243 case 011:
1244 case 012:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001245 case 013:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001246 EMIT_REX();
H. Peter Anvin839eca22007-10-29 23:12:47 -07001247 bytes[0] = *codes++ + ((regval(opx)) & 7);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001248 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001249 offset += 1;
1250 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001251
H. Peter Anvine2c80182005-01-15 22:15:51 +00001252 case 014:
1253 case 015:
1254 case 016:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001255 case 017:
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001256 /* XXX: warns for legitimate optimizer actions */
H. Peter Anvin839eca22007-10-29 23:12:47 -07001257 if (opx->offset < -128 || opx->offset > 127) {
H. Peter Anvin72c64372008-01-08 22:13:48 -08001258 errfunc(ERR_WARNING | ERR_WARN_NOV,
1259 "signed byte value exceeds bounds");
H. Peter Anvine2c80182005-01-15 22:15:51 +00001260 }
H. Peter Anvineba20a72002-04-30 20:53:55 +00001261
H. Peter Anvin839eca22007-10-29 23:12:47 -07001262 if (opx->segment != NO_SEG) {
1263 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001264 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001265 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001266 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001267 bytes[0] = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001268 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001269 NO_SEG);
1270 }
1271 offset += 1;
1272 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001273
H. Peter Anvine2c80182005-01-15 22:15:51 +00001274 case 020:
1275 case 021:
1276 case 022:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001277 case 023:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001278 if (opx->offset < -256 || opx->offset > 255) {
H. Peter Anvin72c64372008-01-08 22:13:48 -08001279 errfunc(ERR_WARNING | ERR_WARN_NOV,
1280 "byte value exceeds bounds");
H. Peter Anvine2c80182005-01-15 22:15:51 +00001281 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001282 if (opx->segment != NO_SEG) {
1283 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001284 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001285 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001286 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001287 bytes[0] = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001288 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001289 NO_SEG);
1290 }
1291 offset += 1;
1292 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001293
H. Peter Anvine2c80182005-01-15 22:15:51 +00001294 case 024:
1295 case 025:
1296 case 026:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001297 case 027:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001298 if (opx->offset < 0 || opx->offset > 255)
H. Peter Anvin72c64372008-01-08 22:13:48 -08001299 errfunc(ERR_WARNING | ERR_WARN_NOV,
1300 "unsigned byte value exceeds bounds");
H. Peter Anvin839eca22007-10-29 23:12:47 -07001301 if (opx->segment != NO_SEG) {
1302 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001303 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001304 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001305 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001306 bytes[0] = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001307 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001308 NO_SEG);
1309 }
1310 offset += 1;
1311 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001312
H. Peter Anvine2c80182005-01-15 22:15:51 +00001313 case 030:
1314 case 031:
1315 case 032:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001316 case 033:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001317 data = opx->offset;
1318 if (opx->segment == NO_SEG && opx->wrt == NO_SEG)
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001319 warn_overflow(2, data);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001320 out(offset, segment, &data, OUT_ADDRESS, 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001321 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001322 offset += 2;
1323 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001324
H. Peter Anvine2c80182005-01-15 22:15:51 +00001325 case 034:
1326 case 035:
1327 case 036:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001328 case 037:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001329 if (opx->type & (BITS16 | BITS32))
1330 size = (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001331 else
1332 size = (bits == 16) ? 2 : 4;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001333 data = opx->offset;
1334 if (opx->segment == NO_SEG && opx->wrt == NO_SEG)
H. Peter Anvin10e27272007-10-29 22:56:08 -07001335 warn_overflow(size, data);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001336 out(offset, segment, &data, OUT_ADDRESS, size,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001337 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001338 offset += size;
1339 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001340
H. Peter Anvine2c80182005-01-15 22:15:51 +00001341 case 040:
1342 case 041:
1343 case 042:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001344 case 043:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001345 data = opx->offset;
H. Peter Anvin72c64372008-01-08 22:13:48 -08001346 if (opx->segment == NO_SEG && opx->wrt == NO_SEG)
1347 warn_overflow(4, data);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001348 out(offset, segment, &data, OUT_ADDRESS, 4,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001349 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001350 offset += 4;
1351 break;
H. Peter Anvin3ba46772002-05-27 23:19:35 +00001352
H. Peter Anvine2c80182005-01-15 22:15:51 +00001353 case 044:
1354 case 045:
1355 case 046:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001356 case 047:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001357 data = opx->offset;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001358 size = ins->addr_size >> 3;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001359 if (opx->segment == NO_SEG &&
1360 opx->wrt == NO_SEG)
H. Peter Anvin10e27272007-10-29 22:56:08 -07001361 warn_overflow(size, data);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001362 out(offset, segment, &data, OUT_ADDRESS, size,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001363 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001364 offset += size;
1365 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001366
H. Peter Anvine2c80182005-01-15 22:15:51 +00001367 case 050:
1368 case 051:
1369 case 052:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001370 case 053:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001371 if (opx->segment != segment)
H. Peter Anvine2c80182005-01-15 22:15:51 +00001372 errfunc(ERR_NONFATAL,
1373 "short relative jump outside segment");
H. Peter Anvin839eca22007-10-29 23:12:47 -07001374 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001375 if (data > 127 || data < -128)
1376 errfunc(ERR_NONFATAL, "short jump is out of range");
1377 bytes[0] = data;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001378 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001379 offset += 1;
1380 break;
H. Peter Anvin70653092007-10-19 14:42:29 -07001381
Keith Kaniosb7a89542007-04-12 02:40:54 +00001382 case 054:
1383 case 055:
1384 case 056:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001385 case 057:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001386 data = (int64_t)opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001387 out(offset, segment, &data, OUT_ADDRESS, 8,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001388 opx->segment, opx->wrt);
Keith Kaniosb7a89542007-04-12 02:40:54 +00001389 offset += 8;
1390 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001391
H. Peter Anvine2c80182005-01-15 22:15:51 +00001392 case 060:
1393 case 061:
1394 case 062:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001395 case 063:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001396 if (opx->segment != segment) {
1397 data = opx->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001398 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001399 OUT_REL2ADR, insn_end - offset,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001400 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001401 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001402 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001403 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001404 OUT_ADDRESS, 2, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001405 }
1406 offset += 2;
1407 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001408
H. Peter Anvine2c80182005-01-15 22:15:51 +00001409 case 064:
1410 case 065:
1411 case 066:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001412 case 067:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001413 if (opx->type & (BITS16 | BITS32 | BITS64))
1414 size = (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001415 else
1416 size = (bits == 16) ? 2 : 4;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001417 if (opx->segment != segment) {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001418 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001419 out(offset, segment, &data,
1420 size == 2 ? OUT_REL2ADR : OUT_REL4ADR,
1421 insn_end - offset, opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001422 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001423 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001424 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001425 OUT_ADDRESS, size, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001426 }
1427 offset += size;
1428 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001429
H. Peter Anvine2c80182005-01-15 22:15:51 +00001430 case 070:
1431 case 071:
1432 case 072:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001433 case 073:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001434 if (opx->segment != segment) {
1435 data = opx->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001436 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001437 OUT_REL4ADR, insn_end - offset,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001438 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001439 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001440 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001441 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001442 OUT_ADDRESS, 4, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001443 }
1444 offset += 4;
1445 break;
H. Peter Anvinaf535c12002-04-30 20:59:21 +00001446
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001447 case 074:
1448 case 075:
1449 case 076:
1450 case 077:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001451 if (opx->segment == NO_SEG)
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001452 errfunc(ERR_NONFATAL, "value referenced by FAR is not"
1453 " relocatable");
H. Peter Anvindfb91802008-05-20 11:43:53 -07001454 data = 0;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001455 out(offset, segment, &data, OUT_ADDRESS, 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001456 outfmt->segbase(1 + opx->segment),
1457 opx->wrt);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001458 offset += 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001459 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001460
H. Peter Anvine2c80182005-01-15 22:15:51 +00001461 case 0140:
1462 case 0141:
1463 case 0142:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001464 case 0143:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001465 data = opx->offset;
H. Peter Anvin1c3277b2008-07-19 21:38:56 -07001466 if (is_sbyte16(opx)) {
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001467 bytes[0] = data;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001468 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001469 NO_SEG);
1470 offset++;
1471 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001472 if (opx->segment == NO_SEG &&
1473 opx->wrt == NO_SEG)
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001474 warn_overflow(2, data);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001475 out(offset, segment, &data, OUT_ADDRESS, 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001476 opx->segment, opx->wrt);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001477 offset += 2;
1478 }
1479 break;
1480
1481 case 0144:
1482 case 0145:
1483 case 0146:
1484 case 0147:
1485 EMIT_REX();
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001486 bytes[0] = *codes++;
H. Peter Anvin1c3277b2008-07-19 21:38:56 -07001487 if (is_sbyte16(opx))
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001488 bytes[0] |= 2; /* s-bit */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001489 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001490 offset++;
1491 break;
1492
1493 case 0150:
1494 case 0151:
1495 case 0152:
1496 case 0153:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001497 data = opx->offset;
H. Peter Anvin1c3277b2008-07-19 21:38:56 -07001498 if (is_sbyte32(opx)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001499 bytes[0] = data;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001500 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001501 NO_SEG);
1502 offset++;
1503 } else {
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001504 out(offset, segment, &data, OUT_ADDRESS, 4,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001505 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001506 offset += 4;
1507 }
1508 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001509
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001510 case 0154:
1511 case 0155:
1512 case 0156:
1513 case 0157:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001514 EMIT_REX();
H. Peter Anvine2c80182005-01-15 22:15:51 +00001515 bytes[0] = *codes++;
H. Peter Anvin1c3277b2008-07-19 21:38:56 -07001516 if (is_sbyte32(opx))
H. Peter Anvine2c80182005-01-15 22:15:51 +00001517 bytes[0] |= 2; /* s-bit */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001518 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001519 offset++;
1520 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001521
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001522 case 0160:
1523 case 0161:
1524 case 0162:
1525 case 0163:
1526 case 0164:
1527 case 0165:
1528 case 0166:
1529 case 0167:
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001530 break;
1531
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001532 case 0171:
1533 bytes[0] =
1534 (ins->drexdst << 4) |
1535 (ins->rex & REX_OC ? 0x08 : 0) |
1536 (ins->rex & (REX_R|REX_X|REX_B));
1537 ins->rex = 0;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001538 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001539 offset++;
1540 break;
1541
H. Peter Anvind85d2502008-05-04 17:53:31 -07001542 case 0172:
1543 c = *codes++;
1544 opx = &ins->oprs[c >> 3];
H. Peter Anvina4835d42008-05-20 14:21:29 -07001545 bytes[0] = nasm_regvals[opx->basereg] << 4;
H. Peter Anvind85d2502008-05-04 17:53:31 -07001546 opx = &ins->oprs[c & 7];
1547 if (opx->segment != NO_SEG || opx->wrt != NO_SEG) {
1548 errfunc(ERR_NONFATAL,
1549 "non-absolute expression not permitted as argument %d",
1550 c & 7);
1551 } else {
1552 if (opx->offset & ~15) {
1553 errfunc(ERR_WARNING | ERR_WARN_NOV,
1554 "four-bit argument exceeds bounds");
1555 }
1556 bytes[0] |= opx->offset & 15;
1557 }
1558 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1559 offset++;
1560 break;
1561
H. Peter Anvind58656f2008-05-06 20:11:14 -07001562 case 0173:
1563 c = *codes++;
1564 opx = &ins->oprs[c >> 4];
H. Peter Anvina4835d42008-05-20 14:21:29 -07001565 bytes[0] = nasm_regvals[opx->basereg] << 4;
H. Peter Anvind58656f2008-05-06 20:11:14 -07001566 bytes[0] |= c & 15;
1567 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1568 offset++;
1569 break;
1570
H. Peter Anvin52dc3532008-05-20 19:29:04 -07001571 case 0174:
1572 c = *codes++;
1573 opx = &ins->oprs[c];
1574 bytes[0] = nasm_regvals[opx->basereg] << 4;
1575 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1576 offset++;
1577 break;
1578
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001579 case 0250:
1580 case 0251:
1581 case 0252:
1582 case 0253:
1583 data = opx->offset;
1584 /* is_sbyte32() is right here, we have already warned */
H. Peter Anvin1c3277b2008-07-19 21:38:56 -07001585 if (is_sbyte32(opx)) {
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001586 bytes[0] = data;
1587 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
1588 NO_SEG);
1589 offset++;
1590 } else {
1591 out(offset, segment, &data, OUT_ADDRESS, 4,
1592 opx->segment, opx->wrt);
1593 offset += 4;
1594 }
1595 break;
1596
H. Peter Anvind85d2502008-05-04 17:53:31 -07001597 case 0260:
1598 case 0261:
1599 case 0262:
1600 case 0263:
1601 case 0270:
1602 codes += 2;
1603 if (ins->vex_m != 1 || (ins->rex & (REX_W|REX_X|REX_B))) {
1604 bytes[0] = 0xc4;
H. Peter Anvin4d2c38c2008-05-04 23:15:13 -07001605 bytes[1] = ins->vex_m | ((~ins->rex & 7) << 5);
H. Peter Anvind85d2502008-05-04 17:53:31 -07001606 bytes[2] = ((ins->rex & REX_W) << (7-3)) |
H. Peter Anvin4d2c38c2008-05-04 23:15:13 -07001607 ((~ins->drexdst & 15)<< 3) | (ins->vex_wlp & 07);
H. Peter Anvind85d2502008-05-04 17:53:31 -07001608 out(offset, segment, &bytes, OUT_RAWDATA, 3, NO_SEG, NO_SEG);
1609 offset += 3;
1610 } else {
1611 bytes[0] = 0xc5;
H. Peter Anvin4d2c38c2008-05-04 23:15:13 -07001612 bytes[1] = ((~ins->rex & REX_R) << (7-2)) |
1613 ((~ins->drexdst & 15) << 3) | (ins->vex_wlp & 07);
H. Peter Anvind85d2502008-05-04 17:53:31 -07001614 out(offset, segment, &bytes, OUT_RAWDATA, 2, NO_SEG, NO_SEG);
1615 offset += 2;
1616 }
1617 break;
1618
H. Peter Anvine2c80182005-01-15 22:15:51 +00001619 case 0300:
1620 case 0301:
1621 case 0302:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001622 case 0303:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001623 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001624
H. Peter Anvine2c80182005-01-15 22:15:51 +00001625 case 0310:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001626 if (bits == 32 && !has_prefix(ins, PPS_ASIZE, P_A16)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001627 *bytes = 0x67;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001628 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001629 offset += 1;
1630 } else
1631 offset += 0;
1632 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001633
H. Peter Anvine2c80182005-01-15 22:15:51 +00001634 case 0311:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001635 if (bits != 32 && !has_prefix(ins, PPS_ASIZE, P_A32)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001636 *bytes = 0x67;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001637 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001638 offset += 1;
1639 } else
1640 offset += 0;
1641 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001642
H. Peter Anvine2c80182005-01-15 22:15:51 +00001643 case 0312:
1644 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001645
Keith Kaniosb7a89542007-04-12 02:40:54 +00001646 case 0313:
1647 ins->rex = 0;
1648 break;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07001649
H. Peter Anvin23440102007-11-12 21:02:33 -08001650 case 0314:
1651 case 0315:
1652 case 0316:
1653 case 0317:
1654 break;
1655
H. Peter Anvine2c80182005-01-15 22:15:51 +00001656 case 0320:
Keith Kaniosb7a89542007-04-12 02:40:54 +00001657 if (bits != 16) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001658 *bytes = 0x66;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001659 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001660 offset += 1;
1661 } else
1662 offset += 0;
1663 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001664
H. Peter Anvine2c80182005-01-15 22:15:51 +00001665 case 0321:
1666 if (bits == 16) {
1667 *bytes = 0x66;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001668 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001669 offset += 1;
1670 } else
1671 offset += 0;
1672 break;
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001673
H. Peter Anvine2c80182005-01-15 22:15:51 +00001674 case 0322:
H. Peter Anvin70653092007-10-19 14:42:29 -07001675 case 0323:
1676 break;
1677
Keith Kaniosb7a89542007-04-12 02:40:54 +00001678 case 0324:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001679 ins->rex |= REX_W;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001680 break;
H. Peter Anvin70653092007-10-19 14:42:29 -07001681
H. Peter Anvine2c80182005-01-15 22:15:51 +00001682 case 0330:
1683 *bytes = *codes++ ^ condval[ins->condition];
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001684 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001685 offset += 1;
1686 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001687
H. Peter Anvine2c80182005-01-15 22:15:51 +00001688 case 0331:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001689 break;
H. Peter Anvinaf535c12002-04-30 20:59:21 +00001690
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001691 case 0332:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001692 case 0333:
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001693 *bytes = c - 0332 + 0xF2;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001694 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001695 offset += 1;
1696 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001697
Keith Kanios48af1772007-08-17 07:37:52 +00001698 case 0334:
1699 if (ins->rex & REX_R) {
1700 *bytes = 0xF0;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001701 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
Keith Kanios48af1772007-08-17 07:37:52 +00001702 offset += 1;
1703 }
1704 ins->rex &= ~(REX_L|REX_R);
1705 break;
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001706
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001707 case 0335:
1708 break;
1709
H. Peter Anvine2c80182005-01-15 22:15:51 +00001710 case 0340:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001711 if (ins->oprs[0].segment != NO_SEG)
1712 errfunc(ERR_PANIC, "non-constant BSS size in pass two");
1713 else {
H. Peter Anvin428fd672007-11-15 10:25:52 -08001714 int64_t size = ins->oprs[0].offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001715 if (size > 0)
1716 out(offset, segment, NULL,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001717 OUT_RESERVE, size, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001718 offset += size;
1719 }
1720 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001721
H. Peter Anvinfff5a472008-05-20 09:46:24 -07001722 case 0360:
1723 break;
1724
1725 case 0361:
1726 bytes[0] = 0x66;
1727 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1728 offset += 1;
1729 break;
1730
1731 case 0362:
1732 case 0363:
1733 bytes[0] = c - 0362 + 0xf2;
1734 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1735 offset += 1;
1736 break;
1737
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001738 case 0364:
1739 case 0365:
1740 break;
1741
Keith Kanios48af1772007-08-17 07:37:52 +00001742 case 0366:
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001743 case 0367:
1744 *bytes = c - 0366 + 0x66;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001745 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
Keith Kanios48af1772007-08-17 07:37:52 +00001746 offset += 1;
1747 break;
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001748
H. Peter Anvine2c80182005-01-15 22:15:51 +00001749 case 0370:
1750 case 0371:
1751 case 0372:
1752 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001753
H. Peter Anvine2c80182005-01-15 22:15:51 +00001754 case 0373:
1755 *bytes = bits == 16 ? 3 : 5;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001756 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001757 offset += 1;
1758 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001759
H. Peter Anvine2c80182005-01-15 22:15:51 +00001760 default: /* can't do it by 'case' statements */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001761 if (c >= 0100 && c <= 0277) { /* it's an EA */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001762 ea ea_data;
1763 int rfield;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001764 int32_t rflags;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001765 uint8_t *p;
1766 int32_t s;
H. Peter Anvin70653092007-10-19 14:42:29 -07001767
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001768 if (c <= 0177) {
1769 /* pick rfield from operand b */
1770 rflags = regflag(&ins->oprs[c & 7]);
H. Peter Anvina4835d42008-05-20 14:21:29 -07001771 rfield = nasm_regvals[ins->oprs[c & 7].basereg];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001772 } else {
1773 /* rfield is constant */
1774 rflags = 0;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001775 rfield = c & 7;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001776 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001777
1778 if (!process_ea
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001779 (&ins->oprs[(c >> 3) & 7], &ea_data, bits,
H. Peter Anvin1c3277b2008-07-19 21:38:56 -07001780 ins->addr_size, rfield, rflags)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001781 errfunc(ERR_NONFATAL, "invalid effective address");
1782 }
H. Peter Anvin70653092007-10-19 14:42:29 -07001783
Charles Crayne7e975552007-11-03 22:06:13 -07001784
H. Peter Anvine2c80182005-01-15 22:15:51 +00001785 p = bytes;
1786 *p++ = ea_data.modrm;
1787 if (ea_data.sib_present)
1788 *p++ = ea_data.sib;
1789
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001790 /* DREX suffixes come between the SIB and the displacement */
1791 if (ins->rex & REX_D) {
1792 *p++ =
1793 (ins->drexdst << 4) |
1794 (ins->rex & REX_OC ? 0x08 : 0) |
1795 (ins->rex & (REX_R|REX_X|REX_B));
1796 ins->rex = 0;
1797 }
1798
H. Peter Anvine2c80182005-01-15 22:15:51 +00001799 s = p - bytes;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001800 out(offset, segment, bytes, OUT_RAWDATA, s, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001801
1802 switch (ea_data.bytes) {
1803 case 0:
1804 break;
1805 case 1:
1806 if (ins->oprs[(c >> 3) & 7].segment != NO_SEG) {
1807 data = ins->oprs[(c >> 3) & 7].offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001808 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001809 ins->oprs[(c >> 3) & 7].segment,
1810 ins->oprs[(c >> 3) & 7].wrt);
1811 } else {
1812 *bytes = ins->oprs[(c >> 3) & 7].offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001813 out(offset, segment, bytes, OUT_RAWDATA, 1,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001814 NO_SEG, NO_SEG);
1815 }
1816 s++;
1817 break;
H. Peter Anvin70653092007-10-19 14:42:29 -07001818 case 8:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001819 case 2:
1820 case 4:
1821 data = ins->oprs[(c >> 3) & 7].offset;
Charles Crayne7e975552007-11-03 22:06:13 -07001822 warn_overflow(ea_data.bytes, data);
H. Peter Anvind0b0d282007-09-28 17:17:20 -07001823 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001824 ea_data.rip ? OUT_REL4ADR : OUT_ADDRESS,
1825 ea_data.bytes,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001826 ins->oprs[(c >> 3) & 7].segment,
1827 ins->oprs[(c >> 3) & 7].wrt);
1828 s += ea_data.bytes;
1829 break;
1830 }
1831 offset += s;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001832 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001833 errfunc(ERR_PANIC, "internal instruction table corrupt"
1834 ": instruction code 0x%02X given", c);
H. Peter Anvin839eca22007-10-29 23:12:47 -07001835 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001836 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001837 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001838}
1839
H. Peter Anvin0ec60e62007-07-07 01:59:52 +00001840static int32_t regflag(const operand * o)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001841{
1842 if (o->basereg < EXPR_REG_START || o->basereg >= REG_ENUM_LIMIT) {
1843 errfunc(ERR_PANIC, "invalid operand passed to regflag()");
1844 }
H. Peter Anvina4835d42008-05-20 14:21:29 -07001845 return nasm_reg_flags[o->basereg];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001846}
1847
H. Peter Anvin5b0e3ec2007-07-07 02:01:08 +00001848static int32_t regval(const operand * o)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001849{
H. Peter Anvine2c80182005-01-15 22:15:51 +00001850 if (o->basereg < EXPR_REG_START || o->basereg >= REG_ENUM_LIMIT) {
1851 errfunc(ERR_PANIC, "invalid operand passed to regval()");
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001852 }
H. Peter Anvina4835d42008-05-20 14:21:29 -07001853 return nasm_regvals[o->basereg];
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001854}
1855
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001856static int op_rexflags(const operand * o, int mask)
1857{
1858 int32_t flags;
1859 int val;
1860
1861 if (o->basereg < EXPR_REG_START || o->basereg >= REG_ENUM_LIMIT) {
1862 errfunc(ERR_PANIC, "invalid operand passed to op_rexflags()");
1863 }
1864
H. Peter Anvina4835d42008-05-20 14:21:29 -07001865 flags = nasm_reg_flags[o->basereg];
1866 val = nasm_regvals[o->basereg];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001867
1868 return rexflags(val, flags, mask);
1869}
1870
1871static int rexflags(int val, int32_t flags, int mask)
1872{
1873 int rex = 0;
1874
1875 if (val >= 8)
1876 rex |= REX_B|REX_X|REX_R;
1877 if (flags & BITS64)
1878 rex |= REX_W;
1879 if (!(REG_HIGH & ~flags)) /* AH, CH, DH, BH */
1880 rex |= REX_H;
1881 else if (!(REG8 & ~flags) && val >= 4) /* SPL, BPL, SIL, DIL */
1882 rex |= REX_P;
1883
1884 return rex & mask;
1885}
1886
H. Peter Anvin3360d792007-09-11 04:16:57 +00001887static int matches(const struct itemplate *itemp, insn * instruction, int bits)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001888{
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001889 int i, size[MAX_OPERANDS], asize, oprs, ret;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001890
1891 ret = 100;
1892
1893 /*
1894 * Check the opcode
1895 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001896 if (itemp->opcode != instruction->opcode)
1897 return 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001898
1899 /*
1900 * Count the operands
1901 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001902 if (itemp->operands != instruction->operands)
1903 return 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001904
1905 /*
1906 * Check that no spurious colons or TOs are present
1907 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001908 for (i = 0; i < itemp->operands; i++)
1909 if (instruction->oprs[i].type & ~itemp->opd[i] & (COLON | TO))
1910 return 0;
H. Peter Anvin70653092007-10-19 14:42:29 -07001911
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001912 /*
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001913 * Process size flags
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001914 */
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001915 if (itemp->flags & IF_ARMASK) {
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001916 memset(size, 0, sizeof size);
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001917
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001918 i = ((itemp->flags & IF_ARMASK) >> IF_ARSHFT) - 1;
1919
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001920 switch (itemp->flags & IF_SMASK) {
1921 case IF_SB:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001922 size[i] = BITS8;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001923 break;
1924 case IF_SW:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001925 size[i] = BITS16;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001926 break;
1927 case IF_SD:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001928 size[i] = BITS32;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001929 break;
1930 case IF_SQ:
Keith Kaniosb7a89542007-04-12 02:40:54 +00001931 size[i] = BITS64;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001932 break;
H. Peter Anvin41c9f6f2007-09-18 13:01:32 -07001933 case IF_SO:
1934 size[i] = BITS128;
1935 break;
H. Peter Anvindfb91802008-05-20 11:43:53 -07001936 case IF_SY:
1937 size[i] = BITS256;
1938 break;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001939 case IF_SZ:
1940 switch (bits) {
1941 case 16:
1942 size[i] = BITS16;
1943 break;
1944 case 32:
1945 size[i] = BITS32;
1946 break;
1947 case 64:
1948 size[i] = BITS64;
1949 break;
1950 }
1951 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001952 default:
1953 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001954 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001955 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001956 asize = 0;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001957 switch (itemp->flags & IF_SMASK) {
1958 case IF_SB:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001959 asize = BITS8;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001960 break;
1961 case IF_SW:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001962 asize = BITS16;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001963 break;
1964 case IF_SD:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001965 asize = BITS32;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001966 break;
1967 case IF_SQ:
Keith Kaniosb7a89542007-04-12 02:40:54 +00001968 asize = BITS64;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001969 break;
H. Peter Anvin41c9f6f2007-09-18 13:01:32 -07001970 case IF_SO:
1971 asize = BITS128;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001972 break;
H. Peter Anvindfb91802008-05-20 11:43:53 -07001973 case IF_SY:
1974 asize = BITS256;
1975 break;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001976 case IF_SZ:
1977 switch (bits) {
1978 case 16:
1979 asize = BITS16;
1980 break;
1981 case 32:
1982 asize = BITS32;
1983 break;
1984 case 64:
1985 asize = BITS64;
1986 break;
1987 }
H. Peter Anvin41c9f6f2007-09-18 13:01:32 -07001988 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001989 default:
1990 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001991 }
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001992 for (i = 0; i < MAX_OPERANDS; i++)
1993 size[i] = asize;
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001994 }
H. Peter Anvin70653092007-10-19 14:42:29 -07001995
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001996 /*
1997 * Check that the operand flags all match up
1998 */
1999 for (i = 0; i < itemp->operands; i++) {
2000 int32_t type = instruction->oprs[i].type;
2001 if (!(type & SIZE_MASK))
2002 type |= size[i];
H. Peter Anvind85d2502008-05-04 17:53:31 -07002003
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002004 if (itemp->opd[i] & SAME_AS) {
2005 int j = itemp->opd[i] & ~SAME_AS;
2006 if (type != instruction->oprs[j].type ||
2007 instruction->oprs[i].basereg != instruction->oprs[j].basereg)
2008 return 0;
2009 } else if (itemp->opd[i] & ~type ||
2010 ((itemp->opd[i] & SIZE_MASK) &&
2011 ((itemp->opd[i] ^ type) & SIZE_MASK))) {
2012 if ((itemp->opd[i] & ~type & ~SIZE_MASK) ||
2013 (type & SIZE_MASK))
2014 return 0;
2015 else
2016 return 1;
2017 }
2018 }
2019
2020 /*
2021 * Check operand sizes
2022 */
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002023 if (itemp->flags & (IF_SM | IF_SM2)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002024 oprs = (itemp->flags & IF_SM2 ? 2 : itemp->operands);
2025 asize = 0;
2026 for (i = 0; i < oprs; i++) {
2027 if ((asize = itemp->opd[i] & SIZE_MASK) != 0) {
2028 int j;
2029 for (j = 0; j < oprs; j++)
2030 size[j] = asize;
2031 break;
2032 }
2033 }
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002034 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002035 oprs = itemp->operands;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002036 }
2037
Keith Kaniosb7a89542007-04-12 02:40:54 +00002038 for (i = 0; i < itemp->operands; i++) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002039 if (!(itemp->opd[i] & SIZE_MASK) &&
2040 (instruction->oprs[i].type & SIZE_MASK & ~size[i]))
H. Peter Anvine2c80182005-01-15 22:15:51 +00002041 return 2;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002042 }
2043
H. Peter Anvinaf535c12002-04-30 20:59:21 +00002044 /*
2045 * Check template is okay at the set cpu level
2046 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002047 if (((itemp->flags & IF_PLEVEL) > cpu))
H. Peter Anvine2c80182005-01-15 22:15:51 +00002048 return 3;
H. Peter Anvin70653092007-10-19 14:42:29 -07002049
Keith Kaniosb7a89542007-04-12 02:40:54 +00002050 /*
2051 * Check if instruction is available in long mode
2052 */
2053 if ((itemp->flags & IF_NOLONG) && (bits == 64))
2054 return 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002055
H. Peter Anvinaf535c12002-04-30 20:59:21 +00002056 /*
2057 * Check if special handling needed for Jumps
2058 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002059 if ((uint8_t)(itemp->code[0]) >= 0370)
H. Peter Anvine2c80182005-01-15 22:15:51 +00002060 return 99;
2061
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002062 return ret;
2063}
2064
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002065static ea *process_ea(operand * input, ea * output, int bits,
H. Peter Anvin1c3277b2008-07-19 21:38:56 -07002066 int addrbits, int rfield, int32_t rflags)
H. Peter Anvineba20a72002-04-30 20:53:55 +00002067{
H. Peter Anvin1c3277b2008-07-19 21:38:56 -07002068 bool forw_ref = !!(input->opflags & OPFLAG_FORWARD);
2069
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002070 output->rip = false;
H. Peter Anvin99c4ecd2007-08-28 23:06:00 +00002071
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002072 /* REX flags for the rfield operand */
2073 output->rex |= rexflags(rfield, rflags, REX_R|REX_P|REX_W|REX_H);
2074
Keith Kaniosb7a89542007-04-12 02:40:54 +00002075 if (!(REGISTER & ~input->type)) { /* register direct */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002076 int i;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002077 int32_t f;
2078
2079 if (input->basereg < EXPR_REG_START /* Verify as Register */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002080 || input->basereg >= REG_ENUM_LIMIT)
H. Peter Anvine2c80182005-01-15 22:15:51 +00002081 return NULL;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002082 f = regflag(input);
H. Peter Anvina4835d42008-05-20 14:21:29 -07002083 i = nasm_regvals[input->basereg];
Keith Kaniosb7a89542007-04-12 02:40:54 +00002084
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002085 if (REG_EA & ~f)
2086 return NULL; /* Invalid EA register */
H. Peter Anvin70653092007-10-19 14:42:29 -07002087
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002088 output->rex |= op_rexflags(input, REX_B|REX_P|REX_W|REX_H);
2089
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002090 output->sib_present = false; /* no SIB necessary */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002091 output->bytes = 0; /* no offset necessary either */
2092 output->modrm = 0xC0 | ((rfield & 7) << 3) | (i & 7);
H. Peter Anvine2c80182005-01-15 22:15:51 +00002093 } else { /* it's a memory reference */
2094 if (input->basereg == -1
2095 && (input->indexreg == -1 || input->scale == 0)) {
2096 /* it's a pure offset */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002097 if (bits == 64 && (~input->type & IP_REL)) {
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002098 int scale, index, base;
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002099 output->sib_present = true;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002100 scale = 0;
2101 index = 4;
2102 base = 5;
2103 output->sib = (scale << 6) | (index << 3) | base;
2104 output->bytes = 4;
2105 output->modrm = 4 | ((rfield & 7) << 3);
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002106 output->rip = false;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002107 } else {
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002108 output->sib_present = false;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002109 output->bytes = (addrbits != 16 ? 4 : 2);
2110 output->modrm = (addrbits != 16 ? 5 : 6) | ((rfield & 7) << 3);
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002111 output->rip = bits == 64;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002112 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00002113 } else { /* it's an indirection */
2114 int i = input->indexreg, b = input->basereg, s = input->scale;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002115 int32_t o = input->offset, seg = input->segment;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002116 int hb = input->hintbase, ht = input->hinttype;
2117 int t;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002118 int it, bt;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002119 int32_t ix, bx; /* register flags */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002120
H. Peter Anvine2c80182005-01-15 22:15:51 +00002121 if (s == 0)
2122 i = -1; /* make this easy, at least */
H. Peter Anvin70653092007-10-19 14:42:29 -07002123
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002124 if (i >= EXPR_REG_START && i < REG_ENUM_LIMIT) {
H. Peter Anvina4835d42008-05-20 14:21:29 -07002125 it = nasm_regvals[i];
2126 ix = nasm_reg_flags[i];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002127 } else {
Keith Kaniosb7a89542007-04-12 02:40:54 +00002128 it = -1;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002129 ix = 0;
2130 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002131
H. Peter Anvinb0c54622007-10-28 23:21:46 -07002132 if (b >= EXPR_REG_START && b < REG_ENUM_LIMIT) {
H. Peter Anvina4835d42008-05-20 14:21:29 -07002133 bt = nasm_regvals[b];
2134 bx = nasm_reg_flags[b];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002135 } else {
Keith Kaniosb7a89542007-04-12 02:40:54 +00002136 bt = -1;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002137 bx = 0;
2138 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002139
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002140 /* check for a 32/64-bit memory reference... */
2141 if ((ix|bx) & (BITS32|BITS64)) {
Keith Kaniosb7a89542007-04-12 02:40:54 +00002142 /* it must be a 32/64-bit memory reference. Firstly we have
2143 * to check that all registers involved are type E/Rxx. */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002144 int32_t sok = BITS32|BITS64;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002145
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002146 if (it != -1) {
2147 if (!(REG64 & ~ix) || !(REG32 & ~ix))
2148 sok &= ix;
2149 else
2150 return NULL;
2151 }
2152
2153 if (bt != -1) {
H. Peter Anvin99c4ecd2007-08-28 23:06:00 +00002154 if (REG_GPR & ~bx)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002155 return NULL; /* Invalid register */
H. Peter Anvina57e8d42007-05-30 03:44:02 +00002156 if (~sok & bx & SIZE_MASK)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002157 return NULL; /* Invalid size */
H. Peter Anvinb0c54622007-10-28 23:21:46 -07002158 sok &= bx;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002159 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002160
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002161 /* While we're here, ensure the user didn't specify
2162 WORD or QWORD. */
2163 if (input->disp_size == 16 || input->disp_size == 64)
2164 return NULL;
2165
2166 if (addrbits == 16 ||
2167 (addrbits == 32 && !(sok & BITS32)) ||
2168 (addrbits == 64 && !(sok & BITS64)))
2169 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002170
Keith Kaniosb7a89542007-04-12 02:40:54 +00002171 /* now reorganize base/index */
2172 if (s == 1 && bt != it && bt != -1 && it != -1 &&
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002173 ((hb == b && ht == EAH_NOTBASE)
2174 || (hb == i && ht == EAH_MAKEBASE))) {
2175 /* swap if hints say so */
2176 t = bt, bt = it, it = t;
2177 t = bx, bx = ix, ix = t;
2178 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00002179 if (bt == it) /* convert EAX+2*EAX to 3*EAX */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002180 bt = -1, bx = 0, s++;
2181 if (bt == -1 && s == 1 && !(hb == it && ht == EAH_NOTBASE)) {
2182 /* make single reg base, unless hint */
2183 bt = it, bx = ix, it = -1, ix = 0;
2184 }
H. Peter Anvinf5843c62007-09-10 18:59:26 +00002185 if (((s == 2 && it != REG_NUM_ESP
H. Peter Anvine2c80182005-01-15 22:15:51 +00002186 && !(input->eaflags & EAF_TIMESTWO)) || s == 3
Keith Kaniosb7a89542007-04-12 02:40:54 +00002187 || s == 5 || s == 9) && bt == -1)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002188 bt = it, bx = ix, s--; /* convert 3*EAX to EAX+2*EAX */
Keith Kanios48af1772007-08-17 07:37:52 +00002189 if (it == -1 && (bt & 7) != REG_NUM_ESP
H. Peter Anvine2c80182005-01-15 22:15:51 +00002190 && (input->eaflags & EAF_TIMESTWO))
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002191 it = bt, ix = bx, bt = -1, bx = 0, s = 1;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002192 /* convert [NOSPLIT EAX] to sib format with 0x0 displacement */
Keith Kanios48af1772007-08-17 07:37:52 +00002193 if (s == 1 && it == REG_NUM_ESP) {
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002194 /* swap ESP into base if scale is 1 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002195 t = it, it = bt, bt = t;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002196 t = ix, ix = bx, bx = t;
2197 }
Keith Kanios48af1772007-08-17 07:37:52 +00002198 if (it == REG_NUM_ESP
Keith Kaniosb7a89542007-04-12 02:40:54 +00002199 || (s != 1 && s != 2 && s != 4 && s != 8 && it != -1))
H. Peter Anvine2c80182005-01-15 22:15:51 +00002200 return NULL; /* wrong, for various reasons */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002201
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002202 output->rex |= rexflags(it, ix, REX_X);
2203 output->rex |= rexflags(bt, bx, REX_B);
Keith Kaniosb7a89542007-04-12 02:40:54 +00002204
Keith Kanios48af1772007-08-17 07:37:52 +00002205 if (it == -1 && (bt & 7) != REG_NUM_ESP) {
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002206 /* no SIB needed */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002207 int mod, rm;
H. Peter Anvin70653092007-10-19 14:42:29 -07002208
Keith Kaniosb7a89542007-04-12 02:40:54 +00002209 if (bt == -1) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002210 rm = 5;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002211 mod = 0;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002212 } else {
2213 rm = (bt & 7);
Keith Kanios48af1772007-08-17 07:37:52 +00002214 if (rm != REG_NUM_EBP && o == 0 &&
Keith Kaniosb7a89542007-04-12 02:40:54 +00002215 seg == NO_SEG && !forw_ref &&
2216 !(input->eaflags &
2217 (EAF_BYTEOFFS | EAF_WORDOFFS)))
2218 mod = 0;
2219 else if (input->eaflags & EAF_BYTEOFFS ||
2220 (o >= -128 && o <= 127 && seg == NO_SEG
2221 && !forw_ref
2222 && !(input->eaflags & EAF_WORDOFFS)))
2223 mod = 1;
2224 else
2225 mod = 2;
2226 }
H. Peter Anvinea838272002-04-30 20:51:53 +00002227
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002228 output->sib_present = false;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002229 output->bytes = (bt == -1 || mod == 2 ? 4 : mod);
2230 output->modrm = (mod << 6) | ((rfield & 7) << 3) | rm;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002231 } else {
2232 /* we need a SIB */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002233 int mod, scale, index, base;
H. Peter Anvin70653092007-10-19 14:42:29 -07002234
Keith Kaniosb7a89542007-04-12 02:40:54 +00002235 if (it == -1)
2236 index = 4, s = 1;
2237 else
2238 index = (it & 7);
H. Peter Anvin70653092007-10-19 14:42:29 -07002239
H. Peter Anvine2c80182005-01-15 22:15:51 +00002240 switch (s) {
2241 case 1:
2242 scale = 0;
2243 break;
2244 case 2:
2245 scale = 1;
2246 break;
2247 case 4:
2248 scale = 2;
2249 break;
2250 case 8:
2251 scale = 3;
2252 break;
2253 default: /* then what the smeg is it? */
2254 return NULL; /* panic */
2255 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002256
Keith Kaniosb7a89542007-04-12 02:40:54 +00002257 if (bt == -1) {
2258 base = 5;
2259 mod = 0;
2260 } else {
2261 base = (bt & 7);
Keith Kanios48af1772007-08-17 07:37:52 +00002262 if (base != REG_NUM_EBP && o == 0 &&
H. Peter Anvine2c80182005-01-15 22:15:51 +00002263 seg == NO_SEG && !forw_ref &&
2264 !(input->eaflags &
Keith Kaniosb7a89542007-04-12 02:40:54 +00002265 (EAF_BYTEOFFS | EAF_WORDOFFS)))
2266 mod = 0;
2267 else if (input->eaflags & EAF_BYTEOFFS ||
2268 (o >= -128 && o <= 127 && seg == NO_SEG
2269 && !forw_ref
2270 && !(input->eaflags & EAF_WORDOFFS)))
2271 mod = 1;
2272 else
2273 mod = 2;
2274 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002275
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002276 output->sib_present = true;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002277 output->bytes = (bt == -1 || mod == 2 ? 4 : mod);
2278 output->modrm = (mod << 6) | ((rfield & 7) << 3) | 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002279 output->sib = (scale << 6) | (index << 3) | base;
2280 }
2281 } else { /* it's 16-bit */
2282 int mod, rm;
H. Peter Anvin70653092007-10-19 14:42:29 -07002283
Keith Kaniosb7a89542007-04-12 02:40:54 +00002284 /* check for 64-bit long mode */
2285 if (addrbits == 64)
2286 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002287
H. Peter Anvine2c80182005-01-15 22:15:51 +00002288 /* check all registers are BX, BP, SI or DI */
2289 if ((b != -1 && b != R_BP && b != R_BX && b != R_SI
2290 && b != R_DI) || (i != -1 && i != R_BP && i != R_BX
2291 && i != R_SI && i != R_DI))
2292 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002293
Keith Kaniosb7a89542007-04-12 02:40:54 +00002294 /* ensure the user didn't specify DWORD/QWORD */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002295 if (input->disp_size == 32 || input->disp_size == 64)
H. Peter Anvine2c80182005-01-15 22:15:51 +00002296 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002297
H. Peter Anvine2c80182005-01-15 22:15:51 +00002298 if (s != 1 && i != -1)
2299 return NULL; /* no can do, in 16-bit EA */
2300 if (b == -1 && i != -1) {
2301 int tmp = b;
2302 b = i;
2303 i = tmp;
2304 } /* swap */
2305 if ((b == R_SI || b == R_DI) && i != -1) {
2306 int tmp = b;
2307 b = i;
2308 i = tmp;
2309 }
2310 /* have BX/BP as base, SI/DI index */
2311 if (b == i)
2312 return NULL; /* shouldn't ever happen, in theory */
2313 if (i != -1 && b != -1 &&
2314 (i == R_BP || i == R_BX || b == R_SI || b == R_DI))
2315 return NULL; /* invalid combinations */
2316 if (b == -1) /* pure offset: handled above */
2317 return NULL; /* so if it gets to here, panic! */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002318
H. Peter Anvine2c80182005-01-15 22:15:51 +00002319 rm = -1;
2320 if (i != -1)
2321 switch (i * 256 + b) {
2322 case R_SI * 256 + R_BX:
2323 rm = 0;
2324 break;
2325 case R_DI * 256 + R_BX:
2326 rm = 1;
2327 break;
2328 case R_SI * 256 + R_BP:
2329 rm = 2;
2330 break;
2331 case R_DI * 256 + R_BP:
2332 rm = 3;
2333 break;
2334 } else
2335 switch (b) {
2336 case R_SI:
2337 rm = 4;
2338 break;
2339 case R_DI:
2340 rm = 5;
2341 break;
2342 case R_BP:
2343 rm = 6;
2344 break;
2345 case R_BX:
2346 rm = 7;
2347 break;
2348 }
2349 if (rm == -1) /* can't happen, in theory */
2350 return NULL; /* so panic if it does */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002351
H. Peter Anvine2c80182005-01-15 22:15:51 +00002352 if (o == 0 && seg == NO_SEG && !forw_ref && rm != 6 &&
2353 !(input->eaflags & (EAF_BYTEOFFS | EAF_WORDOFFS)))
2354 mod = 0;
2355 else if (input->eaflags & EAF_BYTEOFFS ||
2356 (o >= -128 && o <= 127 && seg == NO_SEG
2357 && !forw_ref
2358 && !(input->eaflags & EAF_WORDOFFS)))
2359 mod = 1;
2360 else
2361 mod = 2;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002362
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002363 output->sib_present = false; /* no SIB - it's 16-bit */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002364 output->bytes = mod; /* bytes of offset needed */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002365 output->modrm = (mod << 6) | ((rfield & 7) << 3) | rm;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002366 }
2367 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002368 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002369
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002370 output->size = 1 + output->sib_present + output->bytes;
2371 return output;
2372}
2373
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002374static void add_asp(insn *ins, int addrbits)
H. Peter Anvineba20a72002-04-30 20:53:55 +00002375{
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002376 int j, valid;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002377 int defdisp;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002378
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002379 valid = (addrbits == 64) ? 64|32 : 32|16;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002380
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002381 switch (ins->prefixes[PPS_ASIZE]) {
2382 case P_A16:
2383 valid &= 16;
2384 break;
2385 case P_A32:
2386 valid &= 32;
2387 break;
2388 case P_A64:
2389 valid &= 64;
2390 break;
2391 case P_ASP:
2392 valid &= (addrbits == 32) ? 16 : 32;
2393 break;
2394 default:
2395 break;
2396 }
2397
2398 for (j = 0; j < ins->operands; j++) {
2399 if (!(MEMORY & ~ins->oprs[j].type)) {
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002400 int32_t i, b;
H. Peter Anvin70653092007-10-19 14:42:29 -07002401
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002402 /* Verify as Register */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002403 if (ins->oprs[j].indexreg < EXPR_REG_START
2404 || ins->oprs[j].indexreg >= REG_ENUM_LIMIT)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002405 i = 0;
2406 else
H. Peter Anvina4835d42008-05-20 14:21:29 -07002407 i = nasm_reg_flags[ins->oprs[j].indexreg];
H. Peter Anvin70653092007-10-19 14:42:29 -07002408
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002409 /* Verify as Register */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002410 if (ins->oprs[j].basereg < EXPR_REG_START
2411 || ins->oprs[j].basereg >= REG_ENUM_LIMIT)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002412 b = 0;
2413 else
H. Peter Anvina4835d42008-05-20 14:21:29 -07002414 b = nasm_reg_flags[ins->oprs[j].basereg];
H. Peter Anvin70653092007-10-19 14:42:29 -07002415
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002416 if (ins->oprs[j].scale == 0)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002417 i = 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002418
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002419 if (!i && !b) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002420 int ds = ins->oprs[j].disp_size;
2421 if ((addrbits != 64 && ds > 8) ||
2422 (addrbits == 64 && ds == 16))
2423 valid &= ds;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002424 } else {
2425 if (!(REG16 & ~b))
2426 valid &= 16;
2427 if (!(REG32 & ~b))
2428 valid &= 32;
2429 if (!(REG64 & ~b))
2430 valid &= 64;
H. Peter Anvin70653092007-10-19 14:42:29 -07002431
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002432 if (!(REG16 & ~i))
2433 valid &= 16;
2434 if (!(REG32 & ~i))
2435 valid &= 32;
2436 if (!(REG64 & ~i))
2437 valid &= 64;
2438 }
2439 }
2440 }
2441
2442 if (valid & addrbits) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002443 ins->addr_size = addrbits;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002444 } else if (valid & ((addrbits == 32) ? 16 : 32)) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002445 /* Add an address size prefix */
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002446 enum prefixes pref = (addrbits == 32) ? P_A16 : P_A32;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002447 ins->prefixes[PPS_ASIZE] = pref;
2448 ins->addr_size = (addrbits == 32) ? 16 : 32;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002449 } else {
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002450 /* Impossible... */
2451 errfunc(ERR_NONFATAL, "impossible combination of address sizes");
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002452 ins->addr_size = addrbits; /* Error recovery */
2453 }
2454
2455 defdisp = ins->addr_size == 16 ? 16 : 32;
2456
2457 for (j = 0; j < ins->operands; j++) {
2458 if (!(MEM_OFFS & ~ins->oprs[j].type) &&
2459 (ins->oprs[j].disp_size ? ins->oprs[j].disp_size : defdisp)
2460 != ins->addr_size) {
2461 /* mem_offs sizes must match the address size; if not,
2462 strip the MEM_OFFS bit and match only EA instructions */
2463 ins->oprs[j].type &= ~(MEM_OFFS & ~MEMORY);
2464 }
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002465 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002466}