blob: 245aea44998bc01c373ff481fb7436302a644f13 [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"
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000122#include "preproc.h"
H. Peter Anvina4835d42008-05-20 14:21:29 -0700123#include "tables.h"
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000124
H. Peter Anvindfb91802008-05-20 11:43:53 -0700125/* Initialized to zero by the C standard */
126static const uint8_t const_zero_buf[256];
127
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000128typedef struct {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000129 int sib_present; /* is a SIB byte necessary? */
130 int bytes; /* # of bytes of offset needed */
131 int size; /* lazy - this is sib+bytes+1 */
132 uint8_t modrm, sib, rex, rip; /* the bytes themselves */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000133} ea;
134
Keith Kaniosb7a89542007-04-12 02:40:54 +0000135static uint32_t cpu; /* cpu level received from nasm.c */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000136static efunc errfunc;
137static struct ofmt *outfmt;
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000138static ListGen *list;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000139
H. Peter Anvin3720f7b2008-05-12 11:00:50 -0700140static int64_t calcsize(int32_t, int64_t, int, insn *, const uint8_t *);
141static void gencode(int32_t, int64_t, int, insn *, const uint8_t *, int64_t);
H. Peter Anvin3360d792007-09-11 04:16:57 +0000142static int matches(const struct itemplate *, insn *, int bits);
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000143static int32_t regflag(const operand *);
144static int32_t regval(const operand *);
145static int rexflags(int, int32_t, int);
146static int op_rexflags(const operand *, int);
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700147static ea *process_ea(operand *, ea *, int, int, int, int32_t, int);
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700148static void add_asp(insn *, int);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000149
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700150static int has_prefix(insn * ins, enum prefix_pos pos, enum prefixes prefix)
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000151{
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700152 return ins->prefixes[pos] == prefix;
153}
154
155static void assert_no_prefix(insn * ins, enum prefix_pos pos)
156{
157 if (ins->prefixes[pos])
158 errfunc(ERR_NONFATAL, "invalid %s prefix",
159 prefix_name(ins->prefixes[pos]));
160}
161
162static const char *size_name(int size)
163{
164 switch (size) {
165 case 1:
166 return "byte";
167 case 2:
168 return "word";
169 case 4:
170 return "dword";
171 case 8:
172 return "qword";
173 case 10:
174 return "tword";
175 case 16:
176 return "oword";
H. Peter Anvindfb91802008-05-20 11:43:53 -0700177 case 32:
178 return "yword";
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700179 default:
180 return "???";
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000181 }
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700182}
183
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700184static void warn_overflow(int size, int64_t data)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700185{
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700186 if (size < 8) {
Charles Craynedd462c82007-11-04 15:28:30 -0800187 int64_t lim = ((int64_t)1 << (size*8))-1;
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000188
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700189 if (data < ~lim || data > lim)
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700190 errfunc(ERR_WARNING | ERR_WARN_NOV,
191 "%s data exceeds bounds", size_name(size));
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700192 }
193}
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000194/*
195 * This routine wrappers the real output format's output routine,
196 * in order to pass a copy of the data off to the listing file
197 * generator at the same time.
198 */
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800199static void out(int64_t offset, int32_t segto, const void *data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800200 enum out_type type, uint64_t size,
201 int32_t segment, int32_t wrt)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000202{
Keith Kaniosb7a89542007-04-12 02:40:54 +0000203 static int32_t lineno = 0; /* static!!! */
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000204 static char *lnfname = NULL;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800205 uint8_t p[8];
H. Peter Anvineba20a72002-04-30 20:53:55 +0000206
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800207 if (type == OUT_ADDRESS && segment == NO_SEG && wrt == NO_SEG) {
208 /*
209 * This is a non-relocated address, and we're going to
210 * convert it into RAWDATA format.
211 */
212 uint8_t *q = p;
H. Peter Anvind1fb15c2007-11-13 09:37:59 -0800213
214 if (size > 8) {
215 errfunc(ERR_PANIC, "OUT_ADDRESS with size > 8");
216 return;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800217 }
H. Peter Anvind85d2502008-05-04 17:53:31 -0700218
H. Peter Anvind1fb15c2007-11-13 09:37:59 -0800219 WRITEADDR(q, *(int64_t *)data, size);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800220 data = p;
221 type = OUT_RAWDATA;
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000222 }
223
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800224 list->output(offset, data, type, size);
225
Frank Kotlerabebb082003-09-06 04:45:37 +0000226 /*
227 * this call to src_get determines when we call the
228 * debug-format-specific "linenum" function
229 * it updates lineno and lnfname to the current values
230 * returning 0 if "same as last time", -2 if lnfname
231 * changed, and the amount by which lineno changed,
232 * if it did. thus, these variables must be static
233 */
234
H. Peter Anvine2c80182005-01-15 22:15:51 +0000235 if (src_get(&lineno, &lnfname)) {
236 outfmt->current_dfmt->linenum(lnfname, lineno, segto);
H. Peter Anvince616072002-04-30 21:02:23 +0000237 }
H. Peter Anvineba20a72002-04-30 20:53:55 +0000238
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800239 outfmt->output(segto, data, type, size, segment, wrt);
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000240}
241
Charles Crayne5fbbc8c2007-11-07 19:03:46 -0800242static int jmp_match(int32_t segment, int64_t offset, int bits,
H. Peter Anvin3720f7b2008-05-12 11:00:50 -0700243 insn * ins, const uint8_t *code)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000244{
Charles Crayne5fbbc8c2007-11-07 19:03:46 -0800245 int64_t isize;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000246 uint8_t c = code[0];
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000247
H. Peter Anvine2c80182005-01-15 22:15:51 +0000248 if (c != 0370 && c != 0371)
249 return 0;
H. Peter Anvin788e6c12002-04-30 21:02:01 +0000250 if (ins->oprs[0].opflags & OPFLAG_FORWARD) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000251 if ((optimizing < 0 || (ins->oprs[0].type & STRICT))
252 && c == 0370)
253 return 1;
254 else
255 return (pass0 == 0); /* match a forward reference */
H. Peter Anvin788e6c12002-04-30 21:02:01 +0000256 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000257 isize = calcsize(segment, offset, bits, ins, code);
258 if (ins->oprs[0].segment != segment)
259 return 0;
260 isize = ins->oprs[0].offset - offset - isize; /* isize is now the delta */
261 if (isize >= -128L && isize <= 127L)
262 return 1; /* it is byte size */
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000263
264 return 0;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000265}
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000266
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800267int64_t assemble(int32_t segment, int64_t offset, int bits, uint32_t cp,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000268 insn * instruction, struct ofmt *output, efunc error,
269 ListGen * listgen)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000270{
H. Peter Anvin3360d792007-09-11 04:16:57 +0000271 const struct itemplate *temp;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000272 int j;
273 int size_prob;
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800274 int64_t insn_end;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000275 int32_t itimes;
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800276 int64_t start = offset;
277 int64_t wsize = 0; /* size for DB etc. */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000278
H. Peter Anvine2c80182005-01-15 22:15:51 +0000279 errfunc = error; /* to pass to other functions */
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000280 cpu = cp;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000281 outfmt = output; /* likewise */
282 list = listgen; /* and again */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000283
H. Peter Anvine2c80182005-01-15 22:15:51 +0000284 switch (instruction->opcode) {
285 case -1:
286 return 0;
287 case I_DB:
288 wsize = 1;
289 break;
290 case I_DW:
291 wsize = 2;
292 break;
293 case I_DD:
294 wsize = 4;
295 break;
296 case I_DQ:
297 wsize = 8;
298 break;
299 case I_DT:
300 wsize = 10;
301 break;
H. Peter Anvincfbe7c32007-09-18 17:49:09 -0700302 case I_DO:
303 wsize = 16;
304 break;
H. Peter Anvindfb91802008-05-20 11:43:53 -0700305 case I_DY:
306 wsize = 32;
307 break;
H. Peter Anvin16b0a332007-09-12 20:27:41 -0700308 default:
309 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000310 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000311
H. Peter Anvineba20a72002-04-30 20:53:55 +0000312 if (wsize) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000313 extop *e;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000314 int32_t t = instruction->times;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000315 if (t < 0)
316 errfunc(ERR_PANIC,
317 "instruction->times < 0 (%ld) in assemble()", t);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000318
H. Peter Anvine2c80182005-01-15 22:15:51 +0000319 while (t--) { /* repeat TIMES times */
320 for (e = instruction->eops; e; e = e->next) {
321 if (e->type == EOT_DB_NUMBER) {
322 if (wsize == 1) {
323 if (e->segment != NO_SEG)
324 errfunc(ERR_NONFATAL,
325 "one-byte relocation attempted");
326 else {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000327 uint8_t out_byte = e->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000328 out(offset, segment, &out_byte,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800329 OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000330 }
Keith Kanios61ff53c2007-04-14 18:54:52 +0000331 } else if (wsize > 8) {
H. Peter Anvin3be5d852008-05-20 14:49:32 -0700332 errfunc(ERR_NONFATAL,
333 "integer supplied to a DT, DO or DY"
Keith Kanios61ff53c2007-04-14 18:54:52 +0000334 " instruction");
H. Peter Anvine2c80182005-01-15 22:15:51 +0000335 } else
336 out(offset, segment, &e->offset,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800337 OUT_ADDRESS, wsize, e->segment, e->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000338 offset += wsize;
339 } else if (e->type == EOT_DB_STRING) {
340 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) {
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000369 static char fname[FILENAME_MAX];
H. Peter Anvine2c80182005-01-15 22:15:51 +0000370 FILE *fp;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000371 int32_t len;
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000372 char *prefix = "", *combine;
373 char **pPrevPath = NULL;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000374
H. Peter Anvine2c80182005-01-15 22:15:51 +0000375 len = FILENAME_MAX - 1;
376 if (len > instruction->eops->stringlen)
377 len = instruction->eops->stringlen;
378 strncpy(fname, instruction->eops->stringval, len);
379 fname[len] = '\0';
H. Peter Anvineba20a72002-04-30 20:53:55 +0000380
Keith Kaniosb7a89542007-04-12 02:40:54 +0000381 while (1) { /* added by alexfru: 'incbin' uses include paths */
H. Peter Anvine2c80182005-01-15 22:15:51 +0000382 combine = nasm_malloc(strlen(prefix) + len + 1);
383 strcpy(combine, prefix);
384 strcat(combine, fname);
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000385
H. Peter Anvine2c80182005-01-15 22:15:51 +0000386 if ((fp = fopen(combine, "rb")) != NULL) {
387 nasm_free(combine);
388 break;
389 }
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000390
H. Peter Anvine2c80182005-01-15 22:15:51 +0000391 nasm_free(combine);
392 pPrevPath = pp_get_include_path_ptr(pPrevPath);
393 if (pPrevPath == NULL)
394 break;
395 prefix = *pPrevPath;
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000396 }
397
398 if (fp == NULL)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000399 error(ERR_NONFATAL, "`incbin': unable to open file `%s'",
400 fname);
401 else if (fseek(fp, 0L, SEEK_END) < 0)
402 error(ERR_NONFATAL, "`incbin': unable to seek on file `%s'",
403 fname);
404 else {
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000405 static char buf[2048];
Keith Kaniosb7a89542007-04-12 02:40:54 +0000406 int32_t t = instruction->times;
407 int32_t base = 0;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000408
H. Peter Anvine2c80182005-01-15 22:15:51 +0000409 len = ftell(fp);
410 if (instruction->eops->next) {
411 base = instruction->eops->next->offset;
412 len -= base;
413 if (instruction->eops->next->next &&
414 len > instruction->eops->next->next->offset)
415 len = instruction->eops->next->next->offset;
416 }
417 /*
418 * Dummy call to list->output to give the offset to the
419 * listing module.
420 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800421 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000422 list->uplevel(LIST_INCBIN);
423 while (t--) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000424 int32_t l;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000425
H. Peter Anvine2c80182005-01-15 22:15:51 +0000426 fseek(fp, base, SEEK_SET);
427 l = len;
428 while (l > 0) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000429 int32_t m =
Charles Crayne192d5b52007-10-18 19:02:42 -0700430 fread(buf, 1, (l > (int32_t) sizeof(buf) ? (int32_t) sizeof(buf) : l),
H. Peter Anvine2c80182005-01-15 22:15:51 +0000431 fp);
432 if (!m) {
433 /*
434 * This shouldn't happen unless the file
435 * actually changes while we are reading
436 * it.
437 */
438 error(ERR_NONFATAL,
439 "`incbin': unexpected EOF while"
440 " reading file `%s'", fname);
441 t = 0; /* Try to exit cleanly */
442 break;
443 }
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800444 out(offset, segment, buf, OUT_RAWDATA, m,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000445 NO_SEG, NO_SEG);
446 l -= m;
447 }
448 }
449 list->downlevel(LIST_INCBIN);
450 if (instruction->times > 1) {
451 /*
452 * Dummy call to list->output to give the offset to the
453 * listing module.
454 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800455 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000456 list->uplevel(LIST_TIMES);
457 list->downlevel(LIST_TIMES);
458 }
459 fclose(fp);
460 return instruction->times * len;
461 }
462 return 0; /* if we're here, there's an error */
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000463 }
464
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700465 /* Check to see if we need an address-size prefix */
466 add_asp(instruction, bits);
467
H. Peter Anvin6867acc2007-10-10 14:58:45 -0700468 size_prob = false;
H. Peter Anvin70653092007-10-19 14:42:29 -0700469
470 for (temp = nasm_instructions[instruction->opcode]; temp->opcode != -1; temp++){
Keith Kaniosb7a89542007-04-12 02:40:54 +0000471 int m = matches(temp, instruction, bits);
H. Peter Anvin70653092007-10-19 14:42:29 -0700472
H. Peter Anvine2c80182005-01-15 22:15:51 +0000473 if (m == 99)
474 m += jmp_match(segment, offset, bits, instruction, temp->code);
H. Peter Anvineba20a72002-04-30 20:53:55 +0000475
H. Peter Anvine2c80182005-01-15 22:15:51 +0000476 if (m == 100) { /* matches! */
H. Peter Anvin3720f7b2008-05-12 11:00:50 -0700477 const uint8_t *codes = temp->code;
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800478 int64_t insn_size = calcsize(segment, offset, bits,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000479 instruction, codes);
480 itimes = instruction->times;
481 if (insn_size < 0) /* shouldn't be, on pass two */
482 error(ERR_PANIC, "errors made it through from pass one");
483 else
484 while (itimes--) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700485 for (j = 0; j < MAXPREFIX; j++) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000486 uint8_t c = 0;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000487 switch (instruction->prefixes[j]) {
488 case P_LOCK:
489 c = 0xF0;
490 break;
491 case P_REPNE:
492 case P_REPNZ:
493 c = 0xF2;
494 break;
495 case P_REPE:
496 case P_REPZ:
497 case P_REP:
498 c = 0xF3;
499 break;
500 case R_CS:
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000501 if (bits == 64) {
502 error(ERR_WARNING,
Charles Crayne1b851dc2007-11-05 21:49:49 -0800503 "cs segment base generated, but will be ignored in 64-bit mode");
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000504 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000505 c = 0x2E;
506 break;
507 case R_DS:
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000508 if (bits == 64) {
509 error(ERR_WARNING,
Charles Crayne1b851dc2007-11-05 21:49:49 -0800510 "ds segment base generated, but will be ignored in 64-bit mode");
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000511 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000512 c = 0x3E;
513 break;
514 case R_ES:
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000515 if (bits == 64) {
516 error(ERR_WARNING,
Charles Crayne1b851dc2007-11-05 21:49:49 -0800517 "es segment base generated, but will be ignored in 64-bit mode");
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000518 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000519 c = 0x26;
520 break;
521 case R_FS:
522 c = 0x64;
523 break;
524 case R_GS:
525 c = 0x65;
526 break;
527 case R_SS:
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000528 if (bits == 64) {
529 error(ERR_WARNING,
Charles Crayne1b851dc2007-11-05 21:49:49 -0800530 "ss segment base generated, but will be ignored in 64-bit mode");
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000531 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000532 c = 0x36;
533 break;
534 case R_SEGR6:
535 case R_SEGR7:
536 error(ERR_NONFATAL,
537 "segr6 and segr7 cannot be used as prefixes");
538 break;
539 case P_A16:
Keith Kaniosb7a89542007-04-12 02:40:54 +0000540 if (bits == 64) {
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000541 error(ERR_NONFATAL,
542 "16-bit addressing is not supported "
543 "in 64-bit mode");
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700544 } else if (bits != 16)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000545 c = 0x67;
546 break;
547 case P_A32:
548 if (bits != 32)
549 c = 0x67;
550 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700551 case P_A64:
552 if (bits != 64) {
553 error(ERR_NONFATAL,
554 "64-bit addressing is only supported "
555 "in 64-bit mode");
556 }
557 break;
558 case P_ASP:
559 c = 0x67;
560 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000561 case P_O16:
562 if (bits != 16)
563 c = 0x66;
564 break;
565 case P_O32:
Keith Kaniosb7a89542007-04-12 02:40:54 +0000566 if (bits == 16)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000567 c = 0x66;
568 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700569 case P_O64:
570 /* REX.W */
571 break;
572 case P_OSP:
573 c = 0x66;
574 break;
575 case P_none:
576 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000577 default:
578 error(ERR_PANIC, "invalid instruction prefix");
579 }
580 if (c != 0) {
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800581 out(offset, segment, &c, OUT_RAWDATA, 1,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000582 NO_SEG, NO_SEG);
583 offset++;
584 }
H. Peter Anvin70653092007-10-19 14:42:29 -0700585 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000586 insn_end = offset + insn_size;
587 gencode(segment, offset, bits, instruction, codes,
588 insn_end);
589 offset += insn_size;
590 if (itimes > 0 && itimes == instruction->times - 1) {
591 /*
592 * Dummy call to list->output to give the offset to the
593 * listing module.
594 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800595 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000596 list->uplevel(LIST_TIMES);
597 }
598 }
599 if (instruction->times > 1)
600 list->downlevel(LIST_TIMES);
601 return offset - start;
602 } else if (m > 0 && m > size_prob) {
603 size_prob = m;
604 }
Keith Kaniosb7a89542007-04-12 02:40:54 +0000605// temp++;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000606 }
H. Peter Anvineba20a72002-04-30 20:53:55 +0000607
H. Peter Anvine2c80182005-01-15 22:15:51 +0000608 if (temp->opcode == -1) { /* didn't match any instruction */
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000609 switch (size_prob) {
610 case 1:
611 error(ERR_NONFATAL, "operation size not specified");
612 break;
613 case 2:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000614 error(ERR_NONFATAL, "mismatch in operand sizes");
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000615 break;
616 case 3:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000617 error(ERR_NONFATAL, "no instruction for this cpu level");
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000618 break;
619 case 4:
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000620 error(ERR_NONFATAL, "instruction not supported in 64-bit mode");
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000621 break;
622 default:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000623 error(ERR_NONFATAL,
624 "invalid combination of opcode and operands");
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000625 break;
626 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000627 }
628 return 0;
629}
630
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800631int64_t insn_size(int32_t segment, int64_t offset, int bits, uint32_t cp,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000632 insn * instruction, efunc error)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000633{
H. Peter Anvin3360d792007-09-11 04:16:57 +0000634 const struct itemplate *temp;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000635
H. Peter Anvine2c80182005-01-15 22:15:51 +0000636 errfunc = error; /* to pass to other functions */
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000637 cpu = cp;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000638
639 if (instruction->opcode == -1)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000640 return 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000641
H. Peter Anvincfbe7c32007-09-18 17:49:09 -0700642 if (instruction->opcode == I_DB || instruction->opcode == I_DW ||
643 instruction->opcode == I_DD || instruction->opcode == I_DQ ||
H. Peter Anvindfb91802008-05-20 11:43:53 -0700644 instruction->opcode == I_DT || instruction->opcode == I_DO ||
645 instruction->opcode == I_DY) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000646 extop *e;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000647 int32_t isize, osize, wsize = 0; /* placate gcc */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000648
H. Peter Anvine2c80182005-01-15 22:15:51 +0000649 isize = 0;
650 switch (instruction->opcode) {
651 case I_DB:
652 wsize = 1;
653 break;
654 case I_DW:
655 wsize = 2;
656 break;
657 case I_DD:
658 wsize = 4;
659 break;
660 case I_DQ:
661 wsize = 8;
662 break;
663 case I_DT:
664 wsize = 10;
665 break;
H. Peter Anvincfbe7c32007-09-18 17:49:09 -0700666 case I_DO:
667 wsize = 16;
668 break;
H. Peter Anvindfb91802008-05-20 11:43:53 -0700669 case I_DY:
670 wsize = 32;
671 break;
H. Peter Anvin16b0a332007-09-12 20:27:41 -0700672 default:
673 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000674 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000675
H. Peter Anvine2c80182005-01-15 22:15:51 +0000676 for (e = instruction->eops; e; e = e->next) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000677 int32_t align;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000678
H. Peter Anvine2c80182005-01-15 22:15:51 +0000679 osize = 0;
680 if (e->type == EOT_DB_NUMBER)
681 osize = 1;
682 else if (e->type == EOT_DB_STRING)
683 osize = e->stringlen;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000684
H. Peter Anvine2c80182005-01-15 22:15:51 +0000685 align = (-osize) % wsize;
686 if (align < 0)
687 align += wsize;
688 isize += osize + align;
689 }
690 return isize * instruction->times;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000691 }
692
H. Peter Anvine2c80182005-01-15 22:15:51 +0000693 if (instruction->opcode == I_INCBIN) {
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000694 char fname[FILENAME_MAX];
H. Peter Anvine2c80182005-01-15 22:15:51 +0000695 FILE *fp;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000696 int32_t len;
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000697 char *prefix = "", *combine;
698 char **pPrevPath = NULL;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000699
H. Peter Anvine2c80182005-01-15 22:15:51 +0000700 len = FILENAME_MAX - 1;
701 if (len > instruction->eops->stringlen)
702 len = instruction->eops->stringlen;
703 strncpy(fname, instruction->eops->stringval, len);
704 fname[len] = '\0';
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000705
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700706 /* added by alexfru: 'incbin' uses include paths */
707 while (1) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000708 combine = nasm_malloc(strlen(prefix) + len + 1);
709 strcpy(combine, prefix);
710 strcat(combine, fname);
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000711
H. Peter Anvine2c80182005-01-15 22:15:51 +0000712 if ((fp = fopen(combine, "rb")) != NULL) {
713 nasm_free(combine);
714 break;
715 }
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000716
H. Peter Anvine2c80182005-01-15 22:15:51 +0000717 nasm_free(combine);
718 pPrevPath = pp_get_include_path_ptr(pPrevPath);
719 if (pPrevPath == NULL)
720 break;
721 prefix = *pPrevPath;
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000722 }
723
724 if (fp == NULL)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000725 error(ERR_NONFATAL, "`incbin': unable to open file `%s'",
726 fname);
727 else if (fseek(fp, 0L, SEEK_END) < 0)
728 error(ERR_NONFATAL, "`incbin': unable to seek on file `%s'",
729 fname);
730 else {
731 len = ftell(fp);
732 fclose(fp);
733 if (instruction->eops->next) {
734 len -= instruction->eops->next->offset;
735 if (instruction->eops->next->next &&
736 len > instruction->eops->next->next->offset) {
737 len = instruction->eops->next->next->offset;
738 }
739 }
740 return instruction->times * len;
741 }
742 return 0; /* if we're here, there's an error */
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000743 }
744
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700745 /* Check to see if we need an address-size prefix */
746 add_asp(instruction, bits);
747
Keith Kaniosb7a89542007-04-12 02:40:54 +0000748 for (temp = nasm_instructions[instruction->opcode]; temp->opcode != -1; temp++) {
749 int m = matches(temp, instruction, bits);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000750 if (m == 99)
751 m += jmp_match(segment, offset, bits, instruction, temp->code);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000752
H. Peter Anvine2c80182005-01-15 22:15:51 +0000753 if (m == 100) {
754 /* we've matched an instruction. */
Charles Crayne5fbbc8c2007-11-07 19:03:46 -0800755 int64_t isize;
H. Peter Anvin3720f7b2008-05-12 11:00:50 -0700756 const uint8_t *codes = temp->code;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000757 int j;
758
759 isize = calcsize(segment, offset, bits, instruction, codes);
760 if (isize < 0)
761 return -1;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700762 for (j = 0; j < MAXPREFIX; j++) {
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700763 switch (instruction->prefixes[j]) {
764 case P_A16:
765 if (bits != 16)
766 isize++;
767 break;
768 case P_A32:
769 if (bits != 32)
770 isize++;
771 break;
772 case P_O16:
773 if (bits != 16)
774 isize++;
775 break;
776 case P_O32:
777 if (bits == 16)
778 isize++;
779 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700780 case P_A64:
781 case P_O64:
782 case P_none:
783 break;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700784 default:
785 isize++;
786 break;
787 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000788 }
789 return isize * instruction->times;
790 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000791 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000792 return -1; /* didn't match any instruction */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000793}
794
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700795static bool possible_sbyte(insn * ins, int op)
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000796{
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700797 return !(ins->forw_ref && ins->oprs[op].opflags) &&
H. Peter Anvine2c80182005-01-15 22:15:51 +0000798 optimizing >= 0 &&
799 !(ins->oprs[op].type & STRICT) &&
800 ins->oprs[op].wrt == NO_SEG && ins->oprs[op].segment == NO_SEG;
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000801}
802
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700803/* check that opn[op] is a signed byte of size 16 or 32 */
804static bool is_sbyte16(insn * ins, int op)
805{
806 int16_t v;
807
808 if (!possible_sbyte(ins, op))
809 return false;
810
811 v = ins->oprs[op].offset;
812 return v >= -128 && v <= 127;
813}
814
815static bool is_sbyte32(insn * ins, int op)
816{
817 int32_t v;
818
819 if (!possible_sbyte(ins, op))
820 return false;
821
822 v = ins->oprs[op].offset;
823 return v >= -128 && v <= 127;
824}
825
826/* check that opn[op] is a signed byte of size 32; warn if this is not
827 the original value when extended to 64 bits */
828static bool is_sbyte64(insn * ins, int op)
829{
830 int64_t v64;
831 int32_t v32;
832
833 /* dead in the water on forward reference or External */
834 if (!possible_sbyte(ins, op))
835 return false;
836
837 v64 = ins->oprs[op].offset;
838 v32 = (int32_t)v64;
839
840 warn_overflow(32, v64);
841
842 return v32 >= -128 && v32 <= 127;
843}
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800844static int64_t calcsize(int32_t segment, int64_t offset, int bits,
H. Peter Anvin3720f7b2008-05-12 11:00:50 -0700845 insn * ins, const uint8_t *codes)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000846{
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800847 int64_t length = 0;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000848 uint8_t c;
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000849 int rex_mask = ~0;
H. Peter Anvin839eca22007-10-29 23:12:47 -0700850 struct operand *opx;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000851
H. Peter Anvine3917fc2007-11-01 14:53:32 -0700852 ins->rex = 0; /* Ensure REX is reset */
853
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700854 if (ins->prefixes[PPS_OSIZE] == P_O64)
855 ins->rex |= REX_W;
856
H. Peter Anvine2c80182005-01-15 22:15:51 +0000857 (void)segment; /* Don't warn that this parameter is unused */
858 (void)offset; /* Don't warn that this parameter is unused */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000859
H. Peter Anvin839eca22007-10-29 23:12:47 -0700860 while (*codes) {
861 c = *codes++;
862 opx = &ins->oprs[c & 3];
863 switch (c) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000864 case 01:
865 case 02:
866 case 03:
867 codes += c, length += c;
868 break;
869 case 04:
870 case 05:
871 case 06:
872 case 07:
873 length++;
874 break;
875 case 010:
876 case 011:
877 case 012:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700878 case 013:
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000879 ins->rex |=
H. Peter Anvin839eca22007-10-29 23:12:47 -0700880 op_rexflags(opx, REX_B|REX_H|REX_P|REX_W);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000881 codes++, length++;
882 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000883 case 014:
884 case 015:
885 case 016:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700886 case 017:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000887 length++;
888 break;
889 case 020:
890 case 021:
891 case 022:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700892 case 023:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000893 length++;
894 break;
895 case 024:
896 case 025:
897 case 026:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700898 case 027:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000899 length++;
900 break;
901 case 030:
902 case 031:
903 case 032:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700904 case 033:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000905 length += 2;
906 break;
907 case 034:
908 case 035:
909 case 036:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700910 case 037:
H. Peter Anvin839eca22007-10-29 23:12:47 -0700911 if (opx->type & (BITS16 | BITS32 | BITS64))
912 length += (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000913 else
914 length += (bits == 16) ? 2 : 4;
915 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000916 case 040:
917 case 041:
918 case 042:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700919 case 043:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000920 length += 4;
921 break;
922 case 044:
923 case 045:
924 case 046:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700925 case 047:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700926 length += ins->addr_size >> 3;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000927 break;
928 case 050:
929 case 051:
930 case 052:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700931 case 053:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000932 length++;
933 break;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000934 case 054:
935 case 055:
936 case 056:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700937 case 057:
Keith Kaniosb7a89542007-04-12 02:40:54 +0000938 length += 8; /* MOV reg64/imm */
939 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000940 case 060:
941 case 061:
942 case 062:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700943 case 063:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000944 length += 2;
945 break;
946 case 064:
947 case 065:
948 case 066:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700949 case 067:
H. Peter Anvin839eca22007-10-29 23:12:47 -0700950 if (opx->type & (BITS16 | BITS32 | BITS64))
951 length += (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000952 else
953 length += (bits == 16) ? 2 : 4;
954 break;
955 case 070:
956 case 071:
957 case 072:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700958 case 073:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000959 length += 4;
960 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700961 case 074:
962 case 075:
963 case 076:
964 case 077:
965 length += 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000966 break;
967 case 0140:
968 case 0141:
969 case 0142:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700970 case 0143:
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700971 length += is_sbyte16(ins, c & 3) ? 1 : 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000972 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000973 case 0144:
974 case 0145:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700975 case 0146:
976 case 0147:
H. Peter Anvina30cc072007-11-18 21:55:26 -0800977 codes++;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000978 length++;
979 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700980 case 0150:
981 case 0151:
982 case 0152:
983 case 0153:
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700984 length += is_sbyte32(ins, c & 3) ? 1 : 4;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700985 break;
986 case 0154:
987 case 0155:
988 case 0156:
989 case 0157:
H. Peter Anvina30cc072007-11-18 21:55:26 -0800990 codes++;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700991 length++;
992 break;
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700993 case 0160:
994 case 0161:
995 case 0162:
996 case 0163:
997 length++;
998 ins->rex |= REX_D;
H. Peter Anvind85d2502008-05-04 17:53:31 -0700999 ins->drexdst = regval(opx);
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001000 break;
1001 case 0164:
1002 case 0165:
1003 case 0166:
1004 case 0167:
1005 length++;
1006 ins->rex |= REX_D|REX_OC;
H. Peter Anvind85d2502008-05-04 17:53:31 -07001007 ins->drexdst = regval(opx);
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001008 break;
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001009 case 0171:
1010 break;
H. Peter Anvind85d2502008-05-04 17:53:31 -07001011 case 0172:
H. Peter Anvind58656f2008-05-06 20:11:14 -07001012 case 0173:
H. Peter Anvin52dc3532008-05-20 19:29:04 -07001013 case 0174:
H. Peter Anvind85d2502008-05-04 17:53:31 -07001014 codes++;
1015 length++;
1016 break;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001017 case 0250:
1018 case 0251:
1019 case 0252:
1020 case 0253:
1021 length += is_sbyte64(ins, c & 3) ? 1 : 4;
1022 break;
H. Peter Anvind85d2502008-05-04 17:53:31 -07001023 case 0260:
1024 case 0261:
1025 case 0262:
1026 case 0263:
1027 length += 2;
1028 ins->rex |= REX_V;
1029 ins->drexdst = regval(opx);
1030 ins->vex_m = *codes++;
1031 ins->vex_wlp = *codes++;
1032 break;
1033 case 0270:
1034 length += 2;
1035 ins->rex |= REX_V;
1036 ins->drexdst = 0;
1037 ins->vex_m = *codes++;
1038 ins->vex_wlp = *codes++;
1039 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001040 case 0300:
1041 case 0301:
H. Peter Anvin70653092007-10-19 14:42:29 -07001042 case 0302:
1043 case 0303:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001044 break;
1045 case 0310:
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07001046 if (bits == 64)
1047 return -1;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001048 length += (bits != 16) && !has_prefix(ins, PPS_ASIZE, P_A16);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001049 break;
1050 case 0311:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001051 length += (bits != 32) && !has_prefix(ins, PPS_ASIZE, P_A32);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001052 break;
1053 case 0312:
H. Peter Anvin70653092007-10-19 14:42:29 -07001054 break;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001055 case 0313:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001056 if (bits != 64 || has_prefix(ins, PPS_ASIZE, P_A16) ||
1057 has_prefix(ins, PPS_ASIZE, P_A32))
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07001058 return -1;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001059 break;
H. Peter Anvin23440102007-11-12 21:02:33 -08001060 case 0314:
1061 case 0315:
1062 case 0316:
1063 case 0317:
1064 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001065 case 0320:
Keith Kaniosb7a89542007-04-12 02:40:54 +00001066 length += (bits != 16);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001067 break;
1068 case 0321:
1069 length += (bits == 16);
1070 break;
1071 case 0322:
1072 break;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001073 case 0323:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001074 rex_mask &= ~REX_W;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001075 break;
1076 case 0324:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001077 ins->rex |= REX_W;
H. Peter Anvin8d7316a2007-04-18 02:27:18 +00001078 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001079 case 0330:
1080 codes++, length++;
1081 break;
1082 case 0331:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001083 break;
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001084 case 0332:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001085 case 0333:
1086 length++;
1087 break;
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001088 case 0334:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001089 ins->rex |= REX_L;
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001090 break;
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001091 case 0335:
1092 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001093 case 0340:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001094 if (ins->oprs[0].segment != NO_SEG)
1095 errfunc(ERR_NONFATAL, "attempt to reserve non-constant"
1096 " quantity of BSS space");
1097 else
H. Peter Anvin428fd672007-11-15 10:25:52 -08001098 length += ins->oprs[0].offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001099 break;
H. Peter Anvinfff5a472008-05-20 09:46:24 -07001100 case 0360:
1101 break;
1102 case 0361:
1103 case 0362:
1104 case 0363:
1105 length++;
1106 break;
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001107 case 0364:
1108 case 0365:
1109 break;
Keith Kanios48af1772007-08-17 07:37:52 +00001110 case 0366:
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001111 case 0367:
1112 length++;
1113 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001114 case 0370:
1115 case 0371:
1116 case 0372:
1117 break;
1118 case 0373:
1119 length++;
1120 break;
1121 default: /* can't do it by 'case' statements */
1122 if (c >= 0100 && c <= 0277) { /* it's an EA */
1123 ea ea_data;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001124 int rfield;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001125 int32_t rflags;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001126 ea_data.rex = 0; /* Ensure ea.REX is initially 0 */
H. Peter Anvin70653092007-10-19 14:42:29 -07001127
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001128 if (c <= 0177) {
1129 /* pick rfield from operand b */
1130 rflags = regflag(&ins->oprs[c & 7]);
H. Peter Anvina4835d42008-05-20 14:21:29 -07001131 rfield = nasm_regvals[ins->oprs[c & 7].basereg];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001132 } else {
1133 rflags = 0;
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001134 rfield = c & 7;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001135 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00001136
H. Peter Anvine2c80182005-01-15 22:15:51 +00001137 if (!process_ea
Keith Kaniosb7a89542007-04-12 02:40:54 +00001138 (&ins->oprs[(c >> 3) & 7], &ea_data, bits,
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001139 ins->addr_size, rfield, rflags, ins->forw_ref)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001140 errfunc(ERR_NONFATAL, "invalid effective address");
1141 return -1;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001142 } else {
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001143 ins->rex |= ea_data.rex;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001144 length += ea_data.size;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001145 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001146 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001147 errfunc(ERR_PANIC, "internal instruction table corrupt"
1148 ": instruction code 0x%02X given", c);
H. Peter Anvin839eca22007-10-29 23:12:47 -07001149 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001150 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001151 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001152
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001153 ins->rex &= rex_mask;
H. Peter Anvin70653092007-10-19 14:42:29 -07001154
H. Peter Anvind85d2502008-05-04 17:53:31 -07001155 if (ins->rex & REX_V) {
1156 int bad32 = REX_R|REX_W|REX_X|REX_B;
1157
1158 if (ins->rex & REX_H) {
1159 errfunc(ERR_NONFATAL, "cannot use high register in vex instruction");
1160 return -1;
1161 }
1162 switch (ins->vex_wlp & 030) {
1163 case 000:
H. Peter Anvinbd420c72008-05-22 11:24:35 -07001164 case 020:
H. Peter Anvind85d2502008-05-04 17:53:31 -07001165 ins->rex &= ~REX_W;
1166 break;
1167 case 010:
1168 ins->rex |= REX_W;
1169 bad32 &= ~REX_W;
1170 break;
H. Peter Anvinbd420c72008-05-22 11:24:35 -07001171 case 030:
H. Peter Anvind85d2502008-05-04 17:53:31 -07001172 /* Follow REX_W */
1173 break;
1174 }
1175
1176 if (bits != 64 && ((ins->rex & bad32) || ins->drexdst > 7)) {
1177 errfunc(ERR_NONFATAL, "invalid operands in non-64-bit mode");
1178 return -1;
1179 }
1180 if (ins->vex_m != 1 || (ins->rex & (REX_W|REX_R|REX_B)))
1181 length += 3;
1182 else
1183 length += 2;
1184 } else if (ins->rex & REX_D) {
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001185 if (ins->rex & REX_H) {
1186 errfunc(ERR_NONFATAL, "cannot use high register in drex instruction");
1187 return -1;
1188 }
H. Peter Anvind85d2502008-05-04 17:53:31 -07001189 if (bits != 64 && ((ins->rex & (REX_R|REX_W|REX_X|REX_B)) ||
H. Peter Anvincf5180a2007-09-17 17:25:27 -07001190 ins->drexdst > 7)) {
1191 errfunc(ERR_NONFATAL, "invalid operands in non-64-bit mode");
1192 return -1;
1193 }
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001194 length++;
1195 } else if (ins->rex & REX_REAL) {
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001196 if (ins->rex & REX_H) {
1197 errfunc(ERR_NONFATAL, "cannot use high register in rex instruction");
1198 return -1;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001199 } else if (bits == 64) {
1200 length++;
1201 } else if ((ins->rex & REX_L) &&
1202 !(ins->rex & (REX_P|REX_W|REX_X|REX_B)) &&
1203 cpu >= IF_X86_64) {
1204 /* LOCK-as-REX.R */
1205 assert_no_prefix(ins, PPS_LREP);
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001206 length++;
H. Peter Anvin8d7316a2007-04-18 02:27:18 +00001207 } else {
H. Peter Anvincf5180a2007-09-17 17:25:27 -07001208 errfunc(ERR_NONFATAL, "invalid operands in non-64-bit mode");
1209 return -1;
H. Peter Anvin8d7316a2007-04-18 02:27:18 +00001210 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00001211 }
1212
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001213 return length;
1214}
Keith Kaniosb7a89542007-04-12 02:40:54 +00001215
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001216#define EMIT_REX() \
H. Peter Anvind85d2502008-05-04 17:53:31 -07001217 if (!(ins->rex & (REX_D|REX_V)) && (ins->rex & REX_REAL) && (bits == 64)) { \
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001218 ins->rex = (ins->rex & REX_REAL)|REX_P; \
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001219 out(offset, segment, &ins->rex, OUT_RAWDATA, 1, NO_SEG, NO_SEG); \
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001220 ins->rex = 0; \
1221 offset += 1; \
1222 }
1223
Charles Crayne1f8bc4c2007-11-06 18:27:23 -08001224static void gencode(int32_t segment, int64_t offset, int bits,
H. Peter Anvin3720f7b2008-05-12 11:00:50 -07001225 insn * ins, const uint8_t *codes, int64_t insn_end)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001226{
Keith Kaniosa6dfa782007-04-13 16:47:53 +00001227 static char condval[] = { /* conditional opcodes */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001228 0x7, 0x3, 0x2, 0x6, 0x2, 0x4, 0xF, 0xD, 0xC, 0xE, 0x6, 0x2,
1229 0x3, 0x7, 0x3, 0x5, 0xE, 0xC, 0xD, 0xF, 0x1, 0xB, 0x9, 0x5,
1230 0x0, 0xA, 0xA, 0xB, 0x8, 0x4
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001231 };
Keith Kaniosb7a89542007-04-12 02:40:54 +00001232 uint8_t c;
1233 uint8_t bytes[4];
Charles Crayne1f8bc4c2007-11-06 18:27:23 -08001234 int64_t size;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001235 int64_t data;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001236 struct operand *opx;
H. Peter Anvin70653092007-10-19 14:42:29 -07001237
H. Peter Anvin839eca22007-10-29 23:12:47 -07001238 while (*codes) {
1239 c = *codes++;
1240 opx = &ins->oprs[c & 3];
1241 switch (c) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001242 case 01:
1243 case 02:
1244 case 03:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001245 EMIT_REX();
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001246 out(offset, segment, codes, OUT_RAWDATA, c, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001247 codes += c;
1248 offset += c;
1249 break;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001250
H. Peter Anvine2c80182005-01-15 22:15:51 +00001251 case 04:
1252 case 06:
1253 switch (ins->oprs[0].basereg) {
1254 case R_CS:
1255 bytes[0] = 0x0E + (c == 0x04 ? 1 : 0);
1256 break;
1257 case R_DS:
1258 bytes[0] = 0x1E + (c == 0x04 ? 1 : 0);
1259 break;
1260 case R_ES:
1261 bytes[0] = 0x06 + (c == 0x04 ? 1 : 0);
1262 break;
1263 case R_SS:
1264 bytes[0] = 0x16 + (c == 0x04 ? 1 : 0);
1265 break;
1266 default:
1267 errfunc(ERR_PANIC,
1268 "bizarre 8086 segment register received");
1269 }
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001270 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001271 offset++;
1272 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001273
H. Peter Anvine2c80182005-01-15 22:15:51 +00001274 case 05:
1275 case 07:
1276 switch (ins->oprs[0].basereg) {
1277 case R_FS:
1278 bytes[0] = 0xA0 + (c == 0x05 ? 1 : 0);
1279 break;
1280 case R_GS:
1281 bytes[0] = 0xA8 + (c == 0x05 ? 1 : 0);
1282 break;
1283 default:
1284 errfunc(ERR_PANIC,
1285 "bizarre 386 segment register received");
1286 }
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001287 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001288 offset++;
1289 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001290
H. Peter Anvine2c80182005-01-15 22:15:51 +00001291 case 010:
1292 case 011:
1293 case 012:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001294 case 013:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001295 EMIT_REX();
H. Peter Anvin839eca22007-10-29 23:12:47 -07001296 bytes[0] = *codes++ + ((regval(opx)) & 7);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001297 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001298 offset += 1;
1299 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001300
H. Peter Anvine2c80182005-01-15 22:15:51 +00001301 case 014:
1302 case 015:
1303 case 016:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001304 case 017:
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001305 /* XXX: warns for legitimate optimizer actions */
H. Peter Anvin839eca22007-10-29 23:12:47 -07001306 if (opx->offset < -128 || opx->offset > 127) {
H. Peter Anvin72c64372008-01-08 22:13:48 -08001307 errfunc(ERR_WARNING | ERR_WARN_NOV,
1308 "signed byte value exceeds bounds");
H. Peter Anvine2c80182005-01-15 22:15:51 +00001309 }
H. Peter Anvineba20a72002-04-30 20:53:55 +00001310
H. Peter Anvin839eca22007-10-29 23:12:47 -07001311 if (opx->segment != NO_SEG) {
1312 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001313 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001314 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001315 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001316 bytes[0] = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001317 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001318 NO_SEG);
1319 }
1320 offset += 1;
1321 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001322
H. Peter Anvine2c80182005-01-15 22:15:51 +00001323 case 020:
1324 case 021:
1325 case 022:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001326 case 023:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001327 if (opx->offset < -256 || opx->offset > 255) {
H. Peter Anvin72c64372008-01-08 22:13:48 -08001328 errfunc(ERR_WARNING | ERR_WARN_NOV,
1329 "byte value exceeds bounds");
H. Peter Anvine2c80182005-01-15 22:15:51 +00001330 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001331 if (opx->segment != NO_SEG) {
1332 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001333 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001334 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001335 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001336 bytes[0] = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001337 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001338 NO_SEG);
1339 }
1340 offset += 1;
1341 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001342
H. Peter Anvine2c80182005-01-15 22:15:51 +00001343 case 024:
1344 case 025:
1345 case 026:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001346 case 027:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001347 if (opx->offset < 0 || opx->offset > 255)
H. Peter Anvin72c64372008-01-08 22:13:48 -08001348 errfunc(ERR_WARNING | ERR_WARN_NOV,
1349 "unsigned byte value exceeds bounds");
H. Peter Anvin839eca22007-10-29 23:12:47 -07001350 if (opx->segment != NO_SEG) {
1351 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001352 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001353 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001354 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001355 bytes[0] = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001356 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001357 NO_SEG);
1358 }
1359 offset += 1;
1360 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001361
H. Peter Anvine2c80182005-01-15 22:15:51 +00001362 case 030:
1363 case 031:
1364 case 032:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001365 case 033:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001366 data = opx->offset;
1367 if (opx->segment == NO_SEG && opx->wrt == NO_SEG)
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001368 warn_overflow(2, data);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001369 out(offset, segment, &data, OUT_ADDRESS, 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001370 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001371 offset += 2;
1372 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001373
H. Peter Anvine2c80182005-01-15 22:15:51 +00001374 case 034:
1375 case 035:
1376 case 036:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001377 case 037:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001378 if (opx->type & (BITS16 | BITS32))
1379 size = (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001380 else
1381 size = (bits == 16) ? 2 : 4;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001382 data = opx->offset;
1383 if (opx->segment == NO_SEG && opx->wrt == NO_SEG)
H. Peter Anvin10e27272007-10-29 22:56:08 -07001384 warn_overflow(size, data);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001385 out(offset, segment, &data, OUT_ADDRESS, size,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001386 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001387 offset += size;
1388 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001389
H. Peter Anvine2c80182005-01-15 22:15:51 +00001390 case 040:
1391 case 041:
1392 case 042:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001393 case 043:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001394 data = opx->offset;
H. Peter Anvin72c64372008-01-08 22:13:48 -08001395 if (opx->segment == NO_SEG && opx->wrt == NO_SEG)
1396 warn_overflow(4, data);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001397 out(offset, segment, &data, OUT_ADDRESS, 4,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001398 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001399 offset += 4;
1400 break;
H. Peter Anvin3ba46772002-05-27 23:19:35 +00001401
H. Peter Anvine2c80182005-01-15 22:15:51 +00001402 case 044:
1403 case 045:
1404 case 046:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001405 case 047:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001406 data = opx->offset;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001407 size = ins->addr_size >> 3;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001408 if (opx->segment == NO_SEG &&
1409 opx->wrt == NO_SEG)
H. Peter Anvin10e27272007-10-29 22:56:08 -07001410 warn_overflow(size, data);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001411 out(offset, segment, &data, OUT_ADDRESS, size,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001412 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001413 offset += size;
1414 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001415
H. Peter Anvine2c80182005-01-15 22:15:51 +00001416 case 050:
1417 case 051:
1418 case 052:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001419 case 053:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001420 if (opx->segment != segment)
H. Peter Anvine2c80182005-01-15 22:15:51 +00001421 errfunc(ERR_NONFATAL,
1422 "short relative jump outside segment");
H. Peter Anvin839eca22007-10-29 23:12:47 -07001423 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001424 if (data > 127 || data < -128)
1425 errfunc(ERR_NONFATAL, "short jump is out of range");
1426 bytes[0] = data;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001427 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001428 offset += 1;
1429 break;
H. Peter Anvin70653092007-10-19 14:42:29 -07001430
Keith Kaniosb7a89542007-04-12 02:40:54 +00001431 case 054:
1432 case 055:
1433 case 056:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001434 case 057:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001435 data = (int64_t)opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001436 out(offset, segment, &data, OUT_ADDRESS, 8,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001437 opx->segment, opx->wrt);
Keith Kaniosb7a89542007-04-12 02:40:54 +00001438 offset += 8;
1439 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001440
H. Peter Anvine2c80182005-01-15 22:15:51 +00001441 case 060:
1442 case 061:
1443 case 062:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001444 case 063:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001445 if (opx->segment != segment) {
1446 data = opx->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001447 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001448 OUT_REL2ADR, insn_end - offset,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001449 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001450 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001451 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001452 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001453 OUT_ADDRESS, 2, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001454 }
1455 offset += 2;
1456 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001457
H. Peter Anvine2c80182005-01-15 22:15:51 +00001458 case 064:
1459 case 065:
1460 case 066:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001461 case 067:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001462 if (opx->type & (BITS16 | BITS32 | BITS64))
1463 size = (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001464 else
1465 size = (bits == 16) ? 2 : 4;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001466 if (opx->segment != segment) {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001467 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001468 out(offset, segment, &data,
1469 size == 2 ? OUT_REL2ADR : OUT_REL4ADR,
1470 insn_end - offset, opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001471 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001472 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001473 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001474 OUT_ADDRESS, size, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001475 }
1476 offset += size;
1477 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001478
H. Peter Anvine2c80182005-01-15 22:15:51 +00001479 case 070:
1480 case 071:
1481 case 072:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001482 case 073:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001483 if (opx->segment != segment) {
1484 data = opx->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001485 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001486 OUT_REL4ADR, insn_end - offset,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001487 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001488 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001489 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001490 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001491 OUT_ADDRESS, 4, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001492 }
1493 offset += 4;
1494 break;
H. Peter Anvinaf535c12002-04-30 20:59:21 +00001495
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001496 case 074:
1497 case 075:
1498 case 076:
1499 case 077:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001500 if (opx->segment == NO_SEG)
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001501 errfunc(ERR_NONFATAL, "value referenced by FAR is not"
1502 " relocatable");
H. Peter Anvindfb91802008-05-20 11:43:53 -07001503 data = 0;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001504 out(offset, segment, &data, OUT_ADDRESS, 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001505 outfmt->segbase(1 + opx->segment),
1506 opx->wrt);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001507 offset += 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001508 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001509
H. Peter Anvine2c80182005-01-15 22:15:51 +00001510 case 0140:
1511 case 0141:
1512 case 0142:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001513 case 0143:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001514 data = opx->offset;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001515 if (is_sbyte16(ins, c & 3)) {
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001516 bytes[0] = data;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001517 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001518 NO_SEG);
1519 offset++;
1520 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001521 if (opx->segment == NO_SEG &&
1522 opx->wrt == NO_SEG)
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001523 warn_overflow(2, data);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001524 out(offset, segment, &data, OUT_ADDRESS, 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001525 opx->segment, opx->wrt);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001526 offset += 2;
1527 }
1528 break;
1529
1530 case 0144:
1531 case 0145:
1532 case 0146:
1533 case 0147:
1534 EMIT_REX();
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001535 bytes[0] = *codes++;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001536 if (is_sbyte16(ins, c & 3))
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001537 bytes[0] |= 2; /* s-bit */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001538 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001539 offset++;
1540 break;
1541
1542 case 0150:
1543 case 0151:
1544 case 0152:
1545 case 0153:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001546 data = opx->offset;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001547 if (is_sbyte32(ins, c & 3)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001548 bytes[0] = data;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001549 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001550 NO_SEG);
1551 offset++;
1552 } else {
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001553 out(offset, segment, &data, OUT_ADDRESS, 4,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001554 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001555 offset += 4;
1556 }
1557 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001558
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001559 case 0154:
1560 case 0155:
1561 case 0156:
1562 case 0157:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001563 EMIT_REX();
H. Peter Anvine2c80182005-01-15 22:15:51 +00001564 bytes[0] = *codes++;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001565 if (is_sbyte32(ins, c & 3))
H. Peter Anvine2c80182005-01-15 22:15:51 +00001566 bytes[0] |= 2; /* s-bit */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001567 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001568 offset++;
1569 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001570
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001571 case 0160:
1572 case 0161:
1573 case 0162:
1574 case 0163:
1575 case 0164:
1576 case 0165:
1577 case 0166:
1578 case 0167:
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001579 break;
1580
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001581 case 0171:
1582 bytes[0] =
1583 (ins->drexdst << 4) |
1584 (ins->rex & REX_OC ? 0x08 : 0) |
1585 (ins->rex & (REX_R|REX_X|REX_B));
1586 ins->rex = 0;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001587 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001588 offset++;
1589 break;
1590
H. Peter Anvind85d2502008-05-04 17:53:31 -07001591 case 0172:
1592 c = *codes++;
1593 opx = &ins->oprs[c >> 3];
H. Peter Anvina4835d42008-05-20 14:21:29 -07001594 bytes[0] = nasm_regvals[opx->basereg] << 4;
H. Peter Anvind85d2502008-05-04 17:53:31 -07001595 opx = &ins->oprs[c & 7];
1596 if (opx->segment != NO_SEG || opx->wrt != NO_SEG) {
1597 errfunc(ERR_NONFATAL,
1598 "non-absolute expression not permitted as argument %d",
1599 c & 7);
1600 } else {
1601 if (opx->offset & ~15) {
1602 errfunc(ERR_WARNING | ERR_WARN_NOV,
1603 "four-bit argument exceeds bounds");
1604 }
1605 bytes[0] |= opx->offset & 15;
1606 }
1607 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1608 offset++;
1609 break;
1610
H. Peter Anvind58656f2008-05-06 20:11:14 -07001611 case 0173:
1612 c = *codes++;
1613 opx = &ins->oprs[c >> 4];
H. Peter Anvina4835d42008-05-20 14:21:29 -07001614 bytes[0] = nasm_regvals[opx->basereg] << 4;
H. Peter Anvind58656f2008-05-06 20:11:14 -07001615 bytes[0] |= c & 15;
1616 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1617 offset++;
1618 break;
1619
H. Peter Anvin52dc3532008-05-20 19:29:04 -07001620 case 0174:
1621 c = *codes++;
1622 opx = &ins->oprs[c];
1623 bytes[0] = nasm_regvals[opx->basereg] << 4;
1624 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1625 offset++;
1626 break;
1627
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001628 case 0250:
1629 case 0251:
1630 case 0252:
1631 case 0253:
1632 data = opx->offset;
1633 /* is_sbyte32() is right here, we have already warned */
1634 if (is_sbyte32(ins, c & 3)) {
1635 bytes[0] = data;
1636 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
1637 NO_SEG);
1638 offset++;
1639 } else {
1640 out(offset, segment, &data, OUT_ADDRESS, 4,
1641 opx->segment, opx->wrt);
1642 offset += 4;
1643 }
1644 break;
1645
H. Peter Anvind85d2502008-05-04 17:53:31 -07001646 case 0260:
1647 case 0261:
1648 case 0262:
1649 case 0263:
1650 case 0270:
1651 codes += 2;
1652 if (ins->vex_m != 1 || (ins->rex & (REX_W|REX_X|REX_B))) {
1653 bytes[0] = 0xc4;
H. Peter Anvin4d2c38c2008-05-04 23:15:13 -07001654 bytes[1] = ins->vex_m | ((~ins->rex & 7) << 5);
H. Peter Anvind85d2502008-05-04 17:53:31 -07001655 bytes[2] = ((ins->rex & REX_W) << (7-3)) |
H. Peter Anvin4d2c38c2008-05-04 23:15:13 -07001656 ((~ins->drexdst & 15)<< 3) | (ins->vex_wlp & 07);
H. Peter Anvind85d2502008-05-04 17:53:31 -07001657 out(offset, segment, &bytes, OUT_RAWDATA, 3, NO_SEG, NO_SEG);
1658 offset += 3;
1659 } else {
1660 bytes[0] = 0xc5;
H. Peter Anvin4d2c38c2008-05-04 23:15:13 -07001661 bytes[1] = ((~ins->rex & REX_R) << (7-2)) |
1662 ((~ins->drexdst & 15) << 3) | (ins->vex_wlp & 07);
H. Peter Anvind85d2502008-05-04 17:53:31 -07001663 out(offset, segment, &bytes, OUT_RAWDATA, 2, NO_SEG, NO_SEG);
1664 offset += 2;
1665 }
1666 break;
1667
H. Peter Anvine2c80182005-01-15 22:15:51 +00001668 case 0300:
1669 case 0301:
1670 case 0302:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001671 case 0303:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001672 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001673
H. Peter Anvine2c80182005-01-15 22:15:51 +00001674 case 0310:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001675 if (bits == 32 && !has_prefix(ins, PPS_ASIZE, P_A16)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001676 *bytes = 0x67;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001677 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001678 offset += 1;
1679 } else
1680 offset += 0;
1681 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001682
H. Peter Anvine2c80182005-01-15 22:15:51 +00001683 case 0311:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001684 if (bits != 32 && !has_prefix(ins, PPS_ASIZE, P_A32)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001685 *bytes = 0x67;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001686 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001687 offset += 1;
1688 } else
1689 offset += 0;
1690 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001691
H. Peter Anvine2c80182005-01-15 22:15:51 +00001692 case 0312:
1693 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001694
Keith Kaniosb7a89542007-04-12 02:40:54 +00001695 case 0313:
1696 ins->rex = 0;
1697 break;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07001698
H. Peter Anvin23440102007-11-12 21:02:33 -08001699 case 0314:
1700 case 0315:
1701 case 0316:
1702 case 0317:
1703 break;
1704
H. Peter Anvine2c80182005-01-15 22:15:51 +00001705 case 0320:
Keith Kaniosb7a89542007-04-12 02:40:54 +00001706 if (bits != 16) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001707 *bytes = 0x66;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001708 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001709 offset += 1;
1710 } else
1711 offset += 0;
1712 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001713
H. Peter Anvine2c80182005-01-15 22:15:51 +00001714 case 0321:
1715 if (bits == 16) {
1716 *bytes = 0x66;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001717 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001718 offset += 1;
1719 } else
1720 offset += 0;
1721 break;
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001722
H. Peter Anvine2c80182005-01-15 22:15:51 +00001723 case 0322:
H. Peter Anvin70653092007-10-19 14:42:29 -07001724 case 0323:
1725 break;
1726
Keith Kaniosb7a89542007-04-12 02:40:54 +00001727 case 0324:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001728 ins->rex |= REX_W;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001729 break;
H. Peter Anvin70653092007-10-19 14:42:29 -07001730
H. Peter Anvine2c80182005-01-15 22:15:51 +00001731 case 0330:
1732 *bytes = *codes++ ^ condval[ins->condition];
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001733 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001734 offset += 1;
1735 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001736
H. Peter Anvine2c80182005-01-15 22:15:51 +00001737 case 0331:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001738 break;
H. Peter Anvinaf535c12002-04-30 20:59:21 +00001739
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001740 case 0332:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001741 case 0333:
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001742 *bytes = c - 0332 + 0xF2;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001743 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001744 offset += 1;
1745 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001746
Keith Kanios48af1772007-08-17 07:37:52 +00001747 case 0334:
1748 if (ins->rex & REX_R) {
1749 *bytes = 0xF0;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001750 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
Keith Kanios48af1772007-08-17 07:37:52 +00001751 offset += 1;
1752 }
1753 ins->rex &= ~(REX_L|REX_R);
1754 break;
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001755
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001756 case 0335:
1757 break;
1758
H. Peter Anvine2c80182005-01-15 22:15:51 +00001759 case 0340:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001760 if (ins->oprs[0].segment != NO_SEG)
1761 errfunc(ERR_PANIC, "non-constant BSS size in pass two");
1762 else {
H. Peter Anvin428fd672007-11-15 10:25:52 -08001763 int64_t size = ins->oprs[0].offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001764 if (size > 0)
1765 out(offset, segment, NULL,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001766 OUT_RESERVE, size, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001767 offset += size;
1768 }
1769 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001770
H. Peter Anvinfff5a472008-05-20 09:46:24 -07001771 case 0360:
1772 break;
1773
1774 case 0361:
1775 bytes[0] = 0x66;
1776 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1777 offset += 1;
1778 break;
1779
1780 case 0362:
1781 case 0363:
1782 bytes[0] = c - 0362 + 0xf2;
1783 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
1784 offset += 1;
1785 break;
1786
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001787 case 0364:
1788 case 0365:
1789 break;
1790
Keith Kanios48af1772007-08-17 07:37:52 +00001791 case 0366:
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001792 case 0367:
1793 *bytes = c - 0366 + 0x66;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001794 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
Keith Kanios48af1772007-08-17 07:37:52 +00001795 offset += 1;
1796 break;
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001797
H. Peter Anvine2c80182005-01-15 22:15:51 +00001798 case 0370:
1799 case 0371:
1800 case 0372:
1801 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001802
H. Peter Anvine2c80182005-01-15 22:15:51 +00001803 case 0373:
1804 *bytes = bits == 16 ? 3 : 5;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001805 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001806 offset += 1;
1807 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001808
H. Peter Anvine2c80182005-01-15 22:15:51 +00001809 default: /* can't do it by 'case' statements */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001810 if (c >= 0100 && c <= 0277) { /* it's an EA */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001811 ea ea_data;
1812 int rfield;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001813 int32_t rflags;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001814 uint8_t *p;
1815 int32_t s;
H. Peter Anvin70653092007-10-19 14:42:29 -07001816
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001817 if (c <= 0177) {
1818 /* pick rfield from operand b */
1819 rflags = regflag(&ins->oprs[c & 7]);
H. Peter Anvina4835d42008-05-20 14:21:29 -07001820 rfield = nasm_regvals[ins->oprs[c & 7].basereg];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001821 } else {
1822 /* rfield is constant */
1823 rflags = 0;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001824 rfield = c & 7;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001825 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001826
1827 if (!process_ea
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001828 (&ins->oprs[(c >> 3) & 7], &ea_data, bits,
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001829 ins->addr_size, rfield, rflags, ins->forw_ref)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001830 errfunc(ERR_NONFATAL, "invalid effective address");
1831 }
H. Peter Anvin70653092007-10-19 14:42:29 -07001832
Charles Crayne7e975552007-11-03 22:06:13 -07001833
H. Peter Anvine2c80182005-01-15 22:15:51 +00001834 p = bytes;
1835 *p++ = ea_data.modrm;
1836 if (ea_data.sib_present)
1837 *p++ = ea_data.sib;
1838
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001839 /* DREX suffixes come between the SIB and the displacement */
1840 if (ins->rex & REX_D) {
1841 *p++ =
1842 (ins->drexdst << 4) |
1843 (ins->rex & REX_OC ? 0x08 : 0) |
1844 (ins->rex & (REX_R|REX_X|REX_B));
1845 ins->rex = 0;
1846 }
1847
H. Peter Anvine2c80182005-01-15 22:15:51 +00001848 s = p - bytes;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001849 out(offset, segment, bytes, OUT_RAWDATA, s, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001850
1851 switch (ea_data.bytes) {
1852 case 0:
1853 break;
1854 case 1:
1855 if (ins->oprs[(c >> 3) & 7].segment != NO_SEG) {
1856 data = ins->oprs[(c >> 3) & 7].offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001857 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001858 ins->oprs[(c >> 3) & 7].segment,
1859 ins->oprs[(c >> 3) & 7].wrt);
1860 } else {
1861 *bytes = ins->oprs[(c >> 3) & 7].offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001862 out(offset, segment, bytes, OUT_RAWDATA, 1,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001863 NO_SEG, NO_SEG);
1864 }
1865 s++;
1866 break;
H. Peter Anvin70653092007-10-19 14:42:29 -07001867 case 8:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001868 case 2:
1869 case 4:
1870 data = ins->oprs[(c >> 3) & 7].offset;
Charles Crayne7e975552007-11-03 22:06:13 -07001871 warn_overflow(ea_data.bytes, data);
H. Peter Anvind0b0d282007-09-28 17:17:20 -07001872 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001873 ea_data.rip ? OUT_REL4ADR : OUT_ADDRESS,
1874 ea_data.bytes,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001875 ins->oprs[(c >> 3) & 7].segment,
1876 ins->oprs[(c >> 3) & 7].wrt);
1877 s += ea_data.bytes;
1878 break;
1879 }
1880 offset += s;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001881 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001882 errfunc(ERR_PANIC, "internal instruction table corrupt"
1883 ": instruction code 0x%02X given", c);
H. Peter Anvin839eca22007-10-29 23:12:47 -07001884 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001885 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001886 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001887}
1888
H. Peter Anvin0ec60e62007-07-07 01:59:52 +00001889static int32_t regflag(const operand * o)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001890{
1891 if (o->basereg < EXPR_REG_START || o->basereg >= REG_ENUM_LIMIT) {
1892 errfunc(ERR_PANIC, "invalid operand passed to regflag()");
1893 }
H. Peter Anvina4835d42008-05-20 14:21:29 -07001894 return nasm_reg_flags[o->basereg];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001895}
1896
H. Peter Anvin5b0e3ec2007-07-07 02:01:08 +00001897static int32_t regval(const operand * o)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001898{
H. Peter Anvine2c80182005-01-15 22:15:51 +00001899 if (o->basereg < EXPR_REG_START || o->basereg >= REG_ENUM_LIMIT) {
1900 errfunc(ERR_PANIC, "invalid operand passed to regval()");
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001901 }
H. Peter Anvina4835d42008-05-20 14:21:29 -07001902 return nasm_regvals[o->basereg];
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001903}
1904
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001905static int op_rexflags(const operand * o, int mask)
1906{
1907 int32_t flags;
1908 int val;
1909
1910 if (o->basereg < EXPR_REG_START || o->basereg >= REG_ENUM_LIMIT) {
1911 errfunc(ERR_PANIC, "invalid operand passed to op_rexflags()");
1912 }
1913
H. Peter Anvina4835d42008-05-20 14:21:29 -07001914 flags = nasm_reg_flags[o->basereg];
1915 val = nasm_regvals[o->basereg];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001916
1917 return rexflags(val, flags, mask);
1918}
1919
1920static int rexflags(int val, int32_t flags, int mask)
1921{
1922 int rex = 0;
1923
1924 if (val >= 8)
1925 rex |= REX_B|REX_X|REX_R;
1926 if (flags & BITS64)
1927 rex |= REX_W;
1928 if (!(REG_HIGH & ~flags)) /* AH, CH, DH, BH */
1929 rex |= REX_H;
1930 else if (!(REG8 & ~flags) && val >= 4) /* SPL, BPL, SIL, DIL */
1931 rex |= REX_P;
1932
1933 return rex & mask;
1934}
1935
H. Peter Anvin3360d792007-09-11 04:16:57 +00001936static int matches(const struct itemplate *itemp, insn * instruction, int bits)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001937{
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001938 int i, size[MAX_OPERANDS], asize, oprs, ret;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001939
1940 ret = 100;
1941
1942 /*
1943 * Check the opcode
1944 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001945 if (itemp->opcode != instruction->opcode)
1946 return 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001947
1948 /*
1949 * Count the operands
1950 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001951 if (itemp->operands != instruction->operands)
1952 return 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001953
1954 /*
1955 * Check that no spurious colons or TOs are present
1956 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001957 for (i = 0; i < itemp->operands; i++)
1958 if (instruction->oprs[i].type & ~itemp->opd[i] & (COLON | TO))
1959 return 0;
H. Peter Anvin70653092007-10-19 14:42:29 -07001960
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001961 /*
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001962 * Process size flags
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001963 */
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001964 if (itemp->flags & IF_ARMASK) {
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001965 memset(size, 0, sizeof size);
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001966
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001967 i = ((itemp->flags & IF_ARMASK) >> IF_ARSHFT) - 1;
1968
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001969 switch (itemp->flags & IF_SMASK) {
1970 case IF_SB:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001971 size[i] = BITS8;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001972 break;
1973 case IF_SW:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001974 size[i] = BITS16;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001975 break;
1976 case IF_SD:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001977 size[i] = BITS32;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001978 break;
1979 case IF_SQ:
Keith Kaniosb7a89542007-04-12 02:40:54 +00001980 size[i] = BITS64;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001981 break;
H. Peter Anvin41c9f6f2007-09-18 13:01:32 -07001982 case IF_SO:
1983 size[i] = BITS128;
1984 break;
H. Peter Anvindfb91802008-05-20 11:43:53 -07001985 case IF_SY:
1986 size[i] = BITS256;
1987 break;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001988 case IF_SZ:
1989 switch (bits) {
1990 case 16:
1991 size[i] = BITS16;
1992 break;
1993 case 32:
1994 size[i] = BITS32;
1995 break;
1996 case 64:
1997 size[i] = BITS64;
1998 break;
1999 }
2000 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07002001 default:
2002 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002003 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002004 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002005 asize = 0;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07002006 switch (itemp->flags & IF_SMASK) {
2007 case IF_SB:
H. Peter Anvine2c80182005-01-15 22:15:51 +00002008 asize = BITS8;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07002009 break;
2010 case IF_SW:
H. Peter Anvine2c80182005-01-15 22:15:51 +00002011 asize = BITS16;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07002012 break;
2013 case IF_SD:
H. Peter Anvine2c80182005-01-15 22:15:51 +00002014 asize = BITS32;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07002015 break;
2016 case IF_SQ:
Keith Kaniosb7a89542007-04-12 02:40:54 +00002017 asize = BITS64;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07002018 break;
H. Peter Anvin41c9f6f2007-09-18 13:01:32 -07002019 case IF_SO:
2020 asize = BITS128;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002021 break;
H. Peter Anvindfb91802008-05-20 11:43:53 -07002022 case IF_SY:
2023 asize = BITS256;
2024 break;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002025 case IF_SZ:
2026 switch (bits) {
2027 case 16:
2028 asize = BITS16;
2029 break;
2030 case 32:
2031 asize = BITS32;
2032 break;
2033 case 64:
2034 asize = BITS64;
2035 break;
2036 }
H. Peter Anvin41c9f6f2007-09-18 13:01:32 -07002037 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07002038 default:
2039 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002040 }
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07002041 for (i = 0; i < MAX_OPERANDS; i++)
2042 size[i] = asize;
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002043 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002044
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002045 /*
2046 * Check that the operand flags all match up
2047 */
2048 for (i = 0; i < itemp->operands; i++) {
2049 int32_t type = instruction->oprs[i].type;
2050 if (!(type & SIZE_MASK))
2051 type |= size[i];
H. Peter Anvind85d2502008-05-04 17:53:31 -07002052
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07002053 if (itemp->opd[i] & SAME_AS) {
2054 int j = itemp->opd[i] & ~SAME_AS;
2055 if (type != instruction->oprs[j].type ||
2056 instruction->oprs[i].basereg != instruction->oprs[j].basereg)
2057 return 0;
2058 } else if (itemp->opd[i] & ~type ||
2059 ((itemp->opd[i] & SIZE_MASK) &&
2060 ((itemp->opd[i] ^ type) & SIZE_MASK))) {
2061 if ((itemp->opd[i] & ~type & ~SIZE_MASK) ||
2062 (type & SIZE_MASK))
2063 return 0;
2064 else
2065 return 1;
2066 }
2067 }
2068
2069 /*
2070 * Check operand sizes
2071 */
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002072 if (itemp->flags & (IF_SM | IF_SM2)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002073 oprs = (itemp->flags & IF_SM2 ? 2 : itemp->operands);
2074 asize = 0;
2075 for (i = 0; i < oprs; i++) {
2076 if ((asize = itemp->opd[i] & SIZE_MASK) != 0) {
2077 int j;
2078 for (j = 0; j < oprs; j++)
2079 size[j] = asize;
2080 break;
2081 }
2082 }
H. Peter Anvinef7468f2002-04-30 20:57:59 +00002083 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002084 oprs = itemp->operands;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002085 }
2086
Keith Kaniosb7a89542007-04-12 02:40:54 +00002087 for (i = 0; i < itemp->operands; i++) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002088 if (!(itemp->opd[i] & SIZE_MASK) &&
2089 (instruction->oprs[i].type & SIZE_MASK & ~size[i]))
H. Peter Anvine2c80182005-01-15 22:15:51 +00002090 return 2;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002091 }
2092
H. Peter Anvinaf535c12002-04-30 20:59:21 +00002093 /*
2094 * Check template is okay at the set cpu level
2095 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002096 if (((itemp->flags & IF_PLEVEL) > cpu))
H. Peter Anvine2c80182005-01-15 22:15:51 +00002097 return 3;
H. Peter Anvin70653092007-10-19 14:42:29 -07002098
Keith Kaniosb7a89542007-04-12 02:40:54 +00002099 /*
2100 * Check if instruction is available in long mode
2101 */
2102 if ((itemp->flags & IF_NOLONG) && (bits == 64))
2103 return 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002104
H. Peter Anvinaf535c12002-04-30 20:59:21 +00002105 /*
2106 * Check if special handling needed for Jumps
2107 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002108 if ((uint8_t)(itemp->code[0]) >= 0370)
H. Peter Anvine2c80182005-01-15 22:15:51 +00002109 return 99;
2110
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002111 return ret;
2112}
2113
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002114static ea *process_ea(operand * input, ea * output, int bits,
2115 int addrbits, int rfield, int32_t rflags, int forw_ref)
H. Peter Anvineba20a72002-04-30 20:53:55 +00002116{
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002117 output->rip = false;
H. Peter Anvin99c4ecd2007-08-28 23:06:00 +00002118
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002119 /* REX flags for the rfield operand */
2120 output->rex |= rexflags(rfield, rflags, REX_R|REX_P|REX_W|REX_H);
2121
Keith Kaniosb7a89542007-04-12 02:40:54 +00002122 if (!(REGISTER & ~input->type)) { /* register direct */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002123 int i;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002124 int32_t f;
2125
2126 if (input->basereg < EXPR_REG_START /* Verify as Register */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002127 || input->basereg >= REG_ENUM_LIMIT)
H. Peter Anvine2c80182005-01-15 22:15:51 +00002128 return NULL;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002129 f = regflag(input);
H. Peter Anvina4835d42008-05-20 14:21:29 -07002130 i = nasm_regvals[input->basereg];
Keith Kaniosb7a89542007-04-12 02:40:54 +00002131
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002132 if (REG_EA & ~f)
2133 return NULL; /* Invalid EA register */
H. Peter Anvin70653092007-10-19 14:42:29 -07002134
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002135 output->rex |= op_rexflags(input, REX_B|REX_P|REX_W|REX_H);
2136
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002137 output->sib_present = false; /* no SIB necessary */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002138 output->bytes = 0; /* no offset necessary either */
2139 output->modrm = 0xC0 | ((rfield & 7) << 3) | (i & 7);
H. Peter Anvine2c80182005-01-15 22:15:51 +00002140 } else { /* it's a memory reference */
2141 if (input->basereg == -1
2142 && (input->indexreg == -1 || input->scale == 0)) {
2143 /* it's a pure offset */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002144 if (bits == 64 && (~input->type & IP_REL)) {
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002145 int scale, index, base;
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002146 output->sib_present = true;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002147 scale = 0;
2148 index = 4;
2149 base = 5;
2150 output->sib = (scale << 6) | (index << 3) | base;
2151 output->bytes = 4;
2152 output->modrm = 4 | ((rfield & 7) << 3);
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002153 output->rip = false;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002154 } else {
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002155 output->sib_present = false;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002156 output->bytes = (addrbits != 16 ? 4 : 2);
2157 output->modrm = (addrbits != 16 ? 5 : 6) | ((rfield & 7) << 3);
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002158 output->rip = bits == 64;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00002159 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00002160 } else { /* it's an indirection */
2161 int i = input->indexreg, b = input->basereg, s = input->scale;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002162 int32_t o = input->offset, seg = input->segment;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002163 int hb = input->hintbase, ht = input->hinttype;
2164 int t;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002165 int it, bt;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002166 int32_t ix, bx; /* register flags */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002167
H. Peter Anvine2c80182005-01-15 22:15:51 +00002168 if (s == 0)
2169 i = -1; /* make this easy, at least */
H. Peter Anvin70653092007-10-19 14:42:29 -07002170
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002171 if (i >= EXPR_REG_START && i < REG_ENUM_LIMIT) {
H. Peter Anvina4835d42008-05-20 14:21:29 -07002172 it = nasm_regvals[i];
2173 ix = nasm_reg_flags[i];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002174 } else {
Keith Kaniosb7a89542007-04-12 02:40:54 +00002175 it = -1;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002176 ix = 0;
2177 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002178
H. Peter Anvinb0c54622007-10-28 23:21:46 -07002179 if (b >= EXPR_REG_START && b < REG_ENUM_LIMIT) {
H. Peter Anvina4835d42008-05-20 14:21:29 -07002180 bt = nasm_regvals[b];
2181 bx = nasm_reg_flags[b];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002182 } else {
Keith Kaniosb7a89542007-04-12 02:40:54 +00002183 bt = -1;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002184 bx = 0;
2185 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002186
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002187 /* check for a 32/64-bit memory reference... */
2188 if ((ix|bx) & (BITS32|BITS64)) {
Keith Kaniosb7a89542007-04-12 02:40:54 +00002189 /* it must be a 32/64-bit memory reference. Firstly we have
2190 * to check that all registers involved are type E/Rxx. */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002191 int32_t sok = BITS32|BITS64;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002192
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002193 if (it != -1) {
2194 if (!(REG64 & ~ix) || !(REG32 & ~ix))
2195 sok &= ix;
2196 else
2197 return NULL;
2198 }
2199
2200 if (bt != -1) {
H. Peter Anvin99c4ecd2007-08-28 23:06:00 +00002201 if (REG_GPR & ~bx)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002202 return NULL; /* Invalid register */
H. Peter Anvina57e8d42007-05-30 03:44:02 +00002203 if (~sok & bx & SIZE_MASK)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002204 return NULL; /* Invalid size */
H. Peter Anvinb0c54622007-10-28 23:21:46 -07002205 sok &= bx;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002206 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002207
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002208 /* While we're here, ensure the user didn't specify
2209 WORD or QWORD. */
2210 if (input->disp_size == 16 || input->disp_size == 64)
2211 return NULL;
2212
2213 if (addrbits == 16 ||
2214 (addrbits == 32 && !(sok & BITS32)) ||
2215 (addrbits == 64 && !(sok & BITS64)))
2216 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002217
Keith Kaniosb7a89542007-04-12 02:40:54 +00002218 /* now reorganize base/index */
2219 if (s == 1 && bt != it && bt != -1 && it != -1 &&
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002220 ((hb == b && ht == EAH_NOTBASE)
2221 || (hb == i && ht == EAH_MAKEBASE))) {
2222 /* swap if hints say so */
2223 t = bt, bt = it, it = t;
2224 t = bx, bx = ix, ix = t;
2225 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00002226 if (bt == it) /* convert EAX+2*EAX to 3*EAX */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002227 bt = -1, bx = 0, s++;
2228 if (bt == -1 && s == 1 && !(hb == it && ht == EAH_NOTBASE)) {
2229 /* make single reg base, unless hint */
2230 bt = it, bx = ix, it = -1, ix = 0;
2231 }
H. Peter Anvinf5843c62007-09-10 18:59:26 +00002232 if (((s == 2 && it != REG_NUM_ESP
H. Peter Anvine2c80182005-01-15 22:15:51 +00002233 && !(input->eaflags & EAF_TIMESTWO)) || s == 3
Keith Kaniosb7a89542007-04-12 02:40:54 +00002234 || s == 5 || s == 9) && bt == -1)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002235 bt = it, bx = ix, s--; /* convert 3*EAX to EAX+2*EAX */
Keith Kanios48af1772007-08-17 07:37:52 +00002236 if (it == -1 && (bt & 7) != REG_NUM_ESP
H. Peter Anvine2c80182005-01-15 22:15:51 +00002237 && (input->eaflags & EAF_TIMESTWO))
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002238 it = bt, ix = bx, bt = -1, bx = 0, s = 1;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002239 /* convert [NOSPLIT EAX] to sib format with 0x0 displacement */
Keith Kanios48af1772007-08-17 07:37:52 +00002240 if (s == 1 && it == REG_NUM_ESP) {
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002241 /* swap ESP into base if scale is 1 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002242 t = it, it = bt, bt = t;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002243 t = ix, ix = bx, bx = t;
2244 }
Keith Kanios48af1772007-08-17 07:37:52 +00002245 if (it == REG_NUM_ESP
Keith Kaniosb7a89542007-04-12 02:40:54 +00002246 || (s != 1 && s != 2 && s != 4 && s != 8 && it != -1))
H. Peter Anvine2c80182005-01-15 22:15:51 +00002247 return NULL; /* wrong, for various reasons */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002248
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002249 output->rex |= rexflags(it, ix, REX_X);
2250 output->rex |= rexflags(bt, bx, REX_B);
Keith Kaniosb7a89542007-04-12 02:40:54 +00002251
Keith Kanios48af1772007-08-17 07:37:52 +00002252 if (it == -1 && (bt & 7) != REG_NUM_ESP) {
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002253 /* no SIB needed */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002254 int mod, rm;
H. Peter Anvin70653092007-10-19 14:42:29 -07002255
Keith Kaniosb7a89542007-04-12 02:40:54 +00002256 if (bt == -1) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002257 rm = 5;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002258 mod = 0;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002259 } else {
2260 rm = (bt & 7);
Keith Kanios48af1772007-08-17 07:37:52 +00002261 if (rm != REG_NUM_EBP && o == 0 &&
Keith Kaniosb7a89542007-04-12 02:40:54 +00002262 seg == NO_SEG && !forw_ref &&
2263 !(input->eaflags &
2264 (EAF_BYTEOFFS | EAF_WORDOFFS)))
2265 mod = 0;
2266 else if (input->eaflags & EAF_BYTEOFFS ||
2267 (o >= -128 && o <= 127 && seg == NO_SEG
2268 && !forw_ref
2269 && !(input->eaflags & EAF_WORDOFFS)))
2270 mod = 1;
2271 else
2272 mod = 2;
2273 }
H. Peter Anvinea838272002-04-30 20:51:53 +00002274
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002275 output->sib_present = false;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002276 output->bytes = (bt == -1 || mod == 2 ? 4 : mod);
2277 output->modrm = (mod << 6) | ((rfield & 7) << 3) | rm;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002278 } else {
2279 /* we need a SIB */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002280 int mod, scale, index, base;
H. Peter Anvin70653092007-10-19 14:42:29 -07002281
Keith Kaniosb7a89542007-04-12 02:40:54 +00002282 if (it == -1)
2283 index = 4, s = 1;
2284 else
2285 index = (it & 7);
H. Peter Anvin70653092007-10-19 14:42:29 -07002286
H. Peter Anvine2c80182005-01-15 22:15:51 +00002287 switch (s) {
2288 case 1:
2289 scale = 0;
2290 break;
2291 case 2:
2292 scale = 1;
2293 break;
2294 case 4:
2295 scale = 2;
2296 break;
2297 case 8:
2298 scale = 3;
2299 break;
2300 default: /* then what the smeg is it? */
2301 return NULL; /* panic */
2302 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002303
Keith Kaniosb7a89542007-04-12 02:40:54 +00002304 if (bt == -1) {
2305 base = 5;
2306 mod = 0;
2307 } else {
2308 base = (bt & 7);
Keith Kanios48af1772007-08-17 07:37:52 +00002309 if (base != REG_NUM_EBP && o == 0 &&
H. Peter Anvine2c80182005-01-15 22:15:51 +00002310 seg == NO_SEG && !forw_ref &&
2311 !(input->eaflags &
Keith Kaniosb7a89542007-04-12 02:40:54 +00002312 (EAF_BYTEOFFS | EAF_WORDOFFS)))
2313 mod = 0;
2314 else if (input->eaflags & EAF_BYTEOFFS ||
2315 (o >= -128 && o <= 127 && seg == NO_SEG
2316 && !forw_ref
2317 && !(input->eaflags & EAF_WORDOFFS)))
2318 mod = 1;
2319 else
2320 mod = 2;
2321 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002322
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002323 output->sib_present = true;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002324 output->bytes = (bt == -1 || mod == 2 ? 4 : mod);
2325 output->modrm = (mod << 6) | ((rfield & 7) << 3) | 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002326 output->sib = (scale << 6) | (index << 3) | base;
2327 }
2328 } else { /* it's 16-bit */
2329 int mod, rm;
H. Peter Anvin70653092007-10-19 14:42:29 -07002330
Keith Kaniosb7a89542007-04-12 02:40:54 +00002331 /* check for 64-bit long mode */
2332 if (addrbits == 64)
2333 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002334
H. Peter Anvine2c80182005-01-15 22:15:51 +00002335 /* check all registers are BX, BP, SI or DI */
2336 if ((b != -1 && b != R_BP && b != R_BX && b != R_SI
2337 && b != R_DI) || (i != -1 && i != R_BP && i != R_BX
2338 && i != R_SI && i != R_DI))
2339 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002340
Keith Kaniosb7a89542007-04-12 02:40:54 +00002341 /* ensure the user didn't specify DWORD/QWORD */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002342 if (input->disp_size == 32 || input->disp_size == 64)
H. Peter Anvine2c80182005-01-15 22:15:51 +00002343 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002344
H. Peter Anvine2c80182005-01-15 22:15:51 +00002345 if (s != 1 && i != -1)
2346 return NULL; /* no can do, in 16-bit EA */
2347 if (b == -1 && i != -1) {
2348 int tmp = b;
2349 b = i;
2350 i = tmp;
2351 } /* swap */
2352 if ((b == R_SI || b == R_DI) && i != -1) {
2353 int tmp = b;
2354 b = i;
2355 i = tmp;
2356 }
2357 /* have BX/BP as base, SI/DI index */
2358 if (b == i)
2359 return NULL; /* shouldn't ever happen, in theory */
2360 if (i != -1 && b != -1 &&
2361 (i == R_BP || i == R_BX || b == R_SI || b == R_DI))
2362 return NULL; /* invalid combinations */
2363 if (b == -1) /* pure offset: handled above */
2364 return NULL; /* so if it gets to here, panic! */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002365
H. Peter Anvine2c80182005-01-15 22:15:51 +00002366 rm = -1;
2367 if (i != -1)
2368 switch (i * 256 + b) {
2369 case R_SI * 256 + R_BX:
2370 rm = 0;
2371 break;
2372 case R_DI * 256 + R_BX:
2373 rm = 1;
2374 break;
2375 case R_SI * 256 + R_BP:
2376 rm = 2;
2377 break;
2378 case R_DI * 256 + R_BP:
2379 rm = 3;
2380 break;
2381 } else
2382 switch (b) {
2383 case R_SI:
2384 rm = 4;
2385 break;
2386 case R_DI:
2387 rm = 5;
2388 break;
2389 case R_BP:
2390 rm = 6;
2391 break;
2392 case R_BX:
2393 rm = 7;
2394 break;
2395 }
2396 if (rm == -1) /* can't happen, in theory */
2397 return NULL; /* so panic if it does */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002398
H. Peter Anvine2c80182005-01-15 22:15:51 +00002399 if (o == 0 && seg == NO_SEG && !forw_ref && rm != 6 &&
2400 !(input->eaflags & (EAF_BYTEOFFS | EAF_WORDOFFS)))
2401 mod = 0;
2402 else if (input->eaflags & EAF_BYTEOFFS ||
2403 (o >= -128 && o <= 127 && seg == NO_SEG
2404 && !forw_ref
2405 && !(input->eaflags & EAF_WORDOFFS)))
2406 mod = 1;
2407 else
2408 mod = 2;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002409
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002410 output->sib_present = false; /* no SIB - it's 16-bit */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002411 output->bytes = mod; /* bytes of offset needed */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002412 output->modrm = (mod << 6) | ((rfield & 7) << 3) | rm;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002413 }
2414 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002415 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002416
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002417 output->size = 1 + output->sib_present + output->bytes;
2418 return output;
2419}
2420
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002421static void add_asp(insn *ins, int addrbits)
H. Peter Anvineba20a72002-04-30 20:53:55 +00002422{
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002423 int j, valid;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002424 int defdisp;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002425
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002426 valid = (addrbits == 64) ? 64|32 : 32|16;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002427
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002428 switch (ins->prefixes[PPS_ASIZE]) {
2429 case P_A16:
2430 valid &= 16;
2431 break;
2432 case P_A32:
2433 valid &= 32;
2434 break;
2435 case P_A64:
2436 valid &= 64;
2437 break;
2438 case P_ASP:
2439 valid &= (addrbits == 32) ? 16 : 32;
2440 break;
2441 default:
2442 break;
2443 }
2444
2445 for (j = 0; j < ins->operands; j++) {
2446 if (!(MEMORY & ~ins->oprs[j].type)) {
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002447 int32_t i, b;
H. Peter Anvin70653092007-10-19 14:42:29 -07002448
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002449 /* Verify as Register */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002450 if (ins->oprs[j].indexreg < EXPR_REG_START
2451 || ins->oprs[j].indexreg >= REG_ENUM_LIMIT)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002452 i = 0;
2453 else
H. Peter Anvina4835d42008-05-20 14:21:29 -07002454 i = nasm_reg_flags[ins->oprs[j].indexreg];
H. Peter Anvin70653092007-10-19 14:42:29 -07002455
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002456 /* Verify as Register */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002457 if (ins->oprs[j].basereg < EXPR_REG_START
2458 || ins->oprs[j].basereg >= REG_ENUM_LIMIT)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002459 b = 0;
2460 else
H. Peter Anvina4835d42008-05-20 14:21:29 -07002461 b = nasm_reg_flags[ins->oprs[j].basereg];
H. Peter Anvin70653092007-10-19 14:42:29 -07002462
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002463 if (ins->oprs[j].scale == 0)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002464 i = 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002465
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002466 if (!i && !b) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002467 int ds = ins->oprs[j].disp_size;
2468 if ((addrbits != 64 && ds > 8) ||
2469 (addrbits == 64 && ds == 16))
2470 valid &= ds;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002471 } else {
2472 if (!(REG16 & ~b))
2473 valid &= 16;
2474 if (!(REG32 & ~b))
2475 valid &= 32;
2476 if (!(REG64 & ~b))
2477 valid &= 64;
H. Peter Anvin70653092007-10-19 14:42:29 -07002478
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002479 if (!(REG16 & ~i))
2480 valid &= 16;
2481 if (!(REG32 & ~i))
2482 valid &= 32;
2483 if (!(REG64 & ~i))
2484 valid &= 64;
2485 }
2486 }
2487 }
2488
2489 if (valid & addrbits) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002490 ins->addr_size = addrbits;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002491 } else if (valid & ((addrbits == 32) ? 16 : 32)) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002492 /* Add an address size prefix */
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002493 enum prefixes pref = (addrbits == 32) ? P_A16 : P_A32;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002494 ins->prefixes[PPS_ASIZE] = pref;
2495 ins->addr_size = (addrbits == 32) ? 16 : 32;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002496 } else {
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002497 /* Impossible... */
2498 errfunc(ERR_NONFATAL, "impossible combination of address sizes");
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002499 ins->addr_size = addrbits; /* Error recovery */
2500 }
2501
2502 defdisp = ins->addr_size == 16 ? 16 : 32;
2503
2504 for (j = 0; j < ins->operands; j++) {
2505 if (!(MEM_OFFS & ~ins->oprs[j].type) &&
2506 (ins->oprs[j].disp_size ? ins->oprs[j].disp_size : defdisp)
2507 != ins->addr_size) {
2508 /* mem_offs sizes must match the address size; if not,
2509 strip the MEM_OFFS bit and match only EA instructions */
2510 ins->oprs[j].type &= ~(MEM_OFFS & ~MEMORY);
2511 }
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002512 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002513}