blob: a56887ec70f3d3f49f47fff709c4f54495b728d0 [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
5 * redistributable under the licence given in the file "Licence"
6 * 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
36 * \144..\147 - or 2 (s-field) into next opcode byte if operand 0..3
H. Peter Anvinaf535c12002-04-30 20:59:21 +000037 * is a signed byte rather than a word.
H. Peter Anvin7eb4a382007-09-17 15:49:30 -070038 * \150..\153 - an immediate dword or signed byte for operand 0..3
39 * \154..\157 - or 2 (s-field) into next opcode byte if operand 0..3
H. Peter Anvinaf535c12002-04-30 20:59:21 +000040 * is a signed byte rather than a dword.
H. Peter Anvin401c07e2007-09-17 16:55:04 -070041 * \160..\163 - this instruction uses DREX rather than REX, with the
42 * OC0 field set to 0, and the dest field taken from
43 * operand 0..3.
44 * \164..\167 - this instruction uses DREX rather than REX, with the
45 * OC0 field set to 1, and the dest field taken from
46 * operand 0..3.
H. Peter Anvin7eb4a382007-09-17 15:49:30 -070047 * \170 - encodes the literal byte 0. (Some compilers don't take
48 * kindly to a zero byte in the _middle_ of a compile time
49 * string constant, so I had to put this hack in.)
H. Peter Anvin401c07e2007-09-17 16:55:04 -070050 * \171 - placement of DREX suffix in the absence of an EA
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000051 * \2ab - a ModRM, calculated on EA in operand a, with the spare
52 * field equal to digit b.
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000053 * \310 - indicates fixed 16-bit address size, i.e. optional 0x67.
54 * \311 - indicates fixed 32-bit address size, i.e. optional 0x67.
Keith Kanios48af1772007-08-17 07:37:52 +000055 * \312 - (disassembler only) marker on LOOP, LOOPxx instructions.
H. Peter Anvince2b3972007-05-30 22:21:11 +000056 * \313 - indicates fixed 64-bit address size, 0x67 invalid.
H. Peter Anvin23440102007-11-12 21:02:33 -080057 * \314 - (disassembler only) invalid with REX.B
58 * \315 - (disassembler only) invalid with REX.X
59 * \316 - (disassembler only) invalid with REX.R
60 * \317 - (disassembler only) invalid with REX.W
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000061 * \320 - indicates fixed 16-bit operand size, i.e. optional 0x66.
62 * \321 - indicates fixed 32-bit operand size, i.e. optional 0x66.
63 * \322 - indicates that this instruction is only valid when the
64 * operand size is the default (instruction to disassembler,
65 * generates no code in the assembler)
H. Peter Anvince2b3972007-05-30 22:21:11 +000066 * \323 - indicates fixed 64-bit operand size, REX on extensions only.
Keith Kaniosb7a89542007-04-12 02:40:54 +000067 * \324 - indicates 64-bit operand size requiring REX prefix.
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000068 * \330 - a literal byte follows in the code stream, to be added
69 * to the condition code value of the instruction.
Keith Kanios48af1772007-08-17 07:37:52 +000070 * \331 - instruction not valid with REP prefix. Hint for
H. Peter Anvinef7468f2002-04-30 20:57:59 +000071 * disassembler only; for SSE instructions.
H. Peter Anvincb9b6902007-09-12 21:58:51 -070072 * \332 - REP prefix (0xF2 byte) used as opcode extension.
73 * \333 - REP prefix (0xF3 byte) used as opcode extension.
Keith Kanios48af1772007-08-17 07:37:52 +000074 * \334 - LOCK prefix used instead of REX.R
H. Peter Anvincb9b6902007-09-12 21:58:51 -070075 * \335 - disassemble a rep (0xF3 byte) prefix as repe not rep.
Keith Kaniosb7a89542007-04-12 02:40:54 +000076 * \340 - reserve <operand 0> bytes of uninitialized storage.
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000077 * Operand 0 had better be a segmentless constant.
H. Peter Anvin62cb6062007-09-11 22:44:03 +000078 * \364 - operand-size prefix (0x66) not permitted
79 * \365 - address-size prefix (0x67) not permitted
80 * \366 - operand-size prefix (0x66) used as opcode extension
81 * \367 - address-size prefix (0x67) used as opcode extension
H. Peter Anvin788e6c12002-04-30 21:02:01 +000082 * \370,\371,\372 - match only if operand 0 meets byte jump criteria.
83 * 370 is used for Jcc, 371 is used for JMP.
H. Peter Anvinaf535c12002-04-30 20:59:21 +000084 * \373 - assemble 0x03 if bits==16, 0x05 if bits==32;
85 * used for conditional jump over longer jump
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000086 */
87
H. Peter Anvinfe501952007-10-02 21:53:51 -070088#include "compiler.h"
89
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000090#include <stdio.h>
91#include <string.h>
Keith Kaniosb7a89542007-04-12 02:40:54 +000092#include <inttypes.h>
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000093
94#include "nasm.h"
H. Peter Anvin6768eb72002-04-30 20:52:26 +000095#include "nasmlib.h"
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000096#include "assemble.h"
97#include "insns.h"
Frank Kotlerd0ed6fd2003-08-27 11:33:56 +000098#include "preproc.h"
H. Peter Anvin3df97a72007-05-30 03:25:21 +000099#include "regflags.c"
Keith Kaniosb7a89542007-04-12 02:40:54 +0000100#include "regvals.c"
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000101
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000102typedef struct {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000103 int sib_present; /* is a SIB byte necessary? */
104 int bytes; /* # of bytes of offset needed */
105 int size; /* lazy - this is sib+bytes+1 */
106 uint8_t modrm, sib, rex, rip; /* the bytes themselves */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000107} ea;
108
Keith Kaniosb7a89542007-04-12 02:40:54 +0000109static uint32_t cpu; /* cpu level received from nasm.c */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000110static efunc errfunc;
111static struct ofmt *outfmt;
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000112static ListGen *list;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000113
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800114static int64_t calcsize(int32_t, int64_t, int, insn *, const char *);
115static void gencode(int32_t, int64_t, int, insn *, const char *, int64_t);
H. Peter Anvin3360d792007-09-11 04:16:57 +0000116static int matches(const struct itemplate *, insn *, int bits);
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000117static int32_t regflag(const operand *);
118static int32_t regval(const operand *);
119static int rexflags(int, int32_t, int);
120static int op_rexflags(const operand *, int);
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700121static ea *process_ea(operand *, ea *, int, int, int, int32_t, int);
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700122static void add_asp(insn *, int);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000123
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700124static int has_prefix(insn * ins, enum prefix_pos pos, enum prefixes prefix)
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000125{
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700126 return ins->prefixes[pos] == prefix;
127}
128
129static void assert_no_prefix(insn * ins, enum prefix_pos pos)
130{
131 if (ins->prefixes[pos])
132 errfunc(ERR_NONFATAL, "invalid %s prefix",
133 prefix_name(ins->prefixes[pos]));
134}
135
136static const char *size_name(int size)
137{
138 switch (size) {
139 case 1:
140 return "byte";
141 case 2:
142 return "word";
143 case 4:
144 return "dword";
145 case 8:
146 return "qword";
147 case 10:
148 return "tword";
149 case 16:
150 return "oword";
151 default:
152 return "???";
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000153 }
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700154}
155
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700156static void warn_overflow(int size, int64_t data)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700157{
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700158 if (size < 8) {
Charles Craynedd462c82007-11-04 15:28:30 -0800159 int64_t lim = ((int64_t)1 << (size*8))-1;
H. Peter Anvin0db11e22007-04-17 20:23:11 +0000160
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700161 if (data < ~lim || data > lim)
162 errfunc(ERR_WARNING, "%s data exceeds bounds", size_name(size));
163 }
164}
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000165/*
166 * This routine wrappers the real output format's output routine,
167 * in order to pass a copy of the data off to the listing file
168 * generator at the same time.
169 */
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800170static void out(int64_t offset, int32_t segto, const void *data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800171 enum out_type type, uint64_t size,
172 int32_t segment, int32_t wrt)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000173{
Keith Kaniosb7a89542007-04-12 02:40:54 +0000174 static int32_t lineno = 0; /* static!!! */
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000175 static char *lnfname = NULL;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800176 uint8_t p[8];
H. Peter Anvineba20a72002-04-30 20:53:55 +0000177
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800178 if (type == OUT_ADDRESS && segment == NO_SEG && wrt == NO_SEG) {
179 /*
180 * This is a non-relocated address, and we're going to
181 * convert it into RAWDATA format.
182 */
183 uint8_t *q = p;
184
185 switch (size) {
186 case 2:
187 WRITESHORT(q, *(int32_t *)data);
188 break;
189 case 4:
190 WRITELONG(q, *(int32_t *)data);
191 break;
192 case 8:
193 WRITEDLONG(q, *(int64_t *)data);
194 break;
195 }
196 data = p;
197 type = OUT_RAWDATA;
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000198 }
199
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800200 list->output(offset, data, type, size);
201
Frank Kotlerabebb082003-09-06 04:45:37 +0000202 /*
203 * this call to src_get determines when we call the
204 * debug-format-specific "linenum" function
205 * it updates lineno and lnfname to the current values
206 * returning 0 if "same as last time", -2 if lnfname
207 * changed, and the amount by which lineno changed,
208 * if it did. thus, these variables must be static
209 */
210
H. Peter Anvine2c80182005-01-15 22:15:51 +0000211 if (src_get(&lineno, &lnfname)) {
212 outfmt->current_dfmt->linenum(lnfname, lineno, segto);
H. Peter Anvince616072002-04-30 21:02:23 +0000213 }
H. Peter Anvineba20a72002-04-30 20:53:55 +0000214
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800215 outfmt->output(segto, data, type, size, segment, wrt);
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000216}
217
Charles Crayne5fbbc8c2007-11-07 19:03:46 -0800218static int jmp_match(int32_t segment, int64_t offset, int bits,
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000219 insn * ins, const char *code)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000220{
Charles Crayne5fbbc8c2007-11-07 19:03:46 -0800221 int64_t isize;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000222 uint8_t c = code[0];
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000223
H. Peter Anvine2c80182005-01-15 22:15:51 +0000224 if (c != 0370 && c != 0371)
225 return 0;
H. Peter Anvin788e6c12002-04-30 21:02:01 +0000226 if (ins->oprs[0].opflags & OPFLAG_FORWARD) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000227 if ((optimizing < 0 || (ins->oprs[0].type & STRICT))
228 && c == 0370)
229 return 1;
230 else
231 return (pass0 == 0); /* match a forward reference */
H. Peter Anvin788e6c12002-04-30 21:02:01 +0000232 }
H. Peter Anvine2c80182005-01-15 22:15:51 +0000233 isize = calcsize(segment, offset, bits, ins, code);
234 if (ins->oprs[0].segment != segment)
235 return 0;
236 isize = ins->oprs[0].offset - offset - isize; /* isize is now the delta */
237 if (isize >= -128L && isize <= 127L)
238 return 1; /* it is byte size */
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000239
240 return 0;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000241}
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000242
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800243int64_t assemble(int32_t segment, int64_t offset, int bits, uint32_t cp,
H. Peter Anvine2c80182005-01-15 22:15:51 +0000244 insn * instruction, struct ofmt *output, efunc error,
245 ListGen * listgen)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000246{
H. Peter Anvin3360d792007-09-11 04:16:57 +0000247 const struct itemplate *temp;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000248 int j;
249 int size_prob;
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800250 int64_t insn_end;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000251 int32_t itimes;
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800252 int64_t start = offset;
253 int64_t wsize = 0; /* size for DB etc. */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000254
H. Peter Anvine2c80182005-01-15 22:15:51 +0000255 errfunc = error; /* to pass to other functions */
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000256 cpu = cp;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000257 outfmt = output; /* likewise */
258 list = listgen; /* and again */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000259
H. Peter Anvine2c80182005-01-15 22:15:51 +0000260 switch (instruction->opcode) {
261 case -1:
262 return 0;
263 case I_DB:
264 wsize = 1;
265 break;
266 case I_DW:
267 wsize = 2;
268 break;
269 case I_DD:
270 wsize = 4;
271 break;
272 case I_DQ:
273 wsize = 8;
274 break;
275 case I_DT:
276 wsize = 10;
277 break;
H. Peter Anvincfbe7c32007-09-18 17:49:09 -0700278 case I_DO:
279 wsize = 16;
280 break;
H. Peter Anvin16b0a332007-09-12 20:27:41 -0700281 default:
282 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000283 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000284
H. Peter Anvineba20a72002-04-30 20:53:55 +0000285 if (wsize) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000286 extop *e;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000287 int32_t t = instruction->times;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000288 if (t < 0)
289 errfunc(ERR_PANIC,
290 "instruction->times < 0 (%ld) in assemble()", t);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000291
H. Peter Anvine2c80182005-01-15 22:15:51 +0000292 while (t--) { /* repeat TIMES times */
293 for (e = instruction->eops; e; e = e->next) {
294 if (e->type == EOT_DB_NUMBER) {
295 if (wsize == 1) {
296 if (e->segment != NO_SEG)
297 errfunc(ERR_NONFATAL,
298 "one-byte relocation attempted");
299 else {
Keith Kaniosb7a89542007-04-12 02:40:54 +0000300 uint8_t out_byte = e->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000301 out(offset, segment, &out_byte,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800302 OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000303 }
Keith Kanios61ff53c2007-04-14 18:54:52 +0000304 } else if (wsize > 8) {
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700305 errfunc(ERR_NONFATAL, "integer supplied to a DT or DO"
Keith Kanios61ff53c2007-04-14 18:54:52 +0000306 " instruction");
H. Peter Anvine2c80182005-01-15 22:15:51 +0000307 } else
308 out(offset, segment, &e->offset,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800309 OUT_ADDRESS, wsize, e->segment, e->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000310 offset += wsize;
311 } else if (e->type == EOT_DB_STRING) {
312 int align;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000313
H. Peter Anvine2c80182005-01-15 22:15:51 +0000314 out(offset, segment, e->stringval,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -0800315 OUT_RAWDATA, e->stringlen, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000316 align = e->stringlen % wsize;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000317
H. Peter Anvine2c80182005-01-15 22:15:51 +0000318 if (align) {
319 align = wsize - align;
320 out(offset, segment, "\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 Anvinaf535c12002-04-30 20:59:21 +0000763/* check that opn[op] is a signed byte of size 16 or 32,
764 and return the signed value*/
H. Peter Anvine2c80182005-01-15 22:15:51 +0000765static int is_sbyte(insn * ins, int op, int size)
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000766{
Keith Kaniosb7a89542007-04-12 02:40:54 +0000767 int32_t v;
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000768 int ret;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000769
770 ret = !(ins->forw_ref && ins->oprs[op].opflags) && /* dead in the water on forward reference or External */
771 optimizing >= 0 &&
772 !(ins->oprs[op].type & STRICT) &&
773 ins->oprs[op].wrt == NO_SEG && ins->oprs[op].segment == NO_SEG;
H. Peter Anvin734b1882002-04-30 21:01:08 +0000774
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000775 v = ins->oprs[op].offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000776 if (size == 16)
Keith Kaniosb7a89542007-04-12 02:40:54 +0000777 v = (int16_t)v; /* sign extend if 16 bits */
H. Peter Anvine2c80182005-01-15 22:15:51 +0000778
779 return ret && v >= -128L && v <= 127L;
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000780}
781
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800782static int64_t calcsize(int32_t segment, int64_t offset, int bits,
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000783 insn * ins, const char *codes)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000784{
Charles Crayne1f8bc4c2007-11-06 18:27:23 -0800785 int64_t length = 0;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000786 uint8_t c;
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000787 int rex_mask = ~0;
H. Peter Anvin839eca22007-10-29 23:12:47 -0700788 struct operand *opx;
H. Peter Anvineba20a72002-04-30 20:53:55 +0000789
H. Peter Anvine3917fc2007-11-01 14:53:32 -0700790 ins->rex = 0; /* Ensure REX is reset */
791
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700792 if (ins->prefixes[PPS_OSIZE] == P_O64)
793 ins->rex |= REX_W;
794
H. Peter Anvine2c80182005-01-15 22:15:51 +0000795 (void)segment; /* Don't warn that this parameter is unused */
796 (void)offset; /* Don't warn that this parameter is unused */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000797
H. Peter Anvin839eca22007-10-29 23:12:47 -0700798 while (*codes) {
799 c = *codes++;
800 opx = &ins->oprs[c & 3];
801 switch (c) {
H. Peter Anvine2c80182005-01-15 22:15:51 +0000802 case 01:
803 case 02:
804 case 03:
805 codes += c, length += c;
806 break;
807 case 04:
808 case 05:
809 case 06:
810 case 07:
811 length++;
812 break;
813 case 010:
814 case 011:
815 case 012:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700816 case 013:
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000817 ins->rex |=
H. Peter Anvin839eca22007-10-29 23:12:47 -0700818 op_rexflags(opx, REX_B|REX_H|REX_P|REX_W);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000819 codes++, length++;
820 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000821 case 014:
822 case 015:
823 case 016:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700824 case 017:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000825 length++;
826 break;
827 case 020:
828 case 021:
829 case 022:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700830 case 023:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000831 length++;
832 break;
833 case 024:
834 case 025:
835 case 026:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700836 case 027:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000837 length++;
838 break;
839 case 030:
840 case 031:
841 case 032:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700842 case 033:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000843 length += 2;
844 break;
845 case 034:
846 case 035:
847 case 036:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700848 case 037:
H. Peter Anvin839eca22007-10-29 23:12:47 -0700849 if (opx->type & (BITS16 | BITS32 | BITS64))
850 length += (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000851 else
852 length += (bits == 16) ? 2 : 4;
853 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000854 case 040:
855 case 041:
856 case 042:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700857 case 043:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000858 length += 4;
859 break;
860 case 044:
861 case 045:
862 case 046:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700863 case 047:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700864 length += ins->addr_size >> 3;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000865 break;
866 case 050:
867 case 051:
868 case 052:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700869 case 053:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000870 length++;
871 break;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000872 case 054:
873 case 055:
874 case 056:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700875 case 057:
Keith Kaniosb7a89542007-04-12 02:40:54 +0000876 length += 8; /* MOV reg64/imm */
877 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000878 case 060:
879 case 061:
880 case 062:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700881 case 063:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000882 length += 2;
883 break;
884 case 064:
885 case 065:
886 case 066:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700887 case 067:
H. Peter Anvin839eca22007-10-29 23:12:47 -0700888 if (opx->type & (BITS16 | BITS32 | BITS64))
889 length += (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000890 else
891 length += (bits == 16) ? 2 : 4;
892 break;
893 case 070:
894 case 071:
895 case 072:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700896 case 073:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000897 length += 4;
898 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700899 case 074:
900 case 075:
901 case 076:
902 case 077:
903 length += 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000904 break;
905 case 0140:
906 case 0141:
907 case 0142:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700908 case 0143:
H. Peter Anvin839eca22007-10-29 23:12:47 -0700909 length += is_sbyte(ins, c & 3, 16) ? 1 : 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000910 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000911 case 0144:
912 case 0145:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700913 case 0146:
914 case 0147:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000915 codes += 2;
916 length++;
917 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700918 case 0150:
919 case 0151:
920 case 0152:
921 case 0153:
H. Peter Anvin839eca22007-10-29 23:12:47 -0700922 length += is_sbyte(ins, c & 3, 32) ? 1 : 4;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700923 break;
924 case 0154:
925 case 0155:
926 case 0156:
927 case 0157:
928 codes += 2;
929 length++;
930 break;
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700931 case 0160:
932 case 0161:
933 case 0162:
934 case 0163:
935 length++;
936 ins->rex |= REX_D;
H. Peter Anvincf5180a2007-09-17 17:25:27 -0700937 ins->drexdst = regval(&ins->oprs[c & 3]);
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700938 break;
939 case 0164:
940 case 0165:
941 case 0166:
942 case 0167:
943 length++;
944 ins->rex |= REX_D|REX_OC;
H. Peter Anvincf5180a2007-09-17 17:25:27 -0700945 ins->drexdst = regval(&ins->oprs[c & 3]);
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700946 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -0700947 case 0170:
948 length++;
949 break;
H. Peter Anvin401c07e2007-09-17 16:55:04 -0700950 case 0171:
951 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000952 case 0300:
953 case 0301:
H. Peter Anvin70653092007-10-19 14:42:29 -0700954 case 0302:
955 case 0303:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000956 break;
957 case 0310:
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700958 if (bits == 64)
959 return -1;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700960 length += (bits != 16) && !has_prefix(ins, PPS_ASIZE, P_A16);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000961 break;
962 case 0311:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700963 length += (bits != 32) && !has_prefix(ins, PPS_ASIZE, P_A32);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000964 break;
965 case 0312:
H. Peter Anvin70653092007-10-19 14:42:29 -0700966 break;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000967 case 0313:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -0700968 if (bits != 64 || has_prefix(ins, PPS_ASIZE, P_A16) ||
969 has_prefix(ins, PPS_ASIZE, P_A32))
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -0700970 return -1;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000971 break;
H. Peter Anvin23440102007-11-12 21:02:33 -0800972 case 0314:
973 case 0315:
974 case 0316:
975 case 0317:
976 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000977 case 0320:
Keith Kaniosb7a89542007-04-12 02:40:54 +0000978 length += (bits != 16);
H. Peter Anvine2c80182005-01-15 22:15:51 +0000979 break;
980 case 0321:
981 length += (bits == 16);
982 break;
983 case 0322:
984 break;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000985 case 0323:
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000986 rex_mask &= ~REX_W;
Keith Kaniosb7a89542007-04-12 02:40:54 +0000987 break;
988 case 0324:
H. Peter Anvin3df97a72007-05-30 03:25:21 +0000989 ins->rex |= REX_W;
H. Peter Anvin8d7316a2007-04-18 02:27:18 +0000990 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000991 case 0330:
992 codes++, length++;
993 break;
994 case 0331:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000995 break;
H. Peter Anvincb9b6902007-09-12 21:58:51 -0700996 case 0332:
H. Peter Anvine2c80182005-01-15 22:15:51 +0000997 case 0333:
998 length++;
999 break;
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001000 case 0334:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001001 ins->rex |= REX_L;
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001002 break;
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001003 case 0335:
1004 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001005 case 0340:
1006 case 0341:
1007 case 0342:
1008 if (ins->oprs[0].segment != NO_SEG)
1009 errfunc(ERR_NONFATAL, "attempt to reserve non-constant"
1010 " quantity of BSS space");
1011 else
H. Peter Anvin839eca22007-10-29 23:12:47 -07001012 length += ins->oprs[0].offset << (c & 3);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001013 break;
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001014 case 0364:
1015 case 0365:
1016 break;
Keith Kanios48af1772007-08-17 07:37:52 +00001017 case 0366:
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001018 case 0367:
1019 length++;
1020 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001021 case 0370:
1022 case 0371:
1023 case 0372:
1024 break;
1025 case 0373:
1026 length++;
1027 break;
1028 default: /* can't do it by 'case' statements */
1029 if (c >= 0100 && c <= 0277) { /* it's an EA */
1030 ea ea_data;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001031 int rfield;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001032 int32_t rflags;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001033 ea_data.rex = 0; /* Ensure ea.REX is initially 0 */
H. Peter Anvin70653092007-10-19 14:42:29 -07001034
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001035 if (c <= 0177) {
1036 /* pick rfield from operand b */
1037 rflags = regflag(&ins->oprs[c & 7]);
1038 rfield = regvals[ins->oprs[c & 7].basereg];
1039 } else {
1040 rflags = 0;
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001041 rfield = c & 7;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001042 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00001043
H. Peter Anvine2c80182005-01-15 22:15:51 +00001044 if (!process_ea
Keith Kaniosb7a89542007-04-12 02:40:54 +00001045 (&ins->oprs[(c >> 3) & 7], &ea_data, bits,
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001046 ins->addr_size, rfield, rflags, ins->forw_ref)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001047 errfunc(ERR_NONFATAL, "invalid effective address");
1048 return -1;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001049 } else {
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001050 ins->rex |= ea_data.rex;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001051 length += ea_data.size;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001052 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001053 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001054 errfunc(ERR_PANIC, "internal instruction table corrupt"
1055 ": instruction code 0x%02X given", c);
H. Peter Anvin839eca22007-10-29 23:12:47 -07001056 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001057 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001058 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001059
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001060 ins->rex &= rex_mask;
H. Peter Anvin70653092007-10-19 14:42:29 -07001061
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001062 if (ins->rex & REX_D) {
1063 if (ins->rex & REX_H) {
1064 errfunc(ERR_NONFATAL, "cannot use high register in drex instruction");
1065 return -1;
1066 }
H. Peter Anvincf5180a2007-09-17 17:25:27 -07001067 if (bits != 64 && ((ins->rex & (REX_W|REX_X|REX_B)) ||
1068 ins->drexdst > 7)) {
1069 errfunc(ERR_NONFATAL, "invalid operands in non-64-bit mode");
1070 return -1;
1071 }
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001072 length++;
1073 } else if (ins->rex & REX_REAL) {
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001074 if (ins->rex & REX_H) {
1075 errfunc(ERR_NONFATAL, "cannot use high register in rex instruction");
1076 return -1;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001077 } else if (bits == 64) {
1078 length++;
1079 } else if ((ins->rex & REX_L) &&
1080 !(ins->rex & (REX_P|REX_W|REX_X|REX_B)) &&
1081 cpu >= IF_X86_64) {
1082 /* LOCK-as-REX.R */
1083 assert_no_prefix(ins, PPS_LREP);
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001084 length++;
H. Peter Anvin8d7316a2007-04-18 02:27:18 +00001085 } else {
H. Peter Anvincf5180a2007-09-17 17:25:27 -07001086 errfunc(ERR_NONFATAL, "invalid operands in non-64-bit mode");
1087 return -1;
H. Peter Anvin8d7316a2007-04-18 02:27:18 +00001088 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00001089 }
1090
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001091 return length;
1092}
Keith Kaniosb7a89542007-04-12 02:40:54 +00001093
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001094#define EMIT_REX() \
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001095 if (!(ins->rex & REX_D) && (ins->rex & REX_REAL) && (bits == 64)) { \
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001096 ins->rex = (ins->rex & REX_REAL)|REX_P; \
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001097 out(offset, segment, &ins->rex, OUT_RAWDATA, 1, NO_SEG, NO_SEG); \
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001098 ins->rex = 0; \
1099 offset += 1; \
1100 }
1101
Charles Crayne1f8bc4c2007-11-06 18:27:23 -08001102static void gencode(int32_t segment, int64_t offset, int bits,
1103 insn * ins, const char *codes, int64_t insn_end)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001104{
Keith Kaniosa6dfa782007-04-13 16:47:53 +00001105 static char condval[] = { /* conditional opcodes */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001106 0x7, 0x3, 0x2, 0x6, 0x2, 0x4, 0xF, 0xD, 0xC, 0xE, 0x6, 0x2,
1107 0x3, 0x7, 0x3, 0x5, 0xE, 0xC, 0xD, 0xF, 0x1, 0xB, 0x9, 0x5,
1108 0x0, 0xA, 0xA, 0xB, 0x8, 0x4
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001109 };
Keith Kaniosb7a89542007-04-12 02:40:54 +00001110 uint8_t c;
1111 uint8_t bytes[4];
Charles Crayne1f8bc4c2007-11-06 18:27:23 -08001112 int64_t size;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001113 int64_t data;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001114 struct operand *opx;
H. Peter Anvin70653092007-10-19 14:42:29 -07001115
H. Peter Anvin839eca22007-10-29 23:12:47 -07001116 while (*codes) {
1117 c = *codes++;
1118 opx = &ins->oprs[c & 3];
1119 switch (c) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001120 case 01:
1121 case 02:
1122 case 03:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001123 EMIT_REX();
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001124 out(offset, segment, codes, OUT_RAWDATA, c, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001125 codes += c;
1126 offset += c;
1127 break;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001128
H. Peter Anvine2c80182005-01-15 22:15:51 +00001129 case 04:
1130 case 06:
1131 switch (ins->oprs[0].basereg) {
1132 case R_CS:
1133 bytes[0] = 0x0E + (c == 0x04 ? 1 : 0);
1134 break;
1135 case R_DS:
1136 bytes[0] = 0x1E + (c == 0x04 ? 1 : 0);
1137 break;
1138 case R_ES:
1139 bytes[0] = 0x06 + (c == 0x04 ? 1 : 0);
1140 break;
1141 case R_SS:
1142 bytes[0] = 0x16 + (c == 0x04 ? 1 : 0);
1143 break;
1144 default:
1145 errfunc(ERR_PANIC,
1146 "bizarre 8086 segment register received");
1147 }
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001148 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001149 offset++;
1150 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001151
H. Peter Anvine2c80182005-01-15 22:15:51 +00001152 case 05:
1153 case 07:
1154 switch (ins->oprs[0].basereg) {
1155 case R_FS:
1156 bytes[0] = 0xA0 + (c == 0x05 ? 1 : 0);
1157 break;
1158 case R_GS:
1159 bytes[0] = 0xA8 + (c == 0x05 ? 1 : 0);
1160 break;
1161 default:
1162 errfunc(ERR_PANIC,
1163 "bizarre 386 segment register received");
1164 }
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001165 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001166 offset++;
1167 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001168
H. Peter Anvine2c80182005-01-15 22:15:51 +00001169 case 010:
1170 case 011:
1171 case 012:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001172 case 013:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001173 EMIT_REX();
H. Peter Anvin839eca22007-10-29 23:12:47 -07001174 bytes[0] = *codes++ + ((regval(opx)) & 7);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001175 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001176 offset += 1;
1177 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001178
H. Peter Anvine2c80182005-01-15 22:15:51 +00001179 case 014:
1180 case 015:
1181 case 016:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001182 case 017:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001183 if (opx->offset < -128 || opx->offset > 127) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001184 errfunc(ERR_WARNING, "signed byte value exceeds bounds");
1185 }
H. Peter Anvineba20a72002-04-30 20:53:55 +00001186
H. Peter Anvin839eca22007-10-29 23:12:47 -07001187 if (opx->segment != NO_SEG) {
1188 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001189 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001190 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001191 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001192 bytes[0] = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001193 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001194 NO_SEG);
1195 }
1196 offset += 1;
1197 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001198
H. Peter Anvine2c80182005-01-15 22:15:51 +00001199 case 020:
1200 case 021:
1201 case 022:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001202 case 023:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001203 if (opx->offset < -256 || opx->offset > 255) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001204 errfunc(ERR_WARNING, "byte value exceeds bounds");
1205 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001206 if (opx->segment != NO_SEG) {
1207 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001208 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001209 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001210 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001211 bytes[0] = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001212 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001213 NO_SEG);
1214 }
1215 offset += 1;
1216 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001217
H. Peter Anvine2c80182005-01-15 22:15:51 +00001218 case 024:
1219 case 025:
1220 case 026:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001221 case 027:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001222 if (opx->offset < 0 || opx->offset > 255)
H. Peter Anvine2c80182005-01-15 22:15:51 +00001223 errfunc(ERR_WARNING, "unsigned byte value exceeds bounds");
H. Peter Anvin839eca22007-10-29 23:12:47 -07001224 if (opx->segment != NO_SEG) {
1225 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001226 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001227 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001228 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001229 bytes[0] = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001230 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001231 NO_SEG);
1232 }
1233 offset += 1;
1234 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001235
H. Peter Anvine2c80182005-01-15 22:15:51 +00001236 case 030:
1237 case 031:
1238 case 032:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001239 case 033:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001240 data = opx->offset;
1241 if (opx->segment == NO_SEG && opx->wrt == NO_SEG)
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001242 warn_overflow(2, data);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001243 out(offset, segment, &data, OUT_ADDRESS, 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001244 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001245 offset += 2;
1246 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001247
H. Peter Anvine2c80182005-01-15 22:15:51 +00001248 case 034:
1249 case 035:
1250 case 036:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001251 case 037:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001252 if (opx->type & (BITS16 | BITS32))
1253 size = (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001254 else
1255 size = (bits == 16) ? 2 : 4;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001256 data = opx->offset;
1257 if (opx->segment == NO_SEG && opx->wrt == NO_SEG)
H. Peter Anvin10e27272007-10-29 22:56:08 -07001258 warn_overflow(size, data);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001259 out(offset, segment, &data, OUT_ADDRESS, size,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001260 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001261 offset += size;
1262 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001263
H. Peter Anvine2c80182005-01-15 22:15:51 +00001264 case 040:
1265 case 041:
1266 case 042:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001267 case 043:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001268 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001269 out(offset, segment, &data, OUT_ADDRESS, 4,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001270 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001271 offset += 4;
1272 break;
H. Peter Anvin3ba46772002-05-27 23:19:35 +00001273
H. Peter Anvine2c80182005-01-15 22:15:51 +00001274 case 044:
1275 case 045:
1276 case 046:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001277 case 047:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001278 data = opx->offset;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001279 size = ins->addr_size >> 3;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001280 if (opx->segment == NO_SEG &&
1281 opx->wrt == NO_SEG)
H. Peter Anvin10e27272007-10-29 22:56:08 -07001282 warn_overflow(size, data);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001283 out(offset, segment, &data, OUT_ADDRESS, size,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001284 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001285 offset += size;
1286 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001287
H. Peter Anvine2c80182005-01-15 22:15:51 +00001288 case 050:
1289 case 051:
1290 case 052:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001291 case 053:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001292 if (opx->segment != segment)
H. Peter Anvine2c80182005-01-15 22:15:51 +00001293 errfunc(ERR_NONFATAL,
1294 "short relative jump outside segment");
H. Peter Anvin839eca22007-10-29 23:12:47 -07001295 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001296 if (data > 127 || data < -128)
1297 errfunc(ERR_NONFATAL, "short jump is out of range");
1298 bytes[0] = data;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001299 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001300 offset += 1;
1301 break;
H. Peter Anvin70653092007-10-19 14:42:29 -07001302
Keith Kaniosb7a89542007-04-12 02:40:54 +00001303 case 054:
1304 case 055:
1305 case 056:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001306 case 057:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001307 data = (int64_t)opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001308 out(offset, segment, &data, OUT_ADDRESS, 8,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001309 opx->segment, opx->wrt);
Keith Kaniosb7a89542007-04-12 02:40:54 +00001310 offset += 8;
1311 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001312
H. Peter Anvine2c80182005-01-15 22:15:51 +00001313 case 060:
1314 case 061:
1315 case 062:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001316 case 063:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001317 if (opx->segment != segment) {
1318 data = opx->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001319 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001320 OUT_REL2ADR, insn_end - offset,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001321 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001322 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001323 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001324 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001325 OUT_ADDRESS, 2, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001326 }
1327 offset += 2;
1328 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001329
H. Peter Anvine2c80182005-01-15 22:15:51 +00001330 case 064:
1331 case 065:
1332 case 066:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001333 case 067:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001334 if (opx->type & (BITS16 | BITS32 | BITS64))
1335 size = (opx->type & BITS16) ? 2 : 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001336 else
1337 size = (bits == 16) ? 2 : 4;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001338 if (opx->segment != segment) {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001339 data = opx->offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001340 out(offset, segment, &data,
1341 size == 2 ? OUT_REL2ADR : OUT_REL4ADR,
1342 insn_end - offset, opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001343 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001344 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001345 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001346 OUT_ADDRESS, size, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001347 }
1348 offset += size;
1349 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001350
H. Peter Anvine2c80182005-01-15 22:15:51 +00001351 case 070:
1352 case 071:
1353 case 072:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001354 case 073:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001355 if (opx->segment != segment) {
1356 data = opx->offset;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001357 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001358 OUT_REL4ADR, insn_end - offset,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001359 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001360 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001361 data = opx->offset - insn_end;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001362 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001363 OUT_ADDRESS, 4, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001364 }
1365 offset += 4;
1366 break;
H. Peter Anvinaf535c12002-04-30 20:59:21 +00001367
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001368 case 074:
1369 case 075:
1370 case 076:
1371 case 077:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001372 if (opx->segment == NO_SEG)
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001373 errfunc(ERR_NONFATAL, "value referenced by FAR is not"
1374 " relocatable");
1375 data = 0L;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001376 out(offset, segment, &data, OUT_ADDRESS, 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001377 outfmt->segbase(1 + opx->segment),
1378 opx->wrt);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001379 offset += 2;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001380 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001381
H. Peter Anvine2c80182005-01-15 22:15:51 +00001382 case 0140:
1383 case 0141:
1384 case 0142:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001385 case 0143:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001386 data = opx->offset;
1387 if (is_sbyte(ins, c & 3, 16)) {
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001388 bytes[0] = data;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001389 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001390 NO_SEG);
1391 offset++;
1392 } else {
H. Peter Anvin839eca22007-10-29 23:12:47 -07001393 if (opx->segment == NO_SEG &&
1394 opx->wrt == NO_SEG)
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001395 warn_overflow(2, data);
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001396 out(offset, segment, &data, OUT_ADDRESS, 2,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001397 opx->segment, opx->wrt);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001398 offset += 2;
1399 }
1400 break;
1401
1402 case 0144:
1403 case 0145:
1404 case 0146:
1405 case 0147:
1406 EMIT_REX();
1407 codes++;
1408 bytes[0] = *codes++;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001409 if (is_sbyte(ins, c & 3, 16))
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001410 bytes[0] |= 2; /* s-bit */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001411 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001412 offset++;
1413 break;
1414
1415 case 0150:
1416 case 0151:
1417 case 0152:
1418 case 0153:
H. Peter Anvin839eca22007-10-29 23:12:47 -07001419 data = opx->offset;
1420 if (is_sbyte(ins, c & 3, 32)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001421 bytes[0] = data;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001422 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001423 NO_SEG);
1424 offset++;
1425 } else {
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001426 out(offset, segment, &data, OUT_ADDRESS, 4,
H. Peter Anvin839eca22007-10-29 23:12:47 -07001427 opx->segment, opx->wrt);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001428 offset += 4;
1429 }
1430 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001431
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001432 case 0154:
1433 case 0155:
1434 case 0156:
1435 case 0157:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001436 EMIT_REX();
H. Peter Anvine2c80182005-01-15 22:15:51 +00001437 codes++;
1438 bytes[0] = *codes++;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001439 if (is_sbyte(ins, c & 3, 32))
H. Peter Anvine2c80182005-01-15 22:15:51 +00001440 bytes[0] |= 2; /* s-bit */
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001441 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001442 offset++;
1443 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001444
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001445 case 0160:
1446 case 0161:
1447 case 0162:
1448 case 0163:
1449 case 0164:
1450 case 0165:
1451 case 0166:
1452 case 0167:
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001453 break;
1454
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001455 case 0170:
H. Peter Anvinc189b442007-10-05 17:04:32 -07001456 EMIT_REX();
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001457 bytes[0] = 0;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001458 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001459 offset += 1;
1460 break;
1461
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001462 case 0171:
1463 bytes[0] =
1464 (ins->drexdst << 4) |
1465 (ins->rex & REX_OC ? 0x08 : 0) |
1466 (ins->rex & (REX_R|REX_X|REX_B));
1467 ins->rex = 0;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001468 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001469 offset++;
1470 break;
1471
H. Peter Anvine2c80182005-01-15 22:15:51 +00001472 case 0300:
1473 case 0301:
1474 case 0302:
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001475 case 0303:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001476 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001477
H. Peter Anvine2c80182005-01-15 22:15:51 +00001478 case 0310:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001479 if (bits == 32 && !has_prefix(ins, PPS_ASIZE, P_A16)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001480 *bytes = 0x67;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001481 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001482 offset += 1;
1483 } else
1484 offset += 0;
1485 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001486
H. Peter Anvine2c80182005-01-15 22:15:51 +00001487 case 0311:
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001488 if (bits != 32 && !has_prefix(ins, PPS_ASIZE, P_A32)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001489 *bytes = 0x67;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001490 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001491 offset += 1;
1492 } else
1493 offset += 0;
1494 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001495
H. Peter Anvine2c80182005-01-15 22:15:51 +00001496 case 0312:
1497 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001498
Keith Kaniosb7a89542007-04-12 02:40:54 +00001499 case 0313:
1500 ins->rex = 0;
1501 break;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07001502
H. Peter Anvin23440102007-11-12 21:02:33 -08001503 case 0314:
1504 case 0315:
1505 case 0316:
1506 case 0317:
1507 break;
1508
H. Peter Anvine2c80182005-01-15 22:15:51 +00001509 case 0320:
Keith Kaniosb7a89542007-04-12 02:40:54 +00001510 if (bits != 16) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001511 *bytes = 0x66;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001512 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001513 offset += 1;
1514 } else
1515 offset += 0;
1516 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001517
H. Peter Anvine2c80182005-01-15 22:15:51 +00001518 case 0321:
1519 if (bits == 16) {
1520 *bytes = 0x66;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001521 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001522 offset += 1;
1523 } else
1524 offset += 0;
1525 break;
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001526
H. Peter Anvine2c80182005-01-15 22:15:51 +00001527 case 0322:
H. Peter Anvin70653092007-10-19 14:42:29 -07001528 case 0323:
1529 break;
1530
Keith Kaniosb7a89542007-04-12 02:40:54 +00001531 case 0324:
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001532 ins->rex |= REX_W;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001533 break;
H. Peter Anvin70653092007-10-19 14:42:29 -07001534
H. Peter Anvine2c80182005-01-15 22:15:51 +00001535 case 0330:
1536 *bytes = *codes++ ^ condval[ins->condition];
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 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001540
H. Peter Anvine2c80182005-01-15 22:15:51 +00001541 case 0331:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001542 break;
H. Peter Anvinaf535c12002-04-30 20:59:21 +00001543
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001544 case 0332:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001545 case 0333:
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001546 *bytes = c - 0332 + 0xF2;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001547 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001548 offset += 1;
1549 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001550
Keith Kanios48af1772007-08-17 07:37:52 +00001551 case 0334:
1552 if (ins->rex & REX_R) {
1553 *bytes = 0xF0;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001554 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
Keith Kanios48af1772007-08-17 07:37:52 +00001555 offset += 1;
1556 }
1557 ins->rex &= ~(REX_L|REX_R);
1558 break;
H. Peter Anvin0db11e22007-04-17 20:23:11 +00001559
H. Peter Anvincb9b6902007-09-12 21:58:51 -07001560 case 0335:
1561 break;
1562
H. Peter Anvine2c80182005-01-15 22:15:51 +00001563 case 0340:
1564 case 0341:
1565 case 0342:
1566 if (ins->oprs[0].segment != NO_SEG)
1567 errfunc(ERR_PANIC, "non-constant BSS size in pass two");
1568 else {
Charles Crayne1f8bc4c2007-11-06 18:27:23 -08001569 int64_t size = ins->oprs[0].offset << (c & 3);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001570 if (size > 0)
1571 out(offset, segment, NULL,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001572 OUT_RESERVE, size, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001573 offset += size;
1574 }
1575 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001576
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001577 case 0364:
1578 case 0365:
1579 break;
1580
Keith Kanios48af1772007-08-17 07:37:52 +00001581 case 0366:
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001582 case 0367:
1583 *bytes = c - 0366 + 0x66;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001584 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
Keith Kanios48af1772007-08-17 07:37:52 +00001585 offset += 1;
1586 break;
H. Peter Anvin62cb6062007-09-11 22:44:03 +00001587
H. Peter Anvine2c80182005-01-15 22:15:51 +00001588 case 0370:
1589 case 0371:
1590 case 0372:
1591 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001592
H. Peter Anvine2c80182005-01-15 22:15:51 +00001593 case 0373:
1594 *bytes = bits == 16 ? 3 : 5;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001595 out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001596 offset += 1;
1597 break;
H. Peter Anvineba20a72002-04-30 20:53:55 +00001598
H. Peter Anvine2c80182005-01-15 22:15:51 +00001599 default: /* can't do it by 'case' statements */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001600 if (c >= 0100 && c <= 0277) { /* it's an EA */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001601 ea ea_data;
1602 int rfield;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001603 int32_t rflags;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001604 uint8_t *p;
1605 int32_t s;
H. Peter Anvin70653092007-10-19 14:42:29 -07001606
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001607 if (c <= 0177) {
1608 /* pick rfield from operand b */
1609 rflags = regflag(&ins->oprs[c & 7]);
1610 rfield = regvals[ins->oprs[c & 7].basereg];
1611 } else {
1612 /* rfield is constant */
1613 rflags = 0;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001614 rfield = c & 7;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001615 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001616
1617 if (!process_ea
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001618 (&ins->oprs[(c >> 3) & 7], &ea_data, bits,
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001619 ins->addr_size, rfield, rflags, ins->forw_ref)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001620 errfunc(ERR_NONFATAL, "invalid effective address");
1621 }
H. Peter Anvin70653092007-10-19 14:42:29 -07001622
Charles Crayne7e975552007-11-03 22:06:13 -07001623
H. Peter Anvine2c80182005-01-15 22:15:51 +00001624 p = bytes;
1625 *p++ = ea_data.modrm;
1626 if (ea_data.sib_present)
1627 *p++ = ea_data.sib;
1628
H. Peter Anvin401c07e2007-09-17 16:55:04 -07001629 /* DREX suffixes come between the SIB and the displacement */
1630 if (ins->rex & REX_D) {
1631 *p++ =
1632 (ins->drexdst << 4) |
1633 (ins->rex & REX_OC ? 0x08 : 0) |
1634 (ins->rex & (REX_R|REX_X|REX_B));
1635 ins->rex = 0;
1636 }
1637
H. Peter Anvine2c80182005-01-15 22:15:51 +00001638 s = p - bytes;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001639 out(offset, segment, bytes, OUT_RAWDATA, s, NO_SEG, NO_SEG);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001640
1641 switch (ea_data.bytes) {
1642 case 0:
1643 break;
1644 case 1:
1645 if (ins->oprs[(c >> 3) & 7].segment != NO_SEG) {
1646 data = ins->oprs[(c >> 3) & 7].offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001647 out(offset, segment, &data, OUT_ADDRESS, 1,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001648 ins->oprs[(c >> 3) & 7].segment,
1649 ins->oprs[(c >> 3) & 7].wrt);
1650 } else {
1651 *bytes = ins->oprs[(c >> 3) & 7].offset;
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001652 out(offset, segment, bytes, OUT_RAWDATA, 1,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001653 NO_SEG, NO_SEG);
1654 }
1655 s++;
1656 break;
H. Peter Anvin70653092007-10-19 14:42:29 -07001657 case 8:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001658 case 2:
1659 case 4:
1660 data = ins->oprs[(c >> 3) & 7].offset;
Charles Crayne7e975552007-11-03 22:06:13 -07001661 warn_overflow(ea_data.bytes, data);
H. Peter Anvind0b0d282007-09-28 17:17:20 -07001662 out(offset, segment, &data,
H. Peter Anvin34f6fb02007-11-09 14:44:02 -08001663 ea_data.rip ? OUT_REL4ADR : OUT_ADDRESS,
1664 ea_data.bytes,
H. Peter Anvine2c80182005-01-15 22:15:51 +00001665 ins->oprs[(c >> 3) & 7].segment,
1666 ins->oprs[(c >> 3) & 7].wrt);
1667 s += ea_data.bytes;
1668 break;
1669 }
1670 offset += s;
H. Peter Anvin839eca22007-10-29 23:12:47 -07001671 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001672 errfunc(ERR_PANIC, "internal instruction table corrupt"
1673 ": instruction code 0x%02X given", c);
H. Peter Anvin839eca22007-10-29 23:12:47 -07001674 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001675 }
H. Peter Anvin839eca22007-10-29 23:12:47 -07001676 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001677}
1678
H. Peter Anvin0ec60e62007-07-07 01:59:52 +00001679static int32_t regflag(const operand * o)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001680{
1681 if (o->basereg < EXPR_REG_START || o->basereg >= REG_ENUM_LIMIT) {
1682 errfunc(ERR_PANIC, "invalid operand passed to regflag()");
1683 }
1684 return reg_flags[o->basereg];
1685}
1686
H. Peter Anvin5b0e3ec2007-07-07 02:01:08 +00001687static int32_t regval(const operand * o)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001688{
H. Peter Anvine2c80182005-01-15 22:15:51 +00001689 if (o->basereg < EXPR_REG_START || o->basereg >= REG_ENUM_LIMIT) {
1690 errfunc(ERR_PANIC, "invalid operand passed to regval()");
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001691 }
H. Peter Anvin232badb2002-06-06 02:41:20 +00001692 return regvals[o->basereg];
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001693}
1694
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001695static int op_rexflags(const operand * o, int mask)
1696{
1697 int32_t flags;
1698 int val;
1699
1700 if (o->basereg < EXPR_REG_START || o->basereg >= REG_ENUM_LIMIT) {
1701 errfunc(ERR_PANIC, "invalid operand passed to op_rexflags()");
1702 }
1703
1704 flags = reg_flags[o->basereg];
1705 val = regvals[o->basereg];
1706
1707 return rexflags(val, flags, mask);
1708}
1709
1710static int rexflags(int val, int32_t flags, int mask)
1711{
1712 int rex = 0;
1713
1714 if (val >= 8)
1715 rex |= REX_B|REX_X|REX_R;
1716 if (flags & BITS64)
1717 rex |= REX_W;
1718 if (!(REG_HIGH & ~flags)) /* AH, CH, DH, BH */
1719 rex |= REX_H;
1720 else if (!(REG8 & ~flags) && val >= 4) /* SPL, BPL, SIL, DIL */
1721 rex |= REX_P;
1722
1723 return rex & mask;
1724}
1725
H. Peter Anvin3360d792007-09-11 04:16:57 +00001726static int matches(const struct itemplate *itemp, insn * instruction, int bits)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001727{
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001728 int i, size[MAX_OPERANDS], asize, oprs, ret;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001729
1730 ret = 100;
1731
1732 /*
1733 * Check the opcode
1734 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001735 if (itemp->opcode != instruction->opcode)
1736 return 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001737
1738 /*
1739 * Count the operands
1740 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001741 if (itemp->operands != instruction->operands)
1742 return 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001743
1744 /*
1745 * Check that no spurious colons or TOs are present
1746 */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001747 for (i = 0; i < itemp->operands; i++)
1748 if (instruction->oprs[i].type & ~itemp->opd[i] & (COLON | TO))
1749 return 0;
H. Peter Anvin70653092007-10-19 14:42:29 -07001750
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001751 /*
1752 * Check that the operand flags all match up
1753 */
H. Peter Anvin16b0a332007-09-12 20:27:41 -07001754 for (i = 0; i < itemp->operands; i++) {
H. Peter Anvincf5180a2007-09-17 17:25:27 -07001755 if (itemp->opd[i] & SAME_AS) {
1756 int j = itemp->opd[i] & ~SAME_AS;
1757 if (instruction->oprs[i].type != instruction->oprs[j].type ||
1758 instruction->oprs[i].basereg != instruction->oprs[j].basereg)
1759 return 0;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001760 } else if (itemp->opd[i] & ~instruction->oprs[i].type ||
H. Peter Anvine2c80182005-01-15 22:15:51 +00001761 ((itemp->opd[i] & SIZE_MASK) &&
1762 ((itemp->opd[i] ^ instruction->oprs[i].type) & SIZE_MASK))) {
H. Peter Anvin5a640e12007-05-29 23:57:12 +00001763 if ((itemp->opd[i] & ~instruction->oprs[i].type & ~SIZE_MASK) ||
H. Peter Anvine2c80182005-01-15 22:15:51 +00001764 (instruction->oprs[i].type & SIZE_MASK))
1765 return 0;
1766 else
H. Peter Anvine2c80182005-01-15 22:15:51 +00001767 return 1;
1768 }
H. Peter Anvin16b0a332007-09-12 20:27:41 -07001769 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001770
1771 /*
1772 * Check operand sizes
1773 */
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001774 if (itemp->flags & IF_ARMASK) {
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001775 memset(size, 0, sizeof size);
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001776
H. Peter Anvine2c80182005-01-15 22:15:51 +00001777 switch (itemp->flags & IF_ARMASK) {
1778 case IF_AR0:
1779 i = 0;
1780 break;
1781 case IF_AR1:
1782 i = 1;
1783 break;
1784 case IF_AR2:
1785 i = 2;
1786 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001787 case IF_AR3:
1788 i = 3;
1789 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001790 default:
1791 break; /* Shouldn't happen */
1792 }
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001793 switch (itemp->flags & IF_SMASK) {
1794 case IF_SB:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001795 size[i] = BITS8;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001796 break;
1797 case IF_SW:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001798 size[i] = BITS16;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001799 break;
1800 case IF_SD:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001801 size[i] = BITS32;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001802 break;
1803 case IF_SQ:
Keith Kaniosb7a89542007-04-12 02:40:54 +00001804 size[i] = BITS64;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001805 break;
H. Peter Anvin41c9f6f2007-09-18 13:01:32 -07001806 case IF_SO:
1807 size[i] = BITS128;
1808 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001809 default:
1810 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001811 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001812 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001813 asize = 0;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001814 switch (itemp->flags & IF_SMASK) {
1815 case IF_SB:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001816 asize = BITS8;
1817 oprs = itemp->operands;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001818 break;
1819 case IF_SW:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001820 asize = BITS16;
1821 oprs = itemp->operands;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001822 break;
1823 case IF_SD:
H. Peter Anvine2c80182005-01-15 22:15:51 +00001824 asize = BITS32;
1825 oprs = itemp->operands;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001826 break;
1827 case IF_SQ:
Keith Kaniosb7a89542007-04-12 02:40:54 +00001828 asize = BITS64;
1829 oprs = itemp->operands;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001830 break;
H. Peter Anvin41c9f6f2007-09-18 13:01:32 -07001831 case IF_SO:
1832 asize = BITS128;
1833 oprs = itemp->operands;
1834 break;
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001835 default:
1836 break;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001837 }
H. Peter Anvin7eb4a382007-09-17 15:49:30 -07001838 for (i = 0; i < MAX_OPERANDS; i++)
1839 size[i] = asize;
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001840 }
H. Peter Anvin70653092007-10-19 14:42:29 -07001841
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001842 if (itemp->flags & (IF_SM | IF_SM2)) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001843 oprs = (itemp->flags & IF_SM2 ? 2 : itemp->operands);
1844 asize = 0;
1845 for (i = 0; i < oprs; i++) {
1846 if ((asize = itemp->opd[i] & SIZE_MASK) != 0) {
1847 int j;
1848 for (j = 0; j < oprs; j++)
1849 size[j] = asize;
1850 break;
1851 }
1852 }
H. Peter Anvinef7468f2002-04-30 20:57:59 +00001853 } else {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001854 oprs = itemp->operands;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001855 }
1856
Keith Kaniosb7a89542007-04-12 02:40:54 +00001857 for (i = 0; i < itemp->operands; i++) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00001858 if (!(itemp->opd[i] & SIZE_MASK) &&
1859 (instruction->oprs[i].type & SIZE_MASK & ~size[i]))
H. Peter Anvine2c80182005-01-15 22:15:51 +00001860 return 2;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001861 }
1862
H. Peter Anvinaf535c12002-04-30 20:59:21 +00001863 /*
1864 * Check template is okay at the set cpu level
1865 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00001866 if (((itemp->flags & IF_PLEVEL) > cpu))
H. Peter Anvine2c80182005-01-15 22:15:51 +00001867 return 3;
H. Peter Anvin70653092007-10-19 14:42:29 -07001868
Keith Kaniosb7a89542007-04-12 02:40:54 +00001869 /*
1870 * Check if instruction is available in long mode
1871 */
1872 if ((itemp->flags & IF_NOLONG) && (bits == 64))
1873 return 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001874
H. Peter Anvinaf535c12002-04-30 20:59:21 +00001875 /*
1876 * Check if special handling needed for Jumps
1877 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00001878 if ((uint8_t)(itemp->code[0]) >= 0370)
H. Peter Anvine2c80182005-01-15 22:15:51 +00001879 return 99;
1880
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001881 return ret;
1882}
1883
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001884static ea *process_ea(operand * input, ea * output, int bits,
1885 int addrbits, int rfield, int32_t rflags, int forw_ref)
H. Peter Anvineba20a72002-04-30 20:53:55 +00001886{
H. Peter Anvin6867acc2007-10-10 14:58:45 -07001887 output->rip = false;
H. Peter Anvin99c4ecd2007-08-28 23:06:00 +00001888
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001889 /* REX flags for the rfield operand */
1890 output->rex |= rexflags(rfield, rflags, REX_R|REX_P|REX_W|REX_H);
1891
Keith Kaniosb7a89542007-04-12 02:40:54 +00001892 if (!(REGISTER & ~input->type)) { /* register direct */
H. Peter Anvine2c80182005-01-15 22:15:51 +00001893 int i;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001894 int32_t f;
1895
1896 if (input->basereg < EXPR_REG_START /* Verify as Register */
Keith Kaniosb7a89542007-04-12 02:40:54 +00001897 || input->basereg >= REG_ENUM_LIMIT)
H. Peter Anvine2c80182005-01-15 22:15:51 +00001898 return NULL;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001899 f = regflag(input);
Keith Kaniosb7a89542007-04-12 02:40:54 +00001900 i = regvals[input->basereg];
Keith Kaniosb7a89542007-04-12 02:40:54 +00001901
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001902 if (REG_EA & ~f)
1903 return NULL; /* Invalid EA register */
H. Peter Anvin70653092007-10-19 14:42:29 -07001904
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001905 output->rex |= op_rexflags(input, REX_B|REX_P|REX_W|REX_H);
1906
H. Peter Anvin6867acc2007-10-10 14:58:45 -07001907 output->sib_present = false; /* no SIB necessary */
Keith Kaniosb7a89542007-04-12 02:40:54 +00001908 output->bytes = 0; /* no offset necessary either */
1909 output->modrm = 0xC0 | ((rfield & 7) << 3) | (i & 7);
H. Peter Anvine2c80182005-01-15 22:15:51 +00001910 } else { /* it's a memory reference */
1911 if (input->basereg == -1
1912 && (input->indexreg == -1 || input->scale == 0)) {
1913 /* it's a pure offset */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001914 if (bits == 64 && (~input->type & IP_REL)) {
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00001915 int scale, index, base;
H. Peter Anvin6867acc2007-10-10 14:58:45 -07001916 output->sib_present = true;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00001917 scale = 0;
1918 index = 4;
1919 base = 5;
1920 output->sib = (scale << 6) | (index << 3) | base;
1921 output->bytes = 4;
1922 output->modrm = 4 | ((rfield & 7) << 3);
H. Peter Anvin6867acc2007-10-10 14:58:45 -07001923 output->rip = false;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00001924 } else {
H. Peter Anvin6867acc2007-10-10 14:58:45 -07001925 output->sib_present = false;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00001926 output->bytes = (addrbits != 16 ? 4 : 2);
1927 output->modrm = (addrbits != 16 ? 5 : 6) | ((rfield & 7) << 3);
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001928 output->rip = bits == 64;
Chuck Crayne42fe6ce2007-06-03 02:42:41 +00001929 }
H. Peter Anvine2c80182005-01-15 22:15:51 +00001930 } else { /* it's an indirection */
1931 int i = input->indexreg, b = input->basereg, s = input->scale;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001932 int32_t o = input->offset, seg = input->segment;
H. Peter Anvine2c80182005-01-15 22:15:51 +00001933 int hb = input->hintbase, ht = input->hinttype;
1934 int t;
Keith Kaniosb7a89542007-04-12 02:40:54 +00001935 int it, bt;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001936 int32_t ix, bx; /* register flags */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001937
H. Peter Anvine2c80182005-01-15 22:15:51 +00001938 if (s == 0)
1939 i = -1; /* make this easy, at least */
H. Peter Anvin70653092007-10-19 14:42:29 -07001940
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001941 if (i >= EXPR_REG_START && i < REG_ENUM_LIMIT) {
Keith Kaniosb7a89542007-04-12 02:40:54 +00001942 it = regvals[i];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001943 ix = reg_flags[i];
1944 } else {
Keith Kaniosb7a89542007-04-12 02:40:54 +00001945 it = -1;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001946 ix = 0;
1947 }
H. Peter Anvin70653092007-10-19 14:42:29 -07001948
H. Peter Anvinb0c54622007-10-28 23:21:46 -07001949 if (b >= EXPR_REG_START && b < REG_ENUM_LIMIT) {
Keith Kaniosb7a89542007-04-12 02:40:54 +00001950 bt = regvals[b];
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001951 bx = reg_flags[b];
1952 } else {
Keith Kaniosb7a89542007-04-12 02:40:54 +00001953 bt = -1;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001954 bx = 0;
1955 }
H. Peter Anvin70653092007-10-19 14:42:29 -07001956
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001957 /* check for a 32/64-bit memory reference... */
1958 if ((ix|bx) & (BITS32|BITS64)) {
Keith Kaniosb7a89542007-04-12 02:40:54 +00001959 /* it must be a 32/64-bit memory reference. Firstly we have
1960 * to check that all registers involved are type E/Rxx. */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001961 int32_t sok = BITS32|BITS64;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001962
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001963 if (it != -1) {
1964 if (!(REG64 & ~ix) || !(REG32 & ~ix))
1965 sok &= ix;
1966 else
1967 return NULL;
1968 }
1969
1970 if (bt != -1) {
H. Peter Anvin99c4ecd2007-08-28 23:06:00 +00001971 if (REG_GPR & ~bx)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001972 return NULL; /* Invalid register */
H. Peter Anvina57e8d42007-05-30 03:44:02 +00001973 if (~sok & bx & SIZE_MASK)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001974 return NULL; /* Invalid size */
H. Peter Anvinb0c54622007-10-28 23:21:46 -07001975 sok &= bx;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001976 }
H. Peter Anvin70653092007-10-19 14:42:29 -07001977
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07001978 /* While we're here, ensure the user didn't specify
1979 WORD or QWORD. */
1980 if (input->disp_size == 16 || input->disp_size == 64)
1981 return NULL;
1982
1983 if (addrbits == 16 ||
1984 (addrbits == 32 && !(sok & BITS32)) ||
1985 (addrbits == 64 && !(sok & BITS64)))
1986 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001987
Keith Kaniosb7a89542007-04-12 02:40:54 +00001988 /* now reorganize base/index */
1989 if (s == 1 && bt != it && bt != -1 && it != -1 &&
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001990 ((hb == b && ht == EAH_NOTBASE)
1991 || (hb == i && ht == EAH_MAKEBASE))) {
1992 /* swap if hints say so */
1993 t = bt, bt = it, it = t;
1994 t = bx, bx = ix, ix = t;
1995 }
Keith Kaniosb7a89542007-04-12 02:40:54 +00001996 if (bt == it) /* convert EAX+2*EAX to 3*EAX */
H. Peter Anvin3df97a72007-05-30 03:25:21 +00001997 bt = -1, bx = 0, s++;
1998 if (bt == -1 && s == 1 && !(hb == it && ht == EAH_NOTBASE)) {
1999 /* make single reg base, unless hint */
2000 bt = it, bx = ix, it = -1, ix = 0;
2001 }
H. Peter Anvinf5843c62007-09-10 18:59:26 +00002002 if (((s == 2 && it != REG_NUM_ESP
H. Peter Anvine2c80182005-01-15 22:15:51 +00002003 && !(input->eaflags & EAF_TIMESTWO)) || s == 3
Keith Kaniosb7a89542007-04-12 02:40:54 +00002004 || s == 5 || s == 9) && bt == -1)
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002005 bt = it, bx = ix, s--; /* convert 3*EAX to EAX+2*EAX */
Keith Kanios48af1772007-08-17 07:37:52 +00002006 if (it == -1 && (bt & 7) != REG_NUM_ESP
H. Peter Anvine2c80182005-01-15 22:15:51 +00002007 && (input->eaflags & EAF_TIMESTWO))
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002008 it = bt, ix = bx, bt = -1, bx = 0, s = 1;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002009 /* convert [NOSPLIT EAX] to sib format with 0x0 displacement */
Keith Kanios48af1772007-08-17 07:37:52 +00002010 if (s == 1 && it == REG_NUM_ESP) {
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002011 /* swap ESP into base if scale is 1 */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002012 t = it, it = bt, bt = t;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002013 t = ix, ix = bx, bx = t;
2014 }
Keith Kanios48af1772007-08-17 07:37:52 +00002015 if (it == REG_NUM_ESP
Keith Kaniosb7a89542007-04-12 02:40:54 +00002016 || (s != 1 && s != 2 && s != 4 && s != 8 && it != -1))
H. Peter Anvine2c80182005-01-15 22:15:51 +00002017 return NULL; /* wrong, for various reasons */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002018
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002019 output->rex |= rexflags(it, ix, REX_X);
2020 output->rex |= rexflags(bt, bx, REX_B);
Keith Kaniosb7a89542007-04-12 02:40:54 +00002021
Keith Kanios48af1772007-08-17 07:37:52 +00002022 if (it == -1 && (bt & 7) != REG_NUM_ESP) {
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002023 /* no SIB needed */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002024 int mod, rm;
H. Peter Anvin70653092007-10-19 14:42:29 -07002025
Keith Kaniosb7a89542007-04-12 02:40:54 +00002026 if (bt == -1) {
H. Peter Anvine2c80182005-01-15 22:15:51 +00002027 rm = 5;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002028 mod = 0;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002029 } else {
2030 rm = (bt & 7);
Keith Kanios48af1772007-08-17 07:37:52 +00002031 if (rm != REG_NUM_EBP && o == 0 &&
Keith Kaniosb7a89542007-04-12 02:40:54 +00002032 seg == NO_SEG && !forw_ref &&
2033 !(input->eaflags &
2034 (EAF_BYTEOFFS | EAF_WORDOFFS)))
2035 mod = 0;
2036 else if (input->eaflags & EAF_BYTEOFFS ||
2037 (o >= -128 && o <= 127 && seg == NO_SEG
2038 && !forw_ref
2039 && !(input->eaflags & EAF_WORDOFFS)))
2040 mod = 1;
2041 else
2042 mod = 2;
2043 }
H. Peter Anvinea838272002-04-30 20:51:53 +00002044
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002045 output->sib_present = false;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002046 output->bytes = (bt == -1 || mod == 2 ? 4 : mod);
2047 output->modrm = (mod << 6) | ((rfield & 7) << 3) | rm;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002048 } else {
2049 /* we need a SIB */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002050 int mod, scale, index, base;
H. Peter Anvin70653092007-10-19 14:42:29 -07002051
Keith Kaniosb7a89542007-04-12 02:40:54 +00002052 if (it == -1)
2053 index = 4, s = 1;
2054 else
2055 index = (it & 7);
H. Peter Anvin70653092007-10-19 14:42:29 -07002056
H. Peter Anvine2c80182005-01-15 22:15:51 +00002057 switch (s) {
2058 case 1:
2059 scale = 0;
2060 break;
2061 case 2:
2062 scale = 1;
2063 break;
2064 case 4:
2065 scale = 2;
2066 break;
2067 case 8:
2068 scale = 3;
2069 break;
2070 default: /* then what the smeg is it? */
2071 return NULL; /* panic */
2072 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002073
Keith Kaniosb7a89542007-04-12 02:40:54 +00002074 if (bt == -1) {
2075 base = 5;
2076 mod = 0;
2077 } else {
2078 base = (bt & 7);
Keith Kanios48af1772007-08-17 07:37:52 +00002079 if (base != REG_NUM_EBP && o == 0 &&
H. Peter Anvine2c80182005-01-15 22:15:51 +00002080 seg == NO_SEG && !forw_ref &&
2081 !(input->eaflags &
Keith Kaniosb7a89542007-04-12 02:40:54 +00002082 (EAF_BYTEOFFS | EAF_WORDOFFS)))
2083 mod = 0;
2084 else if (input->eaflags & EAF_BYTEOFFS ||
2085 (o >= -128 && o <= 127 && seg == NO_SEG
2086 && !forw_ref
2087 && !(input->eaflags & EAF_WORDOFFS)))
2088 mod = 1;
2089 else
2090 mod = 2;
2091 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002092
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002093 output->sib_present = true;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002094 output->bytes = (bt == -1 || mod == 2 ? 4 : mod);
2095 output->modrm = (mod << 6) | ((rfield & 7) << 3) | 4;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002096 output->sib = (scale << 6) | (index << 3) | base;
2097 }
2098 } else { /* it's 16-bit */
2099 int mod, rm;
H. Peter Anvin70653092007-10-19 14:42:29 -07002100
Keith Kaniosb7a89542007-04-12 02:40:54 +00002101 /* check for 64-bit long mode */
2102 if (addrbits == 64)
2103 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002104
H. Peter Anvine2c80182005-01-15 22:15:51 +00002105 /* check all registers are BX, BP, SI or DI */
2106 if ((b != -1 && b != R_BP && b != R_BX && b != R_SI
2107 && b != R_DI) || (i != -1 && i != R_BP && i != R_BX
2108 && i != R_SI && i != R_DI))
2109 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002110
Keith Kaniosb7a89542007-04-12 02:40:54 +00002111 /* ensure the user didn't specify DWORD/QWORD */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002112 if (input->disp_size == 32 || input->disp_size == 64)
H. Peter Anvine2c80182005-01-15 22:15:51 +00002113 return NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002114
H. Peter Anvine2c80182005-01-15 22:15:51 +00002115 if (s != 1 && i != -1)
2116 return NULL; /* no can do, in 16-bit EA */
2117 if (b == -1 && i != -1) {
2118 int tmp = b;
2119 b = i;
2120 i = tmp;
2121 } /* swap */
2122 if ((b == R_SI || b == R_DI) && i != -1) {
2123 int tmp = b;
2124 b = i;
2125 i = tmp;
2126 }
2127 /* have BX/BP as base, SI/DI index */
2128 if (b == i)
2129 return NULL; /* shouldn't ever happen, in theory */
2130 if (i != -1 && b != -1 &&
2131 (i == R_BP || i == R_BX || b == R_SI || b == R_DI))
2132 return NULL; /* invalid combinations */
2133 if (b == -1) /* pure offset: handled above */
2134 return NULL; /* so if it gets to here, panic! */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002135
H. Peter Anvine2c80182005-01-15 22:15:51 +00002136 rm = -1;
2137 if (i != -1)
2138 switch (i * 256 + b) {
2139 case R_SI * 256 + R_BX:
2140 rm = 0;
2141 break;
2142 case R_DI * 256 + R_BX:
2143 rm = 1;
2144 break;
2145 case R_SI * 256 + R_BP:
2146 rm = 2;
2147 break;
2148 case R_DI * 256 + R_BP:
2149 rm = 3;
2150 break;
2151 } else
2152 switch (b) {
2153 case R_SI:
2154 rm = 4;
2155 break;
2156 case R_DI:
2157 rm = 5;
2158 break;
2159 case R_BP:
2160 rm = 6;
2161 break;
2162 case R_BX:
2163 rm = 7;
2164 break;
2165 }
2166 if (rm == -1) /* can't happen, in theory */
2167 return NULL; /* so panic if it does */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002168
H. Peter Anvine2c80182005-01-15 22:15:51 +00002169 if (o == 0 && seg == NO_SEG && !forw_ref && rm != 6 &&
2170 !(input->eaflags & (EAF_BYTEOFFS | EAF_WORDOFFS)))
2171 mod = 0;
2172 else if (input->eaflags & EAF_BYTEOFFS ||
2173 (o >= -128 && o <= 127 && seg == NO_SEG
2174 && !forw_ref
2175 && !(input->eaflags & EAF_WORDOFFS)))
2176 mod = 1;
2177 else
2178 mod = 2;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002179
H. Peter Anvin6867acc2007-10-10 14:58:45 -07002180 output->sib_present = false; /* no SIB - it's 16-bit */
H. Peter Anvine2c80182005-01-15 22:15:51 +00002181 output->bytes = mod; /* bytes of offset needed */
Keith Kaniosb7a89542007-04-12 02:40:54 +00002182 output->modrm = (mod << 6) | ((rfield & 7) << 3) | rm;
H. Peter Anvine2c80182005-01-15 22:15:51 +00002183 }
2184 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002185 }
H. Peter Anvin70653092007-10-19 14:42:29 -07002186
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002187 output->size = 1 + output->sib_present + output->bytes;
2188 return output;
2189}
2190
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002191static void add_asp(insn *ins, int addrbits)
H. Peter Anvineba20a72002-04-30 20:53:55 +00002192{
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002193 int j, valid;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002194 int defdisp;
Keith Kaniosb7a89542007-04-12 02:40:54 +00002195
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002196 valid = (addrbits == 64) ? 64|32 : 32|16;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002197
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002198 switch (ins->prefixes[PPS_ASIZE]) {
2199 case P_A16:
2200 valid &= 16;
2201 break;
2202 case P_A32:
2203 valid &= 32;
2204 break;
2205 case P_A64:
2206 valid &= 64;
2207 break;
2208 case P_ASP:
2209 valid &= (addrbits == 32) ? 16 : 32;
2210 break;
2211 default:
2212 break;
2213 }
2214
2215 for (j = 0; j < ins->operands; j++) {
2216 if (!(MEMORY & ~ins->oprs[j].type)) {
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002217 int32_t i, b;
H. Peter Anvin70653092007-10-19 14:42:29 -07002218
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002219 /* Verify as Register */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002220 if (ins->oprs[j].indexreg < EXPR_REG_START
2221 || ins->oprs[j].indexreg >= REG_ENUM_LIMIT)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002222 i = 0;
2223 else
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002224 i = reg_flags[ins->oprs[j].indexreg];
H. Peter Anvin70653092007-10-19 14:42:29 -07002225
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002226 /* Verify as Register */
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002227 if (ins->oprs[j].basereg < EXPR_REG_START
2228 || ins->oprs[j].basereg >= REG_ENUM_LIMIT)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002229 b = 0;
2230 else
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002231 b = reg_flags[ins->oprs[j].basereg];
H. Peter Anvin70653092007-10-19 14:42:29 -07002232
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002233 if (ins->oprs[j].scale == 0)
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002234 i = 0;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002235
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002236 if (!i && !b) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002237 int ds = ins->oprs[j].disp_size;
2238 if ((addrbits != 64 && ds > 8) ||
2239 (addrbits == 64 && ds == 16))
2240 valid &= ds;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002241 } else {
2242 if (!(REG16 & ~b))
2243 valid &= 16;
2244 if (!(REG32 & ~b))
2245 valid &= 32;
2246 if (!(REG64 & ~b))
2247 valid &= 64;
H. Peter Anvin70653092007-10-19 14:42:29 -07002248
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002249 if (!(REG16 & ~i))
2250 valid &= 16;
2251 if (!(REG32 & ~i))
2252 valid &= 32;
2253 if (!(REG64 & ~i))
2254 valid &= 64;
2255 }
2256 }
2257 }
2258
2259 if (valid & addrbits) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002260 ins->addr_size = addrbits;
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002261 } else if (valid & ((addrbits == 32) ? 16 : 32)) {
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002262 /* Add an address size prefix */
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002263 enum prefixes pref = (addrbits == 32) ? P_A16 : P_A32;
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002264 ins->prefixes[PPS_ASIZE] = pref;
2265 ins->addr_size = (addrbits == 32) ? 16 : 32;
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002266 } else {
H. Peter Anvinc5b9ce02007-09-22 21:49:51 -07002267 /* Impossible... */
2268 errfunc(ERR_NONFATAL, "impossible combination of address sizes");
H. Peter Anvinde4b89b2007-10-01 15:41:25 -07002269 ins->addr_size = addrbits; /* Error recovery */
2270 }
2271
2272 defdisp = ins->addr_size == 16 ? 16 : 32;
2273
2274 for (j = 0; j < ins->operands; j++) {
2275 if (!(MEM_OFFS & ~ins->oprs[j].type) &&
2276 (ins->oprs[j].disp_size ? ins->oprs[j].disp_size : defdisp)
2277 != ins->addr_size) {
2278 /* mem_offs sizes must match the address size; if not,
2279 strip the MEM_OFFS bit and match only EA instructions */
2280 ins->oprs[j].type &= ~(MEM_OFFS & ~MEMORY);
2281 }
H. Peter Anvin3df97a72007-05-30 03:25:21 +00002282 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00002283}