blob: 8d144121d32a1bc78c5ca003bac20af837cf7921 [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
15 * \10, \11, \12 - a literal byte follows in the code stream, to be added
16 * to the register value of operand 0, 1 or 2
17 * \17 - encodes the literal byte 0. (Some compilers don't take
18 * kindly to a zero byte in the _middle_ of a compile time
19 * string constant, so I had to put this hack in.)
20 * \14, \15, \16 - a signed byte immediate operand, from operand 0, 1 or 2
21 * \20, \21, \22 - a byte immediate operand, from operand 0, 1 or 2
22 * \24, \25, \26 - an unsigned byte immediate operand, from operand 0, 1 or 2
23 * \30, \31, \32 - a word immediate operand, from operand 0, 1 or 2
24 * \34, \35, \36 - select between \3[012] and \4[012] depending on 16/32 bit
25 * assembly mode or the address-size override on the operand
26 * \37 - a word constant, from the _segment_ part of operand 0
27 * \40, \41, \42 - a long immediate operand, from operand 0, 1 or 2
28 * \50, \51, \52 - a byte relative operand, from operand 0, 1 or 2
29 * \60, \61, \62 - a word relative operand, from operand 0, 1 or 2
30 * \64, \65, \66 - select between \6[012] and \7[012] depending on 16/32 bit
31 * assembly mode or the address-size override on the operand
32 * \70, \71, \72 - a long relative operand, from operand 0, 1 or 2
33 * \1ab - a ModRM, calculated on EA in operand a, with the spare
34 * field the register value of operand b.
35 * \2ab - a ModRM, calculated on EA in operand a, with the spare
36 * field equal to digit b.
37 * \30x - might be an 0x67 byte, depending on the address size of
38 * the memory reference in operand x.
39 * \310 - indicates fixed 16-bit address size, i.e. optional 0x67.
40 * \311 - indicates fixed 32-bit address size, i.e. optional 0x67.
41 * \320 - indicates fixed 16-bit operand size, i.e. optional 0x66.
42 * \321 - indicates fixed 32-bit operand size, i.e. optional 0x66.
43 * \322 - indicates that this instruction is only valid when the
44 * operand size is the default (instruction to disassembler,
45 * generates no code in the assembler)
46 * \330 - a literal byte follows in the code stream, to be added
47 * to the condition code value of the instruction.
48 * \340 - reserve <operand 0> bytes of uninitialised storage.
49 * Operand 0 had better be a segmentless constant.
50 */
51
52#include <stdio.h>
53#include <string.h>
54
55#include "nasm.h"
H. Peter Anvin6768eb72002-04-30 20:52:26 +000056#include "nasmlib.h"
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000057#include "assemble.h"
58#include "insns.h"
59
60extern struct itemplate *nasm_instructions[];
61
62typedef struct {
63 int sib_present; /* is a SIB byte necessary? */
64 int bytes; /* # of bytes of offset needed */
65 int size; /* lazy - this is sib+bytes+1 */
66 unsigned char modrm, sib; /* the bytes themselves */
67} ea;
68
69static efunc errfunc;
70static struct ofmt *outfmt;
H. Peter Anvin6768eb72002-04-30 20:52:26 +000071static ListGen *list;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000072
73static long calcsize (long, long, int, insn *, char *);
74static void gencode (long, long, int, insn *, char *, long);
75static int regval (operand *o);
76static int matches (struct itemplate *, insn *);
H. Peter Anvinea838272002-04-30 20:51:53 +000077static ea *process_ea (operand *, ea *, int, int, int);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000078static int chsize (operand *, int);
79
H. Peter Anvin6768eb72002-04-30 20:52:26 +000080/*
81 * This routine wrappers the real output format's output routine,
82 * in order to pass a copy of the data off to the listing file
83 * generator at the same time.
84 */
85static void out (long offset, long segto, void *data, unsigned long type,
86 long segment, long wrt) {
87 if ((type & OUT_TYPMASK) == OUT_ADDRESS) {
88 if (segment != NO_SEG || wrt != NO_SEG) {
89 /*
90 * This address is relocated. We must write it as
91 * OUT_ADDRESS, so there's no work to be done here.
92 */
93 list->output (offset, data, type);
94 } else {
95 unsigned char p[4], *q = p;
96 /*
97 * This is a non-relocated address, and we're going to
98 * convert it into RAWDATA format.
99 */
100 if ((type & OUT_SIZMASK) == 4) {
101 WRITELONG (q, * (long *) data);
102 list->output (offset, p, OUT_RAWDATA+4);
103 } else {
104 WRITESHORT (q, * (long *) data);
105 list->output (offset, p, OUT_RAWDATA+2);
106 }
107 }
108 } else if ((type & OUT_TYPMASK) == OUT_RAWDATA) {
109 list->output (offset, data, type);
110 } else if ((type & OUT_TYPMASK) == OUT_RESERVE) {
111 list->output (offset, NULL, type);
112 } else if ((type & OUT_TYPMASK) == OUT_REL2ADR ||
113 (type & OUT_TYPMASK) == OUT_REL4ADR) {
114 list->output (offset, data, type);
115 }
116
117 outfmt->output (segto, data, type, segment, wrt);
118}
119
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000120long assemble (long segment, long offset, int bits,
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000121 insn *instruction, struct ofmt *output, efunc error,
122 ListGen *listgen) {
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000123 int j, size_prob;
124 long insn_end, itimes;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000125 long start = offset;
126 struct itemplate *temp;
127
128 errfunc = error; /* to pass to other functions */
129 outfmt = output; /* likewise */
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000130 list = listgen; /* and again */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000131
132 if (instruction->opcode == -1)
133 return 0;
134
135 if (instruction->opcode == I_DB ||
136 instruction->opcode == I_DW ||
137 instruction->opcode == I_DD ||
138 instruction->opcode == I_DQ ||
139 instruction->opcode == I_DT) {
140 extop *e;
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000141 long wsize = 0; /* placate gcc */
142 long t = instruction->times;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000143
144 switch (instruction->opcode) {
145 case I_DB: wsize = 1; break;
146 case I_DW: wsize = 2; break;
147 case I_DD: wsize = 4; break;
148 case I_DQ: wsize = 8; break;
149 case I_DT: wsize = 10; break;
150 }
151
152 while (t--) {
153 for (e = instruction->eops; e; e = e->next) {
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000154 if (e->type == EOT_DB_NUMBER) {
155 if (wsize == 1) {
156 if (e->segment != NO_SEG)
157 errfunc (ERR_NONFATAL,
158 "one-byte relocation attempted");
159 else {
160 unsigned char c = e->offset;
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000161 out (offset, segment, &c, OUT_RAWDATA+1,
162 NO_SEG, NO_SEG);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000163 }
164 } else if (wsize > 5) {
165 errfunc (ERR_NONFATAL, "integer supplied to a D%c"
166 " instruction", wsize==8 ? 'Q' : 'T');
167 } else
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000168 out (offset, segment, &e->offset,
169 OUT_ADDRESS+wsize, e->segment,
170 e->wrt);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000171 offset += wsize;
172 } else if (e->type == EOT_DB_STRING) {
173 int align;
174
175 align = (-e->stringlen) % wsize;
176 if (align < 0)
177 align += wsize;
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000178 out (offset, segment, e->stringval,
179 OUT_RAWDATA+e->stringlen, NO_SEG, NO_SEG);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000180 if (align)
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000181 out (offset, segment, "\0\0\0\0",
182 OUT_RAWDATA+align, NO_SEG, NO_SEG);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000183 offset += e->stringlen + align;
184 }
185 }
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000186 if (t > 0 && t == instruction->times-1) {
187 /*
188 * Dummy call to list->output to give the offset to the
189 * listing module.
190 */
191 list->output (offset, NULL, OUT_RAWDATA);
192 list->uplevel (LIST_TIMES);
193 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000194 }
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000195 if (instruction->times > 1)
196 list->downlevel (LIST_TIMES);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000197 return offset - start;
198 }
199
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000200 if (instruction->opcode == I_INCBIN) {
201 static char fname[FILENAME_MAX];
202 FILE *fp;
203 long len;
204
205 len = FILENAME_MAX-1;
206 if (len > instruction->eops->stringlen)
207 len = instruction->eops->stringlen;
208 strncpy (fname, instruction->eops->stringval, len);
209 fname[len] = '\0';
210 if (!(fp = fopen(fname, "rb")))
211 error (ERR_NONFATAL, "`incbin': unable to open file `%s'", fname);
212 else if (fseek(fp, 0L, SEEK_END) < 0)
213 error (ERR_NONFATAL, "`incbin': unable to seek on file `%s'",
214 fname);
215 else {
216 static char buf[2048];
217 long t = instruction->times;
218 long l;
219
220 len = ftell (fp);
221 if (instruction->eops->next) {
222 len -= instruction->eops->next->offset;
223 if (instruction->eops->next->next &&
224 len > instruction->eops->next->next->offset)
225 len = instruction->eops->next->next->offset;
226 }
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000227 /*
228 * Dummy call to list->output to give the offset to the
229 * listing module.
230 */
231 list->output (offset, NULL, OUT_RAWDATA);
232 list->uplevel(LIST_INCBIN);
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000233 while (t--) {
234 fseek (fp,
235 (instruction->eops->next ?
236 instruction->eops->next->offset : 0),
237 SEEK_SET);
238 l = len;
239 while (l > 0) {
240 long m = fread (buf, 1, (l>sizeof(buf)?sizeof(buf):l),
241 fp);
242 if (!m) {
243 /*
244 * This shouldn't happen unless the file
245 * actually changes while we are reading
246 * it.
247 */
248 error (ERR_NONFATAL, "`incbin': unexpected EOF while"
249 " reading file `%s'", fname);
250 return 0; /* it doesn't much matter... */
251 }
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000252 out (offset, segment, buf, OUT_RAWDATA+m,
253 NO_SEG, NO_SEG);
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000254 l -= m;
255 }
256 }
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000257 list->downlevel(LIST_INCBIN);
258 if (instruction->times > 1) {
259 /*
260 * Dummy call to list->output to give the offset to the
261 * listing module.
262 */
263 list->output (offset, NULL, OUT_RAWDATA);
264 list->uplevel(LIST_TIMES);
265 list->downlevel(LIST_TIMES);
266 }
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000267 fclose (fp);
268 return instruction->times * len;
269 }
270 return 0; /* if we're here, there's an error */
271 }
272
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000273 size_prob = FALSE;
274 temp = nasm_instructions[instruction->opcode];
275 while (temp->opcode != -1) {
276 int m = matches (temp, instruction);
277 if (m == 100) { /* matches! */
278 char *codes = temp->code;
279 long insn_size = calcsize(segment, offset, bits,
280 instruction, codes);
281 itimes = instruction->times;
282 if (insn_size < 0) /* shouldn't be, on pass two */
283 error (ERR_PANIC, "errors made it through from pass one");
284 else while (itimes--) {
285 insn_end = offset + insn_size;
286 for (j=0; j<instruction->nprefix; j++) {
287 unsigned char c;
288 switch (instruction->prefixes[j]) {
289 case P_LOCK:
290 c = 0xF0; break;
291 case P_REPNE: case P_REPNZ:
292 c = 0xF2; break;
293 case P_REPE: case P_REPZ: case P_REP:
294 c = 0xF3; break;
295 case R_CS: c = 0x2E; break;
296 case R_DS: c = 0x3E; break;
297 case R_ES: c = 0x26; break;
298 case R_FS: c = 0x64; break;
299 case R_GS: c = 0x65; break;
300 case R_SS: c = 0x36; break;
301 case P_A16:
302 if (bits == 16)
303 c = 0; /* no prefix */
304 else
305 c = 0x67;
306 break;
307 case P_A32:
308 if (bits == 32)
309 c = 0; /* no prefix */
310 else
311 c = 0x67;
312 break;
313 case P_O16:
314 if (bits == 16)
315 c = 0; /* no prefix */
316 else
317 c = 0x66;
318 break;
319 case P_O32:
320 if (bits == 32)
321 c = 0; /* no prefix */
322 else
323 c = 0x66;
324 break;
325 default:
326 error (ERR_PANIC,
327 "invalid instruction prefix");
328 }
329 if (c != 0)
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000330 out (offset, segment, &c, OUT_RAWDATA+1,
331 NO_SEG, NO_SEG);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000332 offset++;
333 }
334 gencode (segment, offset, bits, instruction, codes, insn_end);
335 offset += insn_size;
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000336 if (itimes > 0 && itimes == instruction->times-1) {
337 /*
338 * Dummy call to list->output to give the offset to the
339 * listing module.
340 */
341 list->output (offset, NULL, OUT_RAWDATA);
342 list->uplevel (LIST_TIMES);
343 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000344 }
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000345 if (instruction->times > 1)
346 list->downlevel (LIST_TIMES);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000347 return offset - start;
348 } else if (m > 0) {
349 size_prob = m;
350 }
351 temp++;
352 }
353 if (temp->opcode == -1) { /* didn't match any instruction */
354 if (size_prob == 1) /* would have matched, but for size */
355 error (ERR_NONFATAL, "operation size not specified");
356 else if (size_prob == 2)
357 error (ERR_NONFATAL, "mismatch in operand sizes");
358 else
359 error (ERR_NONFATAL,
360 "invalid combination of opcode and operands");
361 }
362 return 0;
363}
364
365long insn_size (long segment, long offset, int bits,
366 insn *instruction, efunc error) {
367 struct itemplate *temp;
368
369 errfunc = error; /* to pass to other functions */
370
371 if (instruction->opcode == -1)
372 return 0;
373
374 if (instruction->opcode == I_DB ||
375 instruction->opcode == I_DW ||
376 instruction->opcode == I_DD ||
377 instruction->opcode == I_DQ ||
378 instruction->opcode == I_DT) {
379 extop *e;
380 long isize, osize, wsize = 0; /* placate gcc */
381
382 isize = 0;
383 switch (instruction->opcode) {
384 case I_DB: wsize = 1; break;
385 case I_DW: wsize = 2; break;
386 case I_DD: wsize = 4; break;
387 case I_DQ: wsize = 8; break;
388 case I_DT: wsize = 10; break;
389 }
390
391 for (e = instruction->eops; e; e = e->next) {
392 long align;
393
394 osize = 0;
395 if (e->type == EOT_DB_NUMBER)
396 osize = 1;
397 else if (e->type == EOT_DB_STRING)
398 osize = e->stringlen;
399
400 align = (-osize) % wsize;
401 if (align < 0)
402 align += wsize;
403 isize += osize + align;
404 }
405 return isize * instruction->times;
406 }
407
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000408 if (instruction->opcode == I_INCBIN) {
409 char fname[FILENAME_MAX];
410 FILE *fp;
411 long len;
412
413 len = FILENAME_MAX-1;
414 if (len > instruction->eops->stringlen)
415 len = instruction->eops->stringlen;
416 strncpy (fname, instruction->eops->stringval, len);
417 fname[len] = '\0';
418 if (!(fp = fopen(fname, "rb")))
419 error (ERR_NONFATAL, "`incbin': unable to open file `%s'", fname);
420 else if (fseek(fp, 0L, SEEK_END) < 0)
421 error (ERR_NONFATAL, "`incbin': unable to seek on file `%s'",
422 fname);
423 else {
424 len = ftell (fp);
425 fclose (fp);
426 if (instruction->eops->next) {
427 len -= instruction->eops->next->offset;
428 if (instruction->eops->next->next &&
429 len > instruction->eops->next->next->offset)
430 len = instruction->eops->next->next->offset;
431 }
432 return instruction->times * len;
433 }
434 return 0; /* if we're here, there's an error */
435 }
436
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000437 temp = nasm_instructions[instruction->opcode];
438 while (temp->opcode != -1) {
439 if (matches(temp, instruction) == 100) {
440 /* we've matched an instruction. */
441 long isize;
442 char *codes = temp->code;
443 int j;
444
445 isize = calcsize(segment, offset, bits, instruction, codes);
446 if (isize < 0)
447 return -1;
448 for (j = 0; j < instruction->nprefix; j++) {
449 if ((instruction->prefixes[j] != P_A16 &&
450 instruction->prefixes[j] != P_O16 && bits==16) ||
451 (instruction->prefixes[j] != P_A32 &&
452 instruction->prefixes[j] != P_O32 && bits==32))
453 isize++;
454 }
455 return isize * instruction->times;
456 }
457 temp++;
458 }
459 return -1; /* didn't match any instruction */
460}
461
462static long calcsize (long segment, long offset, int bits,
463 insn *ins, char *codes) {
464 long length = 0;
465 unsigned char c;
466
467 while (*codes) switch (c = *codes++) {
468 case 01: case 02: case 03:
469 codes += c, length += c; break;
470 case 04: case 05: case 06: case 07:
471 length++; break;
472 case 010: case 011: case 012:
473 codes++, length++; break;
474 case 017:
475 length++; break;
476 case 014: case 015: case 016:
477 length++; break;
478 case 020: case 021: case 022:
479 length++; break;
480 case 024: case 025: case 026:
481 length++; break;
482 case 030: case 031: case 032:
483 length += 2; break;
484 case 034: case 035: case 036:
485 length += ((ins->oprs[c-034].addr_size ?
486 ins->oprs[c-034].addr_size : bits) == 16 ? 2 : 4); break;
487 case 037:
488 length += 2; break;
489 case 040: case 041: case 042:
490 length += 4; break;
491 case 050: case 051: case 052:
492 length++; break;
493 case 060: case 061: case 062:
494 length += 2; break;
495 case 064: case 065: case 066:
496 length += ((ins->oprs[c-064].addr_size ?
497 ins->oprs[c-064].addr_size : bits) == 16 ? 2 : 4); break;
498 case 070: case 071: case 072:
499 length += 4; break;
500 case 0300: case 0301: case 0302:
501 length += chsize (&ins->oprs[c-0300], bits);
502 break;
503 case 0310:
504 length += (bits==32);
505 break;
506 case 0311:
507 length += (bits==16);
508 break;
509 case 0312:
510 break;
511 case 0320:
512 length += (bits==32);
513 break;
514 case 0321:
515 length += (bits==16);
516 break;
517 case 0322:
518 break;
519 case 0330:
520 codes++, length++; break;
521 case 0340: case 0341: case 0342:
522 if (ins->oprs[0].segment != NO_SEG)
523 errfunc (ERR_NONFATAL, "attempt to reserve non-constant"
524 " quantity of BSS space");
525 else
526 length += ins->oprs[0].offset << (c-0340);
527 break;
528 default: /* can't do it by 'case' statements */
529 if (c>=0100 && c<=0277) { /* it's an EA */
530 ea ea_data;
H. Peter Anvinea838272002-04-30 20:51:53 +0000531 if (!process_ea (&ins->oprs[(c>>3)&7], &ea_data, bits, 0,
532 ins->forw_ref)) {
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000533 errfunc (ERR_NONFATAL, "invalid effective address");
534 return -1;
535 } else
536 length += ea_data.size;
537 } else
538 errfunc (ERR_PANIC, "internal instruction table corrupt"
539 ": instruction code 0x%02X given", c);
540 }
541 return length;
542}
543
544static void gencode (long segment, long offset, int bits,
545 insn *ins, char *codes, long insn_end) {
546 static char condval[] = { /* conditional opcodes */
547 0x7, 0x3, 0x2, 0x6, 0x2, 0x4, 0xF, 0xD, 0xC, 0xE, 0x6, 0x2,
548 0x3, 0x7, 0x3, 0x5, 0xE, 0xC, 0xD, 0xF, 0x1, 0xB, 0x9, 0x5,
549 0x0, 0xA, 0xA, 0xB, 0x8, 0x4
550 };
551 unsigned char c, bytes[4];
552 long data, size;
553
554 while (*codes) switch (c = *codes++) {
555 case 01: case 02: case 03:
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000556 out (offset, segment, codes, OUT_RAWDATA+c, NO_SEG, NO_SEG);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000557 codes += c;
558 offset += c;
559 break;
560 case 04: case 06:
561 switch (ins->oprs[0].basereg) {
562 case R_CS: bytes[0] = 0x0E + (c == 0x04 ? 1 : 0); break;
563 case R_DS: bytes[0] = 0x1E + (c == 0x04 ? 1 : 0); break;
564 case R_ES: bytes[0] = 0x06 + (c == 0x04 ? 1 : 0); break;
565 case R_SS: bytes[0] = 0x16 + (c == 0x04 ? 1 : 0); break;
566 default:
567 errfunc (ERR_PANIC, "bizarre 8086 segment register received");
568 }
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000569 out (offset, segment, bytes, OUT_RAWDATA+1, NO_SEG, NO_SEG);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000570 offset++;
571 break;
572 case 05: case 07:
573 switch (ins->oprs[0].basereg) {
574 case R_FS: bytes[0] = 0xA0 + (c == 0x05 ? 1 : 0); break;
575 case R_GS: bytes[0] = 0xA8 + (c == 0x05 ? 1 : 0); break;
576 default:
577 errfunc (ERR_PANIC, "bizarre 386 segment register received");
578 }
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000579 out (offset, segment, bytes, OUT_RAWDATA+1, NO_SEG, NO_SEG);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000580 offset++;
581 break;
582 case 010: case 011: case 012:
583 bytes[0] = *codes++ + regval(&ins->oprs[c-010]);
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000584 out (offset, segment, bytes, OUT_RAWDATA+1, NO_SEG, NO_SEG);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000585 offset += 1;
586 break;
587 case 017:
588 bytes[0] = 0;
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000589 out (offset, segment, bytes, OUT_RAWDATA+1, NO_SEG, NO_SEG);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000590 offset += 1;
591 break;
592 case 014: case 015: case 016:
593 if (ins->oprs[c-014].offset < -128 || ins->oprs[c-014].offset > 127)
594 errfunc (ERR_WARNING, "signed byte value exceeds bounds");
H. Peter Anvin76690a12002-04-30 20:52:49 +0000595 if (ins->oprs[c-014].segment != NO_SEG) {
596 data = ins->oprs[c-014].offset;
597 out (offset, segment, &data, OUT_ADDRESS+1,
598 ins->oprs[c-014].segment, ins->oprs[c-014].wrt);
599 } else {
600 bytes[0] = ins->oprs[c-014].offset;
601 out (offset, segment, bytes, OUT_RAWDATA+1, NO_SEG, NO_SEG);
602 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000603 offset += 1;
604 break;
605 case 020: case 021: case 022:
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000606 if (ins->oprs[c-020].offset < -256 || ins->oprs[c-020].offset > 255)
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000607 errfunc (ERR_WARNING, "byte value exceeds bounds");
H. Peter Anvin76690a12002-04-30 20:52:49 +0000608 if (ins->oprs[c-020].segment != NO_SEG) {
609 data = ins->oprs[c-020].offset;
610 out (offset, segment, &data, OUT_ADDRESS+1,
611 ins->oprs[c-020].segment, ins->oprs[c-020].wrt);
612 } else {
613 bytes[0] = ins->oprs[c-020].offset;
614 out (offset, segment, bytes, OUT_RAWDATA+1, NO_SEG, NO_SEG);
615 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000616 offset += 1;
617 break;
618 case 024: case 025: case 026:
619 if (ins->oprs[c-024].offset < 0 || ins->oprs[c-024].offset > 255)
620 errfunc (ERR_WARNING, "unsigned byte value exceeds bounds");
H. Peter Anvin76690a12002-04-30 20:52:49 +0000621 if (ins->oprs[c-024].segment != NO_SEG) {
622 data = ins->oprs[c-024].offset;
623 out (offset, segment, &data, OUT_ADDRESS+1,
624 ins->oprs[c-024].segment, ins->oprs[c-024].wrt);
625 } else {
626 bytes[0] = ins->oprs[c-024].offset;
627 out (offset, segment, bytes, OUT_RAWDATA+1, NO_SEG, NO_SEG);
628 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000629 offset += 1;
630 break;
631 case 030: case 031: case 032:
632 if (ins->oprs[c-030].segment == NO_SEG &&
633 ins->oprs[c-030].wrt == NO_SEG &&
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000634 (ins->oprs[c-030].offset < -65536L ||
H. Peter Anvind7ed89e2002-04-30 20:52:08 +0000635 ins->oprs[c-030].offset > 65535L))
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000636 errfunc (ERR_WARNING, "word value exceeds bounds");
637 data = ins->oprs[c-030].offset;
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000638 out (offset, segment, &data, OUT_ADDRESS+2,
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000639 ins->oprs[c-030].segment, ins->oprs[c-030].wrt);
640 offset += 2;
641 break;
642 case 034: case 035: case 036:
643 data = ins->oprs[c-034].offset;
644 size = ((ins->oprs[c-034].addr_size ?
645 ins->oprs[c-034].addr_size : bits) == 16 ? 2 : 4);
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000646 if (size==16 && (data < -65536L || data > 65535L))
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000647 errfunc (ERR_WARNING, "word value exceeds bounds");
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000648 out (offset, segment, &data, OUT_ADDRESS+size,
649 ins->oprs[c-034].segment, ins->oprs[c-034].wrt);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000650 offset += size;
651 break;
652 case 037:
653 if (ins->oprs[0].segment == NO_SEG)
654 errfunc (ERR_NONFATAL, "value referenced by FAR is not"
655 " relocatable");
656 data = 0L;
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000657 out (offset, segment, &data, OUT_ADDRESS+2,
658 outfmt->segbase(1+ins->oprs[0].segment),
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000659 ins->oprs[0].wrt);
660 offset += 2;
661 break;
662 case 040: case 041: case 042:
663 data = ins->oprs[c-040].offset;
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000664 out (offset, segment, &data, OUT_ADDRESS+4,
665 ins->oprs[c-040].segment, ins->oprs[c-040].wrt);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000666 offset += 4;
667 break;
668 case 050: case 051: case 052:
669 if (ins->oprs[c-050].segment != segment)
670 errfunc (ERR_NONFATAL, "short relative jump outside segment");
671 data = ins->oprs[c-050].offset - insn_end;
672 if (data > 127 || data < -128)
673 errfunc (ERR_NONFATAL, "short jump is out of range");
674 bytes[0] = data;
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000675 out (offset, segment, bytes, OUT_RAWDATA+1, NO_SEG, NO_SEG);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000676 offset += 1;
677 break;
678 case 060: case 061: case 062:
679 if (ins->oprs[c-060].segment != segment) {
680 data = ins->oprs[c-060].offset;
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000681 out (offset, segment, &data, OUT_REL2ADR+insn_end-offset,
682 ins->oprs[c-060].segment, ins->oprs[c-060].wrt);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000683 } else {
684 data = ins->oprs[c-060].offset - insn_end;
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000685 out (offset, segment, &data,
686 OUT_ADDRESS+2, NO_SEG, NO_SEG);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000687 }
688 offset += 2;
689 break;
690 case 064: case 065: case 066:
691 size = ((ins->oprs[c-064].addr_size ?
692 ins->oprs[c-064].addr_size : bits) == 16 ? 2 : 4);
693 if (ins->oprs[c-064].segment != segment) {
694 data = ins->oprs[c-064].offset;
695 size = (bits == 16 ? OUT_REL2ADR : OUT_REL4ADR);
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000696 out (offset, segment, &data, size+insn_end-offset,
697 ins->oprs[c-064].segment, ins->oprs[c-064].wrt);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000698 size = (bits == 16 ? 2 : 4);
699 } else {
700 data = ins->oprs[c-064].offset - insn_end;
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000701 out (offset, segment, &data,
702 OUT_ADDRESS+size, NO_SEG, NO_SEG);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000703 }
704 offset += size;
705 break;
706 case 070: case 071: case 072:
707 if (ins->oprs[c-070].segment != segment) {
708 data = ins->oprs[c-070].offset;
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000709 out (offset, segment, &data, OUT_REL4ADR+insn_end-offset,
710 ins->oprs[c-070].segment, ins->oprs[c-070].wrt);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000711 } else {
712 data = ins->oprs[c-070].offset - insn_end;
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000713 out (offset, segment, &data,
714 OUT_ADDRESS+4, NO_SEG, NO_SEG);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000715 }
716 offset += 4;
717 break;
718 case 0300: case 0301: case 0302:
719 if (chsize (&ins->oprs[c-0300], bits)) {
720 *bytes = 0x67;
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000721 out (offset, segment, bytes,
722 OUT_RAWDATA+1, NO_SEG, NO_SEG);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000723 offset += 1;
724 } else
725 offset += 0;
726 break;
727 case 0310:
728 if (bits==32) {
729 *bytes = 0x67;
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000730 out (offset, segment, bytes,
731 OUT_RAWDATA+1, NO_SEG, NO_SEG);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000732 offset += 1;
733 } else
734 offset += 0;
735 break;
736 case 0311:
737 if (bits==16) {
738 *bytes = 0x67;
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000739 out (offset, segment, bytes,
740 OUT_RAWDATA+1, NO_SEG, NO_SEG);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000741 offset += 1;
742 } else
743 offset += 0;
744 break;
745 case 0312:
746 break;
747 case 0320:
748 if (bits==32) {
749 *bytes = 0x66;
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000750 out (offset, segment, bytes,
751 OUT_RAWDATA+1, NO_SEG, NO_SEG);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000752 offset += 1;
753 } else
754 offset += 0;
755 break;
756 case 0321:
757 if (bits==16) {
758 *bytes = 0x66;
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000759 out (offset, segment, bytes,
760 OUT_RAWDATA+1, NO_SEG, NO_SEG);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000761 offset += 1;
762 } else
763 offset += 0;
764 break;
765 case 0322:
766 break;
767 case 0330:
768 *bytes = *codes++ + condval[ins->condition];
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000769 out (offset, segment, bytes,
770 OUT_RAWDATA+1, NO_SEG, NO_SEG);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000771 offset += 1;
772 break;
773 case 0340: case 0341: case 0342:
774 if (ins->oprs[0].segment != NO_SEG)
775 errfunc (ERR_PANIC, "non-constant BSS size in pass two");
776 else {
777 long size = ins->oprs[0].offset << (c-0340);
H. Peter Anvin76690a12002-04-30 20:52:49 +0000778 if (size > 0)
779 out (offset, segment, NULL,
780 OUT_RESERVE+size, NO_SEG, NO_SEG);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000781 offset += size;
782 }
783 break;
784 default: /* can't do it by 'case' statements */
785 if (c>=0100 && c<=0277) { /* it's an EA */
786 ea ea_data;
787 int rfield;
788 unsigned char *p;
789 long s;
790
791 if (c<=0177) /* pick rfield from operand b */
792 rfield = regval (&ins->oprs[c&7]);
793 else /* rfield is constant */
794 rfield = c & 7;
H. Peter Anvinea838272002-04-30 20:51:53 +0000795 if (!process_ea (&ins->oprs[(c>>3)&7], &ea_data, bits, rfield,
796 ins->forw_ref))
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000797 errfunc (ERR_NONFATAL, "invalid effective address");
798
799 p = bytes;
800 *p++ = ea_data.modrm;
801 if (ea_data.sib_present)
802 *p++ = ea_data.sib;
803 /*
804 * the cast in the next line is to placate MS C...
805 */
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000806 out (offset, segment, bytes, OUT_RAWDATA+(long)(p-bytes),
807 NO_SEG, NO_SEG);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000808 s = p-bytes;
809
810 switch (ea_data.bytes) {
811 case 0:
812 break;
813 case 1:
H. Peter Anvin76690a12002-04-30 20:52:49 +0000814 if (ins->oprs[(c>>3)&7].segment != NO_SEG) {
815 data = ins->oprs[(c>>3)&7].offset;
816 out (offset, segment, &data, OUT_ADDRESS+1,
817 ins->oprs[(c>>3)&7].segment,
818 ins->oprs[(c>>3)&7].wrt);
819 } else {
820 *bytes = ins->oprs[(c>>3)&7].offset;
821 out (offset, segment, bytes, OUT_RAWDATA+1,
822 NO_SEG, NO_SEG);
823 }
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000824 s++;
825 break;
826 case 2:
827 case 4:
828 data = ins->oprs[(c>>3)&7].offset;
H. Peter Anvin6768eb72002-04-30 20:52:26 +0000829 out (offset, segment, &data,
830 OUT_ADDRESS+ea_data.bytes,
831 ins->oprs[(c>>3)&7].segment, ins->oprs[(c>>3)&7].wrt);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000832 s += ea_data.bytes;
833 break;
834 }
835 offset += s;
836 } else
837 errfunc (ERR_PANIC, "internal instruction table corrupt"
838 ": instruction code 0x%02X given", c);
839 }
840}
841
842static int regval (operand *o) {
843 switch (o->basereg) {
844 case R_EAX: case R_AX: case R_AL: case R_ES: case R_CR0: case R_DR0:
845 case R_ST0: case R_MM0:
846 return 0;
847 case R_ECX: case R_CX: case R_CL: case R_CS: case R_DR1: case R_ST1:
848 case R_MM1:
849 return 1;
850 case R_EDX: case R_DX: case R_DL: case R_SS: case R_CR2: case R_DR2:
851 case R_ST2: case R_MM2:
852 return 2;
853 case R_EBX: case R_BX: case R_BL: case R_DS: case R_CR3: case R_DR3:
854 case R_TR3: case R_ST3: case R_MM3:
855 return 3;
856 case R_ESP: case R_SP: case R_AH: case R_FS: case R_CR4: case R_TR4:
857 case R_ST4: case R_MM4:
858 return 4;
859 case R_EBP: case R_BP: case R_CH: case R_GS: case R_TR5: case R_ST5:
860 case R_MM5:
861 return 5;
862 case R_ESI: case R_SI: case R_DH: case R_DR6: case R_TR6: case R_ST6:
863 case R_MM6:
864 return 6;
865 case R_EDI: case R_DI: case R_BH: case R_DR7: case R_TR7: case R_ST7:
866 case R_MM7:
867 return 7;
868 default: /* panic */
869 errfunc (ERR_PANIC, "invalid register operand given to regval()");
870 return 0;
871 }
872}
873
874static int matches (struct itemplate *itemp, insn *instruction) {
875 int i, size, oprs, ret;
876
877 ret = 100;
878
879 /*
880 * Check the opcode
881 */
882 if (itemp->opcode != instruction->opcode) return 0;
883
884 /*
885 * Count the operands
886 */
887 if (itemp->operands != instruction->operands) return 0;
888
889 /*
890 * Check that no spurious colons or TOs are present
891 */
892 for (i=0; i<itemp->operands; i++)
893 if (instruction->oprs[i].type & ~itemp->opd[i] & (COLON|TO))
894 return 0;
895
896 /*
897 * Check that the operand flags all match up
898 */
899 for (i=0; i<itemp->operands; i++)
900 if (itemp->opd[i] & ~instruction->oprs[i].type ||
901 ((itemp->opd[i] & SIZE_MASK) &&
902 ((itemp->opd[i] ^ instruction->oprs[i].type) & SIZE_MASK))) {
903 if ((itemp->opd[i] & ~instruction->oprs[i].type & NON_SIZE) ||
904 (instruction->oprs[i].type & SIZE_MASK))
905 return 0;
906 else
907 ret = 1;
908 }
909
910 /*
911 * Check operand sizes
912 */
913 if (itemp->flags & IF_SB) {
914 size = BITS8;
915 oprs = itemp->operands;
H. Peter Anvin76690a12002-04-30 20:52:49 +0000916 } else if (itemp->flags & IF_SW) {
917 size = BITS16;
918 oprs = itemp->operands;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000919 } else if (itemp->flags & IF_SD) {
920 size = BITS32;
921 oprs = itemp->operands;
922 } else if (itemp->flags & (IF_SM | IF_SM2)) {
923 oprs = (itemp->flags & IF_SM2 ? 2 : itemp->operands);
924 size = 0; /* placate gcc */
925 for (i=0; i<oprs; i++)
926 if ( (size = itemp->opd[i] & SIZE_MASK) != 0)
927 break;
928 } else {
929 size = 0;
930 oprs = itemp->operands;
931 }
932
933 for (i=0; i<itemp->operands; i++)
934 if (!(itemp->opd[i] & SIZE_MASK) &&
935 (instruction->oprs[i].type & SIZE_MASK & ~size))
936 ret = 2;
937
938 return ret;
939}
940
H. Peter Anvinea838272002-04-30 20:51:53 +0000941static ea *process_ea (operand *input, ea *output, int addrbits, int rfield,
942 int forw_ref) {
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000943 if (!(REGISTER & ~input->type)) { /* it's a single register */
944 static int regs[] = {
945 R_MM0, R_EAX, R_AX, R_AL, R_MM1, R_ECX, R_CX, R_CL,
946 R_MM2, R_EDX, R_DX, R_DL, R_MM3, R_EBX, R_BX, R_BL,
947 R_MM4, R_ESP, R_SP, R_AH, R_MM5, R_EBP, R_BP, R_CH,
948 R_MM6, R_ESI, R_SI, R_DH, R_MM7, R_EDI, R_DI, R_BH
949 };
950 int i;
951
952 for (i=0; i<elements(regs); i++)
953 if (input->basereg == regs[i]) break;
954 if (i<elements(regs)) {
955 output->sib_present = FALSE;/* no SIB necessary */
956 output->bytes = 0; /* no offset necessary either */
957 output->modrm = 0xC0 | (rfield << 3) | (i/4);
958 } else
959 return NULL;
960 } else { /* it's a memory reference */
961 if (input->basereg==-1 && (input->indexreg==-1 || input->scale==0)) {
962 /* it's a pure offset */
963 if (input->addr_size)
964 addrbits = input->addr_size;
965 output->sib_present = FALSE;
966 output->bytes = (addrbits==32 ? 4 : 2);
967 output->modrm = (addrbits==32 ? 5 : 6) | (rfield << 3);
968 } else { /* it's an indirection */
969 int i=input->indexreg, b=input->basereg, s=input->scale;
970 long o=input->offset, seg=input->segment;
H. Peter Anvin76690a12002-04-30 20:52:49 +0000971 int hb=input->hintbase, ht=input->hinttype;
972 int t;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000973
974 if (s==0) i = -1; /* make this easy, at least */
975
976 if (i==R_EAX || i==R_EBX || i==R_ECX || i==R_EDX
977 || i==R_EBP || i==R_ESP || i==R_ESI || i==R_EDI
978 || b==R_EAX || b==R_EBX || b==R_ECX || b==R_EDX
979 || b==R_EBP || b==R_ESP || b==R_ESI || b==R_EDI) {
980 /* it must be a 32-bit memory reference. Firstly we have
981 * to check that all registers involved are type Exx. */
982 if (i!=-1 && i!=R_EAX && i!=R_EBX && i!=R_ECX && i!=R_EDX
983 && i!=R_EBP && i!=R_ESP && i!=R_ESI && i!=R_EDI)
984 return NULL;
985 if (b!=-1 && b!=R_EAX && b!=R_EBX && b!=R_ECX && b!=R_EDX
986 && b!=R_EBP && b!=R_ESP && b!=R_ESI && b!=R_EDI)
987 return NULL;
988
989 /* While we're here, ensure the user didn't specify WORD. */
990 if (input->addr_size == 16)
991 return NULL;
992
993 /* now reorganise base/index */
H. Peter Anvin76690a12002-04-30 20:52:49 +0000994 if (s == 1 && b != i && b != -1 && i != -1 &&
995 ((hb==b&&ht==EAH_NOTBASE) || (hb==i&&ht==EAH_MAKEBASE)))
996 t = b, b = i, i = t; /* swap if hints say so */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000997 if (b==i) /* convert EAX+2*EAX to 3*EAX */
998 b = -1, s++;
H. Peter Anvin76690a12002-04-30 20:52:49 +0000999 if (b==-1 && s==1 && !(hb == i && ht == EAH_NOTBASE))
1000 b = i, i = -1; /* make single reg base, unless hint */
1001 if (((s==2 && i!=R_ESP && !(input->eaflags & EAF_TIMESTWO)) ||
1002 s==3 || s==5 || s==9) && b==-1)
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001003 b = i, s--; /* convert 3*EAX to EAX+2*EAX */
H. Peter Anvinea838272002-04-30 20:51:53 +00001004 if (s==1 && i==R_ESP) /* swap ESP into base if scale is 1 */
1005 i = b, b = R_ESP;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001006 if (i==R_ESP || (s!=1 && s!=2 && s!=4 && s!=8 && i!=-1))
1007 return NULL; /* wrong, for various reasons */
1008
1009 if (i==-1 && b!=R_ESP) {/* no SIB needed */
1010 int mod, rm;
1011 switch(b) {
1012 case R_EAX: rm = 0; break;
1013 case R_ECX: rm = 1; break;
1014 case R_EDX: rm = 2; break;
1015 case R_EBX: rm = 3; break;
1016 case R_EBP: rm = 5; break;
1017 case R_ESI: rm = 6; break;
1018 case R_EDI: rm = 7; break;
1019 case -1: rm = 5; break;
1020 default: /* should never happen */
1021 return NULL;
1022 }
H. Peter Anvinea838272002-04-30 20:51:53 +00001023 if (b==-1 || (b!=R_EBP && o==0 &&
H. Peter Anvin76690a12002-04-30 20:52:49 +00001024 seg==NO_SEG && !forw_ref &&
1025 !(input->eaflags &
1026 (EAF_BYTEOFFS|EAF_WORDOFFS))))
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001027 mod = 0;
H. Peter Anvin76690a12002-04-30 20:52:49 +00001028 else if (input->eaflags & EAF_BYTEOFFS ||
1029 (o>=-128 && o<=127 && seg==NO_SEG && !forw_ref &&
1030 !(input->eaflags & EAF_WORDOFFS))) {
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001031 mod = 1;
H. Peter Anvin76690a12002-04-30 20:52:49 +00001032 } else
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001033 mod = 2;
H. Peter Anvinea838272002-04-30 20:51:53 +00001034
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001035 output->sib_present = FALSE;
1036 output->bytes = (b==-1 || mod==2 ? 4 : mod);
1037 output->modrm = (mod<<6) | (rfield<<3) | rm;
1038 } else { /* we need a SIB */
1039 int mod, scale, index, base;
1040
1041 switch (b) {
1042 case R_EAX: base = 0; break;
1043 case R_ECX: base = 1; break;
1044 case R_EDX: base = 2; break;
1045 case R_EBX: base = 3; break;
1046 case R_ESP: base = 4; break;
1047 case R_EBP: case -1: base = 5; break;
1048 case R_ESI: base = 6; break;
1049 case R_EDI: base = 7; break;
1050 default: /* then what the smeg is it? */
1051 return NULL; /* panic */
1052 }
1053
1054 switch (i) {
1055 case R_EAX: index = 0; break;
1056 case R_ECX: index = 1; break;
1057 case R_EDX: index = 2; break;
1058 case R_EBX: index = 3; break;
1059 case -1: index = 4; break;
1060 case R_EBP: index = 5; break;
1061 case R_ESI: index = 6; break;
1062 case R_EDI: index = 7; break;
1063 default: /* then what the smeg is it? */
1064 return NULL; /* panic */
1065 }
1066
1067 if (i==-1) s = 1;
1068 switch (s) {
1069 case 1: scale = 0; break;
1070 case 2: scale = 1; break;
1071 case 4: scale = 2; break;
1072 case 8: scale = 3; break;
1073 default: /* then what the smeg is it? */
1074 return NULL; /* panic */
1075 }
1076
H. Peter Anvinea838272002-04-30 20:51:53 +00001077 if (b==-1 || (b!=R_EBP && o==0 &&
H. Peter Anvin76690a12002-04-30 20:52:49 +00001078 seg==NO_SEG && !forw_ref &&
1079 !(input->eaflags &
1080 (EAF_BYTEOFFS|EAF_WORDOFFS))))
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001081 mod = 0;
H. Peter Anvin76690a12002-04-30 20:52:49 +00001082 else if (input->eaflags & EAF_BYTEOFFS ||
1083 (o>=-128 && o<=127 && seg==NO_SEG && !forw_ref &&
1084 !(input->eaflags & EAF_WORDOFFS)))
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001085 mod = 1;
1086 else
1087 mod = 2;
1088
1089 output->sib_present = TRUE;
1090 output->bytes = (b==-1 || mod==2 ? 4 : mod);
1091 output->modrm = (mod<<6) | (rfield<<3) | 4;
1092 output->sib = (scale<<6) | (index<<3) | base;
1093 }
1094 } else { /* it's 16-bit */
1095 int mod, rm;
1096
1097 /* check all registers are BX, BP, SI or DI */
1098 if ((b!=-1 && b!=R_BP && b!=R_BX && b!=R_SI && b!=R_DI) ||
1099 (i!=-1 && i!=R_BP && i!=R_BX && i!=R_SI && i!=R_DI))
1100 return NULL;
1101
1102 /* ensure the user didn't specify DWORD */
1103 if (input->addr_size == 32)
1104 return NULL;
1105
1106 if (s!=1 && i!=-1) return NULL;/* no can do, in 16-bit EA */
1107 if (b==-1 && i!=-1) b ^= i ^= b ^= i; /* swap them round */
1108 if ((b==R_SI || b==R_DI) && i!=-1)
1109 b ^= i ^= b ^= i; /* have BX/BP as base, SI/DI index */
1110 if (b==i) return NULL;/* shouldn't ever happen, in theory */
1111 if (i!=-1 && b!=-1 &&
1112 (i==R_BP || i==R_BX || b==R_SI || b==R_DI))
1113 return NULL; /* invalid combinations */
1114 if (b==-1) /* pure offset: handled above */
1115 return NULL; /* so if it gets to here, panic! */
1116
1117 rm = -1;
1118 if (i!=-1)
1119 switch (i*256 + b) {
1120 case R_SI*256+R_BX: rm=0; break;
1121 case R_DI*256+R_BX: rm=1; break;
1122 case R_SI*256+R_BP: rm=2; break;
1123 case R_DI*256+R_BP: rm=3; break;
1124 }
1125 else
1126 switch (b) {
1127 case R_SI: rm=4; break;
1128 case R_DI: rm=5; break;
1129 case R_BP: rm=6; break;
1130 case R_BX: rm=7; break;
1131 }
1132 if (rm==-1) /* can't happen, in theory */
1133 return NULL; /* so panic if it does */
1134
H. Peter Anvin76690a12002-04-30 20:52:49 +00001135 if (o==0 && seg==NO_SEG && !forw_ref && rm!=6 &&
1136 !(input->eaflags & (EAF_BYTEOFFS|EAF_WORDOFFS)))
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001137 mod = 0;
H. Peter Anvin76690a12002-04-30 20:52:49 +00001138 else if (input->eaflags & EAF_BYTEOFFS ||
1139 (o>=-128 && o<=127 && seg==NO_SEG && !forw_ref &&
1140 !(input->eaflags & EAF_WORDOFFS)))
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00001141 mod = 1;
1142 else
1143 mod = 2;
1144
1145 output->sib_present = FALSE; /* no SIB - it's 16-bit */
1146 output->bytes = mod; /* bytes of offset needed */
1147 output->modrm = (mod<<6) | (rfield<<3) | rm;
1148 }
1149 }
1150 }
1151 output->size = 1 + output->sib_present + output->bytes;
1152 return output;
1153}
1154
1155static int chsize (operand *input, int addrbits) {
1156 if (!(MEMORY & ~input->type)) {
1157 int i=input->indexreg, b=input->basereg;
1158
1159 if (input->scale==0) i = -1;
1160
1161 if (i == -1 && b == -1) /* pure offset */
1162 return (input->addr_size != 0 && input->addr_size != addrbits);
1163
1164 if (i==R_EAX || i==R_EBX || i==R_ECX || i==R_EDX
1165 || i==R_EBP || i==R_ESP || i==R_ESI || i==R_EDI
1166 || b==R_EAX || b==R_EBX || b==R_ECX || b==R_EDX
1167 || b==R_EBP || b==R_ESP || b==R_ESI || b==R_EDI)
1168 return (addrbits==16);
1169 else
1170 return (addrbits==32);
1171 } else
1172 return 0;
1173}