blob: f15b11a8d3d691f4ac605361190a3698811f6173 [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
40 * is a signed byte rather than a word. 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 Anvin7eb4a382007-09-17 15:49:30 -070047 * \170 - encodes the literal byte 0. (Some compilers don't take
48 * kindly to a zero byte in the _middle_ of a compile time
49 * string constant, so I had to put this hack in.)
H. Peter Anvin401c07e2007-09-17 16:55:04 -070050 * \171 - placement of DREX suffix in the absence of an EA
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000051 * \2ab - a ModRM, calculated on EA in operand a, with the spare
52 * field equal to digit b.
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000053 * \310 - indicates fixed 16-bit address size, i.e. optional 0x67.
54 * \311 - indicates fixed 32-bit address size, i.e. optional 0x67.
Keith Kanios48af1772007-08-17 07:37:52 +000055 * \312 - (disassembler only) marker on LOOP, LOOPxx instructions.
H. Peter Anvince2b3972007-05-30 22:21:11 +000056 * \313 - indicates fixed 64-bit address size, 0x67 invalid.
H. Peter Anvin23440102007-11-12 21:02:33 -080057 * \314 - (disassembler only) invalid with REX.B
58 * \315 - (disassembler only) invalid with REX.X
59 * \316 - (disassembler only) invalid with REX.R
60 * \317 - (disassembler only) invalid with REX.W
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000061 * \320 - indicates fixed 16-bit operand size, i.e. optional 0x66.
62 * \321 - indicates fixed 32-bit operand size, i.e. optional 0x66.
63 * \322 - indicates that this instruction is only valid when the
64 * operand size is the default (instruction to disassembler,
65 * generates no code in the assembler)
H. Peter Anvince2b3972007-05-30 22:21:11 +000066 * \323 - indicates fixed 64-bit operand size, REX on extensions only.
Keith Kaniosb7a89542007-04-12 02:40:54 +000067 * \324 - indicates 64-bit operand size requiring REX prefix.
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000068 * \330 - a literal byte follows in the code stream, to be added
69 * to the condition code value of the instruction.
Keith Kanios48af1772007-08-17 07:37:52 +000070 * \331 - instruction not valid with REP prefix. Hint for
H. Peter Anvinef7468f2002-04-30 20:57:59 +000071 * disassembler only; for SSE instructions.
H. Peter Anvincb9b6902007-09-12 21:58:51 -070072 * \332 - REP prefix (0xF2 byte) used as opcode extension.
73 * \333 - REP prefix (0xF3 byte) used as opcode extension.
Keith Kanios48af1772007-08-17 07:37:52 +000074 * \334 - LOCK prefix used instead of REX.R
H. Peter Anvincb9b6902007-09-12 21:58:51 -070075 * \335 - disassemble a rep (0xF3 byte) prefix as repe not rep.
Keith Kaniosb7a89542007-04-12 02:40:54 +000076 * \340 - reserve <operand 0> bytes of uninitialized storage.
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000077 * Operand 0 had better be a segmentless constant.
H. Peter Anvin62cb6062007-09-11 22:44:03 +000078 * \364 - operand-size prefix (0x66) not permitted
79 * \365 - address-size prefix (0x67) not permitted
80 * \366 - operand-size prefix (0x66) used as opcode extension
81 * \367 - address-size prefix (0x67) used as opcode extension
H. Peter Anvin788e6c12002-04-30 21:02:01 +000082 * \370,\371,\372 - match only if operand 0 meets byte jump criteria.
83 * 370 is used for Jcc, 371 is used for JMP.
H. Peter Anvinaf535c12002-04-30 20:59:21 +000084 * \373 - assemble 0x03 if bits==16, 0x05 if bits==32;
85 * used for conditional jump over longer jump
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000086 */
87
H. Peter Anvinfe501952007-10-02 21:53:51 -070088#include "compiler.h"
89
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000090#include <stdio.h>
91#include <string.h>
Keith Kaniosb7a89542007-04-12 02:40:54 +000092#include <inttypes.h>
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000093
94#include "nasm.h"
H. Peter Anvin6768eb72002-04-30 20:52:26 +000095#include "nasmlib.h"
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000096#include "assemble.h"
97#include "insns.h"
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +000098#include "preproc.h"
H. Peter Anvin3df97a72007-05-30 03:25:21 +000099#include "regflags.c"
Keith Kaniosb7a89542007-04-12 02:40:54 +0000100#include "regvals.c"
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000101
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000102typedef struct {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000103 int sib_present; /* is a SIB byte necessary? */
104 int bytes; /* # of bytes of offset needed */
105 int size; /* lazy - this is sib+bytes+1 */
106 uint8_t modrm, sib, rex, rip; /* the bytes themselves */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000107} ea;
108
Keith Kaniosb7a89542007-04-12 02:40:54 +0000109static uint32_t cpu; /* cpu level received from nasm.c */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000110static efunc errfunc;
111static struct ofmt *outfmt;
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000112static ListGen *list;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000113
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800114static int64_t calcsize(int32_t, int64_t, int, insn *, const char *);
115static void gencode(int32_t, int64_t, int, insn *, const char *, int64_t);
H. Peter Anvin3360d792007-09-11 04:16:57 +0000116static int matches(const struct itemplate *, insn *, int bits);
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000117static int32_t regflag(const operand *);
118static int32_t regval(const operand *);
119static int rexflags(int, int32_t, int);
120static int op_rexflags(const operand *, int);
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700121static ea *process_ea(operand *, ea *, int, int, int, int32_t, int);
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700122static void add_asp(insn *, int);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000123
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700124static int has_prefix(insn * ins, enum prefix_pos pos, enum prefixes prefix)
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000125{
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700126 return ins->prefixes[pos] == prefix;
127}
128
129static void assert_no_prefix(insn * ins, enum prefix_pos pos)
130{
131 if (ins->prefixes[pos])
132 errfunc(ERR_NONFATAL, "invalid %s prefix",
133 prefix_name(ins->prefixes[pos]));
134}
135
136static const char *size_name(int size)
137{
138 switch (size) {
139 case 1:
140 return "byte";
141 case 2:
142 return "word";
143 case 4:
144 return "dword";
145 case 8:
146 return "qword";
147 case 10:
148 return "tword";
149 case 16:
150 return "oword";
151 default:
152 return "???";
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000153 }
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700154}
155
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700156static void warn_overflow(int size, int64_t data)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700157{
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700158 if (size < 8) {
Charles Craynedd462c82007-11-04 15:28:30 -0800159 int64_t lim = ((int64_t)1 << (size*8))-1;
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000160
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700161 if (data < ~lim || data > lim)
H. Peter Anvin72c64372008-01-08 22:13:48 -0800162 errfunc(ERR_WARNING | ERR_WARN_NOV, "%s data exceeds bounds", size_name(size));
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700163 }
164}
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000165/*
166 * This routine wrappers the real output format's output routine,
167 * in order to pass a copy of the data off to the listing file
168 * generator at the same time.
169 */
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800170static void out(int64_t offset, int32_t segto, const void *data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800171 enum out_type type, uint64_t size,
172 int32_t segment, int32_t wrt)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000173{
Keith Kaniosb7a89542007-04-12 02:40:54 +0000174 static int32_t lineno = 0; /* static!!! */
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000175 static char *lnfname = NULL;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800176 uint8_t p[8];
H. Peter Anvineba20a72002-04-30 20:53:55 +0000177
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800178 if (type == OUT_ADDRESS && segment == NO_SEG && wrt == NO_SEG) {
179 /*
180 * This is a non-relocated address, and we're going to
181 * convert it into RAWDATA format.
182 */
183 uint8_t *q = p;
H. Peter Anvind1fb15c2007-11-13 09:37:59 -0800184
185 if (size > 8) {
186 errfunc(ERR_PANIC, "OUT_ADDRESS with size > 8");
187 return;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800188 }
H. Peter Anvind1fb15c2007-11-13 09:37:59 -0800189
190 WRITEADDR(q, *(int64_t *)data, size);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800191 data = p;
192 type = OUT_RAWDATA;
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000193 }
194
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800195 list->output(offset, data, type, size);
196
Frank Kotlerabebb082003-09-06 04:45:37 +0000197 /*
198 * this call to src_get determines when we call the
199 * debug-format-specific "linenum" function
200 * it updates lineno and lnfname to the current values
201 * returning 0 if "same as last time", -2 if lnfname
202 * changed, and the amount by which lineno changed,
203 * if it did. thus, these variables must be static
204 */
205
H. Peter Anvine2c80182005-01-15 22:15:51 +0000206 if (src_get(&lineno, &lnfname)) {
207 outfmt->current_dfmt->linenum(lnfname, lineno, segto);
H. Peter Anvince616072002-04-30 21:02:23 +0000208 }
H. Peter Anvineba20a72002-04-30 20:53:55 +0000209
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800210 outfmt->output(segto, data, type, size, segment, wrt);
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000211}
212
Charles Crayne5fbbc8c2007-11-07 19:03:46 -0800213static int jmp_match(int32_t segment, int64_t offset, int bits,
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000214 insn * ins, const char *code)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000215{
Charles Crayne5fbbc8c2007-11-07 19:03:46 -0800216 int64_t isize;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000217 uint8_t c = code[0];
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000218
H. Peter Anvine2c80182005-01-15 22:15:51 +0000219 if (c != 0370 && c != 0371)
220 return 0;
H. Peter Anvin788e6c12002-04-30 21:02:01 +0000221 if (ins->oprs[0].opflags & OPFLAG_FORWARD) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000222 if ((optimizing < 0 || (ins->oprs[0].type & STRICT))
223 && c == 0370)
224 return 1;
225 else
226 return (pass0 == 0); /* match a forward reference */
H. Peter Anvin788e6c12002-04-30 21:02:01 +0000227 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000228 isize = calcsize(segment, offset, bits, ins, code);
229 if (ins->oprs[0].segment != segment)
230 return 0;
231 isize = ins->oprs[0].offset - offset - isize; /* isize is now the delta */
232 if (isize >= -128L && isize <= 127L)
233 return 1; /* it is byte size */
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000234
235 return 0;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000236}
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000237
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800238int64_t assemble(int32_t segment, int64_t offset, int bits, uint32_t cp,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000239 insn * instruction, struct ofmt *output, efunc error,
240 ListGen * listgen)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000241{
H. Peter Anvin3360d792007-09-11 04:16:57 +0000242 const struct itemplate *temp;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000243 int j;
244 int size_prob;
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800245 int64_t insn_end;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000246 int32_t itimes;
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800247 int64_t start = offset;
248 int64_t wsize = 0; /* size for DB etc. */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000249
H. Peter Anvine2c80182005-01-15 22:15:51 +0000250 errfunc = error; /* to pass to other functions */
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000251 cpu = cp;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000252 outfmt = output; /* likewise */
253 list = listgen; /* and again */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000254
H. Peter Anvine2c80182005-01-15 22:15:51 +0000255 switch (instruction->opcode) {
256 case -1:
257 return 0;
258 case I_DB:
259 wsize = 1;
260 break;
261 case I_DW:
262 wsize = 2;
263 break;
264 case I_DD:
265 wsize = 4;
266 break;
267 case I_DQ:
268 wsize = 8;
269 break;
270 case I_DT:
271 wsize = 10;
272 break;
H. Peter Anvincfbe7c32007-09-18 17:49:09 -0700273 case I_DO:
274 wsize = 16;
275 break;
H. Peter Anvin16b0a332007-09-12 20:27:41 -0700276 default:
277 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000278 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000279
H. Peter Anvineba20a72002-04-30 20:53:55 +0000280 if (wsize) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000281 extop *e;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000282 int32_t t = instruction->times;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000283 if (t < 0)
284 errfunc(ERR_PANIC,
285 "instruction->times < 0 (%ld) in assemble()", t);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000286
H. Peter Anvine2c80182005-01-15 22:15:51 +0000287 while (t--) { /* repeat TIMES times */
288 for (e = instruction->eops; e; e = e->next) {
289 if (e->type == EOT_DB_NUMBER) {
290 if (wsize == 1) {
291 if (e->segment != NO_SEG)
292 errfunc(ERR_NONFATAL,
293 "one-byte relocation attempted");
294 else {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000295 uint8_t out_byte = e->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000296 out(offset, segment, &out_byte,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800297 OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000298 }
Keith Kanios61ff53c2007-04-14 18:54:52 +0000299 } else if (wsize > 8) {
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700300 errfunc(ERR_NONFATAL, "integer supplied to a DT or DO"
Keith Kanios61ff53c2007-04-14 18:54:52 +0000301 " instruction");
H. Peter Anvine2c80182005-01-15 22:15:51 +0000302 } else
303 out(offset, segment, &e->offset,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800304 OUT_ADDRESS, wsize, e->segment, e->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000305 offset += wsize;
306 } else if (e->type == EOT_DB_STRING) {
307 int align;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000308
H. Peter Anvine2c80182005-01-15 22:15:51 +0000309 out(offset, segment, e->stringval,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800310 OUT_RAWDATA, e->stringlen, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000311 align = e->stringlen % wsize;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000312
H. Peter Anvine2c80182005-01-15 22:15:51 +0000313 if (align) {
314 align = wsize - align;
315 out(offset, segment, "\0\0\0\0\0\0\0\0",
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800316 OUT_RAWDATA, align, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000317 }
318 offset += e->stringlen + align;
319 }
320 }
321 if (t > 0 && t == instruction->times - 1) {
322 /*
323 * Dummy call to list->output to give the offset to the
324 * listing module.
325 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800326 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000327 list->uplevel(LIST_TIMES);
328 }
329 }
330 if (instruction->times > 1)
331 list->downlevel(LIST_TIMES);
332 return offset - start;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000333 }
334
H. Peter Anvine2c80182005-01-15 22:15:51 +0000335 if (instruction->opcode == I_INCBIN) {
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000336 static char fname[FILENAME_MAX];
H. Peter Anvine2c80182005-01-15 22:15:51 +0000337 FILE *fp;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000338 int32_t len;
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000339 char *prefix = "", *combine;
340 char **pPrevPath = NULL;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000341
H. Peter Anvine2c80182005-01-15 22:15:51 +0000342 len = FILENAME_MAX - 1;
343 if (len > instruction->eops->stringlen)
344 len = instruction->eops->stringlen;
345 strncpy(fname, instruction->eops->stringval, len);
346 fname[len] = '\0';
H. Peter Anvineba20a72002-04-30 20:53:55 +0000347
Keith Kaniosb7a89542007-04-12 02:40:54 +0000348 while (1) { /* added by alexfru: 'incbin' uses include paths */
H. Peter Anvine2c80182005-01-15 22:15:51 +0000349 combine = nasm_malloc(strlen(prefix) + len + 1);
350 strcpy(combine, prefix);
351 strcat(combine, fname);
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000352
H. Peter Anvine2c80182005-01-15 22:15:51 +0000353 if ((fp = fopen(combine, "rb")) != NULL) {
354 nasm_free(combine);
355 break;
356 }
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000357
H. Peter Anvine2c80182005-01-15 22:15:51 +0000358 nasm_free(combine);
359 pPrevPath = pp_get_include_path_ptr(pPrevPath);
360 if (pPrevPath == NULL)
361 break;
362 prefix = *pPrevPath;
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000363 }
364
365 if (fp == NULL)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000366 error(ERR_NONFATAL, "`incbin': unable to open file `%s'",
367 fname);
368 else if (fseek(fp, 0L, SEEK_END) < 0)
369 error(ERR_NONFATAL, "`incbin': unable to seek on file `%s'",
370 fname);
371 else {
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000372 static char buf[2048];
Keith Kaniosb7a89542007-04-12 02:40:54 +0000373 int32_t t = instruction->times;
374 int32_t base = 0;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000375
H. Peter Anvine2c80182005-01-15 22:15:51 +0000376 len = ftell(fp);
377 if (instruction->eops->next) {
378 base = instruction->eops->next->offset;
379 len -= base;
380 if (instruction->eops->next->next &&
381 len > instruction->eops->next->next->offset)
382 len = instruction->eops->next->next->offset;
383 }
384 /*
385 * Dummy call to list->output to give the offset to the
386 * listing module.
387 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800388 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000389 list->uplevel(LIST_INCBIN);
390 while (t--) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000391 int32_t l;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000392
H. Peter Anvine2c80182005-01-15 22:15:51 +0000393 fseek(fp, base, SEEK_SET);
394 l = len;
395 while (l > 0) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000396 int32_t m =
Charles Crayne192d5b52007-10-18 19:02:42 -0700397 fread(buf, 1, (l > (int32_t) sizeof(buf) ? (int32_t) sizeof(buf) : l),
H. Peter Anvine2c80182005-01-15 22:15:51 +0000398 fp);
399 if (!m) {
400 /*
401 * This shouldn't happen unless the file
402 * actually changes while we are reading
403 * it.
404 */
405 error(ERR_NONFATAL,
406 "`incbin': unexpected EOF while"
407 " reading file `%s'", fname);
408 t = 0; /* Try to exit cleanly */
409 break;
410 }
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800411 out(offset, segment, buf, OUT_RAWDATA, m,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000412 NO_SEG, NO_SEG);
413 l -= m;
414 }
415 }
416 list->downlevel(LIST_INCBIN);
417 if (instruction->times > 1) {
418 /*
419 * Dummy call to list->output to give the offset to the
420 * listing module.
421 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800422 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000423 list->uplevel(LIST_TIMES);
424 list->downlevel(LIST_TIMES);
425 }
426 fclose(fp);
427 return instruction->times * len;
428 }
429 return 0; /* if we're here, there's an error */
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000430 }
431
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700432 /* Check to see if we need an address-size prefix */
433 add_asp(instruction, bits);
434
H. Peter Anvin6867acc2007-10-10 14:58:45 -0700435 size_prob = false;
H. Peter Anvin70653092007-10-19 14:42:29 -0700436
437 for (temp = nasm_instructions[instruction->opcode]; temp->opcode != -1; temp++){
Keith Kaniosb7a89542007-04-12 02:40:54 +0000438 int m = matches(temp, instruction, bits);
H. Peter Anvin70653092007-10-19 14:42:29 -0700439
H. Peter Anvine2c80182005-01-15 22:15:51 +0000440 if (m == 99)
441 m += jmp_match(segment, offset, bits, instruction, temp->code);
H. Peter Anvineba20a72002-04-30 20:53:55 +0000442
H. Peter Anvine2c80182005-01-15 22:15:51 +0000443 if (m == 100) { /* matches! */
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000444 const char *codes = temp->code;
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800445 int64_t insn_size = calcsize(segment, offset, bits,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000446 instruction, codes);
447 itimes = instruction->times;
448 if (insn_size < 0) /* shouldn't be, on pass two */
449 error(ERR_PANIC, "errors made it through from pass one");
450 else
451 while (itimes--) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700452 for (j = 0; j < MAXPREFIX; j++) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000453 uint8_t c = 0;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000454 switch (instruction->prefixes[j]) {
455 case P_LOCK:
456 c = 0xF0;
457 break;
458 case P_REPNE:
459 case P_REPNZ:
460 c = 0xF2;
461 break;
462 case P_REPE:
463 case P_REPZ:
464 case P_REP:
465 c = 0xF3;
466 break;
467 case R_CS:
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000468 if (bits == 64) {
469 error(ERR_WARNING,
Charles Crayne1b851dc2007-11-05 21:49:49 -0800470 "cs segment base generated, but will be ignored in 64-bit mode");
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000471 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000472 c = 0x2E;
473 break;
474 case R_DS:
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000475 if (bits == 64) {
476 error(ERR_WARNING,
Charles Crayne1b851dc2007-11-05 21:49:49 -0800477 "ds segment base generated, but will be ignored in 64-bit mode");
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000478 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000479 c = 0x3E;
480 break;
481 case R_ES:
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000482 if (bits == 64) {
483 error(ERR_WARNING,
Charles Crayne1b851dc2007-11-05 21:49:49 -0800484 "es segment base generated, but will be ignored in 64-bit mode");
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000485 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000486 c = 0x26;
487 break;
488 case R_FS:
489 c = 0x64;
490 break;
491 case R_GS:
492 c = 0x65;
493 break;
494 case R_SS:
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000495 if (bits == 64) {
496 error(ERR_WARNING,
Charles Crayne1b851dc2007-11-05 21:49:49 -0800497 "ss segment base generated, but will be ignored in 64-bit mode");
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000498 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000499 c = 0x36;
500 break;
501 case R_SEGR6:
502 case R_SEGR7:
503 error(ERR_NONFATAL,
504 "segr6 and segr7 cannot be used as prefixes");
505 break;
506 case P_A16:
Keith Kaniosb7a89542007-04-12 02:40:54 +0000507 if (bits == 64) {
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000508 error(ERR_NONFATAL,
509 "16-bit addressing is not supported "
510 "in 64-bit mode");
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700511 } else if (bits != 16)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000512 c = 0x67;
513 break;
514 case P_A32:
515 if (bits != 32)
516 c = 0x67;
517 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700518 case P_A64:
519 if (bits != 64) {
520 error(ERR_NONFATAL,
521 "64-bit addressing is only supported "
522 "in 64-bit mode");
523 }
524 break;
525 case P_ASP:
526 c = 0x67;
527 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000528 case P_O16:
529 if (bits != 16)
530 c = 0x66;
531 break;
532 case P_O32:
Keith Kaniosb7a89542007-04-12 02:40:54 +0000533 if (bits == 16)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000534 c = 0x66;
535 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700536 case P_O64:
537 /* REX.W */
538 break;
539 case P_OSP:
540 c = 0x66;
541 break;
542 case P_none:
543 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000544 default:
545 error(ERR_PANIC, "invalid instruction prefix");
546 }
547 if (c != 0) {
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800548 out(offset, segment, &c, OUT_RAWDATA, 1,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000549 NO_SEG, NO_SEG);
550 offset++;
551 }
H. Peter Anvin70653092007-10-19 14:42:29 -0700552 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000553 insn_end = offset + insn_size;
554 gencode(segment, offset, bits, instruction, codes,
555 insn_end);
556 offset += insn_size;
557 if (itimes > 0 && itimes == instruction->times - 1) {
558 /*
559 * Dummy call to list->output to give the offset to the
560 * listing module.
561 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800562 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000563 list->uplevel(LIST_TIMES);
564 }
565 }
566 if (instruction->times > 1)
567 list->downlevel(LIST_TIMES);
568 return offset - start;
569 } else if (m > 0 && m > size_prob) {
570 size_prob = m;
571 }
Keith Kaniosb7a89542007-04-12 02:40:54 +0000572// temp++;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000573 }
H. Peter Anvineba20a72002-04-30 20:53:55 +0000574
H. Peter Anvine2c80182005-01-15 22:15:51 +0000575 if (temp->opcode == -1) { /* didn't match any instruction */
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000576 switch (size_prob) {
577 case 1:
578 error(ERR_NONFATAL, "operation size not specified");
579 break;
580 case 2:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000581 error(ERR_NONFATAL, "mismatch in operand sizes");
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000582 break;
583 case 3:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000584 error(ERR_NONFATAL, "no instruction for this cpu level");
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000585 break;
586 case 4:
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000587 error(ERR_NONFATAL, "instruction not supported in 64-bit mode");
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000588 break;
589 default:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000590 error(ERR_NONFATAL,
591 "invalid combination of opcode and operands");
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000592 break;
593 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000594 }
595 return 0;
596}
597
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800598int64_t insn_size(int32_t segment, int64_t offset, int bits, uint32_t cp,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000599 insn * instruction, efunc error)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000600{
H. Peter Anvin3360d792007-09-11 04:16:57 +0000601 const struct itemplate *temp;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000602
H. Peter Anvine2c80182005-01-15 22:15:51 +0000603 errfunc = error; /* to pass to other functions */
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000604 cpu = cp;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000605
606 if (instruction->opcode == -1)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000607 return 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000608
H. Peter Anvincfbe7c32007-09-18 17:49:09 -0700609 if (instruction->opcode == I_DB || instruction->opcode == I_DW ||
610 instruction->opcode == I_DD || instruction->opcode == I_DQ ||
611 instruction->opcode == I_DT || instruction->opcode == I_DO) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000612 extop *e;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000613 int32_t isize, osize, wsize = 0; /* placate gcc */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000614
H. Peter Anvine2c80182005-01-15 22:15:51 +0000615 isize = 0;
616 switch (instruction->opcode) {
617 case I_DB:
618 wsize = 1;
619 break;
620 case I_DW:
621 wsize = 2;
622 break;
623 case I_DD:
624 wsize = 4;
625 break;
626 case I_DQ:
627 wsize = 8;
628 break;
629 case I_DT:
630 wsize = 10;
631 break;
H. Peter Anvincfbe7c32007-09-18 17:49:09 -0700632 case I_DO:
633 wsize = 16;
634 break;
H. Peter Anvin16b0a332007-09-12 20:27:41 -0700635 default:
636 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000637 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000638
H. Peter Anvine2c80182005-01-15 22:15:51 +0000639 for (e = instruction->eops; e; e = e->next) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000640 int32_t align;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000641
H. Peter Anvine2c80182005-01-15 22:15:51 +0000642 osize = 0;
643 if (e->type == EOT_DB_NUMBER)
644 osize = 1;
645 else if (e->type == EOT_DB_STRING)
646 osize = e->stringlen;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000647
H. Peter Anvine2c80182005-01-15 22:15:51 +0000648 align = (-osize) % wsize;
649 if (align < 0)
650 align += wsize;
651 isize += osize + align;
652 }
653 return isize * instruction->times;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000654 }
655
H. Peter Anvine2c80182005-01-15 22:15:51 +0000656 if (instruction->opcode == I_INCBIN) {
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000657 char fname[FILENAME_MAX];
H. Peter Anvine2c80182005-01-15 22:15:51 +0000658 FILE *fp;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000659 int32_t len;
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000660 char *prefix = "", *combine;
661 char **pPrevPath = NULL;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000662
H. Peter Anvine2c80182005-01-15 22:15:51 +0000663 len = FILENAME_MAX - 1;
664 if (len > instruction->eops->stringlen)
665 len = instruction->eops->stringlen;
666 strncpy(fname, instruction->eops->stringval, len);
667 fname[len] = '\0';
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000668
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700669 /* added by alexfru: 'incbin' uses include paths */
670 while (1) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000671 combine = nasm_malloc(strlen(prefix) + len + 1);
672 strcpy(combine, prefix);
673 strcat(combine, fname);
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000674
H. Peter Anvine2c80182005-01-15 22:15:51 +0000675 if ((fp = fopen(combine, "rb")) != NULL) {
676 nasm_free(combine);
677 break;
678 }
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000679
H. Peter Anvine2c80182005-01-15 22:15:51 +0000680 nasm_free(combine);
681 pPrevPath = pp_get_include_path_ptr(pPrevPath);
682 if (pPrevPath == NULL)
683 break;
684 prefix = *pPrevPath;
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000685 }
686
687 if (fp == NULL)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000688 error(ERR_NONFATAL, "`incbin': unable to open file `%s'",
689 fname);
690 else if (fseek(fp, 0L, SEEK_END) < 0)
691 error(ERR_NONFATAL, "`incbin': unable to seek on file `%s'",
692 fname);
693 else {
694 len = ftell(fp);
695 fclose(fp);
696 if (instruction->eops->next) {
697 len -= instruction->eops->next->offset;
698 if (instruction->eops->next->next &&
699 len > instruction->eops->next->next->offset) {
700 len = instruction->eops->next->next->offset;
701 }
702 }
703 return instruction->times * len;
704 }
705 return 0; /* if we're here, there's an error */
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000706 }
707
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700708 /* Check to see if we need an address-size prefix */
709 add_asp(instruction, bits);
710
Keith Kaniosb7a89542007-04-12 02:40:54 +0000711 for (temp = nasm_instructions[instruction->opcode]; temp->opcode != -1; temp++) {
712 int m = matches(temp, instruction, bits);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000713 if (m == 99)
714 m += jmp_match(segment, offset, bits, instruction, temp->code);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000715
H. Peter Anvine2c80182005-01-15 22:15:51 +0000716 if (m == 100) {
717 /* we've matched an instruction. */
Charles Crayne5fbbc8c2007-11-07 19:03:46 -0800718 int64_t isize;
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000719 const char *codes = temp->code;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000720 int j;
721
722 isize = calcsize(segment, offset, bits, instruction, codes);
723 if (isize < 0)
724 return -1;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700725 for (j = 0; j < MAXPREFIX; j++) {
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700726 switch (instruction->prefixes[j]) {
727 case P_A16:
728 if (bits != 16)
729 isize++;
730 break;
731 case P_A32:
732 if (bits != 32)
733 isize++;
734 break;
735 case P_O16:
736 if (bits != 16)
737 isize++;
738 break;
739 case P_O32:
740 if (bits == 16)
741 isize++;
742 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700743 case P_A64:
744 case P_O64:
745 case P_none:
746 break;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700747 default:
748 isize++;
749 break;
750 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000751 }
752 return isize * instruction->times;
753 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000754 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000755 return -1; /* didn't match any instruction */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000756}
757
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000758/* check that opn[op] is a signed byte of size 16 or 32,
759 and return the signed value*/
H. Peter Anvine2c80182005-01-15 22:15:51 +0000760static int is_sbyte(insn * ins, int op, int size)
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000761{
Keith Kaniosb7a89542007-04-12 02:40:54 +0000762 int32_t v;
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000763 int ret;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000764
765 ret = !(ins->forw_ref && ins->oprs[op].opflags) && /* dead in the water on forward reference or External */
766 optimizing >= 0 &&
767 !(ins->oprs[op].type & STRICT) &&
768 ins->oprs[op].wrt == NO_SEG && ins->oprs[op].segment == NO_SEG;
H. Peter Anvin734b1882002-04-30 21:01:08 +0000769
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000770 v = ins->oprs[op].offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000771 if (size == 16)
Keith Kaniosb7a89542007-04-12 02:40:54 +0000772 v = (int16_t)v; /* sign extend if 16 bits */
H. Peter Anvine2c80182005-01-15 22:15:51 +0000773
774 return ret && v >= -128L && v <= 127L;
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000775}
776
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800777static int64_t calcsize(int32_t segment, int64_t offset, int bits,
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000778 insn * ins, const char *codes)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000779{
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800780 int64_t length = 0;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000781 uint8_t c;
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000782 int rex_mask = ~0;
H. Peter Anvin839eca22007-10-29 23:12:47 -0700783 struct operand *opx;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000784
H. Peter Anvine3917fc2007-11-01 14:53:32 -0700785 ins->rex = 0; /* Ensure REX is reset */
786
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700787 if (ins->prefixes[PPS_OSIZE] == P_O64)
788 ins->rex |= REX_W;
789
H. Peter Anvine2c80182005-01-15 22:15:51 +0000790 (void)segment; /* Don't warn that this parameter is unused */
791 (void)offset; /* Don't warn that this parameter is unused */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000792
H. Peter Anvin839eca22007-10-29 23:12:47 -0700793 while (*codes) {
794 c = *codes++;
795 opx = &ins->oprs[c & 3];
796 switch (c) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000797 case 01:
798 case 02:
799 case 03:
800 codes += c, length += c;
801 break;
802 case 04:
803 case 05:
804 case 06:
805 case 07:
806 length++;
807 break;
808 case 010:
809 case 011:
810 case 012:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700811 case 013:
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000812 ins->rex |=
H. Peter Anvin839eca22007-10-29 23:12:47 -0700813 op_rexflags(opx, REX_B|REX_H|REX_P|REX_W);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000814 codes++, length++;
815 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000816 case 014:
817 case 015:
818 case 016:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700819 case 017:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000820 length++;
821 break;
822 case 020:
823 case 021:
824 case 022:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700825 case 023:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000826 length++;
827 break;
828 case 024:
829 case 025:
830 case 026:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700831 case 027:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000832 length++;
833 break;
834 case 030:
835 case 031:
836 case 032:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700837 case 033:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000838 length += 2;
839 break;
840 case 034:
841 case 035:
842 case 036:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700843 case 037:
H. Peter Anvin839eca22007-10-29 23:12:47 -0700844 if (opx->type & (BITS16 | BITS32 | BITS64))
845 length += (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000846 else
847 length += (bits == 16) ? 2 : 4;
848 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000849 case 040:
850 case 041:
851 case 042:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700852 case 043:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000853 length += 4;
854 break;
855 case 044:
856 case 045:
857 case 046:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700858 case 047:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700859 length += ins->addr_size >> 3;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000860 break;
861 case 050:
862 case 051:
863 case 052:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700864 case 053:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000865 length++;
866 break;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000867 case 054:
868 case 055:
869 case 056:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700870 case 057:
Keith Kaniosb7a89542007-04-12 02:40:54 +0000871 length += 8; /* MOV reg64/imm */
872 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000873 case 060:
874 case 061:
875 case 062:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700876 case 063:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000877 length += 2;
878 break;
879 case 064:
880 case 065:
881 case 066:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700882 case 067:
H. Peter Anvin839eca22007-10-29 23:12:47 -0700883 if (opx->type & (BITS16 | BITS32 | BITS64))
884 length += (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000885 else
886 length += (bits == 16) ? 2 : 4;
887 break;
888 case 070:
889 case 071:
890 case 072:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700891 case 073:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000892 length += 4;
893 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700894 case 074:
895 case 075:
896 case 076:
897 case 077:
898 length += 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000899 break;
900 case 0140:
901 case 0141:
902 case 0142:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700903 case 0143:
H. Peter Anvin839eca22007-10-29 23:12:47 -0700904 length += is_sbyte(ins, c & 3, 16) ? 1 : 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000905 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000906 case 0144:
907 case 0145:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700908 case 0146:
909 case 0147:
H. Peter Anvina30cc072007-11-18 21:55:26 -0800910 codes++;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000911 length++;
912 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700913 case 0150:
914 case 0151:
915 case 0152:
916 case 0153:
H. Peter Anvin839eca22007-10-29 23:12:47 -0700917 length += is_sbyte(ins, c & 3, 32) ? 1 : 4;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700918 break;
919 case 0154:
920 case 0155:
921 case 0156:
922 case 0157:
H. Peter Anvina30cc072007-11-18 21:55:26 -0800923 codes++;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700924 length++;
925 break;
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700926 case 0160:
927 case 0161:
928 case 0162:
929 case 0163:
930 length++;
931 ins->rex |= REX_D;
H. Peter Anvincf5180a2007-09-17 17:25:27 -0700932 ins->drexdst = regval(&ins->oprs[c & 3]);
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700933 break;
934 case 0164:
935 case 0165:
936 case 0166:
937 case 0167:
938 length++;
939 ins->rex |= REX_D|REX_OC;
H. Peter Anvincf5180a2007-09-17 17:25:27 -0700940 ins->drexdst = regval(&ins->oprs[c & 3]);
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700941 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700942 case 0170:
943 length++;
944 break;
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700945 case 0171:
946 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000947 case 0300:
948 case 0301:
H. Peter Anvin70653092007-10-19 14:42:29 -0700949 case 0302:
950 case 0303:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000951 break;
952 case 0310:
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700953 if (bits == 64)
954 return -1;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700955 length += (bits != 16) && !has_prefix(ins, PPS_ASIZE, P_A16);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000956 break;
957 case 0311:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700958 length += (bits != 32) && !has_prefix(ins, PPS_ASIZE, P_A32);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000959 break;
960 case 0312:
H. Peter Anvin70653092007-10-19 14:42:29 -0700961 break;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000962 case 0313:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700963 if (bits != 64 || has_prefix(ins, PPS_ASIZE, P_A16) ||
964 has_prefix(ins, PPS_ASIZE, P_A32))
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700965 return -1;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000966 break;
H. Peter Anvin23440102007-11-12 21:02:33 -0800967 case 0314:
968 case 0315:
969 case 0316:
970 case 0317:
971 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000972 case 0320:
Keith Kaniosb7a89542007-04-12 02:40:54 +0000973 length += (bits != 16);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000974 break;
975 case 0321:
976 length += (bits == 16);
977 break;
978 case 0322:
979 break;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000980 case 0323:
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000981 rex_mask &= ~REX_W;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000982 break;
983 case 0324:
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000984 ins->rex |= REX_W;
H. Peter Anvin8d7316a2007-04-18 02:27:18 +0000985 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000986 case 0330:
987 codes++, length++;
988 break;
989 case 0331:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000990 break;
H. Peter Anvincb9b6902007-09-12 21:58:51 -0700991 case 0332:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000992 case 0333:
993 length++;
994 break;
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000995 case 0334:
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000996 ins->rex |= REX_L;
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000997 break;
H. Peter Anvincb9b6902007-09-12 21:58:51 -0700998 case 0335:
999 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001000 case 0340:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001001 if (ins->oprs[0].segment != NO_SEG)
1002 errfunc(ERR_NONFATAL, "attempt to reserve non-constant"
1003 " quantity of BSS space");
1004 else
H. Peter Anvin428fd672007-11-15 10:25:52 -08001005 length += ins->oprs[0].offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001006 break;
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001007 case 0364:
1008 case 0365:
1009 break;
Keith Kanios48af1772007-08-17 07:37:52 +00001010 case 0366:
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001011 case 0367:
1012 length++;
1013 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001014 case 0370:
1015 case 0371:
1016 case 0372:
1017 break;
1018 case 0373:
1019 length++;
1020 break;
1021 default: /* can't do it by 'case' statements */
1022 if (c >= 0100 && c <= 0277) { /* it's an EA */
1023 ea ea_data;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001024 int rfield;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001025 int32_t rflags;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001026 ea_data.rex = 0; /* Ensure ea.REX is initially 0 */
H. Peter Anvin70653092007-10-19 14:42:29 -07001027
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001028 if (c <= 0177) {
1029 /* pick rfield from operand b */
1030 rflags = regflag(&ins->oprs[c & 7]);
1031 rfield = regvals[ins->oprs[c & 7].basereg];
1032 } else {
1033 rflags = 0;
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001034 rfield = c & 7;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001035 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00001036
H. Peter Anvine2c80182005-01-15 22:15:51 +00001037 if (!process_ea
Keith Kaniosb7a89542007-04-12 02:40:54 +00001038 (&ins->oprs[(c >> 3) & 7], &ea_data, bits,
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001039 ins->addr_size, rfield, rflags, ins->forw_ref)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001040 errfunc(ERR_NONFATAL, "invalid effective address");
1041 return -1;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001042 } else {
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001043 ins->rex |= ea_data.rex;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001044 length += ea_data.size;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001045 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001046 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001047 errfunc(ERR_PANIC, "internal instruction table corrupt"
1048 ": instruction code 0x%02X given", c);
H. Peter Anvin839eca22007-10-29 23:12:47 -07001049 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001050 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001051 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001052
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001053 ins->rex &= rex_mask;
H. Peter Anvin70653092007-10-19 14:42:29 -07001054
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001055 if (ins->rex & REX_D) {
1056 if (ins->rex & REX_H) {
1057 errfunc(ERR_NONFATAL, "cannot use high register in drex instruction");
1058 return -1;
1059 }
H. Peter Anvincf5180a2007-09-17 17:25:27 -07001060 if (bits != 64 && ((ins->rex & (REX_W|REX_X|REX_B)) ||
1061 ins->drexdst > 7)) {
1062 errfunc(ERR_NONFATAL, "invalid operands in non-64-bit mode");
1063 return -1;
1064 }
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001065 length++;
1066 } else if (ins->rex & REX_REAL) {
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001067 if (ins->rex & REX_H) {
1068 errfunc(ERR_NONFATAL, "cannot use high register in rex instruction");
1069 return -1;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001070 } else if (bits == 64) {
1071 length++;
1072 } else if ((ins->rex & REX_L) &&
1073 !(ins->rex & (REX_P|REX_W|REX_X|REX_B)) &&
1074 cpu >= IF_X86_64) {
1075 /* LOCK-as-REX.R */
1076 assert_no_prefix(ins, PPS_LREP);
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001077 length++;
H. Peter Anvin8d7316a2007-04-18 02:27:18 +00001078 } else {
H. Peter Anvincf5180a2007-09-17 17:25:27 -07001079 errfunc(ERR_NONFATAL, "invalid operands in non-64-bit mode");
1080 return -1;
H. Peter Anvin8d7316a2007-04-18 02:27:18 +00001081 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00001082 }
1083
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001084 return length;
1085}
Keith Kaniosb7a89542007-04-12 02:40:54 +00001086
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001087#define EMIT_REX() \
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001088 if (!(ins->rex & REX_D) && (ins->rex & REX_REAL) && (bits == 64)) { \
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001089 ins->rex = (ins->rex & REX_REAL)|REX_P; \
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001090 out(offset, segment, &ins->rex, OUT_RAWDATA, 1, NO_SEG, NO_SEG); \
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001091 ins->rex = 0; \
1092 offset += 1; \
1093 }
1094
Charles Crayne1f8bc4c2007-11-06 18:27:23 -08001095static void gencode(int32_t segment, int64_t offset, int bits,
1096 insn * ins, const char *codes, int64_t insn_end)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001097{
Keith Kaniosa6dfa782007-04-13 16:47:53 +00001098 static char condval[] = { /* conditional opcodes */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001099 0x7, 0x3, 0x2, 0x6, 0x2, 0x4, 0xF, 0xD, 0xC, 0xE, 0x6, 0x2,
1100 0x3, 0x7, 0x3, 0x5, 0xE, 0xC, 0xD, 0xF, 0x1, 0xB, 0x9, 0x5,
1101 0x0, 0xA, 0xA, 0xB, 0x8, 0x4
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001102 };
Keith Kaniosb7a89542007-04-12 02:40:54 +00001103 uint8_t c;
1104 uint8_t bytes[4];
Charles Crayne1f8bc4c2007-11-06 18:27:23 -08001105 int64_t size;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001106 int64_t data;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001107 struct operand *opx;
H. Peter Anvin70653092007-10-19 14:42:29 -07001108
H. Peter Anvin839eca22007-10-29 23:12:47 -07001109 while (*codes) {
1110 c = *codes++;
1111 opx = &ins->oprs[c & 3];
1112 switch (c) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001113 case 01:
1114 case 02:
1115 case 03:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001116 EMIT_REX();
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001117 out(offset, segment, codes, OUT_RAWDATA, c, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001118 codes += c;
1119 offset += c;
1120 break;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001121
H. Peter Anvine2c80182005-01-15 22:15:51 +00001122 case 04:
1123 case 06:
1124 switch (ins->oprs[0].basereg) {
1125 case R_CS:
1126 bytes[0] = 0x0E + (c == 0x04 ? 1 : 0);
1127 break;
1128 case R_DS:
1129 bytes[0] = 0x1E + (c == 0x04 ? 1 : 0);
1130 break;
1131 case R_ES:
1132 bytes[0] = 0x06 + (c == 0x04 ? 1 : 0);
1133 break;
1134 case R_SS:
1135 bytes[0] = 0x16 + (c == 0x04 ? 1 : 0);
1136 break;
1137 default:
1138 errfunc(ERR_PANIC,
1139 "bizarre 8086 segment register received");
1140 }
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001141 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001142 offset++;
1143 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001144
H. Peter Anvine2c80182005-01-15 22:15:51 +00001145 case 05:
1146 case 07:
1147 switch (ins->oprs[0].basereg) {
1148 case R_FS:
1149 bytes[0] = 0xA0 + (c == 0x05 ? 1 : 0);
1150 break;
1151 case R_GS:
1152 bytes[0] = 0xA8 + (c == 0x05 ? 1 : 0);
1153 break;
1154 default:
1155 errfunc(ERR_PANIC,
1156 "bizarre 386 segment register received");
1157 }
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001158 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001159 offset++;
1160 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001161
H. Peter Anvine2c80182005-01-15 22:15:51 +00001162 case 010:
1163 case 011:
1164 case 012:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001165 case 013:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001166 EMIT_REX();
H. Peter Anvin839eca22007-10-29 23:12:47 -07001167 bytes[0] = *codes++ + ((regval(opx)) & 7);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001168 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001169 offset += 1;
1170 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001171
H. Peter Anvine2c80182005-01-15 22:15:51 +00001172 case 014:
1173 case 015:
1174 case 016:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001175 case 017:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001176 if (opx->offset < -128 || opx->offset > 127) {
H. Peter Anvin72c64372008-01-08 22:13:48 -08001177 errfunc(ERR_WARNING | ERR_WARN_NOV,
1178 "signed byte value exceeds bounds");
H. Peter Anvine2c80182005-01-15 22:15:51 +00001179 }
H. Peter Anvineba20a72002-04-30 20:53:55 +00001180
H. Peter Anvin839eca22007-10-29 23:12:47 -07001181 if (opx->segment != NO_SEG) {
1182 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001183 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001184 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001185 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001186 bytes[0] = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001187 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001188 NO_SEG);
1189 }
1190 offset += 1;
1191 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001192
H. Peter Anvine2c80182005-01-15 22:15:51 +00001193 case 020:
1194 case 021:
1195 case 022:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001196 case 023:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001197 if (opx->offset < -256 || opx->offset > 255) {
H. Peter Anvin72c64372008-01-08 22:13:48 -08001198 errfunc(ERR_WARNING | ERR_WARN_NOV,
1199 "byte value exceeds bounds");
H. Peter Anvine2c80182005-01-15 22:15:51 +00001200 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001201 if (opx->segment != NO_SEG) {
1202 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001203 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001204 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001205 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001206 bytes[0] = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001207 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001208 NO_SEG);
1209 }
1210 offset += 1;
1211 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001212
H. Peter Anvine2c80182005-01-15 22:15:51 +00001213 case 024:
1214 case 025:
1215 case 026:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001216 case 027:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001217 if (opx->offset < 0 || opx->offset > 255)
H. Peter Anvin72c64372008-01-08 22:13:48 -08001218 errfunc(ERR_WARNING | ERR_WARN_NOV,
1219 "unsigned byte value exceeds bounds");
H. Peter Anvin839eca22007-10-29 23:12:47 -07001220 if (opx->segment != NO_SEG) {
1221 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001222 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001223 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001224 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001225 bytes[0] = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001226 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001227 NO_SEG);
1228 }
1229 offset += 1;
1230 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001231
H. Peter Anvine2c80182005-01-15 22:15:51 +00001232 case 030:
1233 case 031:
1234 case 032:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001235 case 033:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001236 data = opx->offset;
1237 if (opx->segment == NO_SEG && opx->wrt == NO_SEG)
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001238 warn_overflow(2, data);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001239 out(offset, segment, &data, OUT_ADDRESS, 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001240 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001241 offset += 2;
1242 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001243
H. Peter Anvine2c80182005-01-15 22:15:51 +00001244 case 034:
1245 case 035:
1246 case 036:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001247 case 037:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001248 if (opx->type & (BITS16 | BITS32))
1249 size = (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001250 else
1251 size = (bits == 16) ? 2 : 4;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001252 data = opx->offset;
1253 if (opx->segment == NO_SEG && opx->wrt == NO_SEG)
H. Peter Anvin10e27272007-10-29 22:56:08 -07001254 warn_overflow(size, data);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001255 out(offset, segment, &data, OUT_ADDRESS, size,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001256 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001257 offset += size;
1258 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001259
H. Peter Anvine2c80182005-01-15 22:15:51 +00001260 case 040:
1261 case 041:
1262 case 042:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001263 case 043:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001264 data = opx->offset;
H. Peter Anvin72c64372008-01-08 22:13:48 -08001265 if (opx->segment == NO_SEG && opx->wrt == NO_SEG)
1266 warn_overflow(4, data);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001267 out(offset, segment, &data, OUT_ADDRESS, 4,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001268 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001269 offset += 4;
1270 break;
H. Peter Anvin3ba46772002-05-27 23:19:35 +00001271
H. Peter Anvine2c80182005-01-15 22:15:51 +00001272 case 044:
1273 case 045:
1274 case 046:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001275 case 047:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001276 data = opx->offset;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001277 size = ins->addr_size >> 3;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001278 if (opx->segment == NO_SEG &&
1279 opx->wrt == NO_SEG)
H. Peter Anvin10e27272007-10-29 22:56:08 -07001280 warn_overflow(size, data);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001281 out(offset, segment, &data, OUT_ADDRESS, size,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001282 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001283 offset += size;
1284 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001285
H. Peter Anvine2c80182005-01-15 22:15:51 +00001286 case 050:
1287 case 051:
1288 case 052:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001289 case 053:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001290 if (opx->segment != segment)
H. Peter Anvine2c80182005-01-15 22:15:51 +00001291 errfunc(ERR_NONFATAL,
1292 "short relative jump outside segment");
H. Peter Anvin839eca22007-10-29 23:12:47 -07001293 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001294 if (data > 127 || data < -128)
1295 errfunc(ERR_NONFATAL, "short jump is out of range");
1296 bytes[0] = data;
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 Anvin70653092007-10-19 14:42:29 -07001300
Keith Kaniosb7a89542007-04-12 02:40:54 +00001301 case 054:
1302 case 055:
1303 case 056:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001304 case 057:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001305 data = (int64_t)opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001306 out(offset, segment, &data, OUT_ADDRESS, 8,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001307 opx->segment, opx->wrt);
Keith Kaniosb7a89542007-04-12 02:40:54 +00001308 offset += 8;
1309 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001310
H. Peter Anvine2c80182005-01-15 22:15:51 +00001311 case 060:
1312 case 061:
1313 case 062:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001314 case 063:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001315 if (opx->segment != segment) {
1316 data = opx->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001317 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001318 OUT_REL2ADR, insn_end - offset,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001319 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001320 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001321 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001322 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001323 OUT_ADDRESS, 2, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001324 }
1325 offset += 2;
1326 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001327
H. Peter Anvine2c80182005-01-15 22:15:51 +00001328 case 064:
1329 case 065:
1330 case 066:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001331 case 067:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001332 if (opx->type & (BITS16 | BITS32 | BITS64))
1333 size = (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001334 else
1335 size = (bits == 16) ? 2 : 4;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001336 if (opx->segment != segment) {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001337 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001338 out(offset, segment, &data,
1339 size == 2 ? OUT_REL2ADR : OUT_REL4ADR,
1340 insn_end - offset, opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001341 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001342 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001343 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001344 OUT_ADDRESS, size, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001345 }
1346 offset += size;
1347 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001348
H. Peter Anvine2c80182005-01-15 22:15:51 +00001349 case 070:
1350 case 071:
1351 case 072:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001352 case 073:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001353 if (opx->segment != segment) {
1354 data = opx->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001355 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001356 OUT_REL4ADR, insn_end - offset,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001357 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001358 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001359 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001360 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001361 OUT_ADDRESS, 4, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001362 }
1363 offset += 4;
1364 break;
H. Peter Anvinaf535c12002-04-30 20:59:21 +00001365
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001366 case 074:
1367 case 075:
1368 case 076:
1369 case 077:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001370 if (opx->segment == NO_SEG)
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001371 errfunc(ERR_NONFATAL, "value referenced by FAR is not"
1372 " relocatable");
1373 data = 0L;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001374 out(offset, segment, &data, OUT_ADDRESS, 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001375 outfmt->segbase(1 + opx->segment),
1376 opx->wrt);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001377 offset += 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001378 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001379
H. Peter Anvine2c80182005-01-15 22:15:51 +00001380 case 0140:
1381 case 0141:
1382 case 0142:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001383 case 0143:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001384 data = opx->offset;
1385 if (is_sbyte(ins, c & 3, 16)) {
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001386 bytes[0] = data;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001387 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001388 NO_SEG);
1389 offset++;
1390 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001391 if (opx->segment == NO_SEG &&
1392 opx->wrt == NO_SEG)
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001393 warn_overflow(2, data);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001394 out(offset, segment, &data, OUT_ADDRESS, 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001395 opx->segment, opx->wrt);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001396 offset += 2;
1397 }
1398 break;
1399
1400 case 0144:
1401 case 0145:
1402 case 0146:
1403 case 0147:
1404 EMIT_REX();
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001405 bytes[0] = *codes++;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001406 if (is_sbyte(ins, c & 3, 16))
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001407 bytes[0] |= 2; /* s-bit */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001408 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001409 offset++;
1410 break;
1411
1412 case 0150:
1413 case 0151:
1414 case 0152:
1415 case 0153:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001416 data = opx->offset;
1417 if (is_sbyte(ins, c & 3, 32)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001418 bytes[0] = data;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001419 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001420 NO_SEG);
1421 offset++;
1422 } else {
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001423 out(offset, segment, &data, OUT_ADDRESS, 4,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001424 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001425 offset += 4;
1426 }
1427 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001428
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001429 case 0154:
1430 case 0155:
1431 case 0156:
1432 case 0157:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001433 EMIT_REX();
H. Peter Anvine2c80182005-01-15 22:15:51 +00001434 bytes[0] = *codes++;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001435 if (is_sbyte(ins, c & 3, 32))
H. Peter Anvine2c80182005-01-15 22:15:51 +00001436 bytes[0] |= 2; /* s-bit */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001437 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001438 offset++;
1439 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001440
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001441 case 0160:
1442 case 0161:
1443 case 0162:
1444 case 0163:
1445 case 0164:
1446 case 0165:
1447 case 0166:
1448 case 0167:
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001449 break;
1450
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001451 case 0170:
H. Peter Anvinc189b442007-10-05 17:04:32 -07001452 EMIT_REX();
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001453 bytes[0] = 0;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001454 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001455 offset += 1;
1456 break;
1457
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001458 case 0171:
1459 bytes[0] =
1460 (ins->drexdst << 4) |
1461 (ins->rex & REX_OC ? 0x08 : 0) |
1462 (ins->rex & (REX_R|REX_X|REX_B));
1463 ins->rex = 0;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001464 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001465 offset++;
1466 break;
1467
H. Peter Anvine2c80182005-01-15 22:15:51 +00001468 case 0300:
1469 case 0301:
1470 case 0302:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001471 case 0303:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001472 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001473
H. Peter Anvine2c80182005-01-15 22:15:51 +00001474 case 0310:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001475 if (bits == 32 && !has_prefix(ins, PPS_ASIZE, P_A16)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001476 *bytes = 0x67;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001477 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001478 offset += 1;
1479 } else
1480 offset += 0;
1481 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001482
H. Peter Anvine2c80182005-01-15 22:15:51 +00001483 case 0311:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001484 if (bits != 32 && !has_prefix(ins, PPS_ASIZE, P_A32)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001485 *bytes = 0x67;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001486 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001487 offset += 1;
1488 } else
1489 offset += 0;
1490 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001491
H. Peter Anvine2c80182005-01-15 22:15:51 +00001492 case 0312:
1493 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001494
Keith Kaniosb7a89542007-04-12 02:40:54 +00001495 case 0313:
1496 ins->rex = 0;
1497 break;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07001498
H. Peter Anvin23440102007-11-12 21:02:33 -08001499 case 0314:
1500 case 0315:
1501 case 0316:
1502 case 0317:
1503 break;
1504
H. Peter Anvine2c80182005-01-15 22:15:51 +00001505 case 0320:
Keith Kaniosb7a89542007-04-12 02:40:54 +00001506 if (bits != 16) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001507 *bytes = 0x66;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001508 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001509 offset += 1;
1510 } else
1511 offset += 0;
1512 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001513
H. Peter Anvine2c80182005-01-15 22:15:51 +00001514 case 0321:
1515 if (bits == 16) {
1516 *bytes = 0x66;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001517 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001518 offset += 1;
1519 } else
1520 offset += 0;
1521 break;
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001522
H. Peter Anvine2c80182005-01-15 22:15:51 +00001523 case 0322:
H. Peter Anvin70653092007-10-19 14:42:29 -07001524 case 0323:
1525 break;
1526
Keith Kaniosb7a89542007-04-12 02:40:54 +00001527 case 0324:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001528 ins->rex |= REX_W;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001529 break;
H. Peter Anvin70653092007-10-19 14:42:29 -07001530
H. Peter Anvine2c80182005-01-15 22:15:51 +00001531 case 0330:
1532 *bytes = *codes++ ^ condval[ins->condition];
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001533 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001534 offset += 1;
1535 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001536
H. Peter Anvine2c80182005-01-15 22:15:51 +00001537 case 0331:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001538 break;
H. Peter Anvinaf535c12002-04-30 20:59:21 +00001539
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001540 case 0332:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001541 case 0333:
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001542 *bytes = c - 0332 + 0xF2;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001543 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001544 offset += 1;
1545 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001546
Keith Kanios48af1772007-08-17 07:37:52 +00001547 case 0334:
1548 if (ins->rex & REX_R) {
1549 *bytes = 0xF0;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001550 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
Keith Kanios48af1772007-08-17 07:37:52 +00001551 offset += 1;
1552 }
1553 ins->rex &= ~(REX_L|REX_R);
1554 break;
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001555
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001556 case 0335:
1557 break;
1558
H. Peter Anvine2c80182005-01-15 22:15:51 +00001559 case 0340:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001560 if (ins->oprs[0].segment != NO_SEG)
1561 errfunc(ERR_PANIC, "non-constant BSS size in pass two");
1562 else {
H. Peter Anvin428fd672007-11-15 10:25:52 -08001563 int64_t size = ins->oprs[0].offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001564 if (size > 0)
1565 out(offset, segment, NULL,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001566 OUT_RESERVE, size, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001567 offset += size;
1568 }
1569 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001570
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001571 case 0364:
1572 case 0365:
1573 break;
1574
Keith Kanios48af1772007-08-17 07:37:52 +00001575 case 0366:
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001576 case 0367:
1577 *bytes = c - 0366 + 0x66;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001578 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
Keith Kanios48af1772007-08-17 07:37:52 +00001579 offset += 1;
1580 break;
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001581
H. Peter Anvine2c80182005-01-15 22:15:51 +00001582 case 0370:
1583 case 0371:
1584 case 0372:
1585 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001586
H. Peter Anvine2c80182005-01-15 22:15:51 +00001587 case 0373:
1588 *bytes = bits == 16 ? 3 : 5;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001589 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001590 offset += 1;
1591 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001592
H. Peter Anvine2c80182005-01-15 22:15:51 +00001593 default: /* can't do it by 'case' statements */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001594 if (c >= 0100 && c <= 0277) { /* it's an EA */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001595 ea ea_data;
1596 int rfield;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001597 int32_t rflags;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001598 uint8_t *p;
1599 int32_t s;
H. Peter Anvin70653092007-10-19 14:42:29 -07001600
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001601 if (c <= 0177) {
1602 /* pick rfield from operand b */
1603 rflags = regflag(&ins->oprs[c & 7]);
1604 rfield = regvals[ins->oprs[c & 7].basereg];
1605 } else {
1606 /* rfield is constant */
1607 rflags = 0;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001608 rfield = c & 7;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001609 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001610
1611 if (!process_ea
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001612 (&ins->oprs[(c >> 3) & 7], &ea_data, bits,
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001613 ins->addr_size, rfield, rflags, ins->forw_ref)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001614 errfunc(ERR_NONFATAL, "invalid effective address");
1615 }
H. Peter Anvin70653092007-10-19 14:42:29 -07001616
Charles Crayne7e975552007-11-03 22:06:13 -07001617
H. Peter Anvine2c80182005-01-15 22:15:51 +00001618 p = bytes;
1619 *p++ = ea_data.modrm;
1620 if (ea_data.sib_present)
1621 *p++ = ea_data.sib;
1622
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001623 /* DREX suffixes come between the SIB and the displacement */
1624 if (ins->rex & REX_D) {
1625 *p++ =
1626 (ins->drexdst << 4) |
1627 (ins->rex & REX_OC ? 0x08 : 0) |
1628 (ins->rex & (REX_R|REX_X|REX_B));
1629 ins->rex = 0;
1630 }
1631
H. Peter Anvine2c80182005-01-15 22:15:51 +00001632 s = p - bytes;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001633 out(offset, segment, bytes, OUT_RAWDATA, s, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001634
1635 switch (ea_data.bytes) {
1636 case 0:
1637 break;
1638 case 1:
1639 if (ins->oprs[(c >> 3) & 7].segment != NO_SEG) {
1640 data = ins->oprs[(c >> 3) & 7].offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001641 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001642 ins->oprs[(c >> 3) & 7].segment,
1643 ins->oprs[(c >> 3) & 7].wrt);
1644 } else {
1645 *bytes = ins->oprs[(c >> 3) & 7].offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001646 out(offset, segment, bytes, OUT_RAWDATA, 1,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001647 NO_SEG, NO_SEG);
1648 }
1649 s++;
1650 break;
H. Peter Anvin70653092007-10-19 14:42:29 -07001651 case 8:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001652 case 2:
1653 case 4:
1654 data = ins->oprs[(c >> 3) & 7].offset;
Charles Crayne7e975552007-11-03 22:06:13 -07001655 warn_overflow(ea_data.bytes, data);
H. Peter Anvind0b0d282007-09-28 17:17:20 -07001656 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001657 ea_data.rip ? OUT_REL4ADR : OUT_ADDRESS,
1658 ea_data.bytes,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001659 ins->oprs[(c >> 3) & 7].segment,
1660 ins->oprs[(c >> 3) & 7].wrt);
1661 s += ea_data.bytes;
1662 break;
1663 }
1664 offset += s;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001665 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001666 errfunc(ERR_PANIC, "internal instruction table corrupt"
1667 ": instruction code 0x%02X given", c);
H. Peter Anvin839eca22007-10-29 23:12:47 -07001668 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001669 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001670 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001671}
1672
H. Peter Anvin0ec60e62007-07-07 01:59:52 +00001673static int32_t regflag(const operand * o)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001674{
1675 if (o->basereg < EXPR_REG_START || o->basereg >= REG_ENUM_LIMIT) {
1676 errfunc(ERR_PANIC, "invalid operand passed to regflag()");
1677 }
1678 return reg_flags[o->basereg];
1679}
1680
H. Peter Anvin5b0e3ec2007-07-07 02:01:08 +00001681static int32_t regval(const operand * o)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001682{
H. Peter Anvine2c80182005-01-15 22:15:51 +00001683 if (o->basereg < EXPR_REG_START || o->basereg >= REG_ENUM_LIMIT) {
1684 errfunc(ERR_PANIC, "invalid operand passed to regval()");
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001685 }
H. Peter Anvin232badb2002-06-06 02:41:20 +00001686 return regvals[o->basereg];
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001687}
1688
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001689static int op_rexflags(const operand * o, int mask)
1690{
1691 int32_t flags;
1692 int val;
1693
1694 if (o->basereg < EXPR_REG_START || o->basereg >= REG_ENUM_LIMIT) {
1695 errfunc(ERR_PANIC, "invalid operand passed to op_rexflags()");
1696 }
1697
1698 flags = reg_flags[o->basereg];
1699 val = regvals[o->basereg];
1700
1701 return rexflags(val, flags, mask);
1702}
1703
1704static int rexflags(int val, int32_t flags, int mask)
1705{
1706 int rex = 0;
1707
1708 if (val >= 8)
1709 rex |= REX_B|REX_X|REX_R;
1710 if (flags & BITS64)
1711 rex |= REX_W;
1712 if (!(REG_HIGH & ~flags)) /* AH, CH, DH, BH */
1713 rex |= REX_H;
1714 else if (!(REG8 & ~flags) && val >= 4) /* SPL, BPL, SIL, DIL */
1715 rex |= REX_P;
1716
1717 return rex & mask;
1718}
1719
H. Peter Anvin3360d792007-09-11 04:16:57 +00001720static int matches(const struct itemplate *itemp, insn * instruction, int bits)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001721{
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001722 int i, size[MAX_OPERANDS], asize, oprs, ret;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001723
1724 ret = 100;
1725
1726 /*
1727 * Check the opcode
1728 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001729 if (itemp->opcode != instruction->opcode)
1730 return 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001731
1732 /*
1733 * Count the operands
1734 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001735 if (itemp->operands != instruction->operands)
1736 return 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001737
1738 /*
1739 * Check that no spurious colons or TOs are present
1740 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001741 for (i = 0; i < itemp->operands; i++)
1742 if (instruction->oprs[i].type & ~itemp->opd[i] & (COLON | TO))
1743 return 0;
H. Peter Anvin70653092007-10-19 14:42:29 -07001744
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001745 /*
1746 * Check that the operand flags all match up
1747 */
H. Peter Anvin16b0a332007-09-12 20:27:41 -07001748 for (i = 0; i < itemp->operands; i++) {
H. Peter Anvincf5180a2007-09-17 17:25:27 -07001749 if (itemp->opd[i] & SAME_AS) {
1750 int j = itemp->opd[i] & ~SAME_AS;
1751 if (instruction->oprs[i].type != instruction->oprs[j].type ||
1752 instruction->oprs[i].basereg != instruction->oprs[j].basereg)
1753 return 0;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001754 } else if (itemp->opd[i] & ~instruction->oprs[i].type ||
H. Peter Anvine2c80182005-01-15 22:15:51 +00001755 ((itemp->opd[i] & SIZE_MASK) &&
1756 ((itemp->opd[i] ^ instruction->oprs[i].type) & SIZE_MASK))) {
H. Peter Anvin5a640e12007-05-29 23:57:12 +00001757 if ((itemp->opd[i] & ~instruction->oprs[i].type & ~SIZE_MASK) ||
H. Peter Anvine2c80182005-01-15 22:15:51 +00001758 (instruction->oprs[i].type & SIZE_MASK))
1759 return 0;
1760 else
H. Peter Anvine2c80182005-01-15 22:15:51 +00001761 return 1;
1762 }
H. Peter Anvin16b0a332007-09-12 20:27:41 -07001763 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001764
1765 /*
1766 * Check operand sizes
1767 */
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001768 if (itemp->flags & IF_ARMASK) {
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001769 memset(size, 0, sizeof size);
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001770
H. Peter Anvine2c80182005-01-15 22:15:51 +00001771 switch (itemp->flags & IF_ARMASK) {
1772 case IF_AR0:
1773 i = 0;
1774 break;
1775 case IF_AR1:
1776 i = 1;
1777 break;
1778 case IF_AR2:
1779 i = 2;
1780 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001781 case IF_AR3:
1782 i = 3;
1783 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001784 default:
1785 break; /* Shouldn't happen */
1786 }
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001787 switch (itemp->flags & IF_SMASK) {
1788 case IF_SB:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001789 size[i] = BITS8;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001790 break;
1791 case IF_SW:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001792 size[i] = BITS16;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001793 break;
1794 case IF_SD:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001795 size[i] = BITS32;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001796 break;
1797 case IF_SQ:
Keith Kaniosb7a89542007-04-12 02:40:54 +00001798 size[i] = BITS64;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001799 break;
H. Peter Anvin41c9f6f2007-09-18 13:01:32 -07001800 case IF_SO:
1801 size[i] = BITS128;
1802 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001803 default:
1804 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001805 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001806 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001807 asize = 0;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001808 switch (itemp->flags & IF_SMASK) {
1809 case IF_SB:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001810 asize = BITS8;
1811 oprs = itemp->operands;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001812 break;
1813 case IF_SW:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001814 asize = BITS16;
1815 oprs = itemp->operands;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001816 break;
1817 case IF_SD:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001818 asize = BITS32;
1819 oprs = itemp->operands;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001820 break;
1821 case IF_SQ:
Keith Kaniosb7a89542007-04-12 02:40:54 +00001822 asize = BITS64;
1823 oprs = itemp->operands;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001824 break;
H. Peter Anvin41c9f6f2007-09-18 13:01:32 -07001825 case IF_SO:
1826 asize = BITS128;
1827 oprs = itemp->operands;
1828 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001829 default:
1830 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001831 }
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001832 for (i = 0; i < MAX_OPERANDS; i++)
1833 size[i] = asize;
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001834 }
H. Peter Anvin70653092007-10-19 14:42:29 -07001835
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001836 if (itemp->flags & (IF_SM | IF_SM2)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001837 oprs = (itemp->flags & IF_SM2 ? 2 : itemp->operands);
1838 asize = 0;
1839 for (i = 0; i < oprs; i++) {
1840 if ((asize = itemp->opd[i] & SIZE_MASK) != 0) {
1841 int j;
1842 for (j = 0; j < oprs; j++)
1843 size[j] = asize;
1844 break;
1845 }
1846 }
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001847 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001848 oprs = itemp->operands;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001849 }
1850
Keith Kaniosb7a89542007-04-12 02:40:54 +00001851 for (i = 0; i < itemp->operands; i++) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001852 if (!(itemp->opd[i] & SIZE_MASK) &&
1853 (instruction->oprs[i].type & SIZE_MASK & ~size[i]))
H. Peter Anvine2c80182005-01-15 22:15:51 +00001854 return 2;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001855 }
1856
H. Peter Anvinaf535c12002-04-30 20:59:21 +00001857 /*
1858 * Check template is okay at the set cpu level
1859 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00001860 if (((itemp->flags & IF_PLEVEL) > cpu))
H. Peter Anvine2c80182005-01-15 22:15:51 +00001861 return 3;
H. Peter Anvin70653092007-10-19 14:42:29 -07001862
Keith Kaniosb7a89542007-04-12 02:40:54 +00001863 /*
1864 * Check if instruction is available in long mode
1865 */
1866 if ((itemp->flags & IF_NOLONG) && (bits == 64))
1867 return 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001868
H. Peter Anvinaf535c12002-04-30 20:59:21 +00001869 /*
1870 * Check if special handling needed for Jumps
1871 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00001872 if ((uint8_t)(itemp->code[0]) >= 0370)
H. Peter Anvine2c80182005-01-15 22:15:51 +00001873 return 99;
1874
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001875 return ret;
1876}
1877
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001878static ea *process_ea(operand * input, ea * output, int bits,
1879 int addrbits, int rfield, int32_t rflags, int forw_ref)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001880{
H. Peter Anvin6867acc2007-10-10 14:58:45 -07001881 output->rip = false;
H. Peter Anvin99c4ecd2007-08-28 23:06:00 +00001882
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001883 /* REX flags for the rfield operand */
1884 output->rex |= rexflags(rfield, rflags, REX_R|REX_P|REX_W|REX_H);
1885
Keith Kaniosb7a89542007-04-12 02:40:54 +00001886 if (!(REGISTER & ~input->type)) { /* register direct */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001887 int i;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001888 int32_t f;
1889
1890 if (input->basereg < EXPR_REG_START /* Verify as Register */
Keith Kaniosb7a89542007-04-12 02:40:54 +00001891 || input->basereg >= REG_ENUM_LIMIT)
H. Peter Anvine2c80182005-01-15 22:15:51 +00001892 return NULL;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001893 f = regflag(input);
Keith Kaniosb7a89542007-04-12 02:40:54 +00001894 i = regvals[input->basereg];
Keith Kaniosb7a89542007-04-12 02:40:54 +00001895
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001896 if (REG_EA & ~f)
1897 return NULL; /* Invalid EA register */
H. Peter Anvin70653092007-10-19 14:42:29 -07001898
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001899 output->rex |= op_rexflags(input, REX_B|REX_P|REX_W|REX_H);
1900
H. Peter Anvin6867acc2007-10-10 14:58:45 -07001901 output->sib_present = false; /* no SIB necessary */
Keith Kaniosb7a89542007-04-12 02:40:54 +00001902 output->bytes = 0; /* no offset necessary either */
1903 output->modrm = 0xC0 | ((rfield & 7) << 3) | (i & 7);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001904 } else { /* it's a memory reference */
1905 if (input->basereg == -1
1906 && (input->indexreg == -1 || input->scale == 0)) {
1907 /* it's a pure offset */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001908 if (bits == 64 && (~input->type & IP_REL)) {
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00001909 int scale, index, base;
H. Peter Anvin6867acc2007-10-10 14:58:45 -07001910 output->sib_present = true;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00001911 scale = 0;
1912 index = 4;
1913 base = 5;
1914 output->sib = (scale << 6) | (index << 3) | base;
1915 output->bytes = 4;
1916 output->modrm = 4 | ((rfield & 7) << 3);
H. Peter Anvin6867acc2007-10-10 14:58:45 -07001917 output->rip = false;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00001918 } else {
H. Peter Anvin6867acc2007-10-10 14:58:45 -07001919 output->sib_present = false;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00001920 output->bytes = (addrbits != 16 ? 4 : 2);
1921 output->modrm = (addrbits != 16 ? 5 : 6) | ((rfield & 7) << 3);
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001922 output->rip = bits == 64;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00001923 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001924 } else { /* it's an indirection */
1925 int i = input->indexreg, b = input->basereg, s = input->scale;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001926 int32_t o = input->offset, seg = input->segment;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001927 int hb = input->hintbase, ht = input->hinttype;
1928 int t;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001929 int it, bt;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001930 int32_t ix, bx; /* register flags */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001931
H. Peter Anvine2c80182005-01-15 22:15:51 +00001932 if (s == 0)
1933 i = -1; /* make this easy, at least */
H. Peter Anvin70653092007-10-19 14:42:29 -07001934
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001935 if (i >= EXPR_REG_START && i < REG_ENUM_LIMIT) {
Keith Kaniosb7a89542007-04-12 02:40:54 +00001936 it = regvals[i];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001937 ix = reg_flags[i];
1938 } else {
Keith Kaniosb7a89542007-04-12 02:40:54 +00001939 it = -1;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001940 ix = 0;
1941 }
H. Peter Anvin70653092007-10-19 14:42:29 -07001942
H. Peter Anvinb0c54622007-10-28 23:21:46 -07001943 if (b >= EXPR_REG_START && b < REG_ENUM_LIMIT) {
Keith Kaniosb7a89542007-04-12 02:40:54 +00001944 bt = regvals[b];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001945 bx = reg_flags[b];
1946 } else {
Keith Kaniosb7a89542007-04-12 02:40:54 +00001947 bt = -1;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001948 bx = 0;
1949 }
H. Peter Anvin70653092007-10-19 14:42:29 -07001950
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001951 /* check for a 32/64-bit memory reference... */
1952 if ((ix|bx) & (BITS32|BITS64)) {
Keith Kaniosb7a89542007-04-12 02:40:54 +00001953 /* it must be a 32/64-bit memory reference. Firstly we have
1954 * to check that all registers involved are type E/Rxx. */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001955 int32_t sok = BITS32|BITS64;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001956
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001957 if (it != -1) {
1958 if (!(REG64 & ~ix) || !(REG32 & ~ix))
1959 sok &= ix;
1960 else
1961 return NULL;
1962 }
1963
1964 if (bt != -1) {
H. Peter Anvin99c4ecd2007-08-28 23:06:00 +00001965 if (REG_GPR & ~bx)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001966 return NULL; /* Invalid register */
H. Peter Anvina57e8d42007-05-30 03:44:02 +00001967 if (~sok & bx & SIZE_MASK)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001968 return NULL; /* Invalid size */
H. Peter Anvinb0c54622007-10-28 23:21:46 -07001969 sok &= bx;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001970 }
H. Peter Anvin70653092007-10-19 14:42:29 -07001971
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001972 /* While we're here, ensure the user didn't specify
1973 WORD or QWORD. */
1974 if (input->disp_size == 16 || input->disp_size == 64)
1975 return NULL;
1976
1977 if (addrbits == 16 ||
1978 (addrbits == 32 && !(sok & BITS32)) ||
1979 (addrbits == 64 && !(sok & BITS64)))
1980 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001981
Keith Kaniosb7a89542007-04-12 02:40:54 +00001982 /* now reorganize base/index */
1983 if (s == 1 && bt != it && bt != -1 && it != -1 &&
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001984 ((hb == b && ht == EAH_NOTBASE)
1985 || (hb == i && ht == EAH_MAKEBASE))) {
1986 /* swap if hints say so */
1987 t = bt, bt = it, it = t;
1988 t = bx, bx = ix, ix = t;
1989 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00001990 if (bt == it) /* convert EAX+2*EAX to 3*EAX */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001991 bt = -1, bx = 0, s++;
1992 if (bt == -1 && s == 1 && !(hb == it && ht == EAH_NOTBASE)) {
1993 /* make single reg base, unless hint */
1994 bt = it, bx = ix, it = -1, ix = 0;
1995 }
H. Peter Anvinf5843c62007-09-10 18:59:26 +00001996 if (((s == 2 && it != REG_NUM_ESP
H. Peter Anvine2c80182005-01-15 22:15:51 +00001997 && !(input->eaflags & EAF_TIMESTWO)) || s == 3
Keith Kaniosb7a89542007-04-12 02:40:54 +00001998 || s == 5 || s == 9) && bt == -1)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001999 bt = it, bx = ix, s--; /* convert 3*EAX to EAX+2*EAX */
Keith Kanios48af1772007-08-17 07:37:52 +00002000 if (it == -1 && (bt & 7) != REG_NUM_ESP
H. Peter Anvine2c80182005-01-15 22:15:51 +00002001 && (input->eaflags & EAF_TIMESTWO))
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002002 it = bt, ix = bx, bt = -1, bx = 0, s = 1;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002003 /* convert [NOSPLIT EAX] to sib format with 0x0 displacement */
Keith Kanios48af1772007-08-17 07:37:52 +00002004 if (s == 1 && it == REG_NUM_ESP) {
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002005 /* swap ESP into base if scale is 1 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002006 t = it, it = bt, bt = t;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002007 t = ix, ix = bx, bx = t;
2008 }
Keith Kanios48af1772007-08-17 07:37:52 +00002009 if (it == REG_NUM_ESP
Keith Kaniosb7a89542007-04-12 02:40:54 +00002010 || (s != 1 && s != 2 && s != 4 && s != 8 && it != -1))
H. Peter Anvine2c80182005-01-15 22:15:51 +00002011 return NULL; /* wrong, for various reasons */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002012
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002013 output->rex |= rexflags(it, ix, REX_X);
2014 output->rex |= rexflags(bt, bx, REX_B);
Keith Kaniosb7a89542007-04-12 02:40:54 +00002015
Keith Kanios48af1772007-08-17 07:37:52 +00002016 if (it == -1 && (bt & 7) != REG_NUM_ESP) {
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002017 /* no SIB needed */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002018 int mod, rm;
H. Peter Anvin70653092007-10-19 14:42:29 -07002019
Keith Kaniosb7a89542007-04-12 02:40:54 +00002020 if (bt == -1) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002021 rm = 5;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002022 mod = 0;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002023 } else {
2024 rm = (bt & 7);
Keith Kanios48af1772007-08-17 07:37:52 +00002025 if (rm != REG_NUM_EBP && o == 0 &&
Keith Kaniosb7a89542007-04-12 02:40:54 +00002026 seg == NO_SEG && !forw_ref &&
2027 !(input->eaflags &
2028 (EAF_BYTEOFFS | EAF_WORDOFFS)))
2029 mod = 0;
2030 else if (input->eaflags & EAF_BYTEOFFS ||
2031 (o >= -128 && o <= 127 && seg == NO_SEG
2032 && !forw_ref
2033 && !(input->eaflags & EAF_WORDOFFS)))
2034 mod = 1;
2035 else
2036 mod = 2;
2037 }
H. Peter Anvinea838272002-04-30 20:51:53 +00002038
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002039 output->sib_present = false;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002040 output->bytes = (bt == -1 || mod == 2 ? 4 : mod);
2041 output->modrm = (mod << 6) | ((rfield & 7) << 3) | rm;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002042 } else {
2043 /* we need a SIB */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002044 int mod, scale, index, base;
H. Peter Anvin70653092007-10-19 14:42:29 -07002045
Keith Kaniosb7a89542007-04-12 02:40:54 +00002046 if (it == -1)
2047 index = 4, s = 1;
2048 else
2049 index = (it & 7);
H. Peter Anvin70653092007-10-19 14:42:29 -07002050
H. Peter Anvine2c80182005-01-15 22:15:51 +00002051 switch (s) {
2052 case 1:
2053 scale = 0;
2054 break;
2055 case 2:
2056 scale = 1;
2057 break;
2058 case 4:
2059 scale = 2;
2060 break;
2061 case 8:
2062 scale = 3;
2063 break;
2064 default: /* then what the smeg is it? */
2065 return NULL; /* panic */
2066 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002067
Keith Kaniosb7a89542007-04-12 02:40:54 +00002068 if (bt == -1) {
2069 base = 5;
2070 mod = 0;
2071 } else {
2072 base = (bt & 7);
Keith Kanios48af1772007-08-17 07:37:52 +00002073 if (base != REG_NUM_EBP && o == 0 &&
H. Peter Anvine2c80182005-01-15 22:15:51 +00002074 seg == NO_SEG && !forw_ref &&
2075 !(input->eaflags &
Keith Kaniosb7a89542007-04-12 02:40:54 +00002076 (EAF_BYTEOFFS | EAF_WORDOFFS)))
2077 mod = 0;
2078 else if (input->eaflags & EAF_BYTEOFFS ||
2079 (o >= -128 && o <= 127 && seg == NO_SEG
2080 && !forw_ref
2081 && !(input->eaflags & EAF_WORDOFFS)))
2082 mod = 1;
2083 else
2084 mod = 2;
2085 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002086
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002087 output->sib_present = true;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002088 output->bytes = (bt == -1 || mod == 2 ? 4 : mod);
2089 output->modrm = (mod << 6) | ((rfield & 7) << 3) | 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002090 output->sib = (scale << 6) | (index << 3) | base;
2091 }
2092 } else { /* it's 16-bit */
2093 int mod, rm;
H. Peter Anvin70653092007-10-19 14:42:29 -07002094
Keith Kaniosb7a89542007-04-12 02:40:54 +00002095 /* check for 64-bit long mode */
2096 if (addrbits == 64)
2097 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002098
H. Peter Anvine2c80182005-01-15 22:15:51 +00002099 /* check all registers are BX, BP, SI or DI */
2100 if ((b != -1 && b != R_BP && b != R_BX && b != R_SI
2101 && b != R_DI) || (i != -1 && i != R_BP && i != R_BX
2102 && i != R_SI && i != R_DI))
2103 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002104
Keith Kaniosb7a89542007-04-12 02:40:54 +00002105 /* ensure the user didn't specify DWORD/QWORD */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002106 if (input->disp_size == 32 || input->disp_size == 64)
H. Peter Anvine2c80182005-01-15 22:15:51 +00002107 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002108
H. Peter Anvine2c80182005-01-15 22:15:51 +00002109 if (s != 1 && i != -1)
2110 return NULL; /* no can do, in 16-bit EA */
2111 if (b == -1 && i != -1) {
2112 int tmp = b;
2113 b = i;
2114 i = tmp;
2115 } /* swap */
2116 if ((b == R_SI || b == R_DI) && i != -1) {
2117 int tmp = b;
2118 b = i;
2119 i = tmp;
2120 }
2121 /* have BX/BP as base, SI/DI index */
2122 if (b == i)
2123 return NULL; /* shouldn't ever happen, in theory */
2124 if (i != -1 && b != -1 &&
2125 (i == R_BP || i == R_BX || b == R_SI || b == R_DI))
2126 return NULL; /* invalid combinations */
2127 if (b == -1) /* pure offset: handled above */
2128 return NULL; /* so if it gets to here, panic! */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002129
H. Peter Anvine2c80182005-01-15 22:15:51 +00002130 rm = -1;
2131 if (i != -1)
2132 switch (i * 256 + b) {
2133 case R_SI * 256 + R_BX:
2134 rm = 0;
2135 break;
2136 case R_DI * 256 + R_BX:
2137 rm = 1;
2138 break;
2139 case R_SI * 256 + R_BP:
2140 rm = 2;
2141 break;
2142 case R_DI * 256 + R_BP:
2143 rm = 3;
2144 break;
2145 } else
2146 switch (b) {
2147 case R_SI:
2148 rm = 4;
2149 break;
2150 case R_DI:
2151 rm = 5;
2152 break;
2153 case R_BP:
2154 rm = 6;
2155 break;
2156 case R_BX:
2157 rm = 7;
2158 break;
2159 }
2160 if (rm == -1) /* can't happen, in theory */
2161 return NULL; /* so panic if it does */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002162
H. Peter Anvine2c80182005-01-15 22:15:51 +00002163 if (o == 0 && seg == NO_SEG && !forw_ref && rm != 6 &&
2164 !(input->eaflags & (EAF_BYTEOFFS | EAF_WORDOFFS)))
2165 mod = 0;
2166 else if (input->eaflags & EAF_BYTEOFFS ||
2167 (o >= -128 && o <= 127 && seg == NO_SEG
2168 && !forw_ref
2169 && !(input->eaflags & EAF_WORDOFFS)))
2170 mod = 1;
2171 else
2172 mod = 2;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002173
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002174 output->sib_present = false; /* no SIB - it's 16-bit */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002175 output->bytes = mod; /* bytes of offset needed */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002176 output->modrm = (mod << 6) | ((rfield & 7) << 3) | rm;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002177 }
2178 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002179 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002180
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002181 output->size = 1 + output->sib_present + output->bytes;
2182 return output;
2183}
2184
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002185static void add_asp(insn *ins, int addrbits)
H. Peter Anvineba20a72002-04-30 20:53:55 +00002186{
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002187 int j, valid;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002188 int defdisp;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002189
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002190 valid = (addrbits == 64) ? 64|32 : 32|16;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002191
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002192 switch (ins->prefixes[PPS_ASIZE]) {
2193 case P_A16:
2194 valid &= 16;
2195 break;
2196 case P_A32:
2197 valid &= 32;
2198 break;
2199 case P_A64:
2200 valid &= 64;
2201 break;
2202 case P_ASP:
2203 valid &= (addrbits == 32) ? 16 : 32;
2204 break;
2205 default:
2206 break;
2207 }
2208
2209 for (j = 0; j < ins->operands; j++) {
2210 if (!(MEMORY & ~ins->oprs[j].type)) {
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002211 int32_t i, b;
H. Peter Anvin70653092007-10-19 14:42:29 -07002212
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002213 /* Verify as Register */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002214 if (ins->oprs[j].indexreg < EXPR_REG_START
2215 || ins->oprs[j].indexreg >= REG_ENUM_LIMIT)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002216 i = 0;
2217 else
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002218 i = reg_flags[ins->oprs[j].indexreg];
H. Peter Anvin70653092007-10-19 14:42:29 -07002219
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002220 /* Verify as Register */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002221 if (ins->oprs[j].basereg < EXPR_REG_START
2222 || ins->oprs[j].basereg >= REG_ENUM_LIMIT)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002223 b = 0;
2224 else
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002225 b = reg_flags[ins->oprs[j].basereg];
H. Peter Anvin70653092007-10-19 14:42:29 -07002226
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002227 if (ins->oprs[j].scale == 0)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002228 i = 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002229
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002230 if (!i && !b) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002231 int ds = ins->oprs[j].disp_size;
2232 if ((addrbits != 64 && ds > 8) ||
2233 (addrbits == 64 && ds == 16))
2234 valid &= ds;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002235 } else {
2236 if (!(REG16 & ~b))
2237 valid &= 16;
2238 if (!(REG32 & ~b))
2239 valid &= 32;
2240 if (!(REG64 & ~b))
2241 valid &= 64;
H. Peter Anvin70653092007-10-19 14:42:29 -07002242
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002243 if (!(REG16 & ~i))
2244 valid &= 16;
2245 if (!(REG32 & ~i))
2246 valid &= 32;
2247 if (!(REG64 & ~i))
2248 valid &= 64;
2249 }
2250 }
2251 }
2252
2253 if (valid & addrbits) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002254 ins->addr_size = addrbits;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002255 } else if (valid & ((addrbits == 32) ? 16 : 32)) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002256 /* Add an address size prefix */
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002257 enum prefixes pref = (addrbits == 32) ? P_A16 : P_A32;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002258 ins->prefixes[PPS_ASIZE] = pref;
2259 ins->addr_size = (addrbits == 32) ? 16 : 32;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002260 } else {
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002261 /* Impossible... */
2262 errfunc(ERR_NONFATAL, "impossible combination of address sizes");
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002263 ins->addr_size = addrbits; /* Error recovery */
2264 }
2265
2266 defdisp = ins->addr_size == 16 ? 16 : 32;
2267
2268 for (j = 0; j < ins->operands; j++) {
2269 if (!(MEM_OFFS & ~ins->oprs[j].type) &&
2270 (ins->oprs[j].disp_size ? ins->oprs[j].disp_size : defdisp)
2271 != ins->addr_size) {
2272 /* mem_offs sizes must match the address size; if not,
2273 strip the MEM_OFFS bit and match only EA instructions */
2274 ins->oprs[j].type &= ~(MEM_OFFS & ~MEMORY);
2275 }
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002276 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002277}