blob: 60fe369e31d41acc499db3e40775ffe90968f3a9 [file] [log] [blame]
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001/* assemble.c code generation for the Netwide Assembler
2 *
3 * The Netwide Assembler is copyright (C) 1996 Simon Tatham and
4 * Julian Hall. All rights reserved. The software is
Beroset095e6a22007-12-29 09:44:23 -05005 * redistributable under the license given in the file "LICENSE"
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00006 * distributed in the NASM archive.
7 *
8 * the actual codes (C syntax, i.e. octal):
9 * \0 - terminates the code. (Unless it's a literal of course.)
10 * \1, \2, \3 - that many literal bytes follow in the code stream
11 * \4, \6 - the POP/PUSH (respectively) codes for CS, DS, ES, SS
12 * (POP is never used for CS) depending on operand 0
13 * \5, \7 - the second byte of POP/PUSH codes for FS, GS, depending
14 * on operand 0
H. Peter Anvin7eb4a382007-09-17 15:49:30 -070015 * \10..\13 - a literal byte follows in the code stream, to be added
16 * to the register value of operand 0..3
17 * \14..\17 - a signed byte immediate operand, from operand 0..3
18 * \20..\23 - a byte immediate operand, from operand 0..3
19 * \24..\27 - an unsigned byte immediate operand, from operand 0..3
20 * \30..\33 - a word immediate operand, from operand 0..3
21 * \34..\37 - select between \3[0-3] and \4[0-3] depending on 16/32 bit
H. Peter Anvin3ba46772002-05-27 23:19:35 +000022 * assembly mode or the operand-size override on the operand
H. Peter Anvin7eb4a382007-09-17 15:49:30 -070023 * \40..\43 - a long immediate operand, from operand 0..3
24 * \44..\47 - select between \3[0-3], \4[0-3] and \5[4-7]
H. Peter Anvinde4b89b2007-10-01 15:41:25 -070025 * depending on the address size of the instruction.
H. Peter Anvin7eb4a382007-09-17 15:49:30 -070026 * \50..\53 - a byte relative operand, from operand 0..3
27 * \54..\57 - a qword immediate operand, from operand 0..3
28 * \60..\63 - a word relative operand, from operand 0..3
29 * \64..\67 - select between \6[0-3] and \7[0-3] depending on 16/32 bit
H. Peter Anvin17799b42002-05-21 03:31:21 +000030 * assembly mode or the operand-size override on the operand
H. Peter Anvin7eb4a382007-09-17 15:49:30 -070031 * \70..\73 - a long relative operand, from operand 0..3
32 * \74..\77 - a word constant, from the _segment_ part of operand 0..3
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000033 * \1ab - a ModRM, calculated on EA in operand a, with the spare
34 * field the register value of operand b.
H. Peter Anvin7eb4a382007-09-17 15:49:30 -070035 * \140..\143 - an immediate word or signed byte for operand 0..3
H. Peter Anvina30cc072007-11-18 21:55:26 -080036 * \144..\147 - or 2 (s-field) into opcode byte if operand 0..3
37 * is a signed byte rather than a word. Opcode byte follows.
H. Peter Anvin7eb4a382007-09-17 15:49:30 -070038 * \150..\153 - an immediate dword or signed byte for operand 0..3
H. Peter Anvina30cc072007-11-18 21:55:26 -080039 * \154..\157 - or 2 (s-field) into opcode byte if operand 0..3
H. Peter Anvin32cd4c22008-04-04 13:34:53 -070040 * is a signed byte rather than a dword. Opcode byte follows.
H. Peter Anvin401c07e2007-09-17 16:55:04 -070041 * \160..\163 - this instruction uses DREX rather than REX, with the
42 * OC0 field set to 0, and the dest field taken from
43 * operand 0..3.
44 * \164..\167 - this instruction uses DREX rather than REX, with the
45 * OC0 field set to 1, and the dest field taken from
46 * operand 0..3.
H. Peter 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 Anvin32cd4c22008-04-04 13:34:53 -070053 * \250..\253 - same as \150..\153, except warn if the 64-bit operand
54 * is not equal to the truncated and sign-extended 32-bit
55 * operand; used for 32-bit immediates in 64-bit mode.
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000056 * \310 - indicates fixed 16-bit address size, i.e. optional 0x67.
57 * \311 - indicates fixed 32-bit address size, i.e. optional 0x67.
Keith Kanios48af1772007-08-17 07:37:52 +000058 * \312 - (disassembler only) marker on LOOP, LOOPxx instructions.
H. Peter Anvince2b3972007-05-30 22:21:11 +000059 * \313 - indicates fixed 64-bit address size, 0x67 invalid.
H. Peter Anvin23440102007-11-12 21:02:33 -080060 * \314 - (disassembler only) invalid with REX.B
61 * \315 - (disassembler only) invalid with REX.X
62 * \316 - (disassembler only) invalid with REX.R
63 * \317 - (disassembler only) invalid with REX.W
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000064 * \320 - indicates fixed 16-bit operand size, i.e. optional 0x66.
65 * \321 - indicates fixed 32-bit operand size, i.e. optional 0x66.
66 * \322 - indicates that this instruction is only valid when the
67 * operand size is the default (instruction to disassembler,
68 * generates no code in the assembler)
H. Peter Anvince2b3972007-05-30 22:21:11 +000069 * \323 - indicates fixed 64-bit operand size, REX on extensions only.
Keith Kaniosb7a89542007-04-12 02:40:54 +000070 * \324 - indicates 64-bit operand size requiring REX prefix.
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000071 * \330 - a literal byte follows in the code stream, to be added
72 * to the condition code value of the instruction.
Keith Kanios48af1772007-08-17 07:37:52 +000073 * \331 - instruction not valid with REP prefix. Hint for
H. Peter Anvinef7468f2002-04-30 20:57:59 +000074 * disassembler only; for SSE instructions.
H. Peter Anvincb9b6902007-09-12 21:58:51 -070075 * \332 - REP prefix (0xF2 byte) used as opcode extension.
76 * \333 - REP prefix (0xF3 byte) used as opcode extension.
Keith Kanios48af1772007-08-17 07:37:52 +000077 * \334 - LOCK prefix used instead of REX.R
H. Peter Anvincb9b6902007-09-12 21:58:51 -070078 * \335 - disassemble a rep (0xF3 byte) prefix as repe not rep.
Keith Kaniosb7a89542007-04-12 02:40:54 +000079 * \340 - reserve <operand 0> bytes of uninitialized storage.
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000080 * Operand 0 had better be a segmentless constant.
H. Peter Anvin62cb6062007-09-11 22:44:03 +000081 * \364 - operand-size prefix (0x66) not permitted
82 * \365 - address-size prefix (0x67) not permitted
83 * \366 - operand-size prefix (0x66) used as opcode extension
84 * \367 - address-size prefix (0x67) used as opcode extension
H. Peter Anvin788e6c12002-04-30 21:02:01 +000085 * \370,\371,\372 - match only if operand 0 meets byte jump criteria.
86 * 370 is used for Jcc, 371 is used for JMP.
H. Peter Anvinaf535c12002-04-30 20:59:21 +000087 * \373 - assemble 0x03 if bits==16, 0x05 if bits==32;
88 * used for conditional jump over longer jump
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000089 */
90
H. Peter Anvinfe501952007-10-02 21:53:51 -070091#include "compiler.h"
92
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000093#include <stdio.h>
94#include <string.h>
Keith Kaniosb7a89542007-04-12 02:40:54 +000095#include <inttypes.h>
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000096
97#include "nasm.h"
H. Peter Anvin6768eb72002-04-30 20:52:26 +000098#include "nasmlib.h"
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000099#include "assemble.h"
100#include "insns.h"
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000101#include "preproc.h"
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000102#include "regflags.c"
Keith Kaniosb7a89542007-04-12 02:40:54 +0000103#include "regvals.c"
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000104
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000105typedef struct {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000106 int sib_present; /* is a SIB byte necessary? */
107 int bytes; /* # of bytes of offset needed */
108 int size; /* lazy - this is sib+bytes+1 */
109 uint8_t modrm, sib, rex, rip; /* the bytes themselves */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000110} ea;
111
Keith Kaniosb7a89542007-04-12 02:40:54 +0000112static uint32_t cpu; /* cpu level received from nasm.c */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000113static efunc errfunc;
114static struct ofmt *outfmt;
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000115static ListGen *list;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000116
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800117static int64_t calcsize(int32_t, int64_t, int, insn *, const char *);
118static void gencode(int32_t, int64_t, int, insn *, const char *, int64_t);
H. Peter Anvin3360d792007-09-11 04:16:57 +0000119static int matches(const struct itemplate *, insn *, int bits);
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000120static int32_t regflag(const operand *);
121static int32_t regval(const operand *);
122static int rexflags(int, int32_t, int);
123static int op_rexflags(const operand *, int);
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700124static ea *process_ea(operand *, ea *, int, int, int, int32_t, int);
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700125static void add_asp(insn *, int);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000126
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700127static int has_prefix(insn * ins, enum prefix_pos pos, enum prefixes prefix)
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000128{
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700129 return ins->prefixes[pos] == prefix;
130}
131
132static void assert_no_prefix(insn * ins, enum prefix_pos pos)
133{
134 if (ins->prefixes[pos])
135 errfunc(ERR_NONFATAL, "invalid %s prefix",
136 prefix_name(ins->prefixes[pos]));
137}
138
139static const char *size_name(int size)
140{
141 switch (size) {
142 case 1:
143 return "byte";
144 case 2:
145 return "word";
146 case 4:
147 return "dword";
148 case 8:
149 return "qword";
150 case 10:
151 return "tword";
152 case 16:
153 return "oword";
154 default:
155 return "???";
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000156 }
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700157}
158
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700159static void warn_overflow(int size, int64_t data)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700160{
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700161 if (size < 8) {
Charles Craynedd462c82007-11-04 15:28:30 -0800162 int64_t lim = ((int64_t)1 << (size*8))-1;
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000163
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700164 if (data < ~lim || data > lim)
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700165 errfunc(ERR_WARNING | ERR_WARN_NOV,
166 "%s data exceeds bounds", size_name(size));
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700167 }
168}
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000169/*
170 * This routine wrappers the real output format's output routine,
171 * in order to pass a copy of the data off to the listing file
172 * generator at the same time.
173 */
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800174static void out(int64_t offset, int32_t segto, const void *data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800175 enum out_type type, uint64_t size,
176 int32_t segment, int32_t wrt)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000177{
Keith Kaniosb7a89542007-04-12 02:40:54 +0000178 static int32_t lineno = 0; /* static!!! */
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000179 static char *lnfname = NULL;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800180 uint8_t p[8];
H. Peter Anvineba20a72002-04-30 20:53:55 +0000181
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800182 if (type == OUT_ADDRESS && segment == NO_SEG && wrt == NO_SEG) {
183 /*
184 * This is a non-relocated address, and we're going to
185 * convert it into RAWDATA format.
186 */
187 uint8_t *q = p;
H. Peter Anvind1fb15c2007-11-13 09:37:59 -0800188
189 if (size > 8) {
190 errfunc(ERR_PANIC, "OUT_ADDRESS with size > 8");
191 return;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800192 }
H. Peter Anvind1fb15c2007-11-13 09:37:59 -0800193
194 WRITEADDR(q, *(int64_t *)data, size);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800195 data = p;
196 type = OUT_RAWDATA;
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000197 }
198
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800199 list->output(offset, data, type, size);
200
Frank Kotlerabebb082003-09-06 04:45:37 +0000201 /*
202 * this call to src_get determines when we call the
203 * debug-format-specific "linenum" function
204 * it updates lineno and lnfname to the current values
205 * returning 0 if "same as last time", -2 if lnfname
206 * changed, and the amount by which lineno changed,
207 * if it did. thus, these variables must be static
208 */
209
H. Peter Anvine2c80182005-01-15 22:15:51 +0000210 if (src_get(&lineno, &lnfname)) {
211 outfmt->current_dfmt->linenum(lnfname, lineno, segto);
H. Peter Anvince616072002-04-30 21:02:23 +0000212 }
H. Peter Anvineba20a72002-04-30 20:53:55 +0000213
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800214 outfmt->output(segto, data, type, size, segment, wrt);
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000215}
216
Charles Crayne5fbbc8c2007-11-07 19:03:46 -0800217static int jmp_match(int32_t segment, int64_t offset, int bits,
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000218 insn * ins, const char *code)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000219{
Charles Crayne5fbbc8c2007-11-07 19:03:46 -0800220 int64_t isize;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000221 uint8_t c = code[0];
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000222
H. Peter Anvine2c80182005-01-15 22:15:51 +0000223 if (c != 0370 && c != 0371)
224 return 0;
H. Peter Anvin788e6c12002-04-30 21:02:01 +0000225 if (ins->oprs[0].opflags & OPFLAG_FORWARD) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000226 if ((optimizing < 0 || (ins->oprs[0].type & STRICT))
227 && c == 0370)
228 return 1;
229 else
230 return (pass0 == 0); /* match a forward reference */
H. Peter Anvin788e6c12002-04-30 21:02:01 +0000231 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000232 isize = calcsize(segment, offset, bits, ins, code);
233 if (ins->oprs[0].segment != segment)
234 return 0;
235 isize = ins->oprs[0].offset - offset - isize; /* isize is now the delta */
236 if (isize >= -128L && isize <= 127L)
237 return 1; /* it is byte size */
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000238
239 return 0;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000240}
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000241
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800242int64_t assemble(int32_t segment, int64_t offset, int bits, uint32_t cp,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000243 insn * instruction, struct ofmt *output, efunc error,
244 ListGen * listgen)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000245{
H. Peter Anvin3360d792007-09-11 04:16:57 +0000246 const struct itemplate *temp;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000247 int j;
248 int size_prob;
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800249 int64_t insn_end;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000250 int32_t itimes;
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800251 int64_t start = offset;
252 int64_t wsize = 0; /* size for DB etc. */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000253
H. Peter Anvine2c80182005-01-15 22:15:51 +0000254 errfunc = error; /* to pass to other functions */
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000255 cpu = cp;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000256 outfmt = output; /* likewise */
257 list = listgen; /* and again */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000258
H. Peter Anvine2c80182005-01-15 22:15:51 +0000259 switch (instruction->opcode) {
260 case -1:
261 return 0;
262 case I_DB:
263 wsize = 1;
264 break;
265 case I_DW:
266 wsize = 2;
267 break;
268 case I_DD:
269 wsize = 4;
270 break;
271 case I_DQ:
272 wsize = 8;
273 break;
274 case I_DT:
275 wsize = 10;
276 break;
H. Peter Anvincfbe7c32007-09-18 17:49:09 -0700277 case I_DO:
278 wsize = 16;
279 break;
H. Peter Anvin16b0a332007-09-12 20:27:41 -0700280 default:
281 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000282 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000283
H. Peter Anvineba20a72002-04-30 20:53:55 +0000284 if (wsize) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000285 extop *e;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000286 int32_t t = instruction->times;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000287 if (t < 0)
288 errfunc(ERR_PANIC,
289 "instruction->times < 0 (%ld) in assemble()", t);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000290
H. Peter Anvine2c80182005-01-15 22:15:51 +0000291 while (t--) { /* repeat TIMES times */
292 for (e = instruction->eops; e; e = e->next) {
293 if (e->type == EOT_DB_NUMBER) {
294 if (wsize == 1) {
295 if (e->segment != NO_SEG)
296 errfunc(ERR_NONFATAL,
297 "one-byte relocation attempted");
298 else {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000299 uint8_t out_byte = e->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000300 out(offset, segment, &out_byte,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800301 OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000302 }
Keith Kanios61ff53c2007-04-14 18:54:52 +0000303 } else if (wsize > 8) {
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700304 errfunc(ERR_NONFATAL, "integer supplied to a DT or DO"
Keith Kanios61ff53c2007-04-14 18:54:52 +0000305 " instruction");
H. Peter Anvine2c80182005-01-15 22:15:51 +0000306 } else
307 out(offset, segment, &e->offset,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800308 OUT_ADDRESS, wsize, e->segment, e->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000309 offset += wsize;
310 } else if (e->type == EOT_DB_STRING) {
311 int align;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000312
H. Peter Anvine2c80182005-01-15 22:15:51 +0000313 out(offset, segment, e->stringval,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800314 OUT_RAWDATA, e->stringlen, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000315 align = e->stringlen % wsize;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000316
H. Peter Anvine2c80182005-01-15 22:15:51 +0000317 if (align) {
318 align = wsize - align;
H. Peter Anvind387b8c2008-01-27 16:39:26 -0800319 out(offset, segment,
320 "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0",
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800321 OUT_RAWDATA, align, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000322 }
323 offset += e->stringlen + align;
324 }
325 }
326 if (t > 0 && t == instruction->times - 1) {
327 /*
328 * Dummy call to list->output to give the offset to the
329 * listing module.
330 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800331 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000332 list->uplevel(LIST_TIMES);
333 }
334 }
335 if (instruction->times > 1)
336 list->downlevel(LIST_TIMES);
337 return offset - start;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000338 }
339
H. Peter Anvine2c80182005-01-15 22:15:51 +0000340 if (instruction->opcode == I_INCBIN) {
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000341 static char fname[FILENAME_MAX];
H. Peter Anvine2c80182005-01-15 22:15:51 +0000342 FILE *fp;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000343 int32_t len;
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000344 char *prefix = "", *combine;
345 char **pPrevPath = NULL;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000346
H. Peter Anvine2c80182005-01-15 22:15:51 +0000347 len = FILENAME_MAX - 1;
348 if (len > instruction->eops->stringlen)
349 len = instruction->eops->stringlen;
350 strncpy(fname, instruction->eops->stringval, len);
351 fname[len] = '\0';
H. Peter Anvineba20a72002-04-30 20:53:55 +0000352
Keith Kaniosb7a89542007-04-12 02:40:54 +0000353 while (1) { /* added by alexfru: 'incbin' uses include paths */
H. Peter Anvine2c80182005-01-15 22:15:51 +0000354 combine = nasm_malloc(strlen(prefix) + len + 1);
355 strcpy(combine, prefix);
356 strcat(combine, fname);
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000357
H. Peter Anvine2c80182005-01-15 22:15:51 +0000358 if ((fp = fopen(combine, "rb")) != NULL) {
359 nasm_free(combine);
360 break;
361 }
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000362
H. Peter Anvine2c80182005-01-15 22:15:51 +0000363 nasm_free(combine);
364 pPrevPath = pp_get_include_path_ptr(pPrevPath);
365 if (pPrevPath == NULL)
366 break;
367 prefix = *pPrevPath;
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000368 }
369
370 if (fp == NULL)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000371 error(ERR_NONFATAL, "`incbin': unable to open file `%s'",
372 fname);
373 else if (fseek(fp, 0L, SEEK_END) < 0)
374 error(ERR_NONFATAL, "`incbin': unable to seek on file `%s'",
375 fname);
376 else {
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000377 static char buf[2048];
Keith Kaniosb7a89542007-04-12 02:40:54 +0000378 int32_t t = instruction->times;
379 int32_t base = 0;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000380
H. Peter Anvine2c80182005-01-15 22:15:51 +0000381 len = ftell(fp);
382 if (instruction->eops->next) {
383 base = instruction->eops->next->offset;
384 len -= base;
385 if (instruction->eops->next->next &&
386 len > instruction->eops->next->next->offset)
387 len = instruction->eops->next->next->offset;
388 }
389 /*
390 * Dummy call to list->output to give the offset to the
391 * listing module.
392 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800393 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000394 list->uplevel(LIST_INCBIN);
395 while (t--) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000396 int32_t l;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000397
H. Peter Anvine2c80182005-01-15 22:15:51 +0000398 fseek(fp, base, SEEK_SET);
399 l = len;
400 while (l > 0) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000401 int32_t m =
Charles Crayne192d5b52007-10-18 19:02:42 -0700402 fread(buf, 1, (l > (int32_t) sizeof(buf) ? (int32_t) sizeof(buf) : l),
H. Peter Anvine2c80182005-01-15 22:15:51 +0000403 fp);
404 if (!m) {
405 /*
406 * This shouldn't happen unless the file
407 * actually changes while we are reading
408 * it.
409 */
410 error(ERR_NONFATAL,
411 "`incbin': unexpected EOF while"
412 " reading file `%s'", fname);
413 t = 0; /* Try to exit cleanly */
414 break;
415 }
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800416 out(offset, segment, buf, OUT_RAWDATA, m,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000417 NO_SEG, NO_SEG);
418 l -= m;
419 }
420 }
421 list->downlevel(LIST_INCBIN);
422 if (instruction->times > 1) {
423 /*
424 * Dummy call to list->output to give the offset to the
425 * listing module.
426 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800427 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000428 list->uplevel(LIST_TIMES);
429 list->downlevel(LIST_TIMES);
430 }
431 fclose(fp);
432 return instruction->times * len;
433 }
434 return 0; /* if we're here, there's an error */
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000435 }
436
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700437 /* Check to see if we need an address-size prefix */
438 add_asp(instruction, bits);
439
H. Peter Anvin6867acc2007-10-10 14:58:45 -0700440 size_prob = false;
H. Peter Anvin70653092007-10-19 14:42:29 -0700441
442 for (temp = nasm_instructions[instruction->opcode]; temp->opcode != -1; temp++){
Keith Kaniosb7a89542007-04-12 02:40:54 +0000443 int m = matches(temp, instruction, bits);
H. Peter Anvin70653092007-10-19 14:42:29 -0700444
H. Peter Anvine2c80182005-01-15 22:15:51 +0000445 if (m == 99)
446 m += jmp_match(segment, offset, bits, instruction, temp->code);
H. Peter Anvineba20a72002-04-30 20:53:55 +0000447
H. Peter Anvine2c80182005-01-15 22:15:51 +0000448 if (m == 100) { /* matches! */
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000449 const char *codes = temp->code;
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800450 int64_t insn_size = calcsize(segment, offset, bits,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000451 instruction, codes);
452 itimes = instruction->times;
453 if (insn_size < 0) /* shouldn't be, on pass two */
454 error(ERR_PANIC, "errors made it through from pass one");
455 else
456 while (itimes--) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700457 for (j = 0; j < MAXPREFIX; j++) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000458 uint8_t c = 0;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000459 switch (instruction->prefixes[j]) {
460 case P_LOCK:
461 c = 0xF0;
462 break;
463 case P_REPNE:
464 case P_REPNZ:
465 c = 0xF2;
466 break;
467 case P_REPE:
468 case P_REPZ:
469 case P_REP:
470 c = 0xF3;
471 break;
472 case R_CS:
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000473 if (bits == 64) {
474 error(ERR_WARNING,
Charles Crayne1b851dc2007-11-05 21:49:49 -0800475 "cs segment base generated, but will be ignored in 64-bit mode");
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000476 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000477 c = 0x2E;
478 break;
479 case R_DS:
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000480 if (bits == 64) {
481 error(ERR_WARNING,
Charles Crayne1b851dc2007-11-05 21:49:49 -0800482 "ds segment base generated, but will be ignored in 64-bit mode");
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000483 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000484 c = 0x3E;
485 break;
486 case R_ES:
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000487 if (bits == 64) {
488 error(ERR_WARNING,
Charles Crayne1b851dc2007-11-05 21:49:49 -0800489 "es segment base generated, but will be ignored in 64-bit mode");
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000490 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000491 c = 0x26;
492 break;
493 case R_FS:
494 c = 0x64;
495 break;
496 case R_GS:
497 c = 0x65;
498 break;
499 case R_SS:
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000500 if (bits == 64) {
501 error(ERR_WARNING,
Charles Crayne1b851dc2007-11-05 21:49:49 -0800502 "ss segment base generated, but will be ignored in 64-bit mode");
Keith Kaniosfd5d9132007-04-16 15:46:46 +0000503 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000504 c = 0x36;
505 break;
506 case R_SEGR6:
507 case R_SEGR7:
508 error(ERR_NONFATAL,
509 "segr6 and segr7 cannot be used as prefixes");
510 break;
511 case P_A16:
Keith Kaniosb7a89542007-04-12 02:40:54 +0000512 if (bits == 64) {
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000513 error(ERR_NONFATAL,
514 "16-bit addressing is not supported "
515 "in 64-bit mode");
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700516 } else if (bits != 16)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000517 c = 0x67;
518 break;
519 case P_A32:
520 if (bits != 32)
521 c = 0x67;
522 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700523 case P_A64:
524 if (bits != 64) {
525 error(ERR_NONFATAL,
526 "64-bit addressing is only supported "
527 "in 64-bit mode");
528 }
529 break;
530 case P_ASP:
531 c = 0x67;
532 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000533 case P_O16:
534 if (bits != 16)
535 c = 0x66;
536 break;
537 case P_O32:
Keith Kaniosb7a89542007-04-12 02:40:54 +0000538 if (bits == 16)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000539 c = 0x66;
540 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700541 case P_O64:
542 /* REX.W */
543 break;
544 case P_OSP:
545 c = 0x66;
546 break;
547 case P_none:
548 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000549 default:
550 error(ERR_PANIC, "invalid instruction prefix");
551 }
552 if (c != 0) {
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800553 out(offset, segment, &c, OUT_RAWDATA, 1,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000554 NO_SEG, NO_SEG);
555 offset++;
556 }
H. Peter Anvin70653092007-10-19 14:42:29 -0700557 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000558 insn_end = offset + insn_size;
559 gencode(segment, offset, bits, instruction, codes,
560 insn_end);
561 offset += insn_size;
562 if (itimes > 0 && itimes == instruction->times - 1) {
563 /*
564 * Dummy call to list->output to give the offset to the
565 * listing module.
566 */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800567 list->output(offset, NULL, OUT_RAWDATA, 0);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000568 list->uplevel(LIST_TIMES);
569 }
570 }
571 if (instruction->times > 1)
572 list->downlevel(LIST_TIMES);
573 return offset - start;
574 } else if (m > 0 && m > size_prob) {
575 size_prob = m;
576 }
Keith Kaniosb7a89542007-04-12 02:40:54 +0000577// temp++;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000578 }
H. Peter Anvineba20a72002-04-30 20:53:55 +0000579
H. Peter Anvine2c80182005-01-15 22:15:51 +0000580 if (temp->opcode == -1) { /* didn't match any instruction */
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000581 switch (size_prob) {
582 case 1:
583 error(ERR_NONFATAL, "operation size not specified");
584 break;
585 case 2:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000586 error(ERR_NONFATAL, "mismatch in operand sizes");
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000587 break;
588 case 3:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000589 error(ERR_NONFATAL, "no instruction for this cpu level");
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000590 break;
591 case 4:
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000592 error(ERR_NONFATAL, "instruction not supported in 64-bit mode");
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000593 break;
594 default:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000595 error(ERR_NONFATAL,
596 "invalid combination of opcode and operands");
H. Peter Anvin34539fb2007-05-30 04:27:58 +0000597 break;
598 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000599 }
600 return 0;
601}
602
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800603int64_t insn_size(int32_t segment, int64_t offset, int bits, uint32_t cp,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000604 insn * instruction, efunc error)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000605{
H. Peter Anvin3360d792007-09-11 04:16:57 +0000606 const struct itemplate *temp;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000607
H. Peter Anvine2c80182005-01-15 22:15:51 +0000608 errfunc = error; /* to pass to other functions */
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000609 cpu = cp;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000610
611 if (instruction->opcode == -1)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000612 return 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000613
H. Peter Anvincfbe7c32007-09-18 17:49:09 -0700614 if (instruction->opcode == I_DB || instruction->opcode == I_DW ||
615 instruction->opcode == I_DD || instruction->opcode == I_DQ ||
616 instruction->opcode == I_DT || instruction->opcode == I_DO) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000617 extop *e;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000618 int32_t isize, osize, wsize = 0; /* placate gcc */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000619
H. Peter Anvine2c80182005-01-15 22:15:51 +0000620 isize = 0;
621 switch (instruction->opcode) {
622 case I_DB:
623 wsize = 1;
624 break;
625 case I_DW:
626 wsize = 2;
627 break;
628 case I_DD:
629 wsize = 4;
630 break;
631 case I_DQ:
632 wsize = 8;
633 break;
634 case I_DT:
635 wsize = 10;
636 break;
H. Peter Anvincfbe7c32007-09-18 17:49:09 -0700637 case I_DO:
638 wsize = 16;
639 break;
H. Peter Anvin16b0a332007-09-12 20:27:41 -0700640 default:
641 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000642 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000643
H. Peter Anvine2c80182005-01-15 22:15:51 +0000644 for (e = instruction->eops; e; e = e->next) {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000645 int32_t align;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000646
H. Peter Anvine2c80182005-01-15 22:15:51 +0000647 osize = 0;
648 if (e->type == EOT_DB_NUMBER)
649 osize = 1;
650 else if (e->type == EOT_DB_STRING)
651 osize = e->stringlen;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000652
H. Peter Anvine2c80182005-01-15 22:15:51 +0000653 align = (-osize) % wsize;
654 if (align < 0)
655 align += wsize;
656 isize += osize + align;
657 }
658 return isize * instruction->times;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000659 }
660
H. Peter Anvine2c80182005-01-15 22:15:51 +0000661 if (instruction->opcode == I_INCBIN) {
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000662 char fname[FILENAME_MAX];
H. Peter Anvine2c80182005-01-15 22:15:51 +0000663 FILE *fp;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000664 int32_t len;
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000665 char *prefix = "", *combine;
666 char **pPrevPath = NULL;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000667
H. Peter Anvine2c80182005-01-15 22:15:51 +0000668 len = FILENAME_MAX - 1;
669 if (len > instruction->eops->stringlen)
670 len = instruction->eops->stringlen;
671 strncpy(fname, instruction->eops->stringval, len);
672 fname[len] = '\0';
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000673
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700674 /* added by alexfru: 'incbin' uses include paths */
675 while (1) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000676 combine = nasm_malloc(strlen(prefix) + len + 1);
677 strcpy(combine, prefix);
678 strcat(combine, fname);
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000679
H. Peter Anvine2c80182005-01-15 22:15:51 +0000680 if ((fp = fopen(combine, "rb")) != NULL) {
681 nasm_free(combine);
682 break;
683 }
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000684
H. Peter Anvine2c80182005-01-15 22:15:51 +0000685 nasm_free(combine);
686 pPrevPath = pp_get_include_path_ptr(pPrevPath);
687 if (pPrevPath == NULL)
688 break;
689 prefix = *pPrevPath;
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +0000690 }
691
692 if (fp == NULL)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000693 error(ERR_NONFATAL, "`incbin': unable to open file `%s'",
694 fname);
695 else if (fseek(fp, 0L, SEEK_END) < 0)
696 error(ERR_NONFATAL, "`incbin': unable to seek on file `%s'",
697 fname);
698 else {
699 len = ftell(fp);
700 fclose(fp);
701 if (instruction->eops->next) {
702 len -= instruction->eops->next->offset;
703 if (instruction->eops->next->next &&
704 len > instruction->eops->next->next->offset) {
705 len = instruction->eops->next->next->offset;
706 }
707 }
708 return instruction->times * len;
709 }
710 return 0; /* if we're here, there's an error */
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000711 }
712
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700713 /* Check to see if we need an address-size prefix */
714 add_asp(instruction, bits);
715
Keith Kaniosb7a89542007-04-12 02:40:54 +0000716 for (temp = nasm_instructions[instruction->opcode]; temp->opcode != -1; temp++) {
717 int m = matches(temp, instruction, bits);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000718 if (m == 99)
719 m += jmp_match(segment, offset, bits, instruction, temp->code);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000720
H. Peter Anvine2c80182005-01-15 22:15:51 +0000721 if (m == 100) {
722 /* we've matched an instruction. */
Charles Crayne5fbbc8c2007-11-07 19:03:46 -0800723 int64_t isize;
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000724 const char *codes = temp->code;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000725 int j;
726
727 isize = calcsize(segment, offset, bits, instruction, codes);
728 if (isize < 0)
729 return -1;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700730 for (j = 0; j < MAXPREFIX; j++) {
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700731 switch (instruction->prefixes[j]) {
732 case P_A16:
733 if (bits != 16)
734 isize++;
735 break;
736 case P_A32:
737 if (bits != 32)
738 isize++;
739 break;
740 case P_O16:
741 if (bits != 16)
742 isize++;
743 break;
744 case P_O32:
745 if (bits == 16)
746 isize++;
747 break;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700748 case P_A64:
749 case P_O64:
750 case P_none:
751 break;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700752 default:
753 isize++;
754 break;
755 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000756 }
757 return isize * instruction->times;
758 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000759 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000760 return -1; /* didn't match any instruction */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000761}
762
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700763static bool possible_sbyte(insn * ins, int op)
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000764{
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700765 return !(ins->forw_ref && ins->oprs[op].opflags) &&
H. Peter Anvine2c80182005-01-15 22:15:51 +0000766 optimizing >= 0 &&
767 !(ins->oprs[op].type & STRICT) &&
768 ins->oprs[op].wrt == NO_SEG && ins->oprs[op].segment == NO_SEG;
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000769}
770
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700771/* check that opn[op] is a signed byte of size 16 or 32 */
772static bool is_sbyte16(insn * ins, int op)
773{
774 int16_t v;
775
776 if (!possible_sbyte(ins, op))
777 return false;
778
779 v = ins->oprs[op].offset;
780 return v >= -128 && v <= 127;
781}
782
783static bool is_sbyte32(insn * ins, int op)
784{
785 int32_t v;
786
787 if (!possible_sbyte(ins, op))
788 return false;
789
790 v = ins->oprs[op].offset;
791 return v >= -128 && v <= 127;
792}
793
794/* check that opn[op] is a signed byte of size 32; warn if this is not
795 the original value when extended to 64 bits */
796static bool is_sbyte64(insn * ins, int op)
797{
798 int64_t v64;
799 int32_t v32;
800
801 /* dead in the water on forward reference or External */
802 if (!possible_sbyte(ins, op))
803 return false;
804
805 v64 = ins->oprs[op].offset;
806 v32 = (int32_t)v64;
807
808 warn_overflow(32, v64);
809
810 return v32 >= -128 && v32 <= 127;
811}
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800812static int64_t calcsize(int32_t segment, int64_t offset, int bits,
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000813 insn * ins, const char *codes)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000814{
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800815 int64_t length = 0;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000816 uint8_t c;
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000817 int rex_mask = ~0;
H. Peter Anvin839eca22007-10-29 23:12:47 -0700818 struct operand *opx;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000819
H. Peter Anvine3917fc2007-11-01 14:53:32 -0700820 ins->rex = 0; /* Ensure REX is reset */
821
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700822 if (ins->prefixes[PPS_OSIZE] == P_O64)
823 ins->rex |= REX_W;
824
H. Peter Anvine2c80182005-01-15 22:15:51 +0000825 (void)segment; /* Don't warn that this parameter is unused */
826 (void)offset; /* Don't warn that this parameter is unused */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000827
H. Peter Anvin839eca22007-10-29 23:12:47 -0700828 while (*codes) {
829 c = *codes++;
830 opx = &ins->oprs[c & 3];
831 switch (c) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000832 case 01:
833 case 02:
834 case 03:
835 codes += c, length += c;
836 break;
837 case 04:
838 case 05:
839 case 06:
840 case 07:
841 length++;
842 break;
843 case 010:
844 case 011:
845 case 012:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700846 case 013:
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000847 ins->rex |=
H. Peter Anvin839eca22007-10-29 23:12:47 -0700848 op_rexflags(opx, REX_B|REX_H|REX_P|REX_W);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000849 codes++, length++;
850 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000851 case 014:
852 case 015:
853 case 016:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700854 case 017:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000855 length++;
856 break;
857 case 020:
858 case 021:
859 case 022:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700860 case 023:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000861 length++;
862 break;
863 case 024:
864 case 025:
865 case 026:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700866 case 027:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000867 length++;
868 break;
869 case 030:
870 case 031:
871 case 032:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700872 case 033:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000873 length += 2;
874 break;
875 case 034:
876 case 035:
877 case 036:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700878 case 037:
H. Peter Anvin839eca22007-10-29 23:12:47 -0700879 if (opx->type & (BITS16 | BITS32 | BITS64))
880 length += (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000881 else
882 length += (bits == 16) ? 2 : 4;
883 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000884 case 040:
885 case 041:
886 case 042:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700887 case 043:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000888 length += 4;
889 break;
890 case 044:
891 case 045:
892 case 046:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700893 case 047:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700894 length += ins->addr_size >> 3;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000895 break;
896 case 050:
897 case 051:
898 case 052:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700899 case 053:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000900 length++;
901 break;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000902 case 054:
903 case 055:
904 case 056:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700905 case 057:
Keith Kaniosb7a89542007-04-12 02:40:54 +0000906 length += 8; /* MOV reg64/imm */
907 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000908 case 060:
909 case 061:
910 case 062:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700911 case 063:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000912 length += 2;
913 break;
914 case 064:
915 case 065:
916 case 066:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700917 case 067:
H. Peter Anvin839eca22007-10-29 23:12:47 -0700918 if (opx->type & (BITS16 | BITS32 | BITS64))
919 length += (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000920 else
921 length += (bits == 16) ? 2 : 4;
922 break;
923 case 070:
924 case 071:
925 case 072:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700926 case 073:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000927 length += 4;
928 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700929 case 074:
930 case 075:
931 case 076:
932 case 077:
933 length += 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000934 break;
935 case 0140:
936 case 0141:
937 case 0142:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700938 case 0143:
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700939 length += is_sbyte16(ins, c & 3) ? 1 : 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000940 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000941 case 0144:
942 case 0145:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700943 case 0146:
944 case 0147:
H. Peter Anvina30cc072007-11-18 21:55:26 -0800945 codes++;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000946 length++;
947 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700948 case 0150:
949 case 0151:
950 case 0152:
951 case 0153:
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700952 length += is_sbyte32(ins, c & 3) ? 1 : 4;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700953 break;
954 case 0154:
955 case 0155:
956 case 0156:
957 case 0157:
H. Peter Anvina30cc072007-11-18 21:55:26 -0800958 codes++;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700959 length++;
960 break;
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700961 case 0160:
962 case 0161:
963 case 0162:
964 case 0163:
965 length++;
966 ins->rex |= REX_D;
H. Peter Anvincf5180a2007-09-17 17:25:27 -0700967 ins->drexdst = regval(&ins->oprs[c & 3]);
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700968 break;
969 case 0164:
970 case 0165:
971 case 0166:
972 case 0167:
973 length++;
974 ins->rex |= REX_D|REX_OC;
H. Peter Anvincf5180a2007-09-17 17:25:27 -0700975 ins->drexdst = regval(&ins->oprs[c & 3]);
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700976 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700977 case 0170:
978 length++;
979 break;
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700980 case 0171:
981 break;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -0700982 case 0250:
983 case 0251:
984 case 0252:
985 case 0253:
986 length += is_sbyte64(ins, c & 3) ? 1 : 4;
987 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000988 case 0300:
989 case 0301:
H. Peter Anvin70653092007-10-19 14:42:29 -0700990 case 0302:
991 case 0303:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000992 break;
993 case 0310:
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700994 if (bits == 64)
995 return -1;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700996 length += (bits != 16) && !has_prefix(ins, PPS_ASIZE, P_A16);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000997 break;
998 case 0311:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700999 length += (bits != 32) && !has_prefix(ins, PPS_ASIZE, P_A32);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001000 break;
1001 case 0312:
H. Peter Anvin70653092007-10-19 14:42:29 -07001002 break;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001003 case 0313:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001004 if (bits != 64 || has_prefix(ins, PPS_ASIZE, P_A16) ||
1005 has_prefix(ins, PPS_ASIZE, P_A32))
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07001006 return -1;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001007 break;
H. Peter Anvin23440102007-11-12 21:02:33 -08001008 case 0314:
1009 case 0315:
1010 case 0316:
1011 case 0317:
1012 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001013 case 0320:
Keith Kaniosb7a89542007-04-12 02:40:54 +00001014 length += (bits != 16);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001015 break;
1016 case 0321:
1017 length += (bits == 16);
1018 break;
1019 case 0322:
1020 break;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001021 case 0323:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001022 rex_mask &= ~REX_W;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001023 break;
1024 case 0324:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001025 ins->rex |= REX_W;
H. Peter Anvin8d7316a2007-04-18 02:27:18 +00001026 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001027 case 0330:
1028 codes++, length++;
1029 break;
1030 case 0331:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001031 break;
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001032 case 0332:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001033 case 0333:
1034 length++;
1035 break;
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001036 case 0334:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001037 ins->rex |= REX_L;
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001038 break;
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001039 case 0335:
1040 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001041 case 0340:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001042 if (ins->oprs[0].segment != NO_SEG)
1043 errfunc(ERR_NONFATAL, "attempt to reserve non-constant"
1044 " quantity of BSS space");
1045 else
H. Peter Anvin428fd672007-11-15 10:25:52 -08001046 length += ins->oprs[0].offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001047 break;
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001048 case 0364:
1049 case 0365:
1050 break;
Keith Kanios48af1772007-08-17 07:37:52 +00001051 case 0366:
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001052 case 0367:
1053 length++;
1054 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001055 case 0370:
1056 case 0371:
1057 case 0372:
1058 break;
1059 case 0373:
1060 length++;
1061 break;
1062 default: /* can't do it by 'case' statements */
1063 if (c >= 0100 && c <= 0277) { /* it's an EA */
1064 ea ea_data;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001065 int rfield;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001066 int32_t rflags;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001067 ea_data.rex = 0; /* Ensure ea.REX is initially 0 */
H. Peter Anvin70653092007-10-19 14:42:29 -07001068
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001069 if (c <= 0177) {
1070 /* pick rfield from operand b */
1071 rflags = regflag(&ins->oprs[c & 7]);
1072 rfield = regvals[ins->oprs[c & 7].basereg];
1073 } else {
1074 rflags = 0;
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001075 rfield = c & 7;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001076 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00001077
H. Peter Anvine2c80182005-01-15 22:15:51 +00001078 if (!process_ea
Keith Kaniosb7a89542007-04-12 02:40:54 +00001079 (&ins->oprs[(c >> 3) & 7], &ea_data, bits,
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001080 ins->addr_size, rfield, rflags, ins->forw_ref)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001081 errfunc(ERR_NONFATAL, "invalid effective address");
1082 return -1;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001083 } else {
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001084 ins->rex |= ea_data.rex;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001085 length += ea_data.size;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001086 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001087 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001088 errfunc(ERR_PANIC, "internal instruction table corrupt"
1089 ": instruction code 0x%02X given", c);
H. Peter Anvin839eca22007-10-29 23:12:47 -07001090 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001091 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001092 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001093
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001094 ins->rex &= rex_mask;
H. Peter Anvin70653092007-10-19 14:42:29 -07001095
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001096 if (ins->rex & REX_D) {
1097 if (ins->rex & REX_H) {
1098 errfunc(ERR_NONFATAL, "cannot use high register in drex instruction");
1099 return -1;
1100 }
H. Peter Anvincf5180a2007-09-17 17:25:27 -07001101 if (bits != 64 && ((ins->rex & (REX_W|REX_X|REX_B)) ||
1102 ins->drexdst > 7)) {
1103 errfunc(ERR_NONFATAL, "invalid operands in non-64-bit mode");
1104 return -1;
1105 }
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001106 length++;
1107 } else if (ins->rex & REX_REAL) {
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001108 if (ins->rex & REX_H) {
1109 errfunc(ERR_NONFATAL, "cannot use high register in rex instruction");
1110 return -1;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001111 } else if (bits == 64) {
1112 length++;
1113 } else if ((ins->rex & REX_L) &&
1114 !(ins->rex & (REX_P|REX_W|REX_X|REX_B)) &&
1115 cpu >= IF_X86_64) {
1116 /* LOCK-as-REX.R */
1117 assert_no_prefix(ins, PPS_LREP);
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001118 length++;
H. Peter Anvin8d7316a2007-04-18 02:27:18 +00001119 } else {
H. Peter Anvincf5180a2007-09-17 17:25:27 -07001120 errfunc(ERR_NONFATAL, "invalid operands in non-64-bit mode");
1121 return -1;
H. Peter Anvin8d7316a2007-04-18 02:27:18 +00001122 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00001123 }
1124
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001125 return length;
1126}
Keith Kaniosb7a89542007-04-12 02:40:54 +00001127
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001128#define EMIT_REX() \
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001129 if (!(ins->rex & REX_D) && (ins->rex & REX_REAL) && (bits == 64)) { \
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001130 ins->rex = (ins->rex & REX_REAL)|REX_P; \
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001131 out(offset, segment, &ins->rex, OUT_RAWDATA, 1, NO_SEG, NO_SEG); \
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001132 ins->rex = 0; \
1133 offset += 1; \
1134 }
1135
Charles Crayne1f8bc4c2007-11-06 18:27:23 -08001136static void gencode(int32_t segment, int64_t offset, int bits,
1137 insn * ins, const char *codes, int64_t insn_end)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001138{
Keith Kaniosa6dfa782007-04-13 16:47:53 +00001139 static char condval[] = { /* conditional opcodes */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001140 0x7, 0x3, 0x2, 0x6, 0x2, 0x4, 0xF, 0xD, 0xC, 0xE, 0x6, 0x2,
1141 0x3, 0x7, 0x3, 0x5, 0xE, 0xC, 0xD, 0xF, 0x1, 0xB, 0x9, 0x5,
1142 0x0, 0xA, 0xA, 0xB, 0x8, 0x4
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001143 };
Keith Kaniosb7a89542007-04-12 02:40:54 +00001144 uint8_t c;
1145 uint8_t bytes[4];
Charles Crayne1f8bc4c2007-11-06 18:27:23 -08001146 int64_t size;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001147 int64_t data;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001148 struct operand *opx;
H. Peter Anvin70653092007-10-19 14:42:29 -07001149
H. Peter Anvin839eca22007-10-29 23:12:47 -07001150 while (*codes) {
1151 c = *codes++;
1152 opx = &ins->oprs[c & 3];
1153 switch (c) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001154 case 01:
1155 case 02:
1156 case 03:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001157 EMIT_REX();
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001158 out(offset, segment, codes, OUT_RAWDATA, c, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001159 codes += c;
1160 offset += c;
1161 break;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001162
H. Peter Anvine2c80182005-01-15 22:15:51 +00001163 case 04:
1164 case 06:
1165 switch (ins->oprs[0].basereg) {
1166 case R_CS:
1167 bytes[0] = 0x0E + (c == 0x04 ? 1 : 0);
1168 break;
1169 case R_DS:
1170 bytes[0] = 0x1E + (c == 0x04 ? 1 : 0);
1171 break;
1172 case R_ES:
1173 bytes[0] = 0x06 + (c == 0x04 ? 1 : 0);
1174 break;
1175 case R_SS:
1176 bytes[0] = 0x16 + (c == 0x04 ? 1 : 0);
1177 break;
1178 default:
1179 errfunc(ERR_PANIC,
1180 "bizarre 8086 segment register received");
1181 }
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001182 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001183 offset++;
1184 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001185
H. Peter Anvine2c80182005-01-15 22:15:51 +00001186 case 05:
1187 case 07:
1188 switch (ins->oprs[0].basereg) {
1189 case R_FS:
1190 bytes[0] = 0xA0 + (c == 0x05 ? 1 : 0);
1191 break;
1192 case R_GS:
1193 bytes[0] = 0xA8 + (c == 0x05 ? 1 : 0);
1194 break;
1195 default:
1196 errfunc(ERR_PANIC,
1197 "bizarre 386 segment register received");
1198 }
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001199 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001200 offset++;
1201 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001202
H. Peter Anvine2c80182005-01-15 22:15:51 +00001203 case 010:
1204 case 011:
1205 case 012:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001206 case 013:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001207 EMIT_REX();
H. Peter Anvin839eca22007-10-29 23:12:47 -07001208 bytes[0] = *codes++ + ((regval(opx)) & 7);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001209 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001210 offset += 1;
1211 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001212
H. Peter Anvine2c80182005-01-15 22:15:51 +00001213 case 014:
1214 case 015:
1215 case 016:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001216 case 017:
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001217 /* XXX: warns for legitimate optimizer actions */
H. Peter Anvin839eca22007-10-29 23:12:47 -07001218 if (opx->offset < -128 || opx->offset > 127) {
H. Peter Anvin72c64372008-01-08 22:13:48 -08001219 errfunc(ERR_WARNING | ERR_WARN_NOV,
1220 "signed byte value exceeds bounds");
H. Peter Anvine2c80182005-01-15 22:15:51 +00001221 }
H. Peter Anvineba20a72002-04-30 20:53:55 +00001222
H. Peter Anvin839eca22007-10-29 23:12:47 -07001223 if (opx->segment != NO_SEG) {
1224 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001225 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001226 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001227 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001228 bytes[0] = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001229 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001230 NO_SEG);
1231 }
1232 offset += 1;
1233 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001234
H. Peter Anvine2c80182005-01-15 22:15:51 +00001235 case 020:
1236 case 021:
1237 case 022:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001238 case 023:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001239 if (opx->offset < -256 || opx->offset > 255) {
H. Peter Anvin72c64372008-01-08 22:13:48 -08001240 errfunc(ERR_WARNING | ERR_WARN_NOV,
1241 "byte value exceeds bounds");
H. Peter Anvine2c80182005-01-15 22:15:51 +00001242 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001243 if (opx->segment != NO_SEG) {
1244 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001245 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001246 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001247 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001248 bytes[0] = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001249 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001250 NO_SEG);
1251 }
1252 offset += 1;
1253 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001254
H. Peter Anvine2c80182005-01-15 22:15:51 +00001255 case 024:
1256 case 025:
1257 case 026:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001258 case 027:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001259 if (opx->offset < 0 || opx->offset > 255)
H. Peter Anvin72c64372008-01-08 22:13:48 -08001260 errfunc(ERR_WARNING | ERR_WARN_NOV,
1261 "unsigned byte value exceeds bounds");
H. Peter Anvin839eca22007-10-29 23:12:47 -07001262 if (opx->segment != NO_SEG) {
1263 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001264 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001265 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001266 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001267 bytes[0] = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001268 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001269 NO_SEG);
1270 }
1271 offset += 1;
1272 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001273
H. Peter Anvine2c80182005-01-15 22:15:51 +00001274 case 030:
1275 case 031:
1276 case 032:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001277 case 033:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001278 data = opx->offset;
1279 if (opx->segment == NO_SEG && opx->wrt == NO_SEG)
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001280 warn_overflow(2, data);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001281 out(offset, segment, &data, OUT_ADDRESS, 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001282 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001283 offset += 2;
1284 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001285
H. Peter Anvine2c80182005-01-15 22:15:51 +00001286 case 034:
1287 case 035:
1288 case 036:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001289 case 037:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001290 if (opx->type & (BITS16 | BITS32))
1291 size = (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001292 else
1293 size = (bits == 16) ? 2 : 4;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001294 data = opx->offset;
1295 if (opx->segment == NO_SEG && opx->wrt == NO_SEG)
H. Peter Anvin10e27272007-10-29 22:56:08 -07001296 warn_overflow(size, data);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001297 out(offset, segment, &data, OUT_ADDRESS, size,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001298 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001299 offset += size;
1300 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001301
H. Peter Anvine2c80182005-01-15 22:15:51 +00001302 case 040:
1303 case 041:
1304 case 042:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001305 case 043:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001306 data = opx->offset;
H. Peter Anvin72c64372008-01-08 22:13:48 -08001307 if (opx->segment == NO_SEG && opx->wrt == NO_SEG)
1308 warn_overflow(4, data);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001309 out(offset, segment, &data, OUT_ADDRESS, 4,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001310 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001311 offset += 4;
1312 break;
H. Peter Anvin3ba46772002-05-27 23:19:35 +00001313
H. Peter Anvine2c80182005-01-15 22:15:51 +00001314 case 044:
1315 case 045:
1316 case 046:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001317 case 047:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001318 data = opx->offset;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001319 size = ins->addr_size >> 3;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001320 if (opx->segment == NO_SEG &&
1321 opx->wrt == NO_SEG)
H. Peter Anvin10e27272007-10-29 22:56:08 -07001322 warn_overflow(size, data);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001323 out(offset, segment, &data, OUT_ADDRESS, size,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001324 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001325 offset += size;
1326 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001327
H. Peter Anvine2c80182005-01-15 22:15:51 +00001328 case 050:
1329 case 051:
1330 case 052:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001331 case 053:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001332 if (opx->segment != segment)
H. Peter Anvine2c80182005-01-15 22:15:51 +00001333 errfunc(ERR_NONFATAL,
1334 "short relative jump outside segment");
H. Peter Anvin839eca22007-10-29 23:12:47 -07001335 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001336 if (data > 127 || data < -128)
1337 errfunc(ERR_NONFATAL, "short jump is out of range");
1338 bytes[0] = data;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001339 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001340 offset += 1;
1341 break;
H. Peter Anvin70653092007-10-19 14:42:29 -07001342
Keith Kaniosb7a89542007-04-12 02:40:54 +00001343 case 054:
1344 case 055:
1345 case 056:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001346 case 057:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001347 data = (int64_t)opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001348 out(offset, segment, &data, OUT_ADDRESS, 8,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001349 opx->segment, opx->wrt);
Keith Kaniosb7a89542007-04-12 02:40:54 +00001350 offset += 8;
1351 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001352
H. Peter Anvine2c80182005-01-15 22:15:51 +00001353 case 060:
1354 case 061:
1355 case 062:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001356 case 063:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001357 if (opx->segment != segment) {
1358 data = opx->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001359 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001360 OUT_REL2ADR, insn_end - offset,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001361 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001362 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001363 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001364 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001365 OUT_ADDRESS, 2, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001366 }
1367 offset += 2;
1368 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001369
H. Peter Anvine2c80182005-01-15 22:15:51 +00001370 case 064:
1371 case 065:
1372 case 066:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001373 case 067:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001374 if (opx->type & (BITS16 | BITS32 | BITS64))
1375 size = (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001376 else
1377 size = (bits == 16) ? 2 : 4;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001378 if (opx->segment != segment) {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001379 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001380 out(offset, segment, &data,
1381 size == 2 ? OUT_REL2ADR : OUT_REL4ADR,
1382 insn_end - offset, opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001383 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001384 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001385 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001386 OUT_ADDRESS, size, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001387 }
1388 offset += size;
1389 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001390
H. Peter Anvine2c80182005-01-15 22:15:51 +00001391 case 070:
1392 case 071:
1393 case 072:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001394 case 073:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001395 if (opx->segment != segment) {
1396 data = opx->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001397 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001398 OUT_REL4ADR, insn_end - offset,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001399 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001400 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001401 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001402 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001403 OUT_ADDRESS, 4, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001404 }
1405 offset += 4;
1406 break;
H. Peter Anvinaf535c12002-04-30 20:59:21 +00001407
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001408 case 074:
1409 case 075:
1410 case 076:
1411 case 077:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001412 if (opx->segment == NO_SEG)
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001413 errfunc(ERR_NONFATAL, "value referenced by FAR is not"
1414 " relocatable");
1415 data = 0L;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001416 out(offset, segment, &data, OUT_ADDRESS, 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001417 outfmt->segbase(1 + opx->segment),
1418 opx->wrt);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001419 offset += 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001420 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001421
H. Peter Anvine2c80182005-01-15 22:15:51 +00001422 case 0140:
1423 case 0141:
1424 case 0142:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001425 case 0143:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001426 data = opx->offset;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001427 if (is_sbyte16(ins, c & 3)) {
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001428 bytes[0] = data;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001429 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001430 NO_SEG);
1431 offset++;
1432 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001433 if (opx->segment == NO_SEG &&
1434 opx->wrt == NO_SEG)
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001435 warn_overflow(2, data);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001436 out(offset, segment, &data, OUT_ADDRESS, 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001437 opx->segment, opx->wrt);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001438 offset += 2;
1439 }
1440 break;
1441
1442 case 0144:
1443 case 0145:
1444 case 0146:
1445 case 0147:
1446 EMIT_REX();
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001447 bytes[0] = *codes++;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001448 if (is_sbyte16(ins, c & 3))
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001449 bytes[0] |= 2; /* s-bit */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001450 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001451 offset++;
1452 break;
1453
1454 case 0150:
1455 case 0151:
1456 case 0152:
1457 case 0153:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001458 data = opx->offset;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001459 if (is_sbyte32(ins, c & 3)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001460 bytes[0] = data;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001461 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001462 NO_SEG);
1463 offset++;
1464 } else {
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001465 out(offset, segment, &data, OUT_ADDRESS, 4,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001466 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001467 offset += 4;
1468 }
1469 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001470
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001471 case 0154:
1472 case 0155:
1473 case 0156:
1474 case 0157:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001475 EMIT_REX();
H. Peter Anvine2c80182005-01-15 22:15:51 +00001476 bytes[0] = *codes++;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001477 if (is_sbyte32(ins, c & 3))
H. Peter Anvine2c80182005-01-15 22:15:51 +00001478 bytes[0] |= 2; /* s-bit */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001479 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001480 offset++;
1481 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001482
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001483 case 0160:
1484 case 0161:
1485 case 0162:
1486 case 0163:
1487 case 0164:
1488 case 0165:
1489 case 0166:
1490 case 0167:
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001491 break;
1492
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001493 case 0170:
H. Peter Anvinc189b442007-10-05 17:04:32 -07001494 EMIT_REX();
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001495 bytes[0] = 0;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001496 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001497 offset += 1;
1498 break;
1499
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001500 case 0171:
1501 bytes[0] =
1502 (ins->drexdst << 4) |
1503 (ins->rex & REX_OC ? 0x08 : 0) |
1504 (ins->rex & (REX_R|REX_X|REX_B));
1505 ins->rex = 0;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001506 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001507 offset++;
1508 break;
1509
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001510 case 0250:
1511 case 0251:
1512 case 0252:
1513 case 0253:
1514 data = opx->offset;
1515 /* is_sbyte32() is right here, we have already warned */
1516 if (is_sbyte32(ins, c & 3)) {
1517 bytes[0] = data;
1518 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
1519 NO_SEG);
1520 offset++;
1521 } else {
1522 out(offset, segment, &data, OUT_ADDRESS, 4,
1523 opx->segment, opx->wrt);
1524 offset += 4;
1525 }
1526 break;
1527
H. Peter Anvine2c80182005-01-15 22:15:51 +00001528 case 0300:
1529 case 0301:
1530 case 0302:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001531 case 0303:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001532 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001533
H. Peter Anvine2c80182005-01-15 22:15:51 +00001534 case 0310:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001535 if (bits == 32 && !has_prefix(ins, PPS_ASIZE, P_A16)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001536 *bytes = 0x67;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001537 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001538 offset += 1;
1539 } else
1540 offset += 0;
1541 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001542
H. Peter Anvine2c80182005-01-15 22:15:51 +00001543 case 0311:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001544 if (bits != 32 && !has_prefix(ins, PPS_ASIZE, P_A32)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001545 *bytes = 0x67;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001546 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001547 offset += 1;
1548 } else
1549 offset += 0;
1550 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001551
H. Peter Anvine2c80182005-01-15 22:15:51 +00001552 case 0312:
1553 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001554
Keith Kaniosb7a89542007-04-12 02:40:54 +00001555 case 0313:
1556 ins->rex = 0;
1557 break;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07001558
H. Peter Anvin23440102007-11-12 21:02:33 -08001559 case 0314:
1560 case 0315:
1561 case 0316:
1562 case 0317:
1563 break;
1564
H. Peter Anvine2c80182005-01-15 22:15:51 +00001565 case 0320:
Keith Kaniosb7a89542007-04-12 02:40:54 +00001566 if (bits != 16) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001567 *bytes = 0x66;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001568 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001569 offset += 1;
1570 } else
1571 offset += 0;
1572 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001573
H. Peter Anvine2c80182005-01-15 22:15:51 +00001574 case 0321:
1575 if (bits == 16) {
1576 *bytes = 0x66;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001577 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001578 offset += 1;
1579 } else
1580 offset += 0;
1581 break;
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001582
H. Peter Anvine2c80182005-01-15 22:15:51 +00001583 case 0322:
H. Peter Anvin70653092007-10-19 14:42:29 -07001584 case 0323:
1585 break;
1586
Keith Kaniosb7a89542007-04-12 02:40:54 +00001587 case 0324:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001588 ins->rex |= REX_W;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001589 break;
H. Peter Anvin70653092007-10-19 14:42:29 -07001590
H. Peter Anvine2c80182005-01-15 22:15:51 +00001591 case 0330:
1592 *bytes = *codes++ ^ condval[ins->condition];
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001593 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001594 offset += 1;
1595 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001596
H. Peter Anvine2c80182005-01-15 22:15:51 +00001597 case 0331:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001598 break;
H. Peter Anvinaf535c12002-04-30 20:59:21 +00001599
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001600 case 0332:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001601 case 0333:
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001602 *bytes = c - 0332 + 0xF2;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001603 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001604 offset += 1;
1605 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001606
Keith Kanios48af1772007-08-17 07:37:52 +00001607 case 0334:
1608 if (ins->rex & REX_R) {
1609 *bytes = 0xF0;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001610 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
Keith Kanios48af1772007-08-17 07:37:52 +00001611 offset += 1;
1612 }
1613 ins->rex &= ~(REX_L|REX_R);
1614 break;
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001615
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001616 case 0335:
1617 break;
1618
H. Peter Anvine2c80182005-01-15 22:15:51 +00001619 case 0340:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001620 if (ins->oprs[0].segment != NO_SEG)
1621 errfunc(ERR_PANIC, "non-constant BSS size in pass two");
1622 else {
H. Peter Anvin428fd672007-11-15 10:25:52 -08001623 int64_t size = ins->oprs[0].offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001624 if (size > 0)
1625 out(offset, segment, NULL,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001626 OUT_RESERVE, size, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001627 offset += size;
1628 }
1629 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001630
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001631 case 0364:
1632 case 0365:
1633 break;
1634
Keith Kanios48af1772007-08-17 07:37:52 +00001635 case 0366:
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001636 case 0367:
1637 *bytes = c - 0366 + 0x66;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001638 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
Keith Kanios48af1772007-08-17 07:37:52 +00001639 offset += 1;
1640 break;
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001641
H. Peter Anvine2c80182005-01-15 22:15:51 +00001642 case 0370:
1643 case 0371:
1644 case 0372:
1645 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001646
H. Peter Anvine2c80182005-01-15 22:15:51 +00001647 case 0373:
1648 *bytes = bits == 16 ? 3 : 5;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001649 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001650 offset += 1;
1651 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001652
H. Peter Anvine2c80182005-01-15 22:15:51 +00001653 default: /* can't do it by 'case' statements */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001654 if (c >= 0100 && c <= 0277) { /* it's an EA */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001655 ea ea_data;
1656 int rfield;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001657 int32_t rflags;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001658 uint8_t *p;
1659 int32_t s;
H. Peter Anvin70653092007-10-19 14:42:29 -07001660
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001661 if (c <= 0177) {
1662 /* pick rfield from operand b */
1663 rflags = regflag(&ins->oprs[c & 7]);
1664 rfield = regvals[ins->oprs[c & 7].basereg];
1665 } else {
1666 /* rfield is constant */
1667 rflags = 0;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001668 rfield = c & 7;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001669 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001670
1671 if (!process_ea
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001672 (&ins->oprs[(c >> 3) & 7], &ea_data, bits,
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001673 ins->addr_size, rfield, rflags, ins->forw_ref)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001674 errfunc(ERR_NONFATAL, "invalid effective address");
1675 }
H. Peter Anvin70653092007-10-19 14:42:29 -07001676
Charles Crayne7e975552007-11-03 22:06:13 -07001677
H. Peter Anvine2c80182005-01-15 22:15:51 +00001678 p = bytes;
1679 *p++ = ea_data.modrm;
1680 if (ea_data.sib_present)
1681 *p++ = ea_data.sib;
1682
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001683 /* DREX suffixes come between the SIB and the displacement */
1684 if (ins->rex & REX_D) {
1685 *p++ =
1686 (ins->drexdst << 4) |
1687 (ins->rex & REX_OC ? 0x08 : 0) |
1688 (ins->rex & (REX_R|REX_X|REX_B));
1689 ins->rex = 0;
1690 }
1691
H. Peter Anvine2c80182005-01-15 22:15:51 +00001692 s = p - bytes;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001693 out(offset, segment, bytes, OUT_RAWDATA, s, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001694
1695 switch (ea_data.bytes) {
1696 case 0:
1697 break;
1698 case 1:
1699 if (ins->oprs[(c >> 3) & 7].segment != NO_SEG) {
1700 data = ins->oprs[(c >> 3) & 7].offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001701 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001702 ins->oprs[(c >> 3) & 7].segment,
1703 ins->oprs[(c >> 3) & 7].wrt);
1704 } else {
1705 *bytes = ins->oprs[(c >> 3) & 7].offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001706 out(offset, segment, bytes, OUT_RAWDATA, 1,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001707 NO_SEG, NO_SEG);
1708 }
1709 s++;
1710 break;
H. Peter Anvin70653092007-10-19 14:42:29 -07001711 case 8:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001712 case 2:
1713 case 4:
1714 data = ins->oprs[(c >> 3) & 7].offset;
Charles Crayne7e975552007-11-03 22:06:13 -07001715 warn_overflow(ea_data.bytes, data);
H. Peter Anvind0b0d282007-09-28 17:17:20 -07001716 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001717 ea_data.rip ? OUT_REL4ADR : OUT_ADDRESS,
1718 ea_data.bytes,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001719 ins->oprs[(c >> 3) & 7].segment,
1720 ins->oprs[(c >> 3) & 7].wrt);
1721 s += ea_data.bytes;
1722 break;
1723 }
1724 offset += s;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001725 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001726 errfunc(ERR_PANIC, "internal instruction table corrupt"
1727 ": instruction code 0x%02X given", c);
H. Peter Anvin839eca22007-10-29 23:12:47 -07001728 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001729 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001730 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001731}
1732
H. Peter Anvin0ec60e62007-07-07 01:59:52 +00001733static int32_t regflag(const operand * o)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001734{
1735 if (o->basereg < EXPR_REG_START || o->basereg >= REG_ENUM_LIMIT) {
1736 errfunc(ERR_PANIC, "invalid operand passed to regflag()");
1737 }
1738 return reg_flags[o->basereg];
1739}
1740
H. Peter Anvin5b0e3ec2007-07-07 02:01:08 +00001741static int32_t regval(const operand * o)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001742{
H. Peter Anvine2c80182005-01-15 22:15:51 +00001743 if (o->basereg < EXPR_REG_START || o->basereg >= REG_ENUM_LIMIT) {
1744 errfunc(ERR_PANIC, "invalid operand passed to regval()");
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001745 }
H. Peter Anvin232badb2002-06-06 02:41:20 +00001746 return regvals[o->basereg];
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001747}
1748
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001749static int op_rexflags(const operand * o, int mask)
1750{
1751 int32_t flags;
1752 int val;
1753
1754 if (o->basereg < EXPR_REG_START || o->basereg >= REG_ENUM_LIMIT) {
1755 errfunc(ERR_PANIC, "invalid operand passed to op_rexflags()");
1756 }
1757
1758 flags = reg_flags[o->basereg];
1759 val = regvals[o->basereg];
1760
1761 return rexflags(val, flags, mask);
1762}
1763
1764static int rexflags(int val, int32_t flags, int mask)
1765{
1766 int rex = 0;
1767
1768 if (val >= 8)
1769 rex |= REX_B|REX_X|REX_R;
1770 if (flags & BITS64)
1771 rex |= REX_W;
1772 if (!(REG_HIGH & ~flags)) /* AH, CH, DH, BH */
1773 rex |= REX_H;
1774 else if (!(REG8 & ~flags) && val >= 4) /* SPL, BPL, SIL, DIL */
1775 rex |= REX_P;
1776
1777 return rex & mask;
1778}
1779
H. Peter Anvin3360d792007-09-11 04:16:57 +00001780static int matches(const struct itemplate *itemp, insn * instruction, int bits)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001781{
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001782 int i, size[MAX_OPERANDS], asize, oprs, ret;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001783
1784 ret = 100;
1785
1786 /*
1787 * Check the opcode
1788 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001789 if (itemp->opcode != instruction->opcode)
1790 return 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001791
1792 /*
1793 * Count the operands
1794 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001795 if (itemp->operands != instruction->operands)
1796 return 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001797
1798 /*
1799 * Check that no spurious colons or TOs are present
1800 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001801 for (i = 0; i < itemp->operands; i++)
1802 if (instruction->oprs[i].type & ~itemp->opd[i] & (COLON | TO))
1803 return 0;
H. Peter Anvin70653092007-10-19 14:42:29 -07001804
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001805 /*
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001806 * Process size flags
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001807 */
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001808 if (itemp->flags & IF_ARMASK) {
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001809 memset(size, 0, sizeof size);
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001810
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001811 i = ((itemp->flags & IF_ARMASK) >> IF_ARSHFT) - 1;
1812
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001813 switch (itemp->flags & IF_SMASK) {
1814 case IF_SB:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001815 size[i] = BITS8;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001816 break;
1817 case IF_SW:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001818 size[i] = BITS16;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001819 break;
1820 case IF_SD:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001821 size[i] = BITS32;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001822 break;
1823 case IF_SQ:
Keith Kaniosb7a89542007-04-12 02:40:54 +00001824 size[i] = BITS64;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001825 break;
H. Peter Anvin41c9f6f2007-09-18 13:01:32 -07001826 case IF_SO:
1827 size[i] = BITS128;
1828 break;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001829 case IF_SZ:
1830 switch (bits) {
1831 case 16:
1832 size[i] = BITS16;
1833 break;
1834 case 32:
1835 size[i] = BITS32;
1836 break;
1837 case 64:
1838 size[i] = BITS64;
1839 break;
1840 }
1841 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001842 default:
1843 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001844 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001845 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001846 asize = 0;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001847 switch (itemp->flags & IF_SMASK) {
1848 case IF_SB:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001849 asize = BITS8;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001850 break;
1851 case IF_SW:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001852 asize = BITS16;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001853 break;
1854 case IF_SD:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001855 asize = BITS32;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001856 break;
1857 case IF_SQ:
Keith Kaniosb7a89542007-04-12 02:40:54 +00001858 asize = BITS64;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001859 break;
H. Peter Anvin41c9f6f2007-09-18 13:01:32 -07001860 case IF_SO:
1861 asize = BITS128;
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001862 break;
1863 case IF_SZ:
1864 switch (bits) {
1865 case 16:
1866 asize = BITS16;
1867 break;
1868 case 32:
1869 asize = BITS32;
1870 break;
1871 case 64:
1872 asize = BITS64;
1873 break;
1874 }
H. Peter Anvin41c9f6f2007-09-18 13:01:32 -07001875 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001876 default:
1877 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001878 }
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001879 for (i = 0; i < MAX_OPERANDS; i++)
1880 size[i] = asize;
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001881 }
H. Peter Anvin70653092007-10-19 14:42:29 -07001882
H. Peter Anvin32cd4c22008-04-04 13:34:53 -07001883 /*
1884 * Check that the operand flags all match up
1885 */
1886 for (i = 0; i < itemp->operands; i++) {
1887 int32_t type = instruction->oprs[i].type;
1888 if (!(type & SIZE_MASK))
1889 type |= size[i];
1890
1891 if (itemp->opd[i] & SAME_AS) {
1892 int j = itemp->opd[i] & ~SAME_AS;
1893 if (type != instruction->oprs[j].type ||
1894 instruction->oprs[i].basereg != instruction->oprs[j].basereg)
1895 return 0;
1896 } else if (itemp->opd[i] & ~type ||
1897 ((itemp->opd[i] & SIZE_MASK) &&
1898 ((itemp->opd[i] ^ type) & SIZE_MASK))) {
1899 if ((itemp->opd[i] & ~type & ~SIZE_MASK) ||
1900 (type & SIZE_MASK))
1901 return 0;
1902 else
1903 return 1;
1904 }
1905 }
1906
1907 /*
1908 * Check operand sizes
1909 */
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001910 if (itemp->flags & (IF_SM | IF_SM2)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001911 oprs = (itemp->flags & IF_SM2 ? 2 : itemp->operands);
1912 asize = 0;
1913 for (i = 0; i < oprs; i++) {
1914 if ((asize = itemp->opd[i] & SIZE_MASK) != 0) {
1915 int j;
1916 for (j = 0; j < oprs; j++)
1917 size[j] = asize;
1918 break;
1919 }
1920 }
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001921 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001922 oprs = itemp->operands;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001923 }
1924
Keith Kaniosb7a89542007-04-12 02:40:54 +00001925 for (i = 0; i < itemp->operands; i++) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001926 if (!(itemp->opd[i] & SIZE_MASK) &&
1927 (instruction->oprs[i].type & SIZE_MASK & ~size[i]))
H. Peter Anvine2c80182005-01-15 22:15:51 +00001928 return 2;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001929 }
1930
H. Peter Anvinaf535c12002-04-30 20:59:21 +00001931 /*
1932 * Check template is okay at the set cpu level
1933 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00001934 if (((itemp->flags & IF_PLEVEL) > cpu))
H. Peter Anvine2c80182005-01-15 22:15:51 +00001935 return 3;
H. Peter Anvin70653092007-10-19 14:42:29 -07001936
Keith Kaniosb7a89542007-04-12 02:40:54 +00001937 /*
1938 * Check if instruction is available in long mode
1939 */
1940 if ((itemp->flags & IF_NOLONG) && (bits == 64))
1941 return 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001942
H. Peter Anvinaf535c12002-04-30 20:59:21 +00001943 /*
1944 * Check if special handling needed for Jumps
1945 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00001946 if ((uint8_t)(itemp->code[0]) >= 0370)
H. Peter Anvine2c80182005-01-15 22:15:51 +00001947 return 99;
1948
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001949 return ret;
1950}
1951
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001952static ea *process_ea(operand * input, ea * output, int bits,
1953 int addrbits, int rfield, int32_t rflags, int forw_ref)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001954{
H. Peter Anvin6867acc2007-10-10 14:58:45 -07001955 output->rip = false;
H. Peter Anvin99c4ecd2007-08-28 23:06:00 +00001956
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001957 /* REX flags for the rfield operand */
1958 output->rex |= rexflags(rfield, rflags, REX_R|REX_P|REX_W|REX_H);
1959
Keith Kaniosb7a89542007-04-12 02:40:54 +00001960 if (!(REGISTER & ~input->type)) { /* register direct */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001961 int i;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001962 int32_t f;
1963
1964 if (input->basereg < EXPR_REG_START /* Verify as Register */
Keith Kaniosb7a89542007-04-12 02:40:54 +00001965 || input->basereg >= REG_ENUM_LIMIT)
H. Peter Anvine2c80182005-01-15 22:15:51 +00001966 return NULL;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001967 f = regflag(input);
Keith Kaniosb7a89542007-04-12 02:40:54 +00001968 i = regvals[input->basereg];
Keith Kaniosb7a89542007-04-12 02:40:54 +00001969
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001970 if (REG_EA & ~f)
1971 return NULL; /* Invalid EA register */
H. Peter Anvin70653092007-10-19 14:42:29 -07001972
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001973 output->rex |= op_rexflags(input, REX_B|REX_P|REX_W|REX_H);
1974
H. Peter Anvin6867acc2007-10-10 14:58:45 -07001975 output->sib_present = false; /* no SIB necessary */
Keith Kaniosb7a89542007-04-12 02:40:54 +00001976 output->bytes = 0; /* no offset necessary either */
1977 output->modrm = 0xC0 | ((rfield & 7) << 3) | (i & 7);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001978 } else { /* it's a memory reference */
1979 if (input->basereg == -1
1980 && (input->indexreg == -1 || input->scale == 0)) {
1981 /* it's a pure offset */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001982 if (bits == 64 && (~input->type & IP_REL)) {
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00001983 int scale, index, base;
H. Peter Anvin6867acc2007-10-10 14:58:45 -07001984 output->sib_present = true;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00001985 scale = 0;
1986 index = 4;
1987 base = 5;
1988 output->sib = (scale << 6) | (index << 3) | base;
1989 output->bytes = 4;
1990 output->modrm = 4 | ((rfield & 7) << 3);
H. Peter Anvin6867acc2007-10-10 14:58:45 -07001991 output->rip = false;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00001992 } else {
H. Peter Anvin6867acc2007-10-10 14:58:45 -07001993 output->sib_present = false;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00001994 output->bytes = (addrbits != 16 ? 4 : 2);
1995 output->modrm = (addrbits != 16 ? 5 : 6) | ((rfield & 7) << 3);
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001996 output->rip = bits == 64;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00001997 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001998 } else { /* it's an indirection */
1999 int i = input->indexreg, b = input->basereg, s = input->scale;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002000 int32_t o = input->offset, seg = input->segment;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002001 int hb = input->hintbase, ht = input->hinttype;
2002 int t;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002003 int it, bt;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002004 int32_t ix, bx; /* register flags */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002005
H. Peter Anvine2c80182005-01-15 22:15:51 +00002006 if (s == 0)
2007 i = -1; /* make this easy, at least */
H. Peter Anvin70653092007-10-19 14:42:29 -07002008
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002009 if (i >= EXPR_REG_START && i < REG_ENUM_LIMIT) {
Keith Kaniosb7a89542007-04-12 02:40:54 +00002010 it = regvals[i];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002011 ix = reg_flags[i];
2012 } else {
Keith Kaniosb7a89542007-04-12 02:40:54 +00002013 it = -1;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002014 ix = 0;
2015 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002016
H. Peter Anvinb0c54622007-10-28 23:21:46 -07002017 if (b >= EXPR_REG_START && b < REG_ENUM_LIMIT) {
Keith Kaniosb7a89542007-04-12 02:40:54 +00002018 bt = regvals[b];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002019 bx = reg_flags[b];
2020 } else {
Keith Kaniosb7a89542007-04-12 02:40:54 +00002021 bt = -1;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002022 bx = 0;
2023 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002024
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002025 /* check for a 32/64-bit memory reference... */
2026 if ((ix|bx) & (BITS32|BITS64)) {
Keith Kaniosb7a89542007-04-12 02:40:54 +00002027 /* it must be a 32/64-bit memory reference. Firstly we have
2028 * to check that all registers involved are type E/Rxx. */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002029 int32_t sok = BITS32|BITS64;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002030
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002031 if (it != -1) {
2032 if (!(REG64 & ~ix) || !(REG32 & ~ix))
2033 sok &= ix;
2034 else
2035 return NULL;
2036 }
2037
2038 if (bt != -1) {
H. Peter Anvin99c4ecd2007-08-28 23:06:00 +00002039 if (REG_GPR & ~bx)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002040 return NULL; /* Invalid register */
H. Peter Anvina57e8d42007-05-30 03:44:02 +00002041 if (~sok & bx & SIZE_MASK)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002042 return NULL; /* Invalid size */
H. Peter Anvinb0c54622007-10-28 23:21:46 -07002043 sok &= bx;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002044 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002045
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002046 /* While we're here, ensure the user didn't specify
2047 WORD or QWORD. */
2048 if (input->disp_size == 16 || input->disp_size == 64)
2049 return NULL;
2050
2051 if (addrbits == 16 ||
2052 (addrbits == 32 && !(sok & BITS32)) ||
2053 (addrbits == 64 && !(sok & BITS64)))
2054 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002055
Keith Kaniosb7a89542007-04-12 02:40:54 +00002056 /* now reorganize base/index */
2057 if (s == 1 && bt != it && bt != -1 && it != -1 &&
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002058 ((hb == b && ht == EAH_NOTBASE)
2059 || (hb == i && ht == EAH_MAKEBASE))) {
2060 /* swap if hints say so */
2061 t = bt, bt = it, it = t;
2062 t = bx, bx = ix, ix = t;
2063 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00002064 if (bt == it) /* convert EAX+2*EAX to 3*EAX */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002065 bt = -1, bx = 0, s++;
2066 if (bt == -1 && s == 1 && !(hb == it && ht == EAH_NOTBASE)) {
2067 /* make single reg base, unless hint */
2068 bt = it, bx = ix, it = -1, ix = 0;
2069 }
H. Peter Anvinf5843c62007-09-10 18:59:26 +00002070 if (((s == 2 && it != REG_NUM_ESP
H. Peter Anvine2c80182005-01-15 22:15:51 +00002071 && !(input->eaflags & EAF_TIMESTWO)) || s == 3
Keith Kaniosb7a89542007-04-12 02:40:54 +00002072 || s == 5 || s == 9) && bt == -1)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002073 bt = it, bx = ix, s--; /* convert 3*EAX to EAX+2*EAX */
Keith Kanios48af1772007-08-17 07:37:52 +00002074 if (it == -1 && (bt & 7) != REG_NUM_ESP
H. Peter Anvine2c80182005-01-15 22:15:51 +00002075 && (input->eaflags & EAF_TIMESTWO))
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002076 it = bt, ix = bx, bt = -1, bx = 0, s = 1;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002077 /* convert [NOSPLIT EAX] to sib format with 0x0 displacement */
Keith Kanios48af1772007-08-17 07:37:52 +00002078 if (s == 1 && it == REG_NUM_ESP) {
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002079 /* swap ESP into base if scale is 1 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002080 t = it, it = bt, bt = t;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002081 t = ix, ix = bx, bx = t;
2082 }
Keith Kanios48af1772007-08-17 07:37:52 +00002083 if (it == REG_NUM_ESP
Keith Kaniosb7a89542007-04-12 02:40:54 +00002084 || (s != 1 && s != 2 && s != 4 && s != 8 && it != -1))
H. Peter Anvine2c80182005-01-15 22:15:51 +00002085 return NULL; /* wrong, for various reasons */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002086
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002087 output->rex |= rexflags(it, ix, REX_X);
2088 output->rex |= rexflags(bt, bx, REX_B);
Keith Kaniosb7a89542007-04-12 02:40:54 +00002089
Keith Kanios48af1772007-08-17 07:37:52 +00002090 if (it == -1 && (bt & 7) != REG_NUM_ESP) {
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002091 /* no SIB needed */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002092 int mod, rm;
H. Peter Anvin70653092007-10-19 14:42:29 -07002093
Keith Kaniosb7a89542007-04-12 02:40:54 +00002094 if (bt == -1) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002095 rm = 5;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002096 mod = 0;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002097 } else {
2098 rm = (bt & 7);
Keith Kanios48af1772007-08-17 07:37:52 +00002099 if (rm != REG_NUM_EBP && o == 0 &&
Keith Kaniosb7a89542007-04-12 02:40:54 +00002100 seg == NO_SEG && !forw_ref &&
2101 !(input->eaflags &
2102 (EAF_BYTEOFFS | EAF_WORDOFFS)))
2103 mod = 0;
2104 else if (input->eaflags & EAF_BYTEOFFS ||
2105 (o >= -128 && o <= 127 && seg == NO_SEG
2106 && !forw_ref
2107 && !(input->eaflags & EAF_WORDOFFS)))
2108 mod = 1;
2109 else
2110 mod = 2;
2111 }
H. Peter Anvinea838272002-04-30 20:51:53 +00002112
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002113 output->sib_present = false;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002114 output->bytes = (bt == -1 || mod == 2 ? 4 : mod);
2115 output->modrm = (mod << 6) | ((rfield & 7) << 3) | rm;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002116 } else {
2117 /* we need a SIB */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002118 int mod, scale, index, base;
H. Peter Anvin70653092007-10-19 14:42:29 -07002119
Keith Kaniosb7a89542007-04-12 02:40:54 +00002120 if (it == -1)
2121 index = 4, s = 1;
2122 else
2123 index = (it & 7);
H. Peter Anvin70653092007-10-19 14:42:29 -07002124
H. Peter Anvine2c80182005-01-15 22:15:51 +00002125 switch (s) {
2126 case 1:
2127 scale = 0;
2128 break;
2129 case 2:
2130 scale = 1;
2131 break;
2132 case 4:
2133 scale = 2;
2134 break;
2135 case 8:
2136 scale = 3;
2137 break;
2138 default: /* then what the smeg is it? */
2139 return NULL; /* panic */
2140 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002141
Keith Kaniosb7a89542007-04-12 02:40:54 +00002142 if (bt == -1) {
2143 base = 5;
2144 mod = 0;
2145 } else {
2146 base = (bt & 7);
Keith Kanios48af1772007-08-17 07:37:52 +00002147 if (base != REG_NUM_EBP && o == 0 &&
H. Peter Anvine2c80182005-01-15 22:15:51 +00002148 seg == NO_SEG && !forw_ref &&
2149 !(input->eaflags &
Keith Kaniosb7a89542007-04-12 02:40:54 +00002150 (EAF_BYTEOFFS | EAF_WORDOFFS)))
2151 mod = 0;
2152 else if (input->eaflags & EAF_BYTEOFFS ||
2153 (o >= -128 && o <= 127 && seg == NO_SEG
2154 && !forw_ref
2155 && !(input->eaflags & EAF_WORDOFFS)))
2156 mod = 1;
2157 else
2158 mod = 2;
2159 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002160
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002161 output->sib_present = true;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002162 output->bytes = (bt == -1 || mod == 2 ? 4 : mod);
2163 output->modrm = (mod << 6) | ((rfield & 7) << 3) | 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002164 output->sib = (scale << 6) | (index << 3) | base;
2165 }
2166 } else { /* it's 16-bit */
2167 int mod, rm;
H. Peter Anvin70653092007-10-19 14:42:29 -07002168
Keith Kaniosb7a89542007-04-12 02:40:54 +00002169 /* check for 64-bit long mode */
2170 if (addrbits == 64)
2171 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002172
H. Peter Anvine2c80182005-01-15 22:15:51 +00002173 /* check all registers are BX, BP, SI or DI */
2174 if ((b != -1 && b != R_BP && b != R_BX && b != R_SI
2175 && b != R_DI) || (i != -1 && i != R_BP && i != R_BX
2176 && i != R_SI && i != R_DI))
2177 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002178
Keith Kaniosb7a89542007-04-12 02:40:54 +00002179 /* ensure the user didn't specify DWORD/QWORD */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002180 if (input->disp_size == 32 || input->disp_size == 64)
H. Peter Anvine2c80182005-01-15 22:15:51 +00002181 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002182
H. Peter Anvine2c80182005-01-15 22:15:51 +00002183 if (s != 1 && i != -1)
2184 return NULL; /* no can do, in 16-bit EA */
2185 if (b == -1 && i != -1) {
2186 int tmp = b;
2187 b = i;
2188 i = tmp;
2189 } /* swap */
2190 if ((b == R_SI || b == R_DI) && i != -1) {
2191 int tmp = b;
2192 b = i;
2193 i = tmp;
2194 }
2195 /* have BX/BP as base, SI/DI index */
2196 if (b == i)
2197 return NULL; /* shouldn't ever happen, in theory */
2198 if (i != -1 && b != -1 &&
2199 (i == R_BP || i == R_BX || b == R_SI || b == R_DI))
2200 return NULL; /* invalid combinations */
2201 if (b == -1) /* pure offset: handled above */
2202 return NULL; /* so if it gets to here, panic! */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002203
H. Peter Anvine2c80182005-01-15 22:15:51 +00002204 rm = -1;
2205 if (i != -1)
2206 switch (i * 256 + b) {
2207 case R_SI * 256 + R_BX:
2208 rm = 0;
2209 break;
2210 case R_DI * 256 + R_BX:
2211 rm = 1;
2212 break;
2213 case R_SI * 256 + R_BP:
2214 rm = 2;
2215 break;
2216 case R_DI * 256 + R_BP:
2217 rm = 3;
2218 break;
2219 } else
2220 switch (b) {
2221 case R_SI:
2222 rm = 4;
2223 break;
2224 case R_DI:
2225 rm = 5;
2226 break;
2227 case R_BP:
2228 rm = 6;
2229 break;
2230 case R_BX:
2231 rm = 7;
2232 break;
2233 }
2234 if (rm == -1) /* can't happen, in theory */
2235 return NULL; /* so panic if it does */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002236
H. Peter Anvine2c80182005-01-15 22:15:51 +00002237 if (o == 0 && seg == NO_SEG && !forw_ref && rm != 6 &&
2238 !(input->eaflags & (EAF_BYTEOFFS | EAF_WORDOFFS)))
2239 mod = 0;
2240 else if (input->eaflags & EAF_BYTEOFFS ||
2241 (o >= -128 && o <= 127 && seg == NO_SEG
2242 && !forw_ref
2243 && !(input->eaflags & EAF_WORDOFFS)))
2244 mod = 1;
2245 else
2246 mod = 2;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002247
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002248 output->sib_present = false; /* no SIB - it's 16-bit */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002249 output->bytes = mod; /* bytes of offset needed */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002250 output->modrm = (mod << 6) | ((rfield & 7) << 3) | rm;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002251 }
2252 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002253 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002254
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002255 output->size = 1 + output->sib_present + output->bytes;
2256 return output;
2257}
2258
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002259static void add_asp(insn *ins, int addrbits)
H. Peter Anvineba20a72002-04-30 20:53:55 +00002260{
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002261 int j, valid;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002262 int defdisp;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002263
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002264 valid = (addrbits == 64) ? 64|32 : 32|16;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002265
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002266 switch (ins->prefixes[PPS_ASIZE]) {
2267 case P_A16:
2268 valid &= 16;
2269 break;
2270 case P_A32:
2271 valid &= 32;
2272 break;
2273 case P_A64:
2274 valid &= 64;
2275 break;
2276 case P_ASP:
2277 valid &= (addrbits == 32) ? 16 : 32;
2278 break;
2279 default:
2280 break;
2281 }
2282
2283 for (j = 0; j < ins->operands; j++) {
2284 if (!(MEMORY & ~ins->oprs[j].type)) {
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002285 int32_t i, b;
H. Peter Anvin70653092007-10-19 14:42:29 -07002286
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002287 /* Verify as Register */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002288 if (ins->oprs[j].indexreg < EXPR_REG_START
2289 || ins->oprs[j].indexreg >= REG_ENUM_LIMIT)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002290 i = 0;
2291 else
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002292 i = reg_flags[ins->oprs[j].indexreg];
H. Peter Anvin70653092007-10-19 14:42:29 -07002293
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002294 /* Verify as Register */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002295 if (ins->oprs[j].basereg < EXPR_REG_START
2296 || ins->oprs[j].basereg >= REG_ENUM_LIMIT)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002297 b = 0;
2298 else
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002299 b = reg_flags[ins->oprs[j].basereg];
H. Peter Anvin70653092007-10-19 14:42:29 -07002300
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002301 if (ins->oprs[j].scale == 0)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002302 i = 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002303
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002304 if (!i && !b) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002305 int ds = ins->oprs[j].disp_size;
2306 if ((addrbits != 64 && ds > 8) ||
2307 (addrbits == 64 && ds == 16))
2308 valid &= ds;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002309 } else {
2310 if (!(REG16 & ~b))
2311 valid &= 16;
2312 if (!(REG32 & ~b))
2313 valid &= 32;
2314 if (!(REG64 & ~b))
2315 valid &= 64;
H. Peter Anvin70653092007-10-19 14:42:29 -07002316
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002317 if (!(REG16 & ~i))
2318 valid &= 16;
2319 if (!(REG32 & ~i))
2320 valid &= 32;
2321 if (!(REG64 & ~i))
2322 valid &= 64;
2323 }
2324 }
2325 }
2326
2327 if (valid & addrbits) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002328 ins->addr_size = addrbits;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002329 } else if (valid & ((addrbits == 32) ? 16 : 32)) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002330 /* Add an address size prefix */
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002331 enum prefixes pref = (addrbits == 32) ? P_A16 : P_A32;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002332 ins->prefixes[PPS_ASIZE] = pref;
2333 ins->addr_size = (addrbits == 32) ? 16 : 32;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002334 } else {
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002335 /* Impossible... */
2336 errfunc(ERR_NONFATAL, "impossible combination of address sizes");
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002337 ins->addr_size = addrbits; /* Error recovery */
2338 }
2339
2340 defdisp = ins->addr_size == 16 ? 16 : 32;
2341
2342 for (j = 0; j < ins->operands; j++) {
2343 if (!(MEM_OFFS & ~ins->oprs[j].type) &&
2344 (ins->oprs[j].disp_size ? ins->oprs[j].disp_size : defdisp)
2345 != ins->addr_size) {
2346 /* mem_offs sizes must match the address size; if not,
2347 strip the MEM_OFFS bit and match only EA instructions */
2348 ins->oprs[j].type &= ~(MEM_OFFS & ~MEMORY);
2349 }
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002350 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002351}