blob: 681af699ac31edc8046848e1cfb67884993620bd [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;
H. Peter Anvind387b8c2008-01-27 16:39:26 -0800315 out(offset, segment,
316 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0",
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800317 OUT_RAWDATA, align, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000318 }
319 offset += e->stringlen + align;
320 }
321 }
322 if (t > 0 && t == instruction->times - 1) {
323 /*
324 * Dummy call to list->output to give the offset to the
325 * listing module.
326 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800327 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000328 list->uplevel(LIST_TIMES);
329 }
330 }
331 if (instruction->times > 1)
332 list->downlevel(LIST_TIMES);
333 return offset - start;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000334 }
335
H. Peter Anvine2c80182005-01-15 22:15:51 +0000336 if (instruction->opcode == I_INCBIN) {
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000337 static char fname[FILENAME_MAX];
H. Peter Anvine2c80182005-01-15 22:15:51 +0000338 FILE *fp;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000339 int32_t len;
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000340 char *prefix = "", *combine;
341 char **pPrevPath = NULL;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000342
H. Peter Anvine2c80182005-01-15 22:15:51 +0000343 len = FILENAME_MAX - 1;
344 if (len > instruction->eops->stringlen)
345 len = instruction->eops->stringlen;
346 strncpy(fname, instruction->eops->stringval, len);
347 fname[len] = '\0';
H. Peter Anvineba20a72002-04-30 20:53:55 +0000348
Keith Kaniosb7a89542007-04-12 02:40:54 +0000349 while (1) { /* added by alexfru: 'incbin' uses include paths */
H. Peter Anvine2c80182005-01-15 22:15:51 +0000350 combine = nasm_malloc(strlen(prefix) + len + 1);
351 strcpy(combine, prefix);
352 strcat(combine, fname);
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000353
H. Peter Anvine2c80182005-01-15 22:15:51 +0000354 if ((fp = fopen(combine, "rb")) != NULL) {
355 nasm_free(combine);
356 break;
357 }
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000358
H. Peter Anvine2c80182005-01-15 22:15:51 +0000359 nasm_free(combine);
360 pPrevPath = pp_get_include_path_ptr(pPrevPath);
361 if (pPrevPath == NULL)
362 break;
363 prefix = *pPrevPath;
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000364 }
365
366 if (fp == NULL)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000367 error(ERR_NONFATAL, "`incbin': unable to open file `%s'",
368 fname);
369 else if (fseek(fp, 0L, SEEK_END) < 0)
370 error(ERR_NONFATAL, "`incbin': unable to seek on file `%s'",
371 fname);
372 else {
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000373 static char buf[2048];
Keith Kaniosb7a89542007-04-12 02:40:54 +0000374 int32_t t = instruction->times;
375 int32_t base = 0;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000376
H. Peter Anvine2c80182005-01-15 22:15:51 +0000377 len = ftell(fp);
378 if (instruction->eops->next) {
379 base = instruction->eops->next->offset;
380 len -= base;
381 if (instruction->eops->next->next &&
382 len > instruction->eops->next->next->offset)
383 len = instruction->eops->next->next->offset;
384 }
385 /*
386 * Dummy call to list->output to give the offset to the
387 * listing module.
388 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800389 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000390 list->uplevel(LIST_INCBIN);
391 while (t--) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000392 int32_t l;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000393
H. Peter Anvine2c80182005-01-15 22:15:51 +0000394 fseek(fp, base, SEEK_SET);
395 l = len;
396 while (l > 0) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000397 int32_t m =
Charles Crayne192d5b52007-10-18 19:02:42 -0700398 fread(buf, 1, (l > (int32_t) sizeof(buf) ? (int32_t) sizeof(buf) : l),
H. Peter Anvine2c80182005-01-15 22:15:51 +0000399 fp);
400 if (!m) {
401 /*
402 * This shouldn't happen unless the file
403 * actually changes while we are reading
404 * it.
405 */
406 error(ERR_NONFATAL,
407 "`incbin': unexpected EOF while"
408 " reading file `%s'", fname);
409 t = 0; /* Try to exit cleanly */
410 break;
411 }
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800412 out(offset, segment, buf, OUT_RAWDATA, m,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000413 NO_SEG, NO_SEG);
414 l -= m;
415 }
416 }
417 list->downlevel(LIST_INCBIN);
418 if (instruction->times > 1) {
419 /*
420 * Dummy call to list->output to give the offset to the
421 * listing module.
422 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800423 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000424 list->uplevel(LIST_TIMES);
425 list->downlevel(LIST_TIMES);
426 }
427 fclose(fp);
428 return instruction->times * len;
429 }
430 return 0; /* if we're here, there's an error */
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000431 }
432
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700433 /* Check to see if we need an address-size prefix */
434 add_asp(instruction, bits);
435
H. Peter Anvin6867acc2007-10-10 14:58:45 -0700436 size_prob = false;
H. Peter Anvin70653092007-10-19 14:42:29 -0700437
438 for (temp = nasm_instructions[instruction->opcode]; temp->opcode != -1; temp++){
Keith Kaniosb7a89542007-04-12 02:40:54 +0000439 int m = matches(temp, instruction, bits);
H. Peter Anvin70653092007-10-19 14:42:29 -0700440
H. Peter Anvine2c80182005-01-15 22:15:51 +0000441 if (m == 99)
442 m += jmp_match(segment, offset, bits, instruction, temp->code);
H. Peter Anvineba20a72002-04-30 20:53:55 +0000443
H. Peter Anvine2c80182005-01-15 22:15:51 +0000444 if (m == 100) { /* matches! */
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000445 const char *codes = temp->code;
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800446 int64_t insn_size = calcsize(segment, offset, bits,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000447 instruction, codes);
448 itimes = instruction->times;
449 if (insn_size < 0) /* shouldn't be, on pass two */
450 error(ERR_PANIC, "errors made it through from pass one");
451 else
452 while (itimes--) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700453 for (j = 0; j < MAXPREFIX; j++) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000454 uint8_t c = 0;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000455 switch (instruction->prefixes[j]) {
456 case P_LOCK:
457 c = 0xF0;
458 break;
459 case P_REPNE:
460 case P_REPNZ:
461 c = 0xF2;
462 break;
463 case P_REPE:
464 case P_REPZ:
465 case P_REP:
466 c = 0xF3;
467 break;
468 case R_CS:
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000469 if (bits == 64) {
470 error(ERR_WARNING,
Charles Crayne1b851dc2007-11-05 21:49:49 -0800471 "cs segment base generated, but will be ignored in 64-bit mode");
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000472 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000473 c = 0x2E;
474 break;
475 case R_DS:
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000476 if (bits == 64) {
477 error(ERR_WARNING,
Charles Crayne1b851dc2007-11-05 21:49:49 -0800478 "ds segment base generated, but will be ignored in 64-bit mode");
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000479 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000480 c = 0x3E;
481 break;
482 case R_ES:
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000483 if (bits == 64) {
484 error(ERR_WARNING,
Charles Crayne1b851dc2007-11-05 21:49:49 -0800485 "es segment base generated, but will be ignored in 64-bit mode");
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000486 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000487 c = 0x26;
488 break;
489 case R_FS:
490 c = 0x64;
491 break;
492 case R_GS:
493 c = 0x65;
494 break;
495 case R_SS:
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000496 if (bits == 64) {
497 error(ERR_WARNING,
Charles Crayne1b851dc2007-11-05 21:49:49 -0800498 "ss segment base generated, but will be ignored in 64-bit mode");
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000499 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000500 c = 0x36;
501 break;
502 case R_SEGR6:
503 case R_SEGR7:
504 error(ERR_NONFATAL,
505 "segr6 and segr7 cannot be used as prefixes");
506 break;
507 case P_A16:
Keith Kaniosb7a89542007-04-12 02:40:54 +0000508 if (bits == 64) {
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000509 error(ERR_NONFATAL,
510 "16-bit addressing is not supported "
511 "in 64-bit mode");
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700512 } else if (bits != 16)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000513 c = 0x67;
514 break;
515 case P_A32:
516 if (bits != 32)
517 c = 0x67;
518 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700519 case P_A64:
520 if (bits != 64) {
521 error(ERR_NONFATAL,
522 "64-bit addressing is only supported "
523 "in 64-bit mode");
524 }
525 break;
526 case P_ASP:
527 c = 0x67;
528 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000529 case P_O16:
530 if (bits != 16)
531 c = 0x66;
532 break;
533 case P_O32:
Keith Kaniosb7a89542007-04-12 02:40:54 +0000534 if (bits == 16)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000535 c = 0x66;
536 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700537 case P_O64:
538 /* REX.W */
539 break;
540 case P_OSP:
541 c = 0x66;
542 break;
543 case P_none:
544 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000545 default:
546 error(ERR_PANIC, "invalid instruction prefix");
547 }
548 if (c != 0) {
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800549 out(offset, segment, &c, OUT_RAWDATA, 1,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000550 NO_SEG, NO_SEG);
551 offset++;
552 }
H. Peter Anvin70653092007-10-19 14:42:29 -0700553 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000554 insn_end = offset + insn_size;
555 gencode(segment, offset, bits, instruction, codes,
556 insn_end);
557 offset += insn_size;
558 if (itimes > 0 && itimes == instruction->times - 1) {
559 /*
560 * Dummy call to list->output to give the offset to the
561 * listing module.
562 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800563 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000564 list->uplevel(LIST_TIMES);
565 }
566 }
567 if (instruction->times > 1)
568 list->downlevel(LIST_TIMES);
569 return offset - start;
570 } else if (m > 0 && m > size_prob) {
571 size_prob = m;
572 }
Keith Kaniosb7a89542007-04-12 02:40:54 +0000573// temp++;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000574 }
H. Peter Anvineba20a72002-04-30 20:53:55 +0000575
H. Peter Anvine2c80182005-01-15 22:15:51 +0000576 if (temp->opcode == -1) { /* didn't match any instruction */
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000577 switch (size_prob) {
578 case 1:
579 error(ERR_NONFATAL, "operation size not specified");
580 break;
581 case 2:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000582 error(ERR_NONFATAL, "mismatch in operand sizes");
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000583 break;
584 case 3:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000585 error(ERR_NONFATAL, "no instruction for this cpu level");
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000586 break;
587 case 4:
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000588 error(ERR_NONFATAL, "instruction not supported in 64-bit mode");
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000589 break;
590 default:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000591 error(ERR_NONFATAL,
592 "invalid combination of opcode and operands");
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000593 break;
594 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000595 }
596 return 0;
597}
598
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800599int64_t insn_size(int32_t segment, int64_t offset, int bits, uint32_t cp,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000600 insn * instruction, efunc error)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000601{
H. Peter Anvin3360d792007-09-11 04:16:57 +0000602 const struct itemplate *temp;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000603
H. Peter Anvine2c80182005-01-15 22:15:51 +0000604 errfunc = error; /* to pass to other functions */
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000605 cpu = cp;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000606
607 if (instruction->opcode == -1)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000608 return 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000609
H. Peter Anvincfbe7c32007-09-18 17:49:09 -0700610 if (instruction->opcode == I_DB || instruction->opcode == I_DW ||
611 instruction->opcode == I_DD || instruction->opcode == I_DQ ||
612 instruction->opcode == I_DT || instruction->opcode == I_DO) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000613 extop *e;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000614 int32_t isize, osize, wsize = 0; /* placate gcc */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000615
H. Peter Anvine2c80182005-01-15 22:15:51 +0000616 isize = 0;
617 switch (instruction->opcode) {
618 case I_DB:
619 wsize = 1;
620 break;
621 case I_DW:
622 wsize = 2;
623 break;
624 case I_DD:
625 wsize = 4;
626 break;
627 case I_DQ:
628 wsize = 8;
629 break;
630 case I_DT:
631 wsize = 10;
632 break;
H. Peter Anvincfbe7c32007-09-18 17:49:09 -0700633 case I_DO:
634 wsize = 16;
635 break;
H. Peter Anvin16b0a332007-09-12 20:27:41 -0700636 default:
637 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000638 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000639
H. Peter Anvine2c80182005-01-15 22:15:51 +0000640 for (e = instruction->eops; e; e = e->next) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000641 int32_t align;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000642
H. Peter Anvine2c80182005-01-15 22:15:51 +0000643 osize = 0;
644 if (e->type == EOT_DB_NUMBER)
645 osize = 1;
646 else if (e->type == EOT_DB_STRING)
647 osize = e->stringlen;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000648
H. Peter Anvine2c80182005-01-15 22:15:51 +0000649 align = (-osize) % wsize;
650 if (align < 0)
651 align += wsize;
652 isize += osize + align;
653 }
654 return isize * instruction->times;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000655 }
656
H. Peter Anvine2c80182005-01-15 22:15:51 +0000657 if (instruction->opcode == I_INCBIN) {
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000658 char fname[FILENAME_MAX];
H. Peter Anvine2c80182005-01-15 22:15:51 +0000659 FILE *fp;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000660 int32_t len;
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000661 char *prefix = "", *combine;
662 char **pPrevPath = NULL;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000663
H. Peter Anvine2c80182005-01-15 22:15:51 +0000664 len = FILENAME_MAX - 1;
665 if (len > instruction->eops->stringlen)
666 len = instruction->eops->stringlen;
667 strncpy(fname, instruction->eops->stringval, len);
668 fname[len] = '\0';
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000669
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700670 /* added by alexfru: 'incbin' uses include paths */
671 while (1) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000672 combine = nasm_malloc(strlen(prefix) + len + 1);
673 strcpy(combine, prefix);
674 strcat(combine, fname);
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000675
H. Peter Anvine2c80182005-01-15 22:15:51 +0000676 if ((fp = fopen(combine, "rb")) != NULL) {
677 nasm_free(combine);
678 break;
679 }
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000680
H. Peter Anvine2c80182005-01-15 22:15:51 +0000681 nasm_free(combine);
682 pPrevPath = pp_get_include_path_ptr(pPrevPath);
683 if (pPrevPath == NULL)
684 break;
685 prefix = *pPrevPath;
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000686 }
687
688 if (fp == NULL)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000689 error(ERR_NONFATAL, "`incbin': unable to open file `%s'",
690 fname);
691 else if (fseek(fp, 0L, SEEK_END) < 0)
692 error(ERR_NONFATAL, "`incbin': unable to seek on file `%s'",
693 fname);
694 else {
695 len = ftell(fp);
696 fclose(fp);
697 if (instruction->eops->next) {
698 len -= instruction->eops->next->offset;
699 if (instruction->eops->next->next &&
700 len > instruction->eops->next->next->offset) {
701 len = instruction->eops->next->next->offset;
702 }
703 }
704 return instruction->times * len;
705 }
706 return 0; /* if we're here, there's an error */
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000707 }
708
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700709 /* Check to see if we need an address-size prefix */
710 add_asp(instruction, bits);
711
Keith Kaniosb7a89542007-04-12 02:40:54 +0000712 for (temp = nasm_instructions[instruction->opcode]; temp->opcode != -1; temp++) {
713 int m = matches(temp, instruction, bits);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000714 if (m == 99)
715 m += jmp_match(segment, offset, bits, instruction, temp->code);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000716
H. Peter Anvine2c80182005-01-15 22:15:51 +0000717 if (m == 100) {
718 /* we've matched an instruction. */
Charles Crayne5fbbc8c2007-11-07 19:03:46 -0800719 int64_t isize;
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000720 const char *codes = temp->code;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000721 int j;
722
723 isize = calcsize(segment, offset, bits, instruction, codes);
724 if (isize < 0)
725 return -1;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700726 for (j = 0; j < MAXPREFIX; j++) {
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700727 switch (instruction->prefixes[j]) {
728 case P_A16:
729 if (bits != 16)
730 isize++;
731 break;
732 case P_A32:
733 if (bits != 32)
734 isize++;
735 break;
736 case P_O16:
737 if (bits != 16)
738 isize++;
739 break;
740 case P_O32:
741 if (bits == 16)
742 isize++;
743 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700744 case P_A64:
745 case P_O64:
746 case P_none:
747 break;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700748 default:
749 isize++;
750 break;
751 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000752 }
753 return isize * instruction->times;
754 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000755 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000756 return -1; /* didn't match any instruction */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000757}
758
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000759/* check that opn[op] is a signed byte of size 16 or 32,
760 and return the signed value*/
H. Peter Anvine2c80182005-01-15 22:15:51 +0000761static int is_sbyte(insn * ins, int op, int size)
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000762{
Keith Kaniosb7a89542007-04-12 02:40:54 +0000763 int32_t v;
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000764 int ret;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000765
766 ret = !(ins->forw_ref && ins->oprs[op].opflags) && /* dead in the water on forward reference or External */
767 optimizing >= 0 &&
768 !(ins->oprs[op].type & STRICT) &&
769 ins->oprs[op].wrt == NO_SEG && ins->oprs[op].segment == NO_SEG;
H. Peter Anvin734b1882002-04-30 21:01:08 +0000770
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000771 v = ins->oprs[op].offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000772 if (size == 16)
Keith Kaniosb7a89542007-04-12 02:40:54 +0000773 v = (int16_t)v; /* sign extend if 16 bits */
H. Peter Anvine2c80182005-01-15 22:15:51 +0000774
775 return ret && v >= -128L && v <= 127L;
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000776}
777
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800778static int64_t calcsize(int32_t segment, int64_t offset, int bits,
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000779 insn * ins, const char *codes)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000780{
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800781 int64_t length = 0;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000782 uint8_t c;
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000783 int rex_mask = ~0;
H. Peter Anvin839eca22007-10-29 23:12:47 -0700784 struct operand *opx;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000785
H. Peter Anvine3917fc2007-11-01 14:53:32 -0700786 ins->rex = 0; /* Ensure REX is reset */
787
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700788 if (ins->prefixes[PPS_OSIZE] == P_O64)
789 ins->rex |= REX_W;
790
H. Peter Anvine2c80182005-01-15 22:15:51 +0000791 (void)segment; /* Don't warn that this parameter is unused */
792 (void)offset; /* Don't warn that this parameter is unused */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000793
H. Peter Anvin839eca22007-10-29 23:12:47 -0700794 while (*codes) {
795 c = *codes++;
796 opx = &ins->oprs[c & 3];
797 switch (c) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000798 case 01:
799 case 02:
800 case 03:
801 codes += c, length += c;
802 break;
803 case 04:
804 case 05:
805 case 06:
806 case 07:
807 length++;
808 break;
809 case 010:
810 case 011:
811 case 012:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700812 case 013:
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000813 ins->rex |=
H. Peter Anvin839eca22007-10-29 23:12:47 -0700814 op_rexflags(opx, REX_B|REX_H|REX_P|REX_W);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000815 codes++, length++;
816 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000817 case 014:
818 case 015:
819 case 016:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700820 case 017:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000821 length++;
822 break;
823 case 020:
824 case 021:
825 case 022:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700826 case 023:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000827 length++;
828 break;
829 case 024:
830 case 025:
831 case 026:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700832 case 027:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000833 length++;
834 break;
835 case 030:
836 case 031:
837 case 032:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700838 case 033:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000839 length += 2;
840 break;
841 case 034:
842 case 035:
843 case 036:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700844 case 037:
H. Peter Anvin839eca22007-10-29 23:12:47 -0700845 if (opx->type & (BITS16 | BITS32 | BITS64))
846 length += (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000847 else
848 length += (bits == 16) ? 2 : 4;
849 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000850 case 040:
851 case 041:
852 case 042:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700853 case 043:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000854 length += 4;
855 break;
856 case 044:
857 case 045:
858 case 046:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700859 case 047:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700860 length += ins->addr_size >> 3;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000861 break;
862 case 050:
863 case 051:
864 case 052:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700865 case 053:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000866 length++;
867 break;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000868 case 054:
869 case 055:
870 case 056:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700871 case 057:
Keith Kaniosb7a89542007-04-12 02:40:54 +0000872 length += 8; /* MOV reg64/imm */
873 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000874 case 060:
875 case 061:
876 case 062:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700877 case 063:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000878 length += 2;
879 break;
880 case 064:
881 case 065:
882 case 066:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700883 case 067:
H. Peter Anvin839eca22007-10-29 23:12:47 -0700884 if (opx->type & (BITS16 | BITS32 | BITS64))
885 length += (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000886 else
887 length += (bits == 16) ? 2 : 4;
888 break;
889 case 070:
890 case 071:
891 case 072:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700892 case 073:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000893 length += 4;
894 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700895 case 074:
896 case 075:
897 case 076:
898 case 077:
899 length += 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000900 break;
901 case 0140:
902 case 0141:
903 case 0142:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700904 case 0143:
H. Peter Anvin839eca22007-10-29 23:12:47 -0700905 length += is_sbyte(ins, c & 3, 16) ? 1 : 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000906 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000907 case 0144:
908 case 0145:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700909 case 0146:
910 case 0147:
H. Peter Anvina30cc072007-11-18 21:55:26 -0800911 codes++;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000912 length++;
913 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700914 case 0150:
915 case 0151:
916 case 0152:
917 case 0153:
H. Peter Anvin839eca22007-10-29 23:12:47 -0700918 length += is_sbyte(ins, c & 3, 32) ? 1 : 4;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700919 break;
920 case 0154:
921 case 0155:
922 case 0156:
923 case 0157:
H. Peter Anvina30cc072007-11-18 21:55:26 -0800924 codes++;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700925 length++;
926 break;
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700927 case 0160:
928 case 0161:
929 case 0162:
930 case 0163:
931 length++;
932 ins->rex |= REX_D;
H. Peter Anvincf5180a2007-09-17 17:25:27 -0700933 ins->drexdst = regval(&ins->oprs[c & 3]);
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700934 break;
935 case 0164:
936 case 0165:
937 case 0166:
938 case 0167:
939 length++;
940 ins->rex |= REX_D|REX_OC;
H. Peter Anvincf5180a2007-09-17 17:25:27 -0700941 ins->drexdst = regval(&ins->oprs[c & 3]);
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700942 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700943 case 0170:
944 length++;
945 break;
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700946 case 0171:
947 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000948 case 0300:
949 case 0301:
H. Peter Anvin70653092007-10-19 14:42:29 -0700950 case 0302:
951 case 0303:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000952 break;
953 case 0310:
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700954 if (bits == 64)
955 return -1;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700956 length += (bits != 16) && !has_prefix(ins, PPS_ASIZE, P_A16);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000957 break;
958 case 0311:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700959 length += (bits != 32) && !has_prefix(ins, PPS_ASIZE, P_A32);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000960 break;
961 case 0312:
H. Peter Anvin70653092007-10-19 14:42:29 -0700962 break;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000963 case 0313:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700964 if (bits != 64 || has_prefix(ins, PPS_ASIZE, P_A16) ||
965 has_prefix(ins, PPS_ASIZE, P_A32))
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700966 return -1;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000967 break;
H. Peter Anvin23440102007-11-12 21:02:33 -0800968 case 0314:
969 case 0315:
970 case 0316:
971 case 0317:
972 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000973 case 0320:
Keith Kaniosb7a89542007-04-12 02:40:54 +0000974 length += (bits != 16);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000975 break;
976 case 0321:
977 length += (bits == 16);
978 break;
979 case 0322:
980 break;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000981 case 0323:
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000982 rex_mask &= ~REX_W;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000983 break;
984 case 0324:
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000985 ins->rex |= REX_W;
H. Peter Anvin8d7316a2007-04-18 02:27:18 +0000986 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000987 case 0330:
988 codes++, length++;
989 break;
990 case 0331:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000991 break;
H. Peter Anvincb9b6902007-09-12 21:58:51 -0700992 case 0332:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000993 case 0333:
994 length++;
995 break;
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000996 case 0334:
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000997 ins->rex |= REX_L;
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000998 break;
H. Peter Anvincb9b6902007-09-12 21:58:51 -0700999 case 0335:
1000 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001001 case 0340:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001002 if (ins->oprs[0].segment != NO_SEG)
1003 errfunc(ERR_NONFATAL, "attempt to reserve non-constant"
1004 " quantity of BSS space");
1005 else
H. Peter Anvin428fd672007-11-15 10:25:52 -08001006 length += ins->oprs[0].offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001007 break;
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001008 case 0364:
1009 case 0365:
1010 break;
Keith Kanios48af1772007-08-17 07:37:52 +00001011 case 0366:
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001012 case 0367:
1013 length++;
1014 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001015 case 0370:
1016 case 0371:
1017 case 0372:
1018 break;
1019 case 0373:
1020 length++;
1021 break;
1022 default: /* can't do it by 'case' statements */
1023 if (c >= 0100 && c <= 0277) { /* it's an EA */
1024 ea ea_data;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001025 int rfield;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001026 int32_t rflags;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001027 ea_data.rex = 0; /* Ensure ea.REX is initially 0 */
H. Peter Anvin70653092007-10-19 14:42:29 -07001028
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001029 if (c <= 0177) {
1030 /* pick rfield from operand b */
1031 rflags = regflag(&ins->oprs[c & 7]);
1032 rfield = regvals[ins->oprs[c & 7].basereg];
1033 } else {
1034 rflags = 0;
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001035 rfield = c & 7;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001036 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00001037
H. Peter Anvine2c80182005-01-15 22:15:51 +00001038 if (!process_ea
Keith Kaniosb7a89542007-04-12 02:40:54 +00001039 (&ins->oprs[(c >> 3) & 7], &ea_data, bits,
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001040 ins->addr_size, rfield, rflags, ins->forw_ref)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001041 errfunc(ERR_NONFATAL, "invalid effective address");
1042 return -1;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001043 } else {
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001044 ins->rex |= ea_data.rex;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001045 length += ea_data.size;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001046 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001047 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001048 errfunc(ERR_PANIC, "internal instruction table corrupt"
1049 ": instruction code 0x%02X given", c);
H. Peter Anvin839eca22007-10-29 23:12:47 -07001050 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001051 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001052 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001053
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001054 ins->rex &= rex_mask;
H. Peter Anvin70653092007-10-19 14:42:29 -07001055
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001056 if (ins->rex & REX_D) {
1057 if (ins->rex & REX_H) {
1058 errfunc(ERR_NONFATAL, "cannot use high register in drex instruction");
1059 return -1;
1060 }
H. Peter Anvincf5180a2007-09-17 17:25:27 -07001061 if (bits != 64 && ((ins->rex & (REX_W|REX_X|REX_B)) ||
1062 ins->drexdst > 7)) {
1063 errfunc(ERR_NONFATAL, "invalid operands in non-64-bit mode");
1064 return -1;
1065 }
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001066 length++;
1067 } else if (ins->rex & REX_REAL) {
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001068 if (ins->rex & REX_H) {
1069 errfunc(ERR_NONFATAL, "cannot use high register in rex instruction");
1070 return -1;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001071 } else if (bits == 64) {
1072 length++;
1073 } else if ((ins->rex & REX_L) &&
1074 !(ins->rex & (REX_P|REX_W|REX_X|REX_B)) &&
1075 cpu >= IF_X86_64) {
1076 /* LOCK-as-REX.R */
1077 assert_no_prefix(ins, PPS_LREP);
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001078 length++;
H. Peter Anvin8d7316a2007-04-18 02:27:18 +00001079 } else {
H. Peter Anvincf5180a2007-09-17 17:25:27 -07001080 errfunc(ERR_NONFATAL, "invalid operands in non-64-bit mode");
1081 return -1;
H. Peter Anvin8d7316a2007-04-18 02:27:18 +00001082 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00001083 }
1084
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001085 return length;
1086}
Keith Kaniosb7a89542007-04-12 02:40:54 +00001087
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001088#define EMIT_REX() \
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001089 if (!(ins->rex & REX_D) && (ins->rex & REX_REAL) && (bits == 64)) { \
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001090 ins->rex = (ins->rex & REX_REAL)|REX_P; \
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001091 out(offset, segment, &ins->rex, OUT_RAWDATA, 1, NO_SEG, NO_SEG); \
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001092 ins->rex = 0; \
1093 offset += 1; \
1094 }
1095
Charles Crayne1f8bc4c2007-11-06 18:27:23 -08001096static void gencode(int32_t segment, int64_t offset, int bits,
1097 insn * ins, const char *codes, int64_t insn_end)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001098{
Keith Kaniosa6dfa782007-04-13 16:47:53 +00001099 static char condval[] = { /* conditional opcodes */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001100 0x7, 0x3, 0x2, 0x6, 0x2, 0x4, 0xF, 0xD, 0xC, 0xE, 0x6, 0x2,
1101 0x3, 0x7, 0x3, 0x5, 0xE, 0xC, 0xD, 0xF, 0x1, 0xB, 0x9, 0x5,
1102 0x0, 0xA, 0xA, 0xB, 0x8, 0x4
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001103 };
Keith Kaniosb7a89542007-04-12 02:40:54 +00001104 uint8_t c;
1105 uint8_t bytes[4];
Charles Crayne1f8bc4c2007-11-06 18:27:23 -08001106 int64_t size;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001107 int64_t data;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001108 struct operand *opx;
H. Peter Anvin70653092007-10-19 14:42:29 -07001109
H. Peter Anvin839eca22007-10-29 23:12:47 -07001110 while (*codes) {
1111 c = *codes++;
1112 opx = &ins->oprs[c & 3];
1113 switch (c) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001114 case 01:
1115 case 02:
1116 case 03:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001117 EMIT_REX();
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001118 out(offset, segment, codes, OUT_RAWDATA, c, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001119 codes += c;
1120 offset += c;
1121 break;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001122
H. Peter Anvine2c80182005-01-15 22:15:51 +00001123 case 04:
1124 case 06:
1125 switch (ins->oprs[0].basereg) {
1126 case R_CS:
1127 bytes[0] = 0x0E + (c == 0x04 ? 1 : 0);
1128 break;
1129 case R_DS:
1130 bytes[0] = 0x1E + (c == 0x04 ? 1 : 0);
1131 break;
1132 case R_ES:
1133 bytes[0] = 0x06 + (c == 0x04 ? 1 : 0);
1134 break;
1135 case R_SS:
1136 bytes[0] = 0x16 + (c == 0x04 ? 1 : 0);
1137 break;
1138 default:
1139 errfunc(ERR_PANIC,
1140 "bizarre 8086 segment register received");
1141 }
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001142 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001143 offset++;
1144 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001145
H. Peter Anvine2c80182005-01-15 22:15:51 +00001146 case 05:
1147 case 07:
1148 switch (ins->oprs[0].basereg) {
1149 case R_FS:
1150 bytes[0] = 0xA0 + (c == 0x05 ? 1 : 0);
1151 break;
1152 case R_GS:
1153 bytes[0] = 0xA8 + (c == 0x05 ? 1 : 0);
1154 break;
1155 default:
1156 errfunc(ERR_PANIC,
1157 "bizarre 386 segment register received");
1158 }
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001159 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001160 offset++;
1161 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001162
H. Peter Anvine2c80182005-01-15 22:15:51 +00001163 case 010:
1164 case 011:
1165 case 012:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001166 case 013:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001167 EMIT_REX();
H. Peter Anvin839eca22007-10-29 23:12:47 -07001168 bytes[0] = *codes++ + ((regval(opx)) & 7);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001169 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001170 offset += 1;
1171 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001172
H. Peter Anvine2c80182005-01-15 22:15:51 +00001173 case 014:
1174 case 015:
1175 case 016:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001176 case 017:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001177 if (opx->offset < -128 || opx->offset > 127) {
H. Peter Anvin72c64372008-01-08 22:13:48 -08001178 errfunc(ERR_WARNING | ERR_WARN_NOV,
1179 "signed byte value exceeds bounds");
H. Peter Anvine2c80182005-01-15 22:15:51 +00001180 }
H. Peter Anvineba20a72002-04-30 20:53:55 +00001181
H. Peter Anvin839eca22007-10-29 23:12:47 -07001182 if (opx->segment != NO_SEG) {
1183 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001184 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001185 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001186 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001187 bytes[0] = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001188 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001189 NO_SEG);
1190 }
1191 offset += 1;
1192 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001193
H. Peter Anvine2c80182005-01-15 22:15:51 +00001194 case 020:
1195 case 021:
1196 case 022:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001197 case 023:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001198 if (opx->offset < -256 || opx->offset > 255) {
H. Peter Anvin72c64372008-01-08 22:13:48 -08001199 errfunc(ERR_WARNING | ERR_WARN_NOV,
1200 "byte value exceeds bounds");
H. Peter Anvine2c80182005-01-15 22:15:51 +00001201 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001202 if (opx->segment != NO_SEG) {
1203 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001204 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001205 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001206 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001207 bytes[0] = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001208 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001209 NO_SEG);
1210 }
1211 offset += 1;
1212 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001213
H. Peter Anvine2c80182005-01-15 22:15:51 +00001214 case 024:
1215 case 025:
1216 case 026:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001217 case 027:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001218 if (opx->offset < 0 || opx->offset > 255)
H. Peter Anvin72c64372008-01-08 22:13:48 -08001219 errfunc(ERR_WARNING | ERR_WARN_NOV,
1220 "unsigned byte value exceeds bounds");
H. Peter Anvin839eca22007-10-29 23:12:47 -07001221 if (opx->segment != NO_SEG) {
1222 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001223 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001224 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001225 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001226 bytes[0] = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001227 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001228 NO_SEG);
1229 }
1230 offset += 1;
1231 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001232
H. Peter Anvine2c80182005-01-15 22:15:51 +00001233 case 030:
1234 case 031:
1235 case 032:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001236 case 033:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001237 data = opx->offset;
1238 if (opx->segment == NO_SEG && opx->wrt == NO_SEG)
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001239 warn_overflow(2, data);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001240 out(offset, segment, &data, OUT_ADDRESS, 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001241 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001242 offset += 2;
1243 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001244
H. Peter Anvine2c80182005-01-15 22:15:51 +00001245 case 034:
1246 case 035:
1247 case 036:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001248 case 037:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001249 if (opx->type & (BITS16 | BITS32))
1250 size = (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001251 else
1252 size = (bits == 16) ? 2 : 4;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001253 data = opx->offset;
1254 if (opx->segment == NO_SEG && opx->wrt == NO_SEG)
H. Peter Anvin10e27272007-10-29 22:56:08 -07001255 warn_overflow(size, data);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001256 out(offset, segment, &data, OUT_ADDRESS, size,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001257 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001258 offset += size;
1259 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001260
H. Peter Anvine2c80182005-01-15 22:15:51 +00001261 case 040:
1262 case 041:
1263 case 042:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001264 case 043:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001265 data = opx->offset;
H. Peter Anvin72c64372008-01-08 22:13:48 -08001266 if (opx->segment == NO_SEG && opx->wrt == NO_SEG)
1267 warn_overflow(4, data);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001268 out(offset, segment, &data, OUT_ADDRESS, 4,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001269 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001270 offset += 4;
1271 break;
H. Peter Anvin3ba46772002-05-27 23:19:35 +00001272
H. Peter Anvine2c80182005-01-15 22:15:51 +00001273 case 044:
1274 case 045:
1275 case 046:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001276 case 047:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001277 data = opx->offset;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001278 size = ins->addr_size >> 3;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001279 if (opx->segment == NO_SEG &&
1280 opx->wrt == NO_SEG)
H. Peter Anvin10e27272007-10-29 22:56:08 -07001281 warn_overflow(size, data);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001282 out(offset, segment, &data, OUT_ADDRESS, size,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001283 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001284 offset += size;
1285 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001286
H. Peter Anvine2c80182005-01-15 22:15:51 +00001287 case 050:
1288 case 051:
1289 case 052:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001290 case 053:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001291 if (opx->segment != segment)
H. Peter Anvine2c80182005-01-15 22:15:51 +00001292 errfunc(ERR_NONFATAL,
1293 "short relative jump outside segment");
H. Peter Anvin839eca22007-10-29 23:12:47 -07001294 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001295 if (data > 127 || data < -128)
1296 errfunc(ERR_NONFATAL, "short jump is out of range");
1297 bytes[0] = data;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001298 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001299 offset += 1;
1300 break;
H. Peter Anvin70653092007-10-19 14:42:29 -07001301
Keith Kaniosb7a89542007-04-12 02:40:54 +00001302 case 054:
1303 case 055:
1304 case 056:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001305 case 057:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001306 data = (int64_t)opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001307 out(offset, segment, &data, OUT_ADDRESS, 8,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001308 opx->segment, opx->wrt);
Keith Kaniosb7a89542007-04-12 02:40:54 +00001309 offset += 8;
1310 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001311
H. Peter Anvine2c80182005-01-15 22:15:51 +00001312 case 060:
1313 case 061:
1314 case 062:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001315 case 063:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001316 if (opx->segment != segment) {
1317 data = opx->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001318 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001319 OUT_REL2ADR, insn_end - offset,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001320 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001321 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001322 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001323 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001324 OUT_ADDRESS, 2, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001325 }
1326 offset += 2;
1327 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001328
H. Peter Anvine2c80182005-01-15 22:15:51 +00001329 case 064:
1330 case 065:
1331 case 066:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001332 case 067:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001333 if (opx->type & (BITS16 | BITS32 | BITS64))
1334 size = (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001335 else
1336 size = (bits == 16) ? 2 : 4;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001337 if (opx->segment != segment) {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001338 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001339 out(offset, segment, &data,
1340 size == 2 ? OUT_REL2ADR : OUT_REL4ADR,
1341 insn_end - offset, opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001342 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001343 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001344 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001345 OUT_ADDRESS, size, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001346 }
1347 offset += size;
1348 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001349
H. Peter Anvine2c80182005-01-15 22:15:51 +00001350 case 070:
1351 case 071:
1352 case 072:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001353 case 073:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001354 if (opx->segment != segment) {
1355 data = opx->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001356 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001357 OUT_REL4ADR, insn_end - offset,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001358 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001359 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001360 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001361 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001362 OUT_ADDRESS, 4, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001363 }
1364 offset += 4;
1365 break;
H. Peter Anvinaf535c12002-04-30 20:59:21 +00001366
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001367 case 074:
1368 case 075:
1369 case 076:
1370 case 077:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001371 if (opx->segment == NO_SEG)
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001372 errfunc(ERR_NONFATAL, "value referenced by FAR is not"
1373 " relocatable");
1374 data = 0L;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001375 out(offset, segment, &data, OUT_ADDRESS, 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001376 outfmt->segbase(1 + opx->segment),
1377 opx->wrt);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001378 offset += 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001379 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001380
H. Peter Anvine2c80182005-01-15 22:15:51 +00001381 case 0140:
1382 case 0141:
1383 case 0142:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001384 case 0143:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001385 data = opx->offset;
1386 if (is_sbyte(ins, c & 3, 16)) {
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001387 bytes[0] = data;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001388 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001389 NO_SEG);
1390 offset++;
1391 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001392 if (opx->segment == NO_SEG &&
1393 opx->wrt == NO_SEG)
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001394 warn_overflow(2, data);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001395 out(offset, segment, &data, OUT_ADDRESS, 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001396 opx->segment, opx->wrt);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001397 offset += 2;
1398 }
1399 break;
1400
1401 case 0144:
1402 case 0145:
1403 case 0146:
1404 case 0147:
1405 EMIT_REX();
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001406 bytes[0] = *codes++;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001407 if (is_sbyte(ins, c & 3, 16))
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001408 bytes[0] |= 2; /* s-bit */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001409 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001410 offset++;
1411 break;
1412
1413 case 0150:
1414 case 0151:
1415 case 0152:
1416 case 0153:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001417 data = opx->offset;
1418 if (is_sbyte(ins, c & 3, 32)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001419 bytes[0] = data;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001420 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001421 NO_SEG);
1422 offset++;
1423 } else {
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001424 out(offset, segment, &data, OUT_ADDRESS, 4,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001425 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001426 offset += 4;
1427 }
1428 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001429
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001430 case 0154:
1431 case 0155:
1432 case 0156:
1433 case 0157:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001434 EMIT_REX();
H. Peter Anvine2c80182005-01-15 22:15:51 +00001435 bytes[0] = *codes++;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001436 if (is_sbyte(ins, c & 3, 32))
H. Peter Anvine2c80182005-01-15 22:15:51 +00001437 bytes[0] |= 2; /* s-bit */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001438 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001439 offset++;
1440 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001441
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001442 case 0160:
1443 case 0161:
1444 case 0162:
1445 case 0163:
1446 case 0164:
1447 case 0165:
1448 case 0166:
1449 case 0167:
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001450 break;
1451
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001452 case 0170:
H. Peter Anvinc189b442007-10-05 17:04:32 -07001453 EMIT_REX();
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001454 bytes[0] = 0;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001455 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001456 offset += 1;
1457 break;
1458
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001459 case 0171:
1460 bytes[0] =
1461 (ins->drexdst << 4) |
1462 (ins->rex & REX_OC ? 0x08 : 0) |
1463 (ins->rex & (REX_R|REX_X|REX_B));
1464 ins->rex = 0;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001465 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001466 offset++;
1467 break;
1468
H. Peter Anvine2c80182005-01-15 22:15:51 +00001469 case 0300:
1470 case 0301:
1471 case 0302:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001472 case 0303:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001473 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001474
H. Peter Anvine2c80182005-01-15 22:15:51 +00001475 case 0310:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001476 if (bits == 32 && !has_prefix(ins, PPS_ASIZE, P_A16)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001477 *bytes = 0x67;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001478 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001479 offset += 1;
1480 } else
1481 offset += 0;
1482 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001483
H. Peter Anvine2c80182005-01-15 22:15:51 +00001484 case 0311:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001485 if (bits != 32 && !has_prefix(ins, PPS_ASIZE, P_A32)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001486 *bytes = 0x67;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001487 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001488 offset += 1;
1489 } else
1490 offset += 0;
1491 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001492
H. Peter Anvine2c80182005-01-15 22:15:51 +00001493 case 0312:
1494 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001495
Keith Kaniosb7a89542007-04-12 02:40:54 +00001496 case 0313:
1497 ins->rex = 0;
1498 break;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07001499
H. Peter Anvin23440102007-11-12 21:02:33 -08001500 case 0314:
1501 case 0315:
1502 case 0316:
1503 case 0317:
1504 break;
1505
H. Peter Anvine2c80182005-01-15 22:15:51 +00001506 case 0320:
Keith Kaniosb7a89542007-04-12 02:40:54 +00001507 if (bits != 16) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001508 *bytes = 0x66;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001509 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001510 offset += 1;
1511 } else
1512 offset += 0;
1513 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001514
H. Peter Anvine2c80182005-01-15 22:15:51 +00001515 case 0321:
1516 if (bits == 16) {
1517 *bytes = 0x66;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001518 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001519 offset += 1;
1520 } else
1521 offset += 0;
1522 break;
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001523
H. Peter Anvine2c80182005-01-15 22:15:51 +00001524 case 0322:
H. Peter Anvin70653092007-10-19 14:42:29 -07001525 case 0323:
1526 break;
1527
Keith Kaniosb7a89542007-04-12 02:40:54 +00001528 case 0324:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001529 ins->rex |= REX_W;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001530 break;
H. Peter Anvin70653092007-10-19 14:42:29 -07001531
H. Peter Anvine2c80182005-01-15 22:15:51 +00001532 case 0330:
1533 *bytes = *codes++ ^ condval[ins->condition];
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001534 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001535 offset += 1;
1536 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001537
H. Peter Anvine2c80182005-01-15 22:15:51 +00001538 case 0331:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001539 break;
H. Peter Anvinaf535c12002-04-30 20:59:21 +00001540
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001541 case 0332:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001542 case 0333:
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001543 *bytes = c - 0332 + 0xF2;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001544 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001545 offset += 1;
1546 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001547
Keith Kanios48af1772007-08-17 07:37:52 +00001548 case 0334:
1549 if (ins->rex & REX_R) {
1550 *bytes = 0xF0;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001551 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
Keith Kanios48af1772007-08-17 07:37:52 +00001552 offset += 1;
1553 }
1554 ins->rex &= ~(REX_L|REX_R);
1555 break;
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001556
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001557 case 0335:
1558 break;
1559
H. Peter Anvine2c80182005-01-15 22:15:51 +00001560 case 0340:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001561 if (ins->oprs[0].segment != NO_SEG)
1562 errfunc(ERR_PANIC, "non-constant BSS size in pass two");
1563 else {
H. Peter Anvin428fd672007-11-15 10:25:52 -08001564 int64_t size = ins->oprs[0].offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001565 if (size > 0)
1566 out(offset, segment, NULL,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001567 OUT_RESERVE, size, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001568 offset += size;
1569 }
1570 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001571
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001572 case 0364:
1573 case 0365:
1574 break;
1575
Keith Kanios48af1772007-08-17 07:37:52 +00001576 case 0366:
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001577 case 0367:
1578 *bytes = c - 0366 + 0x66;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001579 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
Keith Kanios48af1772007-08-17 07:37:52 +00001580 offset += 1;
1581 break;
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001582
H. Peter Anvine2c80182005-01-15 22:15:51 +00001583 case 0370:
1584 case 0371:
1585 case 0372:
1586 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001587
H. Peter Anvine2c80182005-01-15 22:15:51 +00001588 case 0373:
1589 *bytes = bits == 16 ? 3 : 5;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001590 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001591 offset += 1;
1592 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001593
H. Peter Anvine2c80182005-01-15 22:15:51 +00001594 default: /* can't do it by 'case' statements */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001595 if (c >= 0100 && c <= 0277) { /* it's an EA */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001596 ea ea_data;
1597 int rfield;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001598 int32_t rflags;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001599 uint8_t *p;
1600 int32_t s;
H. Peter Anvin70653092007-10-19 14:42:29 -07001601
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001602 if (c <= 0177) {
1603 /* pick rfield from operand b */
1604 rflags = regflag(&ins->oprs[c & 7]);
1605 rfield = regvals[ins->oprs[c & 7].basereg];
1606 } else {
1607 /* rfield is constant */
1608 rflags = 0;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001609 rfield = c & 7;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001610 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001611
1612 if (!process_ea
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001613 (&ins->oprs[(c >> 3) & 7], &ea_data, bits,
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001614 ins->addr_size, rfield, rflags, ins->forw_ref)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001615 errfunc(ERR_NONFATAL, "invalid effective address");
1616 }
H. Peter Anvin70653092007-10-19 14:42:29 -07001617
Charles Crayne7e975552007-11-03 22:06:13 -07001618
H. Peter Anvine2c80182005-01-15 22:15:51 +00001619 p = bytes;
1620 *p++ = ea_data.modrm;
1621 if (ea_data.sib_present)
1622 *p++ = ea_data.sib;
1623
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001624 /* DREX suffixes come between the SIB and the displacement */
1625 if (ins->rex & REX_D) {
1626 *p++ =
1627 (ins->drexdst << 4) |
1628 (ins->rex & REX_OC ? 0x08 : 0) |
1629 (ins->rex & (REX_R|REX_X|REX_B));
1630 ins->rex = 0;
1631 }
1632
H. Peter Anvine2c80182005-01-15 22:15:51 +00001633 s = p - bytes;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001634 out(offset, segment, bytes, OUT_RAWDATA, s, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001635
1636 switch (ea_data.bytes) {
1637 case 0:
1638 break;
1639 case 1:
1640 if (ins->oprs[(c >> 3) & 7].segment != NO_SEG) {
1641 data = ins->oprs[(c >> 3) & 7].offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001642 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001643 ins->oprs[(c >> 3) & 7].segment,
1644 ins->oprs[(c >> 3) & 7].wrt);
1645 } else {
1646 *bytes = ins->oprs[(c >> 3) & 7].offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001647 out(offset, segment, bytes, OUT_RAWDATA, 1,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001648 NO_SEG, NO_SEG);
1649 }
1650 s++;
1651 break;
H. Peter Anvin70653092007-10-19 14:42:29 -07001652 case 8:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001653 case 2:
1654 case 4:
1655 data = ins->oprs[(c >> 3) & 7].offset;
Charles Crayne7e975552007-11-03 22:06:13 -07001656 warn_overflow(ea_data.bytes, data);
H. Peter Anvind0b0d282007-09-28 17:17:20 -07001657 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001658 ea_data.rip ? OUT_REL4ADR : OUT_ADDRESS,
1659 ea_data.bytes,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001660 ins->oprs[(c >> 3) & 7].segment,
1661 ins->oprs[(c >> 3) & 7].wrt);
1662 s += ea_data.bytes;
1663 break;
1664 }
1665 offset += s;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001666 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001667 errfunc(ERR_PANIC, "internal instruction table corrupt"
1668 ": instruction code 0x%02X given", c);
H. Peter Anvin839eca22007-10-29 23:12:47 -07001669 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001670 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001671 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001672}
1673
H. Peter Anvin0ec60e62007-07-07 01:59:52 +00001674static int32_t regflag(const operand * o)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001675{
1676 if (o->basereg < EXPR_REG_START || o->basereg >= REG_ENUM_LIMIT) {
1677 errfunc(ERR_PANIC, "invalid operand passed to regflag()");
1678 }
1679 return reg_flags[o->basereg];
1680}
1681
H. Peter Anvin5b0e3ec2007-07-07 02:01:08 +00001682static int32_t regval(const operand * o)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001683{
H. Peter Anvine2c80182005-01-15 22:15:51 +00001684 if (o->basereg < EXPR_REG_START || o->basereg >= REG_ENUM_LIMIT) {
1685 errfunc(ERR_PANIC, "invalid operand passed to regval()");
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001686 }
H. Peter Anvin232badb2002-06-06 02:41:20 +00001687 return regvals[o->basereg];
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001688}
1689
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001690static int op_rexflags(const operand * o, int mask)
1691{
1692 int32_t flags;
1693 int val;
1694
1695 if (o->basereg < EXPR_REG_START || o->basereg >= REG_ENUM_LIMIT) {
1696 errfunc(ERR_PANIC, "invalid operand passed to op_rexflags()");
1697 }
1698
1699 flags = reg_flags[o->basereg];
1700 val = regvals[o->basereg];
1701
1702 return rexflags(val, flags, mask);
1703}
1704
1705static int rexflags(int val, int32_t flags, int mask)
1706{
1707 int rex = 0;
1708
1709 if (val >= 8)
1710 rex |= REX_B|REX_X|REX_R;
1711 if (flags & BITS64)
1712 rex |= REX_W;
1713 if (!(REG_HIGH & ~flags)) /* AH, CH, DH, BH */
1714 rex |= REX_H;
1715 else if (!(REG8 & ~flags) && val >= 4) /* SPL, BPL, SIL, DIL */
1716 rex |= REX_P;
1717
1718 return rex & mask;
1719}
1720
H. Peter Anvin3360d792007-09-11 04:16:57 +00001721static int matches(const struct itemplate *itemp, insn * instruction, int bits)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001722{
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001723 int i, size[MAX_OPERANDS], asize, oprs, ret;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001724
1725 ret = 100;
1726
1727 /*
1728 * Check the opcode
1729 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001730 if (itemp->opcode != instruction->opcode)
1731 return 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001732
1733 /*
1734 * Count the operands
1735 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001736 if (itemp->operands != instruction->operands)
1737 return 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001738
1739 /*
1740 * Check that no spurious colons or TOs are present
1741 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001742 for (i = 0; i < itemp->operands; i++)
1743 if (instruction->oprs[i].type & ~itemp->opd[i] & (COLON | TO))
1744 return 0;
H. Peter Anvin70653092007-10-19 14:42:29 -07001745
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001746 /*
1747 * Check that the operand flags all match up
1748 */
H. Peter Anvin16b0a332007-09-12 20:27:41 -07001749 for (i = 0; i < itemp->operands; i++) {
H. Peter Anvincf5180a2007-09-17 17:25:27 -07001750 if (itemp->opd[i] & SAME_AS) {
1751 int j = itemp->opd[i] & ~SAME_AS;
1752 if (instruction->oprs[i].type != instruction->oprs[j].type ||
1753 instruction->oprs[i].basereg != instruction->oprs[j].basereg)
1754 return 0;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001755 } else if (itemp->opd[i] & ~instruction->oprs[i].type ||
H. Peter Anvine2c80182005-01-15 22:15:51 +00001756 ((itemp->opd[i] & SIZE_MASK) &&
1757 ((itemp->opd[i] ^ instruction->oprs[i].type) & SIZE_MASK))) {
H. Peter Anvin5a640e12007-05-29 23:57:12 +00001758 if ((itemp->opd[i] & ~instruction->oprs[i].type & ~SIZE_MASK) ||
H. Peter Anvine2c80182005-01-15 22:15:51 +00001759 (instruction->oprs[i].type & SIZE_MASK))
1760 return 0;
1761 else
H. Peter Anvine2c80182005-01-15 22:15:51 +00001762 return 1;
1763 }
H. Peter Anvin16b0a332007-09-12 20:27:41 -07001764 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001765
1766 /*
1767 * Check operand sizes
1768 */
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001769 if (itemp->flags & IF_ARMASK) {
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001770 memset(size, 0, sizeof size);
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001771
H. Peter Anvine2c80182005-01-15 22:15:51 +00001772 switch (itemp->flags & IF_ARMASK) {
1773 case IF_AR0:
1774 i = 0;
1775 break;
1776 case IF_AR1:
1777 i = 1;
1778 break;
1779 case IF_AR2:
1780 i = 2;
1781 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001782 case IF_AR3:
1783 i = 3;
1784 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001785 default:
1786 break; /* Shouldn't happen */
1787 }
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001788 switch (itemp->flags & IF_SMASK) {
1789 case IF_SB:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001790 size[i] = BITS8;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001791 break;
1792 case IF_SW:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001793 size[i] = BITS16;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001794 break;
1795 case IF_SD:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001796 size[i] = BITS32;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001797 break;
1798 case IF_SQ:
Keith Kaniosb7a89542007-04-12 02:40:54 +00001799 size[i] = BITS64;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001800 break;
H. Peter Anvin41c9f6f2007-09-18 13:01:32 -07001801 case IF_SO:
1802 size[i] = BITS128;
1803 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001804 default:
1805 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001806 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001807 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001808 asize = 0;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001809 switch (itemp->flags & IF_SMASK) {
1810 case IF_SB:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001811 asize = BITS8;
1812 oprs = itemp->operands;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001813 break;
1814 case IF_SW:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001815 asize = BITS16;
1816 oprs = itemp->operands;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001817 break;
1818 case IF_SD:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001819 asize = BITS32;
1820 oprs = itemp->operands;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001821 break;
1822 case IF_SQ:
Keith Kaniosb7a89542007-04-12 02:40:54 +00001823 asize = BITS64;
1824 oprs = itemp->operands;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001825 break;
H. Peter Anvin41c9f6f2007-09-18 13:01:32 -07001826 case IF_SO:
1827 asize = BITS128;
1828 oprs = itemp->operands;
1829 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001830 default:
1831 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001832 }
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001833 for (i = 0; i < MAX_OPERANDS; i++)
1834 size[i] = asize;
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001835 }
H. Peter Anvin70653092007-10-19 14:42:29 -07001836
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001837 if (itemp->flags & (IF_SM | IF_SM2)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001838 oprs = (itemp->flags & IF_SM2 ? 2 : itemp->operands);
1839 asize = 0;
1840 for (i = 0; i < oprs; i++) {
1841 if ((asize = itemp->opd[i] & SIZE_MASK) != 0) {
1842 int j;
1843 for (j = 0; j < oprs; j++)
1844 size[j] = asize;
1845 break;
1846 }
1847 }
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001848 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001849 oprs = itemp->operands;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001850 }
1851
Keith Kaniosb7a89542007-04-12 02:40:54 +00001852 for (i = 0; i < itemp->operands; i++) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001853 if (!(itemp->opd[i] & SIZE_MASK) &&
1854 (instruction->oprs[i].type & SIZE_MASK & ~size[i]))
H. Peter Anvine2c80182005-01-15 22:15:51 +00001855 return 2;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001856 }
1857
H. Peter Anvinaf535c12002-04-30 20:59:21 +00001858 /*
1859 * Check template is okay at the set cpu level
1860 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00001861 if (((itemp->flags & IF_PLEVEL) > cpu))
H. Peter Anvine2c80182005-01-15 22:15:51 +00001862 return 3;
H. Peter Anvin70653092007-10-19 14:42:29 -07001863
Keith Kaniosb7a89542007-04-12 02:40:54 +00001864 /*
1865 * Check if instruction is available in long mode
1866 */
1867 if ((itemp->flags & IF_NOLONG) && (bits == 64))
1868 return 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001869
H. Peter Anvinaf535c12002-04-30 20:59:21 +00001870 /*
1871 * Check if special handling needed for Jumps
1872 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00001873 if ((uint8_t)(itemp->code[0]) >= 0370)
H. Peter Anvine2c80182005-01-15 22:15:51 +00001874 return 99;
1875
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001876 return ret;
1877}
1878
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001879static ea *process_ea(operand * input, ea * output, int bits,
1880 int addrbits, int rfield, int32_t rflags, int forw_ref)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001881{
H. Peter Anvin6867acc2007-10-10 14:58:45 -07001882 output->rip = false;
H. Peter Anvin99c4ecd2007-08-28 23:06:00 +00001883
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001884 /* REX flags for the rfield operand */
1885 output->rex |= rexflags(rfield, rflags, REX_R|REX_P|REX_W|REX_H);
1886
Keith Kaniosb7a89542007-04-12 02:40:54 +00001887 if (!(REGISTER & ~input->type)) { /* register direct */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001888 int i;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001889 int32_t f;
1890
1891 if (input->basereg < EXPR_REG_START /* Verify as Register */
Keith Kaniosb7a89542007-04-12 02:40:54 +00001892 || input->basereg >= REG_ENUM_LIMIT)
H. Peter Anvine2c80182005-01-15 22:15:51 +00001893 return NULL;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001894 f = regflag(input);
Keith Kaniosb7a89542007-04-12 02:40:54 +00001895 i = regvals[input->basereg];
Keith Kaniosb7a89542007-04-12 02:40:54 +00001896
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001897 if (REG_EA & ~f)
1898 return NULL; /* Invalid EA register */
H. Peter Anvin70653092007-10-19 14:42:29 -07001899
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001900 output->rex |= op_rexflags(input, REX_B|REX_P|REX_W|REX_H);
1901
H. Peter Anvin6867acc2007-10-10 14:58:45 -07001902 output->sib_present = false; /* no SIB necessary */
Keith Kaniosb7a89542007-04-12 02:40:54 +00001903 output->bytes = 0; /* no offset necessary either */
1904 output->modrm = 0xC0 | ((rfield & 7) << 3) | (i & 7);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001905 } else { /* it's a memory reference */
1906 if (input->basereg == -1
1907 && (input->indexreg == -1 || input->scale == 0)) {
1908 /* it's a pure offset */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001909 if (bits == 64 && (~input->type & IP_REL)) {
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00001910 int scale, index, base;
H. Peter Anvin6867acc2007-10-10 14:58:45 -07001911 output->sib_present = true;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00001912 scale = 0;
1913 index = 4;
1914 base = 5;
1915 output->sib = (scale << 6) | (index << 3) | base;
1916 output->bytes = 4;
1917 output->modrm = 4 | ((rfield & 7) << 3);
H. Peter Anvin6867acc2007-10-10 14:58:45 -07001918 output->rip = false;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00001919 } else {
H. Peter Anvin6867acc2007-10-10 14:58:45 -07001920 output->sib_present = false;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00001921 output->bytes = (addrbits != 16 ? 4 : 2);
1922 output->modrm = (addrbits != 16 ? 5 : 6) | ((rfield & 7) << 3);
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001923 output->rip = bits == 64;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00001924 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001925 } else { /* it's an indirection */
1926 int i = input->indexreg, b = input->basereg, s = input->scale;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001927 int32_t o = input->offset, seg = input->segment;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001928 int hb = input->hintbase, ht = input->hinttype;
1929 int t;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001930 int it, bt;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001931 int32_t ix, bx; /* register flags */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001932
H. Peter Anvine2c80182005-01-15 22:15:51 +00001933 if (s == 0)
1934 i = -1; /* make this easy, at least */
H. Peter Anvin70653092007-10-19 14:42:29 -07001935
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001936 if (i >= EXPR_REG_START && i < REG_ENUM_LIMIT) {
Keith Kaniosb7a89542007-04-12 02:40:54 +00001937 it = regvals[i];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001938 ix = reg_flags[i];
1939 } else {
Keith Kaniosb7a89542007-04-12 02:40:54 +00001940 it = -1;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001941 ix = 0;
1942 }
H. Peter Anvin70653092007-10-19 14:42:29 -07001943
H. Peter Anvinb0c54622007-10-28 23:21:46 -07001944 if (b >= EXPR_REG_START && b < REG_ENUM_LIMIT) {
Keith Kaniosb7a89542007-04-12 02:40:54 +00001945 bt = regvals[b];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001946 bx = reg_flags[b];
1947 } else {
Keith Kaniosb7a89542007-04-12 02:40:54 +00001948 bt = -1;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001949 bx = 0;
1950 }
H. Peter Anvin70653092007-10-19 14:42:29 -07001951
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001952 /* check for a 32/64-bit memory reference... */
1953 if ((ix|bx) & (BITS32|BITS64)) {
Keith Kaniosb7a89542007-04-12 02:40:54 +00001954 /* it must be a 32/64-bit memory reference. Firstly we have
1955 * to check that all registers involved are type E/Rxx. */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001956 int32_t sok = BITS32|BITS64;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001957
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001958 if (it != -1) {
1959 if (!(REG64 & ~ix) || !(REG32 & ~ix))
1960 sok &= ix;
1961 else
1962 return NULL;
1963 }
1964
1965 if (bt != -1) {
H. Peter Anvin99c4ecd2007-08-28 23:06:00 +00001966 if (REG_GPR & ~bx)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001967 return NULL; /* Invalid register */
H. Peter Anvina57e8d42007-05-30 03:44:02 +00001968 if (~sok & bx & SIZE_MASK)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001969 return NULL; /* Invalid size */
H. Peter Anvinb0c54622007-10-28 23:21:46 -07001970 sok &= bx;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001971 }
H. Peter Anvin70653092007-10-19 14:42:29 -07001972
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001973 /* While we're here, ensure the user didn't specify
1974 WORD or QWORD. */
1975 if (input->disp_size == 16 || input->disp_size == 64)
1976 return NULL;
1977
1978 if (addrbits == 16 ||
1979 (addrbits == 32 && !(sok & BITS32)) ||
1980 (addrbits == 64 && !(sok & BITS64)))
1981 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001982
Keith Kaniosb7a89542007-04-12 02:40:54 +00001983 /* now reorganize base/index */
1984 if (s == 1 && bt != it && bt != -1 && it != -1 &&
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001985 ((hb == b && ht == EAH_NOTBASE)
1986 || (hb == i && ht == EAH_MAKEBASE))) {
1987 /* swap if hints say so */
1988 t = bt, bt = it, it = t;
1989 t = bx, bx = ix, ix = t;
1990 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00001991 if (bt == it) /* convert EAX+2*EAX to 3*EAX */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001992 bt = -1, bx = 0, s++;
1993 if (bt == -1 && s == 1 && !(hb == it && ht == EAH_NOTBASE)) {
1994 /* make single reg base, unless hint */
1995 bt = it, bx = ix, it = -1, ix = 0;
1996 }
H. Peter Anvinf5843c62007-09-10 18:59:26 +00001997 if (((s == 2 && it != REG_NUM_ESP
H. Peter Anvine2c80182005-01-15 22:15:51 +00001998 && !(input->eaflags & EAF_TIMESTWO)) || s == 3
Keith Kaniosb7a89542007-04-12 02:40:54 +00001999 || s == 5 || s == 9) && bt == -1)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002000 bt = it, bx = ix, s--; /* convert 3*EAX to EAX+2*EAX */
Keith Kanios48af1772007-08-17 07:37:52 +00002001 if (it == -1 && (bt & 7) != REG_NUM_ESP
H. Peter Anvine2c80182005-01-15 22:15:51 +00002002 && (input->eaflags & EAF_TIMESTWO))
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002003 it = bt, ix = bx, bt = -1, bx = 0, s = 1;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002004 /* convert [NOSPLIT EAX] to sib format with 0x0 displacement */
Keith Kanios48af1772007-08-17 07:37:52 +00002005 if (s == 1 && it == REG_NUM_ESP) {
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002006 /* swap ESP into base if scale is 1 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002007 t = it, it = bt, bt = t;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002008 t = ix, ix = bx, bx = t;
2009 }
Keith Kanios48af1772007-08-17 07:37:52 +00002010 if (it == REG_NUM_ESP
Keith Kaniosb7a89542007-04-12 02:40:54 +00002011 || (s != 1 && s != 2 && s != 4 && s != 8 && it != -1))
H. Peter Anvine2c80182005-01-15 22:15:51 +00002012 return NULL; /* wrong, for various reasons */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002013
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002014 output->rex |= rexflags(it, ix, REX_X);
2015 output->rex |= rexflags(bt, bx, REX_B);
Keith Kaniosb7a89542007-04-12 02:40:54 +00002016
Keith Kanios48af1772007-08-17 07:37:52 +00002017 if (it == -1 && (bt & 7) != REG_NUM_ESP) {
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002018 /* no SIB needed */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002019 int mod, rm;
H. Peter Anvin70653092007-10-19 14:42:29 -07002020
Keith Kaniosb7a89542007-04-12 02:40:54 +00002021 if (bt == -1) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002022 rm = 5;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002023 mod = 0;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002024 } else {
2025 rm = (bt & 7);
Keith Kanios48af1772007-08-17 07:37:52 +00002026 if (rm != REG_NUM_EBP && o == 0 &&
Keith Kaniosb7a89542007-04-12 02:40:54 +00002027 seg == NO_SEG && !forw_ref &&
2028 !(input->eaflags &
2029 (EAF_BYTEOFFS | EAF_WORDOFFS)))
2030 mod = 0;
2031 else if (input->eaflags & EAF_BYTEOFFS ||
2032 (o >= -128 && o <= 127 && seg == NO_SEG
2033 && !forw_ref
2034 && !(input->eaflags & EAF_WORDOFFS)))
2035 mod = 1;
2036 else
2037 mod = 2;
2038 }
H. Peter Anvinea838272002-04-30 20:51:53 +00002039
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002040 output->sib_present = false;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002041 output->bytes = (bt == -1 || mod == 2 ? 4 : mod);
2042 output->modrm = (mod << 6) | ((rfield & 7) << 3) | rm;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002043 } else {
2044 /* we need a SIB */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002045 int mod, scale, index, base;
H. Peter Anvin70653092007-10-19 14:42:29 -07002046
Keith Kaniosb7a89542007-04-12 02:40:54 +00002047 if (it == -1)
2048 index = 4, s = 1;
2049 else
2050 index = (it & 7);
H. Peter Anvin70653092007-10-19 14:42:29 -07002051
H. Peter Anvine2c80182005-01-15 22:15:51 +00002052 switch (s) {
2053 case 1:
2054 scale = 0;
2055 break;
2056 case 2:
2057 scale = 1;
2058 break;
2059 case 4:
2060 scale = 2;
2061 break;
2062 case 8:
2063 scale = 3;
2064 break;
2065 default: /* then what the smeg is it? */
2066 return NULL; /* panic */
2067 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002068
Keith Kaniosb7a89542007-04-12 02:40:54 +00002069 if (bt == -1) {
2070 base = 5;
2071 mod = 0;
2072 } else {
2073 base = (bt & 7);
Keith Kanios48af1772007-08-17 07:37:52 +00002074 if (base != REG_NUM_EBP && o == 0 &&
H. Peter Anvine2c80182005-01-15 22:15:51 +00002075 seg == NO_SEG && !forw_ref &&
2076 !(input->eaflags &
Keith Kaniosb7a89542007-04-12 02:40:54 +00002077 (EAF_BYTEOFFS | EAF_WORDOFFS)))
2078 mod = 0;
2079 else if (input->eaflags & EAF_BYTEOFFS ||
2080 (o >= -128 && o <= 127 && seg == NO_SEG
2081 && !forw_ref
2082 && !(input->eaflags & EAF_WORDOFFS)))
2083 mod = 1;
2084 else
2085 mod = 2;
2086 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002087
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002088 output->sib_present = true;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002089 output->bytes = (bt == -1 || mod == 2 ? 4 : mod);
2090 output->modrm = (mod << 6) | ((rfield & 7) << 3) | 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002091 output->sib = (scale << 6) | (index << 3) | base;
2092 }
2093 } else { /* it's 16-bit */
2094 int mod, rm;
H. Peter Anvin70653092007-10-19 14:42:29 -07002095
Keith Kaniosb7a89542007-04-12 02:40:54 +00002096 /* check for 64-bit long mode */
2097 if (addrbits == 64)
2098 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002099
H. Peter Anvine2c80182005-01-15 22:15:51 +00002100 /* check all registers are BX, BP, SI or DI */
2101 if ((b != -1 && b != R_BP && b != R_BX && b != R_SI
2102 && b != R_DI) || (i != -1 && i != R_BP && i != R_BX
2103 && i != R_SI && i != R_DI))
2104 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002105
Keith Kaniosb7a89542007-04-12 02:40:54 +00002106 /* ensure the user didn't specify DWORD/QWORD */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002107 if (input->disp_size == 32 || input->disp_size == 64)
H. Peter Anvine2c80182005-01-15 22:15:51 +00002108 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002109
H. Peter Anvine2c80182005-01-15 22:15:51 +00002110 if (s != 1 && i != -1)
2111 return NULL; /* no can do, in 16-bit EA */
2112 if (b == -1 && i != -1) {
2113 int tmp = b;
2114 b = i;
2115 i = tmp;
2116 } /* swap */
2117 if ((b == R_SI || b == R_DI) && i != -1) {
2118 int tmp = b;
2119 b = i;
2120 i = tmp;
2121 }
2122 /* have BX/BP as base, SI/DI index */
2123 if (b == i)
2124 return NULL; /* shouldn't ever happen, in theory */
2125 if (i != -1 && b != -1 &&
2126 (i == R_BP || i == R_BX || b == R_SI || b == R_DI))
2127 return NULL; /* invalid combinations */
2128 if (b == -1) /* pure offset: handled above */
2129 return NULL; /* so if it gets to here, panic! */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002130
H. Peter Anvine2c80182005-01-15 22:15:51 +00002131 rm = -1;
2132 if (i != -1)
2133 switch (i * 256 + b) {
2134 case R_SI * 256 + R_BX:
2135 rm = 0;
2136 break;
2137 case R_DI * 256 + R_BX:
2138 rm = 1;
2139 break;
2140 case R_SI * 256 + R_BP:
2141 rm = 2;
2142 break;
2143 case R_DI * 256 + R_BP:
2144 rm = 3;
2145 break;
2146 } else
2147 switch (b) {
2148 case R_SI:
2149 rm = 4;
2150 break;
2151 case R_DI:
2152 rm = 5;
2153 break;
2154 case R_BP:
2155 rm = 6;
2156 break;
2157 case R_BX:
2158 rm = 7;
2159 break;
2160 }
2161 if (rm == -1) /* can't happen, in theory */
2162 return NULL; /* so panic if it does */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002163
H. Peter Anvine2c80182005-01-15 22:15:51 +00002164 if (o == 0 && seg == NO_SEG && !forw_ref && rm != 6 &&
2165 !(input->eaflags & (EAF_BYTEOFFS | EAF_WORDOFFS)))
2166 mod = 0;
2167 else if (input->eaflags & EAF_BYTEOFFS ||
2168 (o >= -128 && o <= 127 && seg == NO_SEG
2169 && !forw_ref
2170 && !(input->eaflags & EAF_WORDOFFS)))
2171 mod = 1;
2172 else
2173 mod = 2;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002174
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002175 output->sib_present = false; /* no SIB - it's 16-bit */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002176 output->bytes = mod; /* bytes of offset needed */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002177 output->modrm = (mod << 6) | ((rfield & 7) << 3) | rm;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002178 }
2179 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002180 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002181
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002182 output->size = 1 + output->sib_present + output->bytes;
2183 return output;
2184}
2185
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002186static void add_asp(insn *ins, int addrbits)
H. Peter Anvineba20a72002-04-30 20:53:55 +00002187{
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002188 int j, valid;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002189 int defdisp;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002190
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002191 valid = (addrbits == 64) ? 64|32 : 32|16;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002192
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002193 switch (ins->prefixes[PPS_ASIZE]) {
2194 case P_A16:
2195 valid &= 16;
2196 break;
2197 case P_A32:
2198 valid &= 32;
2199 break;
2200 case P_A64:
2201 valid &= 64;
2202 break;
2203 case P_ASP:
2204 valid &= (addrbits == 32) ? 16 : 32;
2205 break;
2206 default:
2207 break;
2208 }
2209
2210 for (j = 0; j < ins->operands; j++) {
2211 if (!(MEMORY & ~ins->oprs[j].type)) {
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002212 int32_t i, b;
H. Peter Anvin70653092007-10-19 14:42:29 -07002213
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002214 /* Verify as Register */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002215 if (ins->oprs[j].indexreg < EXPR_REG_START
2216 || ins->oprs[j].indexreg >= REG_ENUM_LIMIT)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002217 i = 0;
2218 else
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002219 i = reg_flags[ins->oprs[j].indexreg];
H. Peter Anvin70653092007-10-19 14:42:29 -07002220
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002221 /* Verify as Register */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002222 if (ins->oprs[j].basereg < EXPR_REG_START
2223 || ins->oprs[j].basereg >= REG_ENUM_LIMIT)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002224 b = 0;
2225 else
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002226 b = reg_flags[ins->oprs[j].basereg];
H. Peter Anvin70653092007-10-19 14:42:29 -07002227
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002228 if (ins->oprs[j].scale == 0)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002229 i = 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002230
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002231 if (!i && !b) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002232 int ds = ins->oprs[j].disp_size;
2233 if ((addrbits != 64 && ds > 8) ||
2234 (addrbits == 64 && ds == 16))
2235 valid &= ds;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002236 } else {
2237 if (!(REG16 & ~b))
2238 valid &= 16;
2239 if (!(REG32 & ~b))
2240 valid &= 32;
2241 if (!(REG64 & ~b))
2242 valid &= 64;
H. Peter Anvin70653092007-10-19 14:42:29 -07002243
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002244 if (!(REG16 & ~i))
2245 valid &= 16;
2246 if (!(REG32 & ~i))
2247 valid &= 32;
2248 if (!(REG64 & ~i))
2249 valid &= 64;
2250 }
2251 }
2252 }
2253
2254 if (valid & addrbits) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002255 ins->addr_size = addrbits;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002256 } else if (valid & ((addrbits == 32) ? 16 : 32)) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002257 /* Add an address size prefix */
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002258 enum prefixes pref = (addrbits == 32) ? P_A16 : P_A32;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002259 ins->prefixes[PPS_ASIZE] = pref;
2260 ins->addr_size = (addrbits == 32) ? 16 : 32;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002261 } else {
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002262 /* Impossible... */
2263 errfunc(ERR_NONFATAL, "impossible combination of address sizes");
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002264 ins->addr_size = addrbits; /* Error recovery */
2265 }
2266
2267 defdisp = ins->addr_size == 16 ? 16 : 32;
2268
2269 for (j = 0; j < ins->operands; j++) {
2270 if (!(MEM_OFFS & ~ins->oprs[j].type) &&
2271 (ins->oprs[j].disp_size ? ins->oprs[j].disp_size : defdisp)
2272 != ins->addr_size) {
2273 /* mem_offs sizes must match the address size; if not,
2274 strip the MEM_OFFS bit and match only EA instructions */
2275 ins->oprs[j].type &= ~(MEM_OFFS & ~MEMORY);
2276 }
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002277 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002278}