1 /* assemble.c code generation for the Netwide Assembler
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.
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
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 * \130,\131,\132 - an immediate word or signed byte for operand 0, 1, or 2
36 * \133,\134,\135 - or 2 (s-field) into next opcode byte if operand 0, 1, or 2
37 * is a signed byte rather than a word.
38 * \140,\141,\142 - an immediate dword or signed byte for operand 0, 1, or 2
39 * \143,\144,\145 - or 2 (s-field) into next opcode byte if operand 0, 1, or 2
40 * is a signed byte rather than a dword.
41 * \2ab - a ModRM, calculated on EA in operand a, with the spare
42 * field equal to digit b.
43 * \30x - might be an 0x67 byte, depending on the address size of
44 * the memory reference in operand x.
45 * \310 - indicates fixed 16-bit address size, i.e. optional 0x67.
46 * \311 - indicates fixed 32-bit address size, i.e. optional 0x67.
47 * \312 - (disassembler only) marker on LOOP, LOOPxx instructions.
48 * \320 - indicates fixed 16-bit operand size, i.e. optional 0x66.
49 * \321 - indicates fixed 32-bit operand size, i.e. optional 0x66.
50 * \322 - indicates that this instruction is only valid when the
51 * operand size is the default (instruction to disassembler,
52 * generates no code in the assembler)
53 * \330 - a literal byte follows in the code stream, to be added
54 * to the condition code value of the instruction.
55 * \331 - instruction not valid with REP prefix. Hint for
56 * disassembler only; for SSE instructions.
57 * \332 - disassemble a rep (0xF3 byte) prefix as repe not rep.
58 * \333 - REP prefix (0xF3 byte); for SSE instructions. Not encoded
59 * as a literal byte in order to aid the disassembler.
60 * \340 - reserve <operand 0> bytes of uninitialised storage.
61 * Operand 0 had better be a segmentless constant.
62 * \370,\371,\372 - match only if operand 0, 1, 2 meets byte jump criteria.
63 * \373 - assemble 0x03 if bits==16, 0x05 if bits==32;
64 * used for conditional jump over longer jump
75 extern struct itemplate
*nasm_instructions
[];
78 int sib_present
; /* is a SIB byte necessary? */
79 int bytes
; /* # of bytes of offset needed */
80 int size
; /* lazy - this is sib+bytes+1 */
81 unsigned char modrm
, sib
; /* the bytes themselves */
84 static unsigned long cpu
; /* cpu level received from nasm.c */
86 static struct ofmt
*outfmt
;
89 static long calcsize (long, long, int, insn
*, char *);
90 static void gencode (long, long, int, insn
*, char *, long);
91 static int regval (operand
*o
);
92 static int matches (struct itemplate
*, insn
*);
93 static ea
* process_ea (operand
*, ea
*, int, int, int);
94 static int chsize (operand
*, int);
97 * This routine wrappers the real output format's output routine,
98 * in order to pass a copy of the data off to the listing file
99 * generator at the same time.
101 static void out (long offset
, long segto
, void *data
, unsigned long type
,
102 long segment
, long wrt
)
105 static char *lnfname
;
107 if ((type
& OUT_TYPMASK
) == OUT_ADDRESS
) {
108 if (segment
!= NO_SEG
|| wrt
!= NO_SEG
) {
110 * This address is relocated. We must write it as
111 * OUT_ADDRESS, so there's no work to be done here.
113 list
->output (offset
, data
, type
);
116 unsigned char p
[4], *q
= p
;
118 * This is a non-relocated address, and we're going to
119 * convert it into RAWDATA format.
121 if ((type
& OUT_SIZMASK
) == 4) {
122 WRITELONG (q
, * (long *) data
);
123 list
->output (offset
, p
, OUT_RAWDATA
+4);
126 WRITESHORT (q
, * (long *) data
);
127 list
->output (offset
, p
, OUT_RAWDATA
+2);
131 else if ((type
& OUT_TYPMASK
) == OUT_RAWDATA
) {
132 list
->output (offset
, data
, type
);
134 else if ((type
& OUT_TYPMASK
) == OUT_RESERVE
) {
135 list
->output (offset
, NULL
, type
);
137 else if ((type
& OUT_TYPMASK
) == OUT_REL2ADR
||
138 (type
& OUT_TYPMASK
) == OUT_REL4ADR
) {
139 list
->output (offset
, data
, type
);
142 if (src_get(&lineno
,&lnfname
))
143 outfmt
->current_dfmt
->linenum(lnfname
,lineno
,segto
);
145 outfmt
->output (segto
, data
, type
, segment
, wrt
);
148 static int jmp_match (long segment
, long offset
, int bits
,
149 insn
*ins
, char *code
)
151 unsigned char c
= code
[0];
154 if (c
!= 0370) return 0;
155 if (ins
->oprs
[0].opflags
& OPFLAG_FORWARD
) return (! pass0
); /*1;*/ /* match a forward reference */
157 isize
= calcsize (segment
, offset
, bits
, ins
, code
);
158 if (ins
->oprs
[0].segment
!= segment
) return 0;
159 isize
= ins
->oprs
[0].offset
- offset
- isize
; /* isize is now the delta */
160 if (isize
>= -128L && isize
<= 127L) return 1; /* it is byte size */
166 long assemble (long segment
, long offset
, int bits
, unsigned long cp
,
167 insn
*instruction
, struct ofmt
*output
, efunc error
,
170 struct itemplate
*temp
;
176 long wsize
= 0; /* size for DB etc. */
178 errfunc
= error
; /* to pass to other functions */
180 outfmt
= output
; /* likewise */
181 list
= listgen
; /* and again */
183 switch (instruction
->opcode
)
186 case I_DB
: wsize
= 1; break;
187 case I_DW
: wsize
= 2; break;
188 case I_DD
: wsize
= 4; break;
189 case I_DQ
: wsize
= 8; break;
190 case I_DT
: wsize
= 10; break;
195 long t
= instruction
->times
;
197 errfunc(ERR_PANIC
, "instruction->times < 0 (%ld) in assemble()",t
);
199 while (t
--) /* repeat TIMES times */
201 for (e
= instruction
->eops
; e
; e
= e
->next
)
203 if (e
->type
== EOT_DB_NUMBER
)
206 if (e
->segment
!= NO_SEG
)
207 errfunc (ERR_NONFATAL
,
208 "one-byte relocation attempted");
210 unsigned char out_byte
= e
->offset
;
211 out (offset
, segment
, &out_byte
, OUT_RAWDATA
+1,
215 else if (wsize
> 5) {
216 errfunc (ERR_NONFATAL
, "integer supplied to a D%c"
217 " instruction", wsize
==8 ? 'Q' : 'T');
220 out (offset
, segment
, &e
->offset
,
221 OUT_ADDRESS
+wsize
, e
->segment
,
225 else if (e
->type
== EOT_DB_STRING
)
229 out (offset
, segment
, e
->stringval
,
230 OUT_RAWDATA
+e
->stringlen
, NO_SEG
, NO_SEG
);
231 align
= e
->stringlen
% wsize
;
234 align
= wsize
- align
;
235 out (offset
, segment
, "\0\0\0\0\0\0\0\0",
236 OUT_RAWDATA
+align
, NO_SEG
, NO_SEG
);
238 offset
+= e
->stringlen
+ align
;
241 if (t
> 0 && t
== instruction
->times
-1)
244 * Dummy call to list->output to give the offset to the
247 list
->output (offset
, NULL
, OUT_RAWDATA
);
248 list
->uplevel (LIST_TIMES
);
251 if (instruction
->times
> 1)
252 list
->downlevel (LIST_TIMES
);
253 return offset
- start
;
256 if (instruction
->opcode
== I_INCBIN
)
258 static char fname
[FILENAME_MAX
];
262 len
= FILENAME_MAX
-1;
263 if (len
> instruction
->eops
->stringlen
)
264 len
= instruction
->eops
->stringlen
;
265 strncpy (fname
, instruction
->eops
->stringval
, len
);
268 if ( (fp
= fopen(fname
, "rb")) == NULL
)
269 error (ERR_NONFATAL
, "`incbin': unable to open file `%s'", fname
);
270 else if (fseek(fp
, 0L, SEEK_END
) < 0)
271 error (ERR_NONFATAL
, "`incbin': unable to seek on file `%s'",
275 static char buf
[2048];
276 long t
= instruction
->times
;
280 if (instruction
->eops
->next
) {
281 base
= instruction
->eops
->next
->offset
;
283 if (instruction
->eops
->next
->next
&&
284 len
> instruction
->eops
->next
->next
->offset
)
285 len
= instruction
->eops
->next
->next
->offset
;
288 * Dummy call to list->output to give the offset to the
291 list
->output (offset
, NULL
, OUT_RAWDATA
);
292 list
->uplevel(LIST_INCBIN
);
297 fseek (fp
, base
, SEEK_SET
);
300 long m
= fread (buf
, 1, (l
>sizeof(buf
)?sizeof(buf
):l
),
304 * This shouldn't happen unless the file
305 * actually changes while we are reading
308 error (ERR_NONFATAL
, "`incbin': unexpected EOF while"
309 " reading file `%s'", fname
);
310 t
=0; /* Try to exit cleanly */
313 out (offset
, segment
, buf
, OUT_RAWDATA
+m
,
318 list
->downlevel(LIST_INCBIN
);
319 if (instruction
->times
> 1) {
321 * Dummy call to list->output to give the offset to the
324 list
->output (offset
, NULL
, OUT_RAWDATA
);
325 list
->uplevel(LIST_TIMES
);
326 list
->downlevel(LIST_TIMES
);
329 return instruction
->times
* len
;
331 return 0; /* if we're here, there's an error */
335 temp
= nasm_instructions
[instruction
->opcode
];
336 while (temp
->opcode
!= -1) {
337 int m
= matches (temp
, instruction
);
339 m
+= jmp_match(segment
, offset
, bits
, instruction
, temp
->code
);
341 if (m
== 100) /* matches! */
343 char *codes
= temp
->code
;
344 long insn_size
= calcsize(segment
, offset
, bits
,
346 itimes
= instruction
->times
;
347 if (insn_size
< 0) /* shouldn't be, on pass two */
348 error (ERR_PANIC
, "errors made it through from pass one");
349 else while (itimes
--) {
350 insn_end
= offset
+ insn_size
;
351 for (j
=0; j
<instruction
->nprefix
; j
++) {
353 switch (instruction
->prefixes
[j
]) {
356 case P_REPNE
: case P_REPNZ
:
358 case P_REPE
: case P_REPZ
: case P_REP
:
360 case R_CS
: c
= 0x2E; break;
361 case R_DS
: c
= 0x3E; break;
362 case R_ES
: c
= 0x26; break;
363 case R_FS
: c
= 0x64; break;
364 case R_GS
: c
= 0x65; break;
365 case R_SS
: c
= 0x36; break;
384 "invalid instruction prefix");
387 out (offset
, segment
, &c
, OUT_RAWDATA
+1,
392 gencode (segment
, offset
, bits
, instruction
, codes
, insn_end
);
394 if (itimes
> 0 && itimes
== instruction
->times
-1) {
396 * Dummy call to list->output to give the offset to the
399 list
->output (offset
, NULL
, OUT_RAWDATA
);
400 list
->uplevel (LIST_TIMES
);
403 if (instruction
->times
> 1)
404 list
->downlevel (LIST_TIMES
);
405 return offset
- start
;
406 } else if (m
> 0 && m
> size_prob
) {
412 if (temp
->opcode
== -1) { /* didn't match any instruction */
413 if (size_prob
== 1) /* would have matched, but for size */
414 error (ERR_NONFATAL
, "operation size not specified");
415 else if (size_prob
== 2)
416 error (ERR_NONFATAL
, "mismatch in operand sizes");
417 else if (size_prob
== 3)
418 error (ERR_NONFATAL
, "no instruction for this cpu level");
421 "invalid combination of opcode and operands");
426 long insn_size (long segment
, long offset
, int bits
, unsigned long cp
,
427 insn
*instruction
, efunc error
)
429 struct itemplate
*temp
;
431 errfunc
= error
; /* to pass to other functions */
434 if (instruction
->opcode
== -1)
437 if (instruction
->opcode
== I_DB
||
438 instruction
->opcode
== I_DW
||
439 instruction
->opcode
== I_DD
||
440 instruction
->opcode
== I_DQ
||
441 instruction
->opcode
== I_DT
)
444 long isize
, osize
, wsize
= 0; /* placate gcc */
447 switch (instruction
->opcode
)
449 case I_DB
: wsize
= 1; break;
450 case I_DW
: wsize
= 2; break;
451 case I_DD
: wsize
= 4; break;
452 case I_DQ
: wsize
= 8; break;
453 case I_DT
: wsize
= 10; break;
456 for (e
= instruction
->eops
; e
; e
= e
->next
)
461 if (e
->type
== EOT_DB_NUMBER
)
463 else if (e
->type
== EOT_DB_STRING
)
464 osize
= e
->stringlen
;
466 align
= (-osize
) % wsize
;
469 isize
+= osize
+ align
;
471 return isize
* instruction
->times
;
474 if (instruction
->opcode
== I_INCBIN
)
476 char fname
[FILENAME_MAX
];
480 len
= FILENAME_MAX
-1;
481 if (len
> instruction
->eops
->stringlen
)
482 len
= instruction
->eops
->stringlen
;
483 strncpy (fname
, instruction
->eops
->stringval
, len
);
485 if ( (fp
= fopen(fname
, "rb")) == NULL
)
486 error (ERR_NONFATAL
, "`incbin': unable to open file `%s'", fname
);
487 else if (fseek(fp
, 0L, SEEK_END
) < 0)
488 error (ERR_NONFATAL
, "`incbin': unable to seek on file `%s'",
494 if (instruction
->eops
->next
)
496 len
-= instruction
->eops
->next
->offset
;
497 if (instruction
->eops
->next
->next
&&
498 len
> instruction
->eops
->next
->next
->offset
)
500 len
= instruction
->eops
->next
->next
->offset
;
503 return instruction
->times
* len
;
505 return 0; /* if we're here, there's an error */
508 temp
= nasm_instructions
[instruction
->opcode
];
509 while (temp
->opcode
!= -1) {
510 int m
= matches(temp
, instruction
);
512 m
+= jmp_match(segment
, offset
, bits
, instruction
, temp
->code
);
515 /* we've matched an instruction. */
517 char * codes
= temp
->code
;
520 isize
= calcsize(segment
, offset
, bits
, instruction
, codes
);
523 for (j
= 0; j
< instruction
->nprefix
; j
++)
525 if ((instruction
->prefixes
[j
] != P_A16
&&
526 instruction
->prefixes
[j
] != P_O16
&& bits
==16) ||
527 (instruction
->prefixes
[j
] != P_A32
&&
528 instruction
->prefixes
[j
] != P_O32
&& bits
==32))
533 return isize
* instruction
->times
;
537 return -1; /* didn't match any instruction */
541 /* check that opn[op] is a signed byte of size 16 or 32,
542 and return the signed value*/
543 static int is_sbyte (insn
*ins
, int op
, int size
)
548 ret
= !(ins
->forw_ref
&& ins
->oprs
[op
].opflags
) && /* dead in the water on forward reference or External */
549 ins
->oprs
[op
].wrt
==NO_SEG
&& ins
->oprs
[op
].segment
==NO_SEG
;
550 v
= ins
->oprs
[op
].offset
;
551 if (size
==16) v
= (signed short)v
; /* sign extend if 16 bits */
553 return ret
&& v
>=-128L && v
<=127L;
556 static long calcsize (long segment
, long offset
, int bits
,
557 insn
*ins
, char *codes
)
562 (void) segment
; /* Don't warn that this parameter is unused */
563 (void) offset
; /* Don't warn that this parameter is unused */
565 while (*codes
) switch (c
= *codes
++) {
566 case 01: case 02: case 03:
567 codes
+= c
, length
+= c
; break;
568 case 04: case 05: case 06: case 07:
570 case 010: case 011: case 012:
571 codes
++, length
++; break;
574 case 014: case 015: case 016:
576 case 020: case 021: case 022:
578 case 024: case 025: case 026:
580 case 030: case 031: case 032:
582 case 034: case 035: case 036:
583 length
+= ((ins
->oprs
[c
-034].addr_size
?
584 ins
->oprs
[c
-034].addr_size
: bits
) == 16 ? 2 : 4); break;
587 case 040: case 041: case 042:
589 case 050: case 051: case 052:
591 case 060: case 061: case 062:
593 case 064: case 065: case 066:
594 length
+= ((ins
->oprs
[c
-064].addr_size
?
595 ins
->oprs
[c
-064].addr_size
: bits
) == 16 ? 2 : 4); break;
596 case 070: case 071: case 072:
598 case 0130: case 0131: case 0132:
599 length
+= is_sbyte(ins
, c
-0130, 16) ? 1 : 2; break;
600 case 0133: case 0134: case 0135:
601 codes
+=2; length
++; break;
602 case 0140: case 0141: case 0142:
603 length
+= is_sbyte(ins
, c
-0140, 32) ? 1 : 4; break;
604 case 0143: case 0144: case 0145:
605 codes
+=2; length
++; break;
606 case 0300: case 0301: case 0302:
607 length
+= chsize (&ins
->oprs
[c
-0300], bits
);
610 length
+= (bits
==32);
613 length
+= (bits
==16);
618 length
+= (bits
==32);
621 length
+= (bits
==16);
626 codes
++, length
++; break;
632 case 0340: case 0341: case 0342:
633 if (ins
->oprs
[0].segment
!= NO_SEG
)
634 errfunc (ERR_NONFATAL
, "attempt to reserve non-constant"
635 " quantity of BSS space");
637 length
+= ins
->oprs
[0].offset
<< (c
-0340);
639 case 0370: case 0371: case 0372:
643 default: /* can't do it by 'case' statements */
644 if (c
>=0100 && c
<=0277) { /* it's an EA */
646 if (!process_ea (&ins
->oprs
[(c
>>3)&7], &ea_data
, bits
, 0,
648 errfunc (ERR_NONFATAL
, "invalid effective address");
651 length
+= ea_data
.size
;
653 errfunc (ERR_PANIC
, "internal instruction table corrupt"
654 ": instruction code 0x%02X given", c
);
659 static void gencode (long segment
, long offset
, int bits
,
660 insn
*ins
, char *codes
, long insn_end
)
662 static char condval
[] = { /* conditional opcodes */
663 0x7, 0x3, 0x2, 0x6, 0x2, 0x4, 0xF, 0xD, 0xC, 0xE, 0x6, 0x2,
664 0x3, 0x7, 0x3, 0x5, 0xE, 0xC, 0xD, 0xF, 0x1, 0xB, 0x9, 0x5,
665 0x0, 0xA, 0xA, 0xB, 0x8, 0x4
668 unsigned char bytes
[4];
672 switch (c
= *codes
++)
674 case 01: case 02: case 03:
675 out (offset
, segment
, codes
, OUT_RAWDATA
+c
, NO_SEG
, NO_SEG
);
681 switch (ins
->oprs
[0].basereg
)
684 bytes
[0] = 0x0E + (c
== 0x04 ? 1 : 0); break;
686 bytes
[0] = 0x1E + (c
== 0x04 ? 1 : 0); break;
688 bytes
[0] = 0x06 + (c
== 0x04 ? 1 : 0); break;
690 bytes
[0] = 0x16 + (c
== 0x04 ? 1 : 0); break;
692 errfunc (ERR_PANIC
, "bizarre 8086 segment register received");
694 out (offset
, segment
, bytes
, OUT_RAWDATA
+1, NO_SEG
, NO_SEG
);
699 switch (ins
->oprs
[0].basereg
) {
700 case R_FS
: bytes
[0] = 0xA0 + (c
== 0x05 ? 1 : 0); break;
701 case R_GS
: bytes
[0] = 0xA8 + (c
== 0x05 ? 1 : 0); break;
703 errfunc (ERR_PANIC
, "bizarre 386 segment register received");
705 out (offset
, segment
, bytes
, OUT_RAWDATA
+1, NO_SEG
, NO_SEG
);
709 case 010: case 011: case 012:
710 bytes
[0] = *codes
++ + regval(&ins
->oprs
[c
-010]);
711 out (offset
, segment
, bytes
, OUT_RAWDATA
+1, NO_SEG
, NO_SEG
);
717 out (offset
, segment
, bytes
, OUT_RAWDATA
+1, NO_SEG
, NO_SEG
);
721 case 014: case 015: case 016:
722 if (ins
->oprs
[c
-014].offset
< -128
723 || ins
->oprs
[c
-014].offset
> 127)
725 errfunc (ERR_WARNING
, "signed byte value exceeds bounds");
728 if (ins
->oprs
[c
-014].segment
!= NO_SEG
)
730 data
= ins
->oprs
[c
-014].offset
;
731 out (offset
, segment
, &data
, OUT_ADDRESS
+1,
732 ins
->oprs
[c
-014].segment
, ins
->oprs
[c
-014].wrt
);
735 bytes
[0] = ins
->oprs
[c
-014].offset
;
736 out (offset
, segment
, bytes
, OUT_RAWDATA
+1, NO_SEG
, NO_SEG
);
741 case 020: case 021: case 022:
742 if (ins
->oprs
[c
-020].offset
< -256
743 || ins
->oprs
[c
-020].offset
> 255)
745 errfunc (ERR_WARNING
, "byte value exceeds bounds");
747 if (ins
->oprs
[c
-020].segment
!= NO_SEG
) {
748 data
= ins
->oprs
[c
-020].offset
;
749 out (offset
, segment
, &data
, OUT_ADDRESS
+1,
750 ins
->oprs
[c
-020].segment
, ins
->oprs
[c
-020].wrt
);
753 bytes
[0] = ins
->oprs
[c
-020].offset
;
754 out (offset
, segment
, bytes
, OUT_RAWDATA
+1, NO_SEG
, NO_SEG
);
759 case 024: case 025: case 026:
760 if (ins
->oprs
[c
-024].offset
< 0 || ins
->oprs
[c
-024].offset
> 255)
761 errfunc (ERR_WARNING
, "unsigned byte value exceeds bounds");
762 if (ins
->oprs
[c
-024].segment
!= NO_SEG
) {
763 data
= ins
->oprs
[c
-024].offset
;
764 out (offset
, segment
, &data
, OUT_ADDRESS
+1,
765 ins
->oprs
[c
-024].segment
, ins
->oprs
[c
-024].wrt
);
768 bytes
[0] = ins
->oprs
[c
-024].offset
;
769 out (offset
, segment
, bytes
, OUT_RAWDATA
+1, NO_SEG
, NO_SEG
);
774 case 030: case 031: case 032:
775 if (ins
->oprs
[c
-030].segment
== NO_SEG
&&
776 ins
->oprs
[c
-030].wrt
== NO_SEG
&&
777 (ins
->oprs
[c
-030].offset
< -65536L ||
778 ins
->oprs
[c
-030].offset
> 65535L))
780 errfunc (ERR_WARNING
, "word value exceeds bounds");
782 data
= ins
->oprs
[c
-030].offset
;
783 out (offset
, segment
, &data
, OUT_ADDRESS
+2,
784 ins
->oprs
[c
-030].segment
, ins
->oprs
[c
-030].wrt
);
788 case 034: case 035: case 036:
789 data
= ins
->oprs
[c
-034].offset
;
790 size
= ((ins
->oprs
[c
-034].addr_size
?
791 ins
->oprs
[c
-034].addr_size
: bits
) == 16 ? 2 : 4);
792 if (size
==16 && (data
< -65536L || data
> 65535L))
793 errfunc (ERR_WARNING
, "word value exceeds bounds");
794 out (offset
, segment
, &data
, OUT_ADDRESS
+size
,
795 ins
->oprs
[c
-034].segment
, ins
->oprs
[c
-034].wrt
);
800 if (ins
->oprs
[0].segment
== NO_SEG
)
801 errfunc (ERR_NONFATAL
, "value referenced by FAR is not"
804 out (offset
, segment
, &data
, OUT_ADDRESS
+2,
805 outfmt
->segbase(1+ins
->oprs
[0].segment
),
810 case 040: case 041: case 042:
811 data
= ins
->oprs
[c
-040].offset
;
812 out (offset
, segment
, &data
, OUT_ADDRESS
+4,
813 ins
->oprs
[c
-040].segment
, ins
->oprs
[c
-040].wrt
);
817 case 050: case 051: case 052:
818 if (ins
->oprs
[c
-050].segment
!= segment
)
819 errfunc (ERR_NONFATAL
, "short relative jump outside segment");
820 data
= ins
->oprs
[c
-050].offset
- insn_end
;
821 if (data
> 127 || data
< -128)
822 errfunc (ERR_NONFATAL
, "short jump is out of range");
824 out (offset
, segment
, bytes
, OUT_RAWDATA
+1, NO_SEG
, NO_SEG
);
828 case 060: case 061: case 062:
829 if (ins
->oprs
[c
-060].segment
!= segment
) {
830 data
= ins
->oprs
[c
-060].offset
;
831 out (offset
, segment
, &data
, OUT_REL2ADR
+insn_end
-offset
,
832 ins
->oprs
[c
-060].segment
, ins
->oprs
[c
-060].wrt
);
834 data
= ins
->oprs
[c
-060].offset
- insn_end
;
835 out (offset
, segment
, &data
,
836 OUT_ADDRESS
+2, NO_SEG
, NO_SEG
);
841 case 064: case 065: case 066:
842 size
= ((ins
->oprs
[c
-064].addr_size
?
843 ins
->oprs
[c
-064].addr_size
: bits
) == 16 ? 2 : 4);
844 if (ins
->oprs
[c
-064].segment
!= segment
) {
845 data
= ins
->oprs
[c
-064].offset
;
846 size
= (bits
== 16 ? OUT_REL2ADR
: OUT_REL4ADR
);
847 out (offset
, segment
, &data
, size
+insn_end
-offset
,
848 ins
->oprs
[c
-064].segment
, ins
->oprs
[c
-064].wrt
);
849 size
= (bits
== 16 ? 2 : 4);
851 data
= ins
->oprs
[c
-064].offset
- insn_end
;
852 out (offset
, segment
, &data
,
853 OUT_ADDRESS
+size
, NO_SEG
, NO_SEG
);
858 case 070: case 071: case 072:
859 if (ins
->oprs
[c
-070].segment
!= segment
) {
860 data
= ins
->oprs
[c
-070].offset
;
861 out (offset
, segment
, &data
, OUT_REL4ADR
+insn_end
-offset
,
862 ins
->oprs
[c
-070].segment
, ins
->oprs
[c
-070].wrt
);
864 data
= ins
->oprs
[c
-070].offset
- insn_end
;
865 out (offset
, segment
, &data
,
866 OUT_ADDRESS
+4, NO_SEG
, NO_SEG
);
871 case 0130: case 0131: case 0132:
872 data
= ins
->oprs
[c
-0130].offset
;
873 if (is_sbyte(ins
, c
-0130, 16)) {
874 out (offset
, segment
, &data
, OUT_RAWDATA
+1, NO_SEG
, NO_SEG
);
877 if (ins
->oprs
[c
-0130].segment
== NO_SEG
&&
878 ins
->oprs
[c
-0130].wrt
== NO_SEG
&&
879 (data
< -65536L || data
> 65535L)) {
880 errfunc (ERR_WARNING
, "word value exceeds bounds");
882 out (offset
, segment
, &data
, OUT_ADDRESS
+2,
883 ins
->oprs
[c
-0130].segment
, ins
->oprs
[c
-0130].wrt
);
888 case 0133: case 0134: case 0135:
891 if (is_sbyte(ins
, c
-0133, 16)) bytes
[0] |= 2; /* s-bit */
892 out (offset
, segment
, bytes
, OUT_RAWDATA
+1, NO_SEG
, NO_SEG
);
896 case 0140: case 0141: case 0142:
897 data
= ins
->oprs
[c
-0140].offset
;
898 if (is_sbyte(ins
, c
-0140, 32)) {
899 out (offset
, segment
, &data
, OUT_RAWDATA
+1, NO_SEG
, NO_SEG
);
902 out (offset
, segment
, &data
, OUT_ADDRESS
+4,
903 ins
->oprs
[c
-0140].segment
, ins
->oprs
[c
-0140].wrt
);
908 case 0143: case 0144: case 0145:
911 if (is_sbyte(ins
, c
-0143, 32)) bytes
[0] |= 2; /* s-bit */
912 out (offset
, segment
, bytes
, OUT_RAWDATA
+1, NO_SEG
, NO_SEG
);
916 case 0300: case 0301: case 0302:
917 if (chsize (&ins
->oprs
[c
-0300], bits
)) {
919 out (offset
, segment
, bytes
,
920 OUT_RAWDATA
+1, NO_SEG
, NO_SEG
);
929 out (offset
, segment
, bytes
,
930 OUT_RAWDATA
+1, NO_SEG
, NO_SEG
);
939 out (offset
, segment
, bytes
,
940 OUT_RAWDATA
+1, NO_SEG
, NO_SEG
);
952 out (offset
, segment
, bytes
,
953 OUT_RAWDATA
+1, NO_SEG
, NO_SEG
);
962 out (offset
, segment
, bytes
,
963 OUT_RAWDATA
+1, NO_SEG
, NO_SEG
);
973 *bytes
= *codes
++ ^ condval
[ins
->condition
];
974 out (offset
, segment
, bytes
,
975 OUT_RAWDATA
+1, NO_SEG
, NO_SEG
);
985 out (offset
, segment
, bytes
,
986 OUT_RAWDATA
+1, NO_SEG
, NO_SEG
);
990 case 0340: case 0341: case 0342:
991 if (ins
->oprs
[0].segment
!= NO_SEG
)
992 errfunc (ERR_PANIC
, "non-constant BSS size in pass two");
994 long size
= ins
->oprs
[0].offset
<< (c
-0340);
996 out (offset
, segment
, NULL
,
997 OUT_RESERVE
+size
, NO_SEG
, NO_SEG
);
1002 case 0370: case 0371: case 0372:
1006 *bytes
= bits
==16 ? 3 : 5;
1007 out (offset
, segment
, bytes
,
1008 OUT_RAWDATA
+1, NO_SEG
, NO_SEG
);
1012 default: /* can't do it by 'case' statements */
1013 if (c
>=0100 && c
<=0277) { /* it's an EA */
1019 if (c
<=0177) /* pick rfield from operand b */
1020 rfield
= regval (&ins
->oprs
[c
&7]);
1021 else /* rfield is constant */
1024 if (!process_ea (&ins
->oprs
[(c
>>3)&7], &ea_data
, bits
, rfield
,
1027 errfunc (ERR_NONFATAL
, "invalid effective address");
1031 *p
++ = ea_data
.modrm
;
1032 if (ea_data
.sib_present
)
1036 out (offset
, segment
, bytes
, OUT_RAWDATA
+ s
,
1039 switch (ea_data
.bytes
) {
1043 if (ins
->oprs
[(c
>>3)&7].segment
!= NO_SEG
) {
1044 data
= ins
->oprs
[(c
>>3)&7].offset
;
1045 out (offset
, segment
, &data
, OUT_ADDRESS
+1,
1046 ins
->oprs
[(c
>>3)&7].segment
,
1047 ins
->oprs
[(c
>>3)&7].wrt
);
1049 *bytes
= ins
->oprs
[(c
>>3)&7].offset
;
1050 out (offset
, segment
, bytes
, OUT_RAWDATA
+1,
1057 data
= ins
->oprs
[(c
>>3)&7].offset
;
1058 out (offset
, segment
, &data
,
1059 OUT_ADDRESS
+ea_data
.bytes
,
1060 ins
->oprs
[(c
>>3)&7].segment
, ins
->oprs
[(c
>>3)&7].wrt
);
1066 errfunc (ERR_PANIC
, "internal instruction table corrupt"
1067 ": instruction code 0x%02X given", c
);
1071 static int regval (operand
*o
)
1073 switch (o
->basereg
) {
1074 case R_EAX
: case R_AX
: case R_AL
: case R_ES
: case R_CR0
: case R_DR0
:
1075 case R_ST0
: case R_MM0
: case R_XMM0
:
1077 case R_ECX
: case R_CX
: case R_CL
: case R_CS
: case R_DR1
: case R_ST1
:
1078 case R_MM1
: case R_XMM1
:
1080 case R_EDX
: case R_DX
: case R_DL
: case R_SS
: case R_CR2
: case R_DR2
:
1081 case R_ST2
: case R_MM2
: case R_XMM2
:
1083 case R_EBX
: case R_BX
: case R_BL
: case R_DS
: case R_CR3
: case R_DR3
:
1084 case R_TR3
: case R_ST3
: case R_MM3
: case R_XMM3
:
1086 case R_ESP
: case R_SP
: case R_AH
: case R_FS
: case R_CR4
: case R_TR4
:
1087 case R_ST4
: case R_MM4
: case R_XMM4
:
1089 case R_EBP
: case R_BP
: case R_CH
: case R_GS
: case R_TR5
: case R_ST5
:
1090 case R_MM5
: case R_XMM5
:
1092 case R_ESI
: case R_SI
: case R_DH
: case R_DR6
: case R_TR6
: case R_ST6
:
1093 case R_MM6
: case R_XMM6
:
1095 case R_EDI
: case R_DI
: case R_BH
: case R_DR7
: case R_TR7
: case R_ST7
:
1096 case R_MM7
: case R_XMM7
:
1098 default: /* panic */
1099 errfunc (ERR_PANIC
, "invalid register operand given to regval()");
1104 static int matches (struct itemplate
*itemp
, insn
*instruction
)
1106 int i
, size
[3], asize
, oprs
, ret
;
1113 if (itemp
->opcode
!= instruction
->opcode
) return 0;
1116 * Count the operands
1118 if (itemp
->operands
!= instruction
->operands
) return 0;
1121 * Check that no spurious colons or TOs are present
1123 for (i
=0; i
<itemp
->operands
; i
++)
1124 if (instruction
->oprs
[i
].type
& ~itemp
->opd
[i
] & (COLON
|TO
))
1128 * Check that the operand flags all match up
1130 for (i
=0; i
<itemp
->operands
; i
++)
1131 if (itemp
->opd
[i
] & ~instruction
->oprs
[i
].type
||
1132 ((itemp
->opd
[i
] & SIZE_MASK
) &&
1133 ((itemp
->opd
[i
] ^ instruction
->oprs
[i
].type
) & SIZE_MASK
)))
1135 if ((itemp
->opd
[i
] & ~instruction
->oprs
[i
].type
& NON_SIZE
) ||
1136 (instruction
->oprs
[i
].type
& SIZE_MASK
))
1144 * Check operand sizes
1146 if (itemp
->flags
& IF_ARMASK
) {
1147 size
[0] = size
[1] = size
[2] = 0;
1149 switch (itemp
->flags
& IF_ARMASK
) {
1150 case IF_AR0
: i
= 0; break;
1151 case IF_AR1
: i
= 1; break;
1152 case IF_AR2
: i
= 2; break;
1153 default: break; /* Shouldn't happen */
1155 if (itemp
->flags
& IF_SB
) {
1157 } else if (itemp
->flags
& IF_SW
) {
1159 } else if (itemp
->flags
& IF_SD
) {
1164 if (itemp
->flags
& IF_SB
) {
1166 oprs
= itemp
->operands
;
1167 } else if (itemp
->flags
& IF_SW
) {
1169 oprs
= itemp
->operands
;
1170 } else if (itemp
->flags
& IF_SD
) {
1172 oprs
= itemp
->operands
;
1174 size
[0] = size
[1] = size
[2] = asize
;
1177 if (itemp
->flags
& (IF_SM
| IF_SM2
)) {
1178 oprs
= (itemp
->flags
& IF_SM2
? 2 : itemp
->operands
);
1180 for (i
=0; i
<oprs
; i
++) {
1181 if ( (asize
= itemp
->opd
[i
] & SIZE_MASK
) != 0) {
1183 for (j
=0; j
<oprs
; j
++)
1189 oprs
= itemp
->operands
;
1192 for (i
=0; i
<itemp
->operands
; i
++)
1193 if (!(itemp
->opd
[i
] & SIZE_MASK
) &&
1194 (instruction
->oprs
[i
].type
& SIZE_MASK
& ~size
[i
]))
1199 * Check template is okay at the set cpu level
1201 if ((itemp
->flags
& IF_PLEVEL
) > cpu
) return 3;
1204 * Check if special handling needed for Jumps
1206 if ((unsigned char)(itemp
->code
[0]) >= 0370) return 99;
1211 static ea
*process_ea (operand
*input
, ea
*output
, int addrbits
, int rfield
,
1214 if (!(REGISTER
& ~input
->type
)) { /* it's a single register */
1215 static int regs
[] = {
1216 R_AL
, R_CL
, R_DL
, R_BL
, R_AH
, R_CH
, R_DH
, R_BH
,
1217 R_AX
, R_CX
, R_DX
, R_BX
, R_SP
, R_BP
, R_SI
, R_DI
,
1218 R_EAX
, R_ECX
, R_EDX
, R_EBX
, R_ESP
, R_EBP
, R_ESI
, R_EDI
,
1219 R_MM0
, R_MM1
, R_MM2
, R_MM3
, R_MM4
, R_MM5
, R_MM6
, R_MM7
,
1220 R_XMM0
, R_XMM1
, R_XMM2
, R_XMM3
, R_XMM4
, R_XMM5
, R_XMM6
, R_XMM7
1224 for (i
=0; i
<elements(regs
); i
++)
1225 if (input
->basereg
== regs
[i
]) break;
1226 if (i
<elements(regs
)) {
1227 output
->sib_present
= FALSE
;/* no SIB necessary */
1228 output
->bytes
= 0; /* no offset necessary either */
1229 output
->modrm
= 0xC0 | (rfield
<< 3) | (i
& 7);
1233 } else { /* it's a memory reference */
1234 if (input
->basereg
==-1 && (input
->indexreg
==-1 || input
->scale
==0)) {
1235 /* it's a pure offset */
1236 if (input
->addr_size
)
1237 addrbits
= input
->addr_size
;
1238 output
->sib_present
= FALSE
;
1239 output
->bytes
= (addrbits
==32 ? 4 : 2);
1240 output
->modrm
= (addrbits
==32 ? 5 : 6) | (rfield
<< 3);
1242 else { /* it's an indirection */
1243 int i
=input
->indexreg
, b
=input
->basereg
, s
=input
->scale
;
1244 long o
=input
->offset
, seg
=input
->segment
;
1245 int hb
=input
->hintbase
, ht
=input
->hinttype
;
1248 if (s
==0) i
= -1; /* make this easy, at least */
1250 if (i
==R_EAX
|| i
==R_EBX
|| i
==R_ECX
|| i
==R_EDX
1251 || i
==R_EBP
|| i
==R_ESP
|| i
==R_ESI
|| i
==R_EDI
1252 || b
==R_EAX
|| b
==R_EBX
|| b
==R_ECX
|| b
==R_EDX
1253 || b
==R_EBP
|| b
==R_ESP
|| b
==R_ESI
|| b
==R_EDI
) {
1254 /* it must be a 32-bit memory reference. Firstly we have
1255 * to check that all registers involved are type Exx. */
1256 if (i
!=-1 && i
!=R_EAX
&& i
!=R_EBX
&& i
!=R_ECX
&& i
!=R_EDX
1257 && i
!=R_EBP
&& i
!=R_ESP
&& i
!=R_ESI
&& i
!=R_EDI
)
1259 if (b
!=-1 && b
!=R_EAX
&& b
!=R_EBX
&& b
!=R_ECX
&& b
!=R_EDX
1260 && b
!=R_EBP
&& b
!=R_ESP
&& b
!=R_ESI
&& b
!=R_EDI
)
1263 /* While we're here, ensure the user didn't specify WORD. */
1264 if (input
->addr_size
== 16)
1267 /* now reorganise base/index */
1268 if (s
== 1 && b
!= i
&& b
!= -1 && i
!= -1 &&
1269 ((hb
==b
&&ht
==EAH_NOTBASE
) || (hb
==i
&&ht
==EAH_MAKEBASE
)))
1270 t
= b
, b
= i
, i
= t
; /* swap if hints say so */
1271 if (b
==i
) /* convert EAX+2*EAX to 3*EAX */
1273 if (b
==-1 && s
==1 && !(hb
== i
&& ht
== EAH_NOTBASE
))
1274 b
= i
, i
= -1; /* make single reg base, unless hint */
1275 if (((s
==2 && i
!=R_ESP
&& !(input
->eaflags
& EAF_TIMESTWO
)) ||
1276 s
==3 || s
==5 || s
==9) && b
==-1)
1277 b
= i
, s
--; /* convert 3*EAX to EAX+2*EAX */
1278 if (s
==1 && i
==R_ESP
) /* swap ESP into base if scale is 1 */
1280 if (i
==R_ESP
|| (s
!=1 && s
!=2 && s
!=4 && s
!=8 && i
!=-1))
1281 return NULL
; /* wrong, for various reasons */
1283 if (i
==-1 && b
!=R_ESP
) {/* no SIB needed */
1286 case R_EAX
: rm
= 0; break;
1287 case R_ECX
: rm
= 1; break;
1288 case R_EDX
: rm
= 2; break;
1289 case R_EBX
: rm
= 3; break;
1290 case R_EBP
: rm
= 5; break;
1291 case R_ESI
: rm
= 6; break;
1292 case R_EDI
: rm
= 7; break;
1293 case -1: rm
= 5; break;
1294 default: /* should never happen */
1297 if (b
==-1 || (b
!=R_EBP
&& o
==0 &&
1298 seg
==NO_SEG
&& !forw_ref
&&
1300 (EAF_BYTEOFFS
|EAF_WORDOFFS
))))
1302 else if (input
->eaflags
& EAF_BYTEOFFS
||
1303 (o
>=-128 && o
<=127 && seg
==NO_SEG
&& !forw_ref
&&
1304 !(input
->eaflags
& EAF_WORDOFFS
))) {
1310 output
->sib_present
= FALSE
;
1311 output
->bytes
= (b
==-1 || mod
==2 ? 4 : mod
);
1312 output
->modrm
= (mod
<<6) | (rfield
<<3) | rm
;
1314 else { /* we need a SIB */
1315 int mod
, scale
, index
, base
;
1318 case R_EAX
: base
= 0; break;
1319 case R_ECX
: base
= 1; break;
1320 case R_EDX
: base
= 2; break;
1321 case R_EBX
: base
= 3; break;
1322 case R_ESP
: base
= 4; break;
1323 case R_EBP
: case -1: base
= 5; break;
1324 case R_ESI
: base
= 6; break;
1325 case R_EDI
: base
= 7; break;
1326 default: /* then what the smeg is it? */
1327 return NULL
; /* panic */
1331 case R_EAX
: index
= 0; break;
1332 case R_ECX
: index
= 1; break;
1333 case R_EDX
: index
= 2; break;
1334 case R_EBX
: index
= 3; break;
1335 case -1: index
= 4; break;
1336 case R_EBP
: index
= 5; break;
1337 case R_ESI
: index
= 6; break;
1338 case R_EDI
: index
= 7; break;
1339 default: /* then what the smeg is it? */
1340 return NULL
; /* panic */
1345 case 1: scale
= 0; break;
1346 case 2: scale
= 1; break;
1347 case 4: scale
= 2; break;
1348 case 8: scale
= 3; break;
1349 default: /* then what the smeg is it? */
1350 return NULL
; /* panic */
1353 if (b
==-1 || (b
!=R_EBP
&& o
==0 &&
1354 seg
==NO_SEG
&& !forw_ref
&&
1356 (EAF_BYTEOFFS
|EAF_WORDOFFS
))))
1358 else if (input
->eaflags
& EAF_BYTEOFFS
||
1359 (o
>=-128 && o
<=127 && seg
==NO_SEG
&& !forw_ref
&&
1360 !(input
->eaflags
& EAF_WORDOFFS
)))
1365 output
->sib_present
= TRUE
;
1366 output
->bytes
= (b
==-1 || mod
==2 ? 4 : mod
);
1367 output
->modrm
= (mod
<<6) | (rfield
<<3) | 4;
1368 output
->sib
= (scale
<<6) | (index
<<3) | base
;
1371 else { /* it's 16-bit */
1374 /* check all registers are BX, BP, SI or DI */
1375 if ((b
!=-1 && b
!=R_BP
&& b
!=R_BX
&& b
!=R_SI
&& b
!=R_DI
) ||
1376 (i
!=-1 && i
!=R_BP
&& i
!=R_BX
&& i
!=R_SI
&& i
!=R_DI
))
1379 /* ensure the user didn't specify DWORD */
1380 if (input
->addr_size
== 32)
1383 if (s
!=1 && i
!=-1) return NULL
;/* no can do, in 16-bit EA */
1384 if (b
==-1 && i
!=-1) b
^= i
^= b
^= i
; /* swap them round */
1385 if ((b
==R_SI
|| b
==R_DI
) && i
!=-1)
1386 b
^= i
^= b
^= i
; /* have BX/BP as base, SI/DI index */
1387 if (b
==i
) return NULL
;/* shouldn't ever happen, in theory */
1388 if (i
!=-1 && b
!=-1 &&
1389 (i
==R_BP
|| i
==R_BX
|| b
==R_SI
|| b
==R_DI
))
1390 return NULL
; /* invalid combinations */
1391 if (b
==-1) /* pure offset: handled above */
1392 return NULL
; /* so if it gets to here, panic! */
1396 switch (i
*256 + b
) {
1397 case R_SI
*256+R_BX
: rm
=0; break;
1398 case R_DI
*256+R_BX
: rm
=1; break;
1399 case R_SI
*256+R_BP
: rm
=2; break;
1400 case R_DI
*256+R_BP
: rm
=3; break;
1404 case R_SI
: rm
=4; break;
1405 case R_DI
: rm
=5; break;
1406 case R_BP
: rm
=6; break;
1407 case R_BX
: rm
=7; break;
1409 if (rm
==-1) /* can't happen, in theory */
1410 return NULL
; /* so panic if it does */
1412 if (o
==0 && seg
==NO_SEG
&& !forw_ref
&& rm
!=6 &&
1413 !(input
->eaflags
& (EAF_BYTEOFFS
|EAF_WORDOFFS
)))
1415 else if (input
->eaflags
& EAF_BYTEOFFS
||
1416 (o
>=-128 && o
<=127 && seg
==NO_SEG
&& !forw_ref
&&
1417 !(input
->eaflags
& EAF_WORDOFFS
)))
1422 output
->sib_present
= FALSE
; /* no SIB - it's 16-bit */
1423 output
->bytes
= mod
; /* bytes of offset needed */
1424 output
->modrm
= (mod
<<6) | (rfield
<<3) | rm
;
1428 output
->size
= 1 + output
->sib_present
+ output
->bytes
;
1432 static int chsize (operand
*input
, int addrbits
)
1434 if (!(MEMORY
& ~input
->type
)) {
1435 int i
=input
->indexreg
, b
=input
->basereg
;
1437 if (input
->scale
==0) i
= -1;
1439 if (i
== -1 && b
== -1) /* pure offset */
1440 return (input
->addr_size
!= 0 && input
->addr_size
!= addrbits
);
1442 if (i
==R_EAX
|| i
==R_EBX
|| i
==R_ECX
|| i
==R_EDX
1443 || i
==R_EBP
|| i
==R_ESP
|| i
==R_ESI
|| i
==R_EDI
1444 || b
==R_EAX
|| b
==R_EBX
|| b
==R_ECX
|| b
==R_EDX
1445 || b
==R_EBP
|| b
==R_ESP
|| b
==R_ESI
|| b
==R_EDI
)
1446 return (addrbits
==16);
1448 return (addrbits
==32);