diff options
-rw-r--r-- | Makefile.in | 2 | ||||
-rw-r--r-- | Mkfiles/Makefile.dj | 2 | ||||
-rw-r--r-- | README03.txt | 49 | ||||
-rw-r--r-- | assemble.c | 148 | ||||
-rw-r--r-- | assemble.h | 4 | ||||
-rw-r--r-- | eval.c | 4 | ||||
-rw-r--r-- | insns.dat | 110 | ||||
-rw-r--r-- | insns.h | 2 | ||||
-rw-r--r-- | labels.c | 237 | ||||
-rw-r--r-- | macros.c | 9 | ||||
-rwxr-xr-x | makedist.sh | 4 | ||||
-rw-r--r-- | nasm.c | 1130 | ||||
-rw-r--r-- | nasm.h | 39 | ||||
-rw-r--r-- | nasmlib.c | 12 | ||||
-rw-r--r-- | nasmlib.h | 17 | ||||
-rw-r--r-- | outobj.c | 18 | ||||
-rw-r--r-- | parser.c | 9 | ||||
-rw-r--r-- | preproc.c | 501 | ||||
-rw-r--r-- | rdoff/Makefile.in | 2 | ||||
-rw-r--r-- | standard.mac | 12 | ||||
-rw-r--r-- | test/test1.asm | 62 | ||||
-rw-r--r-- | test/test2.asm | 18 | ||||
-rw-r--r-- | test/test2a.asm | 22 | ||||
-rw-r--r-- | test/test3.asm | 45 | ||||
-rw-r--r-- | test/test4.asm | 16 | ||||
-rw-r--r-- | test/test4a.asm | 16 | ||||
-rw-r--r-- | test/test4b.asm | 17 | ||||
-rw-r--r-- | test/test4c.asm | 17 | ||||
-rw-r--r-- | test/test5.asm | 43 | ||||
-rw-r--r-- | test/test6.asm | 9 | ||||
-rw-r--r-- | zoutieee.c | 9 |
31 files changed, 1680 insertions, 905 deletions
diff --git a/Makefile.in b/Makefile.in index 3a94ae3..3d31f56 100644 --- a/Makefile.in +++ b/Makefile.in @@ -66,7 +66,7 @@ insnsd.o: insnsd.c nasm.h insnsi.h insns.h labels.o: labels.c nasm.h insnsi.h nasmlib.h listing.o: listing.c nasm.h insnsi.h nasmlib.h listing.h nasm.o: nasm.c nasm.h insnsi.h nasmlib.h preproc.h parser.h assemble.h labels.h \ - outform.h listing.h + outform.h listing.h insns.h nasmlib.o: nasmlib.c nasm.h insnsi.h nasmlib.h names.c insnsn.c ndisasm.o: ndisasm.c nasm.h insnsi.h nasmlib.h sync.h disasm.h outaout.o: outaout.c nasm.h insnsi.h nasmlib.h outform.h diff --git a/Mkfiles/Makefile.dj b/Mkfiles/Makefile.dj index 7cb2399..fb33748 100644 --- a/Mkfiles/Makefile.dj +++ b/Mkfiles/Makefile.dj @@ -13,7 +13,7 @@ # You may need to adjust these values. -CC = gcc +CC = gcc -s CFLAGS = -O2 -I. # You _shouldn't_ need to adjust anything below this line. diff --git a/README03.txt b/README03.txt new file mode 100644 index 0000000..8d35390 --- /dev/null +++ b/README03.txt @@ -0,0 +1,49 @@ + + README + NASM, the Netwide Assembler + + + Changes from 0.98 release to 98.03 as of 27-Jul-2000 + ==================================================== + +1. Added signed byte optimizations for the 0x81/0x83 class +of instructions: ADC, ADD, AND, CMP, OR, SBB, SUB, XOR: +when used as 'ADD reg16,imm' or 'ADD reg32,imm.' Also +optimization of signed byte form of 'PUSH imm' and 'IMUL +reg,imm'/'IMUL reg,reg,imm.' No size specification is needed. + +2. Added multi-pass JMP and Jcc offset optimization. Offsets +on forward references will preferentially use the short form, +without the need to code a specific size (short or near) for +the branch. Added instructions for 'Jcc label' to use the +form 'Jnotcc $+3/JMP label', in cases where a short offset +is out of bounds. If compiling for a 386 or higher CPU, then +the 386 form of Jcc will be used instead. + +This feature is controlled by a new command-line switch: "O", +(upper case letter O). "-O0" reverts the assembler to no +extra optimization passes, "-O1" allows up to 5 extra passes, +and "-O2"(default), allows up to 10 extra optimization passes. + +3. Added a new directive: 'cpu XXX', where XXX is any of: +8086, 186, 286, 386, 486, 586, pentium, 686, PPro, P2, P3 or +Katmai. All are case insensitive. All instructions will +be selected only if they apply to the selected cpu or lower. +Corrected a couple of bugs in cpu-dependence in 'insns.dat'. + +4. Added to 'standard.mac', the "use16" and "use32" forms of +the "bits 16/32" directive. This is nothing new, just conforms +to a lot of other assemblers. (minor) + +5. Changed label allocation from 320/32 (10000 labels @ 200K+) +to 32/37 (1000 labels); makes running under DOS much easier. +Since additional label space is allocated dynamically, this +should have no effect on large programs with lots of labels. +The 37 is a prime, believed to be better for hashing. (minor) + +6. Integrated patchfile 0.98-0.98.01. I call this version +0.98.03, for historical reasons: 0.98.02 was trashed. + +--John Coffman <johninsd@san.rr.com> 27-Jul-2000 + +(end)
\ No newline at end of file @@ -32,12 +32,19 @@ * \70, \71, \72 - a long relative operand, from operand 0, 1 or 2 * \1ab - a ModRM, calculated on EA in operand a, with the spare * field the register value of operand b. + * \130,\131,\132 - an immediate word or signed byte for operand 0, 1, or 2 + * \133,\134,\135 - or 2 (s-field) into next opcode byte if operand 0, 1, or 2 + * is a signed byte rather than a word. + * \140,\141,\142 - an immediate dword or signed byte for operand 0, 1, or 2 + * \143,\144,\145 - or 2 (s-field) into next opcode byte if operand 0, 1, or 2 + * is a signed byte rather than a dword. * \2ab - a ModRM, calculated on EA in operand a, with the spare * field equal to digit b. * \30x - might be an 0x67 byte, depending on the address size of * the memory reference in operand x. * \310 - indicates fixed 16-bit address size, i.e. optional 0x67. * \311 - indicates fixed 32-bit address size, i.e. optional 0x67. + * \312 - (disassembler only) marker on LOOP, LOOPxx instructions. * \320 - indicates fixed 16-bit operand size, i.e. optional 0x66. * \321 - indicates fixed 32-bit operand size, i.e. optional 0x66. * \322 - indicates that this instruction is only valid when the @@ -52,6 +59,9 @@ * as a literal byte in order to aid the disassembler. * \340 - reserve <operand 0> bytes of uninitialised storage. * Operand 0 had better be a segmentless constant. + * \370,\371,\372 - match only if operand 0, 1, 2 meets byte jump criteria. + * \373 - assemble 0x03 if bits==16, 0x05 if bits==32; + * used for conditional jump over longer jump */ #include <stdio.h> @@ -71,6 +81,7 @@ typedef struct { unsigned char modrm, sib; /* the bytes themselves */ } ea; +static unsigned long cpu; /* cpu level received from nasm.c */ static efunc errfunc; static struct ofmt *outfmt; static ListGen *list; @@ -134,7 +145,25 @@ static void out (long offset, long segto, void *data, unsigned long type, outfmt->output (segto, data, type, segment, wrt); } -long assemble (long segment, long offset, int bits, +static int jmp_match (long segment, long offset, int bits, + insn *ins, char *code) +{ long isize; + unsigned char c = code[0]; + + + if (c != 0370) return 0; + if (ins->oprs[0].opflags & OPFLAG_FORWARD) return 1; /* match a forward reference */ + + isize = calcsize (segment, offset, bits, ins, code); + if (ins->oprs[0].segment != segment) return 0; + isize = ins->oprs[0].offset - offset - isize; /* isize is now the delta */ + if (isize >= -128L && isize <= 127L) return 1; /* it is byte size */ + + return 0; +} + + +long assemble (long segment, long offset, int bits, unsigned long cp, insn *instruction, struct ofmt *output, efunc error, ListGen *listgen) { @@ -147,6 +176,7 @@ long assemble (long segment, long offset, int bits, long wsize = 0; /* size for DB etc. */ errfunc = error; /* to pass to other functions */ + cpu = cp; outfmt = output; /* likewise */ list = listgen; /* and again */ @@ -305,6 +335,8 @@ long assemble (long segment, long offset, int bits, temp = nasm_instructions[instruction->opcode]; while (temp->opcode != -1) { int m = matches (temp, instruction); + if (m == 99) + m += jmp_match(segment, offset, bits, instruction, temp->code); if (m == 100) /* matches! */ { @@ -371,7 +403,7 @@ long assemble (long segment, long offset, int bits, if (instruction->times > 1) list->downlevel (LIST_TIMES); return offset - start; - } else if (m > 0) { + } else if (m > 0 && m > size_prob) { size_prob = m; } temp++; @@ -382,6 +414,8 @@ long assemble (long segment, long offset, int bits, error (ERR_NONFATAL, "operation size not specified"); else if (size_prob == 2) error (ERR_NONFATAL, "mismatch in operand sizes"); + else if (size_prob == 3) + error (ERR_NONFATAL, "no instruction for this cpu level"); else error (ERR_NONFATAL, "invalid combination of opcode and operands"); @@ -389,12 +423,13 @@ long assemble (long segment, long offset, int bits, return 0; } -long insn_size (long segment, long offset, int bits, +long insn_size (long segment, long offset, int bits, unsigned long cp, insn *instruction, efunc error) { struct itemplate *temp; errfunc = error; /* to pass to other functions */ + cpu = cp; if (instruction->opcode == -1) return 0; @@ -472,7 +507,11 @@ long insn_size (long segment, long offset, int bits, temp = nasm_instructions[instruction->opcode]; while (temp->opcode != -1) { - if (matches(temp, instruction) == 100) { + int m = matches(temp, instruction); + if (m == 99) + m += jmp_match(segment, offset, bits, instruction, temp->code); + + if (m == 100) { /* we've matched an instruction. */ long isize; char * codes = temp->code; @@ -498,6 +537,22 @@ long insn_size (long segment, long offset, int bits, return -1; /* didn't match any instruction */ } + +/* check that opn[op] is a signed byte of size 16 or 32, + and return the signed value*/ +static int is_sbyte (insn *ins, int op, int size) +{ + signed long v; + int ret; + + ret = !(ins->forw_ref && ins->oprs[op].opflags ) && /* dead in the water on forward reference or External */ + ins->oprs[op].wrt==NO_SEG && ins->oprs[op].segment==NO_SEG; + v = ins->oprs[op].offset; + if (size==16) v = (signed short)v; /* sign extend if 16 bits */ + + return ret && v>=-128L && v<=127L; +} + static long calcsize (long segment, long offset, int bits, insn *ins, char *codes) { @@ -540,6 +595,14 @@ static long calcsize (long segment, long offset, int bits, ins->oprs[c-064].addr_size : bits) == 16 ? 2 : 4); break; case 070: case 071: case 072: length += 4; break; + case 0130: case 0131: case 0132: + length += is_sbyte(ins, c-0130, 16) ? 1 : 2; break; + case 0133: case 0134: case 0135: + codes+=2; length++; break; + case 0140: case 0141: case 0142: + length += is_sbyte(ins, c-0140, 32) ? 1 : 4; break; + case 0143: case 0144: case 0145: + codes+=2; length++; break; case 0300: case 0301: case 0302: length += chsize (&ins->oprs[c-0300], bits); break; @@ -573,6 +636,10 @@ static long calcsize (long segment, long offset, int bits, else length += ins->oprs[0].offset << (c-0340); break; + case 0370: case 0371: case 0372: + break; + case 0373: + length++; break; default: /* can't do it by 'case' statements */ if (c>=0100 && c<=0277) { /* it's an EA */ ea ea_data; @@ -801,6 +868,51 @@ static void gencode (long segment, long offset, int bits, offset += 4; break; + case 0130: case 0131: case 0132: + data = ins->oprs[c-0130].offset; + if (is_sbyte(ins, c-0130, 16)) { + out (offset, segment, &data, OUT_RAWDATA+1, NO_SEG, NO_SEG); + offset++; + } else { + if (ins->oprs[c-0130].segment == NO_SEG && + ins->oprs[c-0130].wrt == NO_SEG && + (data < -65536L || data > 65535L)) { + errfunc (ERR_WARNING, "word value exceeds bounds"); + } + out (offset, segment, &data, OUT_ADDRESS+2, + ins->oprs[c-0130].segment, ins->oprs[c-0130].wrt); + offset += 2; + } + break; + + case 0133: case 0134: case 0135: + codes++; + bytes[0] = *codes++; + if (is_sbyte(ins, c-0133, 16)) bytes[0] |= 2; /* s-bit */ + out (offset, segment, bytes, OUT_RAWDATA+1, NO_SEG, NO_SEG); + offset++; + break; + + case 0140: case 0141: case 0142: + data = ins->oprs[c-0140].offset; + if (is_sbyte(ins, c-0140, 32)) { + out (offset, segment, &data, OUT_RAWDATA+1, NO_SEG, NO_SEG); + offset++; + } else { + out (offset, segment, &data, OUT_ADDRESS+4, + ins->oprs[c-0140].segment, ins->oprs[c-0140].wrt); + offset += 4; + } + break; + + case 0143: case 0144: case 0145: + codes++; + bytes[0] = *codes++; + if (is_sbyte(ins, c-0143, 32)) bytes[0] |= 2; /* s-bit */ + out (offset, segment, bytes, OUT_RAWDATA+1, NO_SEG, NO_SEG); + offset++; + break; + case 0300: case 0301: case 0302: if (chsize (&ins->oprs[c-0300], bits)) { *bytes = 0x67; @@ -858,7 +970,7 @@ static void gencode (long segment, long offset, int bits, break; case 0330: - *bytes = *codes++ + condval[ins->condition]; + *bytes = *codes++ ^ condval[ins->condition]; out (offset, segment, bytes, OUT_RAWDATA+1, NO_SEG, NO_SEG); offset += 1; @@ -887,6 +999,16 @@ static void gencode (long segment, long offset, int bits, } break; + case 0370: case 0371: case 0372: + break; + + case 0373: + *bytes = bits==16 ? 3 : 5; + out (offset, segment, bytes, + OUT_RAWDATA+1, NO_SEG, NO_SEG); + offset += 1; + break; + default: /* can't do it by 'case' statements */ if (c>=0100 && c<=0277) { /* it's an EA */ ea ea_data; @@ -1014,7 +1136,8 @@ static int matches (struct itemplate *itemp, insn *instruction) (instruction->oprs[i].type & SIZE_MASK)) return 0; else - ret = 1; +/* ret = 1; */ + return 1; } /* @@ -1069,8 +1192,19 @@ static int matches (struct itemplate *itemp, insn *instruction) for (i=0; i<itemp->operands; i++) if (!(itemp->opd[i] & SIZE_MASK) && (instruction->oprs[i].type & SIZE_MASK & ~size[i])) - ret = 2; +/* ret = 2; */ + return 2; + /* + * Check template is okay at the set cpu level + */ + if ((itemp->flags & IF_PLEVEL) > cpu) return 3; + + /* + * Check if special handling needed for Jumps + */ + if ((unsigned char)(itemp->code[0]) >= 0370) return 99; + return ret; } @@ -9,9 +9,9 @@ #ifndef NASM_ASSEMBLE_H #define NASM_ASSEMBLE_H -long insn_size (long segment, long offset, int bits, +long insn_size (long segment, long offset, int bits, unsigned long cpu, insn *instruction, efunc error); -long assemble (long segment, long offset, int bits, +long assemble (long segment, long offset, int bits, unsigned long cpu, insn *instruction, struct ofmt *output, efunc error, ListGen *listgen); @@ -760,8 +760,8 @@ expr *evaluate (scanner sc, void *scprivate, struct tokenval *tv, if (hint) hint->type = EAH_NOHINT; - if (critical & 0x10) { - critical &= ~0x10; + if (critical & CRITICAL) { + critical &= ~CRITICAL; bexpr = rexp0; } else bexpr = expr0; @@ -37,13 +37,14 @@ ADC rm16,imm8 \320\300\1\x83\202\15 8086 ADC rm32,imm8 \321\300\1\x83\202\15 386 ADC reg_al,imm \1\x14\21 8086,SM ADC reg_ax,imm \320\1\x15\31 8086,SM +ADC reg_eax,sbyte \321\1\x83\202\15 386,ND ADC reg_eax,imm \321\1\x15\41 386,SM ADC rm8,imm \300\1\x80\202\21 8086,SM -ADC rm16,imm \320\300\1\x81\202\31 8086,SM -ADC rm32,imm \321\300\1\x81\202\41 386,SM +ADC rm16,imm \320\300\134\1\x81\202\131 8086,SM,ND +ADC rm32,imm \321\300\144\1\x81\202\141 386,SM,ND ADC mem,imm8 \300\1\x80\202\21 8086,SM -ADC mem,imm16 \320\300\1\x81\202\31 8086,SM -ADC mem,imm32 \321\300\1\x81\202\41 386,SM +ADC mem,imm16 \320\300\134\1\x81\202\131 8086,SM,ND +ADC mem,imm32 \321\300\144\1\x81\202\141 386,SM,ND ADD mem,reg8 \300\17\101 8086,SM ADD reg8,reg8 \300\17\101 8086 ADD mem,reg16 \320\300\1\x01\101 8086,SM @@ -60,13 +61,14 @@ ADD rm16,imm8 \320\300\1\x83\200\15 8086 ADD rm32,imm8 \321\300\1\x83\200\15 386 ADD reg_al,imm \1\x04\21 8086,SM ADD reg_ax,imm \320\1\x05\31 8086,SM +ADD reg_eax,sbyte \321\1\x83\200\15 386,ND ADD reg_eax,imm \321\1\x05\41 386,SM ADD rm8,imm \300\1\x80\200\21 8086,SM -ADD rm16,imm \320\300\1\x81\200\31 8086,SM -ADD rm32,imm \321\300\1\x81\200\41 386,SM +ADD rm16,imm \320\300\134\1\x81\200\131 8086,SM,ND +ADD rm32,imm \321\300\144\1\x81\200\141 386,SM,ND ADD mem,imm8 \300\1\x80\200\21 8086,SM -ADD mem,imm16 \320\300\1\x81\200\31 8086,SM -ADD mem,imm32 \321\300\1\x81\200\41 386,SM +ADD mem,imm16 \320\300\134\1\x81\200\131 8086,SM,ND +ADD mem,imm32 \321\300\144\1\x81\200\141 386,SM,ND AND mem,reg8 \300\1\x20\101 8086,SM AND reg8,reg8 \300\1\x20\101 8086 AND mem,reg16 \320\300\1\x21\101 8086,SM @@ -83,13 +85,14 @@ AND rm16,imm8 \320\300\1\x83\204\15 8086 AND rm32,imm8 \321\300\1\x83\204\15 386 AND reg_al,imm \1\x24\21 8086,SM AND reg_ax,imm \320\1\x25\31 8086,SM +AND reg_eax,sbyte \321\1\x83\204\15 386,ND AND reg_eax,imm \321\1\x25\41 386,SM AND rm8,imm \300\1\x80\204\21 8086,SM -AND rm16,imm \320\300\1\x81\204\31 8086,SM -AND rm32,imm \321\300\1\x81\204\41 386,SM +AND rm16,imm \320\300\134\1\x81\204\131 8086,SM,ND +AND rm32,imm \321\300\144\1\x81\204\141 386,SM,ND AND mem,imm8 \300\1\x80\204\21 8086,SM -AND mem,imm16 \320\300\1\x81\204\31 8086,SM -AND mem,imm32 \321\300\1\x81\204\41 386,SM +AND mem,imm16 \320\300\134\1\x81\204\131 8086,SM,ND +AND mem,imm32 \321\300\144\1\x81\204\141 386,SM,ND ARPL mem,reg16 \300\1\x63\101 286,PROT,SM ARPL reg16,reg16 \300\1\x63\101 286,PROT BOUND reg16,mem \320\301\1\x62\110 186 @@ -175,13 +178,14 @@ CMP rm16,imm8 \320\300\1\x83\207\15 8086 CMP rm32,imm8 \321\300\1\x83\207\15 386 CMP reg_al,imm \1\x3C\21 8086,SM CMP reg_ax,imm \320\1\x3D\31 8086,SM +CMP reg_eax,sbyte \321\1\x83\207\15 386,ND CMP reg_eax,imm \321\1\x3D\41 386,SM CMP rm8,imm \300\1\x80\207\21 8086,SM -CMP rm16,imm \320\300\1\x81\207\31 8086,SM -CMP rm32,imm \321\300\1\x81\207\41 386,SM +CMP rm16,imm \320\300\134\1\x81\207\131 8086,SM,ND +CMP rm32,imm \321\300\144\1\x81\207\141 386,SM,ND CMP mem,imm8 \300\1\x80\207\21 8086,SM -CMP mem,imm16 \320\300\1\x81\207\31 8086,SM -CMP mem,imm32 \321\300\1\x81\207\41 386,SM +CMP mem,imm16 \320\300\134\1\x81\207\131 8086,SM,ND +CMP mem,imm32 \321\300\144\1\x81\207\141 386,SM,ND CMPSB void \332\1\xA6 8086 CMPSD void \332\321\1\xA7 386 CMPSW void \332\320\1\xA7 8086 @@ -414,21 +418,21 @@ IMUL rm8 \300\1\xF6\205 8086 IMUL rm16 \320\300\1\xF7\205 8086 IMUL rm32 \321\300\1\xF7\205 386 IMUL reg16,mem \320\301\2\x0F\xAF\110 386,SM -IMUL reg16,reg16 \320\301\2\x0F\xAF\110 386 +IMUL reg16,reg16 \320\2\x0F\xAF\110 386 IMUL reg32,mem \321\301\2\x0F\xAF\110 386,SM -IMUL reg32,reg32 \321\301\2\x0F\xAF\110 386 -IMUL reg16,mem,imm8 \320\301\1\x6B\110\16 286,SM -IMUL reg16,reg16,imm8 \320\301\1\x6B\110\16 286 -IMUL reg16,mem,imm \320\301\1\x69\110\32 286,SM -IMUL reg16,reg16,imm \320\301\1\x69\110\32 286,SM +IMUL reg32,reg32 \321\2\x0F\xAF\110 386 +IMUL reg16,mem,imm8 \320\301\1\x6B\110\16 186,SM +IMUL reg16,reg16,imm8 \320\301\1\x6B\110\16 186 +IMUL reg16,mem,imm \320\301\135\1\x69\110\132 186,SM +IMUL reg16,reg16,imm \320\135\1\x69\110\132 186,SM IMUL reg32,mem,imm8 \321\301\1\x6B\110\16 386,SM -IMUL reg32,reg32,imm8 \321\301\1\x6B\110\16 386 -IMUL reg32,mem,imm \321\301\1\x69\110\42 386,SM -IMUL reg32,reg32,imm \321\301\1\x69\110\42 386,SM -IMUL reg16,imm8 \320\1\x6B\100\15 286 -IMUL reg16,imm \320\1\x69\100\31 286,SM +IMUL reg32,reg32,imm8 \321\1\x6B\110\16 386 +IMUL reg32,mem,imm \321\301\145\1\x69\110\142 386,SM +IMUL reg32,reg32,imm \321\145\1\x69\110\142 386,SM +IMUL reg16,imm8 \320\1\x6B\100\15 186 +IMUL reg16,imm \320\134\1\x69\100\131 186,SM IMUL reg32,imm8 \321\1\x6B\100\15 386 -IMUL reg32,imm \321\1\x69\100\41 386,SM +IMUL reg32,imm \321\144\1\x69\100\141 386,SM IN reg_al,imm \1\xE4\25 8086,SB IN reg_ax,imm \320\1\xE5\25 8086,SB IN reg_eax,imm \321\1\xE5\25 386,SB @@ -458,6 +462,7 @@ IRETW void \320\1\xCF 8086 JCXZ imm \320\1\xE3\50 8086 JECXZ imm \321\1\xE3\50 386 JMP imm|short \1\xEB\50 8086 +JMP imm \370\1\xEB\50 8086,ND JMP imm \322\1\xE9\64 8086 JMP imm|near \322\1\xE9\64 8086,ND JMP imm|far \322\1\xEA\34\37 8086,ND @@ -631,13 +636,14 @@ OR rm16,imm8 \320\300\1\x83\201\15 8086 OR rm32,imm8 \321\300\1\x83\201\15 386 OR reg_al,imm \1\x0C\21 8086,SM OR reg_ax,imm \320\1\x0D\31 8086,SM +OR reg_eax,sbyte \321\1\x83\201\15 386,ND OR reg_eax,imm \321\1\x0D\41 386,SM OR rm8,imm \300\1\x80\201\21 8086,SM -OR rm16,imm \320\300\1\x81\201\31 8086,SM -OR rm32,imm \321\300\1\x81\201\41 386,SM +OR rm16,imm \320\300\134\1\x81\201\131 8086,SM,ND +OR rm32,imm \321\300\144\1\x81\201\141 386,SM,ND OR mem,imm8 \300\1\x80\201\21 8086,SM -OR mem,imm16 \320\300\1\x81\201\31 8086,SM -OR mem,imm32 \321\300\1\x81\201\41 386,SM +OR mem,imm16 \320\300\134\1\x81\201\131 8086,SM,ND +OR mem,imm32 \321\300\144\1\x81\201\141 386,SM,ND OUT imm,reg_al \1\xE6\24 8086,SB OUT imm,reg_ax \320\1\xE7\24 8086,SB OUT imm,reg_eax \321\1\xE7\24 386,SB @@ -818,9 +824,10 @@ PUSH rm16 \320\300\1\xFF\206 8086 PUSH rm32 \321\300\1\xFF\206 386 PUSH reg_fsgs \1\x0F\7 386 PUSH reg_sreg \6 8086 -PUSH imm8 \1\x6A\14 286 -PUSH imm16 \320\1\x68\30 286 -PUSH imm32 \321\1\x68\40 386 +PUSH imm8 \1\x6A\14 186 +PUSH sbyte \1\x6A\14 186,ND +PUSH imm16 \320\133\1\x68\130 186 +PUSH imm32 \321\143\1\x68\140 386 PUSHA void \322\1\x60 186 PUSHAD void \321\1\x60 386 PUSHAW void \320\1\x60 186 @@ -919,13 +926,14 @@ SBB rm16,imm8 \320\300\1\x83\203\15 8086 SBB rm32,imm8 \321\300\1\x83\203\15 8086 SBB reg_al,imm \1\x1C\21 8086,SM SBB reg_ax,imm \320\1\x1D\31 8086,SM +SBB reg_eax,sbyte \321\1\x83\203\15 386,ND SBB reg_eax,imm \321\1\x1D\41 386,SM SBB rm8,imm \300\1\x80\203\21 8086,SM -SBB rm16,imm \320\300\1\x81\203\31 8086,SM -SBB rm32,imm \321\300\1\x81\203\41 386,SM +SBB rm16,imm \320\300\134\1\x81\203\131 8086,SM,ND +SBB rm32,imm \321\300\144\1\x81\203\141 386,SM,ND SBB mem,imm8 \300\1\x80\203\21 8086,SM -SBB mem,imm16 \320\300\1\x81\203\31 8086,SM -SBB mem,imm32 \321\300\1\x81\203\41 386,SM +SBB mem,imm16 \320\300\134\1\x81\203\131 8086,SM,ND +SBB mem,imm32 \321\300\144\1\x81\203\141 386,SM,ND SCASB void \332\1\xAE 8086 SCASD void \332\321\1\xAF 386 SCASW void \332\320\1\xAF 8086 @@ -1000,13 +1008,14 @@ SUB rm16,imm8 \320\300\1\x83\205\15 8086 SUB rm32,imm8 \321\300\1\x83\205\15 386 SUB reg_al,imm \1\x2C\21 8086,SM SUB reg_ax,imm \320\1\x2D\31 8086,SM +SUB reg_eax,sbyte \321\1\x83\205\15 386,ND SUB reg_eax,imm \321\1\x2D\41 386,SM SUB rm8,imm \300\1\x80\205\21 8086,SM -SUB rm16,imm \320\300\1\x81\205\31 8086,SM -SUB rm32,imm \321\300\1\x81\205\41 386,SM +SUB rm16,imm \320\300\134\1\x81\205\131 8086,SM,ND +SUB rm32,imm \321\300\144\1\x81\205\141 386,SM,ND SUB mem,imm8 \300\1\x80\205\21 8086,SM -SUB mem,imm16 \320\300\1\x81\205\31 8086,SM -SUB mem,imm32 \321\300\1\x81\205\41 386,SM +SUB mem,imm16 \320\300\134\1\x81\205\131 8086,SM,ND +SUB mem,imm32 \321\300\144\1\x81\205\141 386,SM,ND SVDC mem80,reg_sreg \300\2\x0F\x78\101 486,CYRIX,SMM SVLDT mem80 \300\2\x0F\x7A\200 486,CYRIX,SMM SVTS mem80 \300\2\x0F\x7C\200 486,CYRIX,SMM @@ -1083,6 +1092,7 @@ XCHG reg16,reg16 \320\300\1\x87\101 8086 XCHG mem,reg32 \321\300\1\x87\101 386,SM XCHG reg32,reg32 \321\300\1\x87\101 386 XLATB void \1\xD7 8086 +XLAT void \1\xD7 8086 XOR mem,reg8 \300\1\x30\101 8086,SM XOR reg8,reg8 \300\1\x30\101 8086 XOR mem,reg16 \320\300\1\x31\101 8086,SM @@ -1099,13 +1109,14 @@ XOR rm16,imm8 \320\300\1\x83\206\15 8086 XOR rm32,imm8 \321\300\1\x83\206\15 386 XOR reg_al,imm \1\x34\21 8086,SM XOR reg_ax,imm \320\1\x35\31 8086,SM +XOR reg_eax,sbyte \321\1\x83\206\15 386,ND XOR reg_eax,imm \321\1\x35\41 386,SM XOR rm8,imm \300\1\x80\206\21 8086,SM -XOR rm16,imm \320\300\1\x81\206\31 8086,SM -XOR rm32,imm \321\300\1\x81\206\41 386,SM +XOR rm16,imm \320\300\134\1\x81\206\131 8086,SM,ND +XOR rm32,imm \321\300\144\1\x81\206\141 386,SM,ND XOR mem,imm8 \300\1\x80\206\21 8086,SM -XOR mem,imm16 \320\300\1\x81\206\31 8086,SM -XOR mem,imm32 \321\300\1\x81\206\41 386,SM +XOR mem,imm16 \320\300\134\1\x81\206\131 8086,SM,ND +XOR mem,imm32 \321\300\144\1\x81\206\141 386,SM,ND CMOVcc reg16,mem \320\301\1\x0F\330\x40\110 P6,SM CMOVcc reg16,reg16 \320\301\1\x0F\330\x40\110 P6 CMOVcc reg32,mem \321\301\1\x0F\330\x40\110 P6,SM @@ -1113,8 +1124,11 @@ CMOVcc reg32,reg32 \321\301\1\x0F\330\x40\110 P6 Jcc imm|near \322\1\x0F\330\x80\64 386 Jcc imm16|near \320\1\x0F\330\x80\64 386 Jcc imm32|near \321\1\x0F\330\x80\64 386 -Jcc imm \330\x70\50 8086 Jcc imm|short \330\x70\50 8086,ND +Jcc imm \370\330\x70\50 8086,ND +Jcc imm \1\x0F\330\x80\64 386,ND +Jcc imm \330\x71\373\1\xE9\64 8086,ND +Jcc imm \330\x70\50 8086 SETcc mem \300\1\x0F\330\x90\200 386,SB SETcc reg8 \300\1\x0F\330\x90\200 386 @@ -63,6 +63,8 @@ struct itemplate { #define IF_3DNOW 0x00008000UL /* it's a 3DNow! instruction */ #define IF_SSE 0x00010000UL /* it's a SSE (KNI, MMX2) instruction */ #define IF_PMASK 0xFF000000UL /* the mask for processor types */ +#define IF_PLEVEL 0x0F000000UL /* the mask for processor instr. level */ + /* also the highest possible processor */ #define IF_PFMASK 0xF001FF00UL /* the mask for disassembly "prefer" */ #define IF_8086 0x00000000UL /* 8086 instruction */ #define IF_186 0x01000000UL /* 186+ instruction */ @@ -18,15 +18,15 @@ */ #define islocal(l) ((l)[0] == '.' && (l)[1] != '.') -#define LABEL_BLOCK 320 /* no. of labels/block */ +#define LABEL_BLOCK 32 /* no. of labels/block */ #define LBLK_SIZE (LABEL_BLOCK*sizeof(union label)) -#define LABEL_HASHES 32 /* no. of hash table entries */ +#define LABEL_HASHES 37 /* no. of hash table entries */ -#define END_LIST -3 /* don't clash with NO_SEG! */ +#define END_LIST -3 /* don't clash with NO_SEG! */ #define END_BLOCK -2 #define BOGUS_VALUE -4 -#define PERMTS_SIZE 4096 /* size of text blocks */ +#define PERMTS_SIZE 4096 /* size of text blocks */ /* values for label.defn.is_global */ #define DEFINED_BIT 1 @@ -39,24 +39,26 @@ #define GLOBAL_PLACEHOLDER (GLOBAL_BIT) #define GLOBAL_SYMBOL (DEFINED_BIT|GLOBAL_BIT) -union label { /* actual label structures */ +union label { /* actual label structures */ struct { - long segment, offset; + long segment, offset; char *label, *special; - int is_global, is_norm; + int is_global, is_norm; } defn; struct { - long movingon, dummy; - union label *next; + long movingon, dummy; + union label *next; } admin; }; -struct permts { /* permanent text storage */ - struct permts *next; /* for the linked list */ - int size, usage; /* size and used space in ... */ - char data[PERMTS_SIZE]; /* ... the data block itself */ +struct permts { /* permanent text storage */ + struct permts *next; /* for the linked list */ + int size, usage; /* size and used space in ... */ + char data[PERMTS_SIZE]; /* ... the data block itself */ }; +extern int global_offset_changed; /* defined in nasm.c */ + static union label *ltab[LABEL_HASHES];/* using a hash table */ static union label *lfree[LABEL_HASHES];/* pointer into the above */ static struct permts *perm_head; /* start of perm. text storage */ @@ -82,9 +84,9 @@ static union label *find_label (char *label, int create) union label *lptr; if (islocal(label)) - prev = prevlabel; + prev = prevlabel; else - prev = ""; + prev = ""; prevlen = strlen(prev); p = prev; while (*p) hash += *p++; @@ -93,34 +95,34 @@ static union label *find_label (char *label, int create) hash %= LABEL_HASHES; lptr = ltab[hash]; while (lptr->admin.movingon != END_LIST) { - if (lptr->admin.movingon == END_BLOCK) { - lptr = lptr->admin.next; - if (!lptr) - break; - } - if (!strncmp(lptr->defn.label, prev, prevlen) && - !strcmp(lptr->defn.label+prevlen, label)) - return lptr; - lptr++; + if (lptr->admin.movingon == END_BLOCK) { + lptr = lptr->admin.next; + if (!lptr) + break; + } + if (!strncmp(lptr->defn.label, prev, prevlen) && + !strcmp(lptr->defn.label+prevlen, label)) + return lptr; + lptr++; } if (create) { - if (lfree[hash]->admin.movingon == END_BLOCK) { - /* - * must allocate a new block - */ - lfree[hash]->admin.next = (union label *) nasm_malloc (LBLK_SIZE); - lfree[hash] = lfree[hash]->admin.next; - init_block(lfree[hash]); - } - - lfree[hash]->admin.movingon = BOGUS_VALUE; - lfree[hash]->defn.label = perm_copy (prev, label); - lfree[hash]->defn.special = NULL; - lfree[hash]->defn.is_global = NOT_DEFINED_YET; - return lfree[hash]++; + if (lfree[hash]->admin.movingon == END_BLOCK) { + /* + * must allocate a new block + */ + lfree[hash]->admin.next = (union label *) nasm_malloc (LBLK_SIZE); + lfree[hash] = lfree[hash]->admin.next; + init_block(lfree[hash]); + } + + lfree[hash]->admin.movingon = BOGUS_VALUE; + lfree[hash]->defn.label = perm_copy (prev, label); + lfree[hash]->defn.special = NULL; + lfree[hash]->defn.is_global = NOT_DEFINED_YET; + return lfree[hash]++; } else - return NULL; + return NULL; } int lookup_label (char *label, long *segment, long *offset) @@ -128,16 +130,16 @@ int lookup_label (char *label, long *segment, long *offset) union label *lptr; if (!initialised) - return 0; + return 0; lptr = find_label (label, 0); if (lptr && (lptr->defn.is_global & DEFINED_BIT)) { - *segment = lptr->defn.segment; - *offset = lptr->defn.offset; - return 1; + *segment = lptr->defn.segment; + *offset = lptr->defn.offset; + return 1; } else - return 0; + return 0; } int is_extern (char *label) @@ -145,17 +147,17 @@ int is_extern (char *label) union label *lptr; if (!initialised) - return 0; + return 0; lptr = find_label (label, 0); if (lptr && (lptr->defn.is_global & EXTERN_BIT)) - return 1; + return 1; else - return 0; + return 0; } void redefine_label (char *label, long segment, long offset, char *special, - int is_norm, int isextrn, struct ofmt *ofmt, efunc error) + int is_norm, int isextrn, struct ofmt *ofmt, efunc error) { union label *lptr; @@ -165,51 +167,58 @@ void redefine_label (char *label, long segment, long offset, char *special, */ (void) segment; /* Don't warn that this parameter is unused */ - (void) offset; /* Don't warn that this parameter is unused */ (void) special; /* Don't warn that this parameter is unused */ (void) is_norm; /* Don't warn that this parameter is unused */ (void) isextrn; /* Don't warn that this parameter is unused */ (void) ofmt; /* Don't warn that this parameter is unused */ #ifdef DEBUG +#if DEBUG<3 if (!strncmp(label, "debugdump", 9)) - fprintf(stderr, "debug: redefine_label (%s, %ld, %08lx, %s, %d, %d)\n", - label, segment, offset, special, is_norm, isextrn); +#endif + error(ERR_DEBUG, "redefine_label (%s, %ld, %08lx, %s, %d, %d)", + label, segment, offset, special, is_norm, isextrn); #endif + lptr = find_label (label, 1); + if (!lptr) + error (ERR_PANIC, "can't find label `%s' on pass two", label); + if (!islocal(label)) { - lptr = find_label (label, 1); - if (!lptr) - error (ERR_PANIC, "can't find label `%s' on pass two", label); - if (*label != '.' && lptr->defn.is_norm) - prevlabel = lptr->defn.label; + if (*label != '.' && lptr->defn.is_norm) + prevlabel = lptr->defn.label; } + + global_offset_changed |= (lptr->defn.offset != offset); + lptr->defn.offset = offset; } void define_label (char *label, long segment, long offset, char *special, - int is_norm, int isextrn, struct ofmt *ofmt, efunc error) + int is_norm, int isextrn, struct ofmt *ofmt, efunc error) { union label *lptr; #ifdef DEBUG +#if DEBUG<3 if (!strncmp(label, "debugdump", 9)) - fprintf(stderr, "debug: define_label (%s, %ld, %08lx, %s, %d, %d)\n", - label, segment, offset, special, is_norm, isextrn); +#endif + error(ERR_DEBUG, "define_label (%s, %ld, %08lx, %s, %d, %d)", + label, segment, offset, special, is_norm, isextrn); #endif lptr = find_label (label, 1); if (lptr->defn.is_global & DEFINED_BIT) { - error(ERR_NONFATAL, "symbol `%s' redefined", label); - return; + error(ERR_NONFATAL, "symbol `%s' redefined", label); + return; } lptr->defn.is_global |= DEFINED_BIT; if (isextrn) - lptr->defn.is_global |= EXTERN_BIT; + lptr->defn.is_global |= EXTERN_BIT; if (label[0] != '.' && is_norm) /* not local, but not special either */ - prevlabel = lptr->defn.label; + prevlabel = lptr->defn.label; else if (label[0] == '.' && label[1] != '.' && !*prevlabel) - error(ERR_NONFATAL, "attempt to define a local label before any" - " non-local labels"); + error(ERR_NONFATAL, "attempt to define a local label before any" + " non-local labels"); lptr->defn.segment = segment; lptr->defn.offset = offset; @@ -217,39 +226,39 @@ void define_label (char *label, long segment, long offset, char *special, if ( (lptr->defn.is_global & (GLOBAL_BIT|EXTERN_BIT)) != EXTERN_BIT ) { ofmt->symdef (lptr->defn.label, segment, offset, - !!(lptr->defn.is_global & GLOBAL_BIT), - special ? special : lptr->defn.special); + !!(lptr->defn.is_global & GLOBAL_BIT), + special ? special : lptr->defn.special); ofmt->current_dfmt->debug_deflabel (label, segment, offset, - !!(lptr->defn.is_global & GLOBAL_BIT), - special ? special : lptr->defn.special); + !!(lptr->defn.is_global & GLOBAL_BIT), + special ? special : lptr->defn.special); } } void define_common (char *label, long segment, long size, char *special, - struct ofmt *ofmt, efunc error) + struct ofmt *ofmt, efunc error) { union label *lptr; lptr = find_label (label, 1); if (lptr->defn.is_global & DEFINED_BIT) { - error(ERR_NONFATAL, "symbol `%s' redefined", label); - return; + error(ERR_NONFATAL, "symbol `%s' redefined", label); + return; } lptr->defn.is_global |= DEFINED_BIT; - if (label[0] != '.') /* not local, but not special either */ - prevlabel = lptr->defn.label; + if (label[0] != '.') /* not local, but not special either */ + prevlabel = lptr->defn.label; else - error(ERR_NONFATAL, "attempt to define a local label as a " - "common variable"); + error(ERR_NONFATAL, "attempt to define a local label as a " + "common variable"); lptr->defn.segment = segment; lptr->defn.offset = 0; ofmt->symdef (lptr->defn.label, segment, size, 2, - special ? special : lptr->defn.special); + special ? special : lptr->defn.special); ofmt->current_dfmt->debug_deflabel(lptr->defn.label, segment, size, 2, - special ? special : lptr->defn.special); + special ? special : lptr->defn.special); } void declare_as_global (char *label, char *special, efunc error) @@ -257,24 +266,24 @@ void declare_as_global (char *label, char *special, efunc error) union label *lptr; if (islocal(label)) { - error(ERR_NONFATAL, "attempt to declare local symbol `%s' as" - " global", label); - return; + error(ERR_NONFATAL, "attempt to declare local symbol `%s' as" + " global", label); + return; } lptr = find_label (label, 1); switch (lptr->defn.is_global & TYPE_MASK) { case NOT_DEFINED_YET: - lptr->defn.is_global = GLOBAL_PLACEHOLDER; - lptr->defn.special = special ? perm_copy(special, "") : NULL; - break; - case GLOBAL_PLACEHOLDER: /* already done: silently ignore */ + lptr->defn.is_global = GLOBAL_PLACEHOLDER; + lptr->defn.special = special ? perm_copy(special, "") : NULL; + break; + case GLOBAL_PLACEHOLDER: /* already done: silently ignore */ case GLOBAL_SYMBOL: - break; + break; case LOCAL_SYMBOL: - if (!lptr->defn.is_global & EXTERN_BIT) - error(ERR_NONFATAL, "symbol `%s': GLOBAL directive must" - " appear before symbol definition", label); - break; + if (!lptr->defn.is_global & EXTERN_BIT) + error(ERR_NONFATAL, "symbol `%s': GLOBAL directive must" + " appear before symbol definition", label); + break; } } @@ -283,18 +292,18 @@ int init_labels (void) int i; for (i=0; i<LABEL_HASHES; i++) { - ltab[i] = (union label *) nasm_malloc (LBLK_SIZE); - if (!ltab[i]) - return -1; /* can't initialise, panic */ - init_block (ltab[i]); - lfree[i] = ltab[i]; + ltab[i] = (union label *) nasm_malloc (LBLK_SIZE); + if (!ltab[i]) + return -1; /* can't initialise, panic */ + init_block (ltab[i]); + lfree[i] = ltab[i]; } perm_head = - perm_tail = (struct permts *) nasm_malloc (sizeof(struct permts)); + perm_tail = (struct permts *) nasm_malloc (sizeof(struct permts)); if (!perm_head) - return -1; + return -1; perm_head->next = NULL; perm_head->size = PERMTS_SIZE; @@ -314,22 +323,22 @@ void cleanup_labels (void) initialised = FALSE; for (i=0; i<LABEL_HASHES; i++) { - union label *lptr, *lhold; + union label *lptr, *lhold; - lptr = lhold = ltab[i]; + lptr = lhold = ltab[i]; - while (lptr) { - while (lptr->admin.movingon != END_BLOCK) lptr++; - lptr = lptr->admin.next; - nasm_free (lhold); - lhold = lptr; - } + while (lptr) { + while (lptr->admin.movingon != END_BLOCK) lptr++; + lptr = lptr->admin.next; + nasm_free (lhold); + lhold = lptr; + } } while (perm_head) { - perm_tail = perm_head; - perm_head = perm_head->next; - nasm_free (perm_tail); + perm_tail = perm_head; + perm_head = perm_head->next; + nasm_free (perm_tail); } } @@ -338,7 +347,7 @@ static void init_block (union label *blk) int j; for (j=0; j<LABEL_BLOCK-1; j++) - blk[j].admin.movingon = END_LIST; + blk[j].admin.movingon = END_LIST; blk[LABEL_BLOCK-1].admin.movingon = END_BLOCK; blk[LABEL_BLOCK-1].admin.next = NULL; } @@ -349,11 +358,11 @@ static char *perm_copy (char *string1, char *string2) int len = strlen(string1)+strlen(string2)+1; if (perm_tail->size - perm_tail->usage < len) { - perm_tail->next = (struct permts *)nasm_malloc(sizeof(struct permts)); - perm_tail = perm_tail->next; - perm_tail->next = NULL; - perm_tail->size = PERMTS_SIZE; - perm_tail->usage = 0; + perm_tail->next = (struct permts *)nasm_malloc(sizeof(struct permts)); + perm_tail = perm_tail->next; + perm_tail->next = NULL; + perm_tail->size = PERMTS_SIZE; + perm_tail->usage = 0; } p = q = perm_tail->data + perm_tail->usage; while ( (*q = *string1++) ) q++; @@ -57,6 +57,12 @@ static char *stdmac[] = { "%imacro bits 1+.nolist", "[bits %1]", "%endmacro", + "%imacro use16 0.nolist", + "[bits 16]", + "%endmacro", + "%imacro use32 0.nolist", + "[bits 32]", + "%endmacro", "%imacro global 1-*.nolist", "%rep %0", "[global %1]", @@ -69,5 +75,8 @@ static char *stdmac[] = { "%rotate 1", "%endrep", "%endmacro", + "%imacro cpu 1+.nolist", + "[cpu %1]", + "%endmacro", NULL }; diff --git a/makedist.sh b/makedist.sh index 5b7abfc..78f078a 100755 --- a/makedist.sh +++ b/makedist.sh @@ -2,7 +2,7 @@ MAJORVER=`grep NASM_MAJOR_VER nasm.h | head -1 | cut -f3 -d' '` MINORVER=`grep NASM_MINOR_VER nasm.h | head -1 | cut -f3 -d' '` -VERSION="${MAJORVER}.${MINORVER}" +VERSION=`grep NASM_VER nasm.h | head -1 | cut -f3 -d' ' | sed s/\"//g` DOSVERSION="${MAJORVER}${MINORVER}" NASM_TAR_GZ=dist/nasm-${VERSION}.tar.gz NASM_ZIP=dist/nasm${DOSVERSION}s.zip @@ -15,7 +15,7 @@ if [ ! -d dist ]; then mkdir dist; fi if [ -f dist/nasm.tar.gz ]; then rm dist/nasm.tar.gz; fi mkdir nasm-${VERSION} (cd nasm-${VERSION}; ln -s ../* .; - rm -f nasm-${VERSION} dist Checklist GNUmakefile z*) + rm -f nasm-${VERSION} dist Checklist GNUmakefile) find nasm-${VERSION}/ -follow -name GNUmakefile > tar-exclude find nasm-${VERSION}/ -follow -name RCS >> tar-exclude find nasm-${VERSION}/ -follow -name '*.exe' >> tar-exclude @@ -14,6 +14,7 @@ #include "nasm.h" #include "nasmlib.h" +#include "insns.h" #include "preproc.h" #include "parser.h" #include "eval.h" @@ -27,6 +28,8 @@ struct forwrefinfo { /* info held on forward refs. */ int operand; }; +static int get_bits (char *value); +static unsigned long get_cpu (char *cpu_str); static void report_error (int, char *, ...); static void parse_cmdline (int, char **); static void assemble_file (char *); @@ -40,13 +43,17 @@ static char inname[FILENAME_MAX]; static char outname[FILENAME_MAX]; static char listname[FILENAME_MAX]; static int globallineno; /* for forward-reference tracking */ -static int pass; +static int pass = 0; static struct ofmt *ofmt = NULL; static FILE *error_file; /* Where to write error messages */ static FILE *ofile = NULL; -static int sb = 16; /* by default */ +static int optimizing = 10; /* number of optimization passes to take */ +static int sb, cmd_sb = 16; /* by default */ +static unsigned long cmd_cpu = IF_PLEVEL; /* highest level by default */ +static unsigned long cpu = IF_PLEVEL; /* passed to insn_size & assemble.c */ +int global_offset_changed; /* referenced in labels.c */ static loc_t location; int in_abs_seg; /* Flag we are in ABSOLUTE seg */ @@ -73,7 +80,7 @@ static enum op_type operating_mode; * doesn't do anything. Initial defaults are given here. */ static char suppressed[1+ERR_WARN_MAX] = { - 0, TRUE, TRUE, FALSE + 0, TRUE, TRUE, TRUE, FALSE }; /* @@ -81,7 +88,7 @@ static char suppressed[1+ERR_WARN_MAX] = { * zero does nothing. */ static char *suppressed_names[1+ERR_WARN_MAX] = { - NULL, "macro-params", "orphan-labels", "number-overflow" + NULL, "macro-params", "macro-selfref", "orphan-labels", "number-overflow", }; /* @@ -89,7 +96,9 @@ static char *suppressed_names[1+ERR_WARN_MAX] = { * zero does nothing. */ static char *suppressed_what[1+ERR_WARN_MAX] = { - NULL, "macro calls with wrong no. of params", + NULL, + "macro calls with wrong no. of params", + "cyclic macro self-references", "labels alone on lines without trailing `:'", "numeric constants greater than 0xFFFFFFFF" }; @@ -112,9 +121,9 @@ static Preproc no_pp = { /* * get/set current offset... */ -#define get_curr_ofs (in_abs_seg?abs_offset:\ +#define GET_CURR_OFFS (in_abs_seg?abs_offset:\ raa_read(offsets,location.segment)) -#define set_curr_ofs(x) (in_abs_seg?(void)(abs_offset=(x)):\ +#define SET_CURR_OFFS(x) (in_abs_seg?(void)(abs_offset=(x)):\ (void)(offsets=raa_write(offsets,location.segment,(x)))) static int want_usage; @@ -160,6 +169,13 @@ int main(int argc, char **argv) parser_global_info (ofmt, &location); eval_global_info (ofmt, lookup_label, &location); + /* define some macros dependent of command-line */ + { + char temp [64]; + sprintf (temp, "__OUTPUT_FORMAT__=%s\n", ofmt->shortname); + pp_pre_define (temp); + } + switch ( operating_mode ) { case op_depend: { @@ -193,6 +209,7 @@ int main(int argc, char **argv) location.known = FALSE; + pass = 1; preproc->reset (inname, 2, report_error, evaluate, &nasmlist); while ( (line = preproc->getline()) ) { /* @@ -253,9 +270,7 @@ int main(int argc, char **argv) if (!terminate_after_phase) { ofmt->cleanup (using_debug_info); cleanup_labels (); - } - else { - + } else { /* * We had an fclose on the output file here, but we * actually do that in all the object file drivers as well, @@ -330,6 +345,7 @@ static int process_arg (char *p, char *q) error_file = stdout; break; case 'o': /* these parameters take values */ + case 'O': case 'f': case 'p': case 'd': @@ -352,6 +368,12 @@ static int process_arg (char *p, char *q) } else ofmt->current_dfmt = ofmt->debug_formats[0]; + } else if (p[1]=='O') { /* Optimization level */ + if (!isdigit(*param)) report_error(ERR_FATAL, + "command line optimization level must be 0..3"); + optimizing = atoi(param); + if (optimizing <= 0) optimizing = 0; + else if (optimizing <= 3) optimizing *= 5; /* 5 passes for each level */ } else if (p[1]=='P' || p[1]=='p') { /* pre-include */ pp_pre_include (param); } else if (p[1]=='D' || p[1]=='d') { /* pre-define */ @@ -396,6 +418,7 @@ static int process_arg (char *p, char *q) " -g enable debug info\n" " -F format select a debugging format\n\n" " -I<path> adds a pathname to the include file path\n" + " -O<digit> optimize branch offsets -O0 disables, -O2 default\n" " -P<file> pre-includes a file\n" " -D<macro>[=<value>] pre-defines a macro\n" " -U<macro> undefines a macro\n" @@ -579,13 +602,14 @@ static void parse_cmdline(int argc, char **argv) int i; argv++; if (!stopoptions && argv[0][0] == '-' && argv[0][1] == '@') { - if ((p = get_param (argv[0], argc > 1 ? argv[1] : NULL, &i))) + if ((p = get_param (argv[0], argc > 1 ? argv[1] : NULL, &i))) { if ((rfile = fopen(p, "r"))) { process_respfile (rfile); fclose(rfile); } else report_error (ERR_NONFATAL | ERR_NOFILE | ERR_USAGE, "unable to open response file `%s'", p); + } } else i = process_arg (argv[0], argc > 1 ? argv[1] : NULL); argv += i, argc -= i; @@ -596,6 +620,7 @@ static void parse_cmdline(int argc, char **argv) "no input file specified"); } + static void assemble_file (char *fname) { char * value, * p, * q, * special, * line, debugid[80]; @@ -604,529 +629,493 @@ static void assemble_file (char *fname) long seg, offs; struct tokenval tokval; expr * e; + int pass_max; + int pass_cnt = 0; /* count actual passes */ - /* - * pass one - */ - pass = 1; - in_abs_seg = FALSE; - location.segment = ofmt->section(NULL, pass, &sb); - preproc->reset(fname, 1, report_error, evaluate, &nasmlist); - globallineno = 0; - location.known = TRUE; - location.offset = offs = get_curr_ofs; - - while ( (line = preproc->getline()) ) - { - globallineno++; - - /* here we parse our directives; this is not handled by the 'real' - * parser. */ - if ( (i = getkw (line, &value)) ) - { - switch (i) { - case 1: /* [SEGMENT n] */ - seg = ofmt->section (value, pass, &sb); - if (seg == NO_SEG) { - report_error (ERR_NONFATAL, - "segment name `%s' not recognised", - value); - } else { - in_abs_seg = FALSE; - location.segment = seg; - } - break; - case 2: /* [EXTERN label:special] */ - if (*value == '$') - value++; /* skip initial $ if present */ - q = value; - validid = TRUE; - if (!isidstart(*q)) - validid = FALSE; - while (*q && *q != ':') { - if (!isidchar(*q)) - validid = FALSE; - q++; - } - if (!validid) { - report_error (ERR_NONFATAL, - "identifier expected after EXTERN"); - break; - } - if (*q == ':') { - *q++ = '\0'; - special = q; - } else - special = NULL; - if (!is_extern(value)) { /* allow re-EXTERN to be ignored */ - declare_as_global (value, special, report_error); - define_label (value, seg_alloc(), 0L, NULL, FALSE, TRUE, - ofmt, report_error); - } - break; - case 3: /* [BITS bits] */ - switch (atoi(value)) { - case 16: - case 32: - sb = atoi(value); - break; - default: - report_error(ERR_NONFATAL, - "`%s' is not a valid argument to [BITS]", - value); - break; - } - break; - case 4: /* [GLOBAL symbol:special] */ - if (*value == '$') - value++; /* skip initial $ if present */ - q = value; - validid = TRUE; - if (!isidstart(*q)) - validid = FALSE; - while (*q && *q != ':') { - if (!isidchar(*q)) - validid = FALSE; - q++; - } - if (!validid) { - report_error (ERR_NONFATAL, - "identifier expected after GLOBAL"); - break; - } - if (*q == ':') { - *q++ = '\0'; - special = q; - } else - special = NULL; - declare_as_global (value, special, report_error); - break; - case 5: /* [COMMON symbol size:special] */ - p = value; - validid = TRUE; - if (!isidstart(*p)) - validid = FALSE; - while (*p && !isspace(*p)) { - if (!isidchar(*p)) - validid = FALSE; - p++; - } - if (!validid) { - report_error (ERR_NONFATAL, - "identifier expected after COMMON"); - break; - } - if (*p) { - long size; - - while (*p && isspace(*p)) - *p++ = '\0'; - q = p; - while (*q && *q != ':') - q++; - if (*q == ':') { - *q++ = '\0'; - special = q; - } else - special = NULL; - size = readnum (p, &rn_error); - if (rn_error) - report_error (ERR_NONFATAL, "invalid size specified" - " in COMMON declaration"); - else - define_common (value, seg_alloc(), size, - special, ofmt, report_error); - } else - report_error (ERR_NONFATAL, "no size specified in" - " COMMON declaration"); - break; - case 6: /* [ABSOLUTE address] */ - stdscan_reset(); - stdscan_bufptr = value; - tokval.t_type = TOKEN_INVALID; - e = evaluate(stdscan, NULL, &tokval, NULL, 1, report_error, - NULL); - if (e) { - if (!is_reloc(e)) - report_error (ERR_NONFATAL, "cannot use non-" - "relocatable expression as ABSOLUTE" - " address"); - else { - abs_seg = reloc_seg(e); - abs_offset = reloc_value(e); - } - } else - abs_offset = 0x100;/* don't go near zero in case of / */ - in_abs_seg = TRUE; - location.segment = abs_seg; - break; - case 7: - p = value; - validid = TRUE; - if (!isidstart(*p)) - validid = FALSE; - while (*p && !isspace(*p)) { - if (!isidchar(*p)) - validid = FALSE; - p++; - } - if (!validid) { - report_error (ERR_NONFATAL, - "identifier expected after DEBUG"); - break; - } - while (*p && isspace(*p)) p++; - break; - default: - if (!ofmt->directive (line+1, value, 1)) - report_error (ERR_NONFATAL, "unrecognised directive [%s]", - line+1); - break; - } - } - else /* it isn't a directive */ - { - parse_line (1, line, &output_ins, - report_error, evaluate, define_label); - - if (output_ins.forw_ref) - { - for(i = 0; i < output_ins.operands; i++) - { - if (output_ins.oprs[i].opflags & OPFLAG_FORWARD) - { - struct forwrefinfo *fwinf = - (struct forwrefinfo *)saa_wstruct(forwrefs); - fwinf->lineno = globallineno; - fwinf->operand = i; - } - } - } + if (cmd_sb == 32 && cmd_cpu < IF_386) + report_error(ERR_FATAL, "command line: " + "32-bit segment size requires a higher cpu"); - if (output_ins.opcode == I_EQU) - { - /* - * Special `..' EQUs get processed in pass two, - * except `..@' macro-processor EQUs which are done - * in the normal place. - */ - if (!output_ins.label) - report_error (ERR_NONFATAL, - "EQU not preceded by label"); - - else if (output_ins.label[0] != '.' || - output_ins.label[1] != '.' || - output_ins.label[2] == '@') - { - if (output_ins.operands == 1 && - (output_ins.oprs[0].type & IMMEDIATE) && - output_ins.oprs[0].wrt == NO_SEG) - { - int isext = output_ins.oprs[0].opflags & OPFLAG_EXTERN; - define_label (output_ins.label, - output_ins.oprs[0].segment, - output_ins.oprs[0].offset, - NULL, FALSE, isext, ofmt, report_error); - } - else if (output_ins.operands == 2 && - (output_ins.oprs[0].type & IMMEDIATE) && - (output_ins.oprs[0].type & COLON) && - output_ins.oprs[0].segment == NO_SEG && - output_ins.oprs[0].wrt == NO_SEG && - (output_ins.oprs[1].type & IMMEDIATE) && - output_ins.oprs[1].segment == NO_SEG && - output_ins.oprs[1].wrt == NO_SEG) - { - define_label (output_ins.label, - output_ins.oprs[0].offset | SEG_ABS, - output_ins.oprs[1].offset, - NULL, FALSE, FALSE, ofmt, report_error); - } - else - report_error(ERR_NONFATAL, "bad syntax for EQU"); - } - } - else /* instruction isn't an EQU */ - { - long l = insn_size (location.segment, offs, sb, - &output_ins, report_error); - if (using_debug_info && output_ins.opcode != -1) { - /* this is done here so we can do debug type info */ - long typeinfo = TYS_ELEMENTS(output_ins.operands); - switch (output_ins.opcode) { - case I_RESB: - typeinfo = TYS_ELEMENTS(output_ins.oprs[0].offset) | TY_BYTE; - break; - case I_RESW: - typeinfo = TYS_ELEMENTS(output_ins.oprs[0].offset) | TY_WORD; - break; - case I_RESD: - typeinfo = TYS_ELEMENTS(output_ins.oprs[0].offset) | TY_DWORD; - break; - case I_RESQ: - typeinfo = TYS_ELEMENTS(output_ins.oprs[0].offset) | TY_QWORD; - break; - case I_REST: - typeinfo = TYS_ELEMENTS(output_ins.oprs[0].offset) | TY_TBYTE; - break; - case I_DB: - typeinfo |= TY_BYTE; - break; - case I_DW: - typeinfo |= TY_WORD; - break; - case I_DD: - if (output_ins.eops_float) - typeinfo |= TY_FLOAT; - else - typeinfo |= TY_DWORD; - break; - case I_DQ: - typeinfo |= TY_QWORD; - break; - case I_DT: - typeinfo |= TY_TBYTE; - break; - default: - typeinfo = TY_LABEL; - } - ofmt->current_dfmt->debug_typevalue(typeinfo); - } - if (l != -1) { - offs += l; - set_curr_ofs (offs); - } - /* - * else l == -1 => invalid instruction, which will be - * flagged as an error on pass 2 - */ - } - cleanup_insn (&output_ins); - } - nasm_free (line); - location.offset = offs = get_curr_ofs; - } - - preproc->cleanup(); - - if (terminate_after_phase) { - fclose(ofile); - remove(outname); - if (want_usage) - usage(); - exit (1); - } + pass_max = optimizing + 2; /* passes 1, optimizing, then 2 */ + for (pass = 1; pass <= pass_max; pass++) { + int pass1, pass2; + ldfunc def_label; - /* - * pass two - */ - - pass = 2; - saa_rewind (forwrefs); - if (*listname) - nasmlist.init(listname, report_error); - forwref = saa_rstruct (forwrefs); - in_abs_seg = FALSE; - location.segment = ofmt->section(NULL, pass, &sb); - raa_free (offsets); - offsets = raa_init(); - preproc->reset(fname, 2, report_error, evaluate, &nasmlist); - globallineno = 0; - location.offset = offs = get_curr_ofs; - - while ( (line = preproc->getline()) ) - { - globallineno++; - - /* here we parse our directives; this is not handled by - * the 'real' parser. */ - if ( (i = getkw (line, &value)) ) { - switch (i) { - case 1: /* [SEGMENT n] */ - seg = ofmt->section (value, pass, &sb); - if (seg == NO_SEG) { - report_error (ERR_PANIC, - "invalid segment name on pass two"); - } else - in_abs_seg = FALSE; - location.segment = seg; - break; - case 2: /* [EXTERN label] */ - q = value; - while (*q && *q != ':') - q++; - if (*q == ':') { - *q++ = '\0'; - ofmt->symdef(value, 0L, 0L, 3, q); - } - break; - case 3: /* [BITS bits] */ - switch (atoi(value)) { - case 16: - case 32: - sb = atoi(value); - break; - default: - report_error(ERR_PANIC, - "invalid [BITS] value on pass two", - value); - break; - } - break; - case 4: /* [GLOBAL symbol] */ - q = value; - while (*q && *q != ':') - q++; - if (*q == ':') { - *q++ = '\0'; - ofmt->symdef(value, 0L, 0L, 3, q); - } - break; - case 5: /* [COMMON symbol size] */ - q = value; - while (*q && *q != ':') { - if (isspace(*q)) - *q = '\0'; - q++; - } - if (*q == ':') { - *q++ = '\0'; - ofmt->symdef(value, 0L, 0L, 3, q); - } - break; - case 6: /* [ABSOLUTE addr] */ - stdscan_reset(); - stdscan_bufptr = value; - tokval.t_type = TOKEN_INVALID; - e = evaluate(stdscan, NULL, &tokval, NULL, 2, report_error, - NULL); - if (e) { - if (!is_reloc(e)) - report_error (ERR_PANIC, "non-reloc ABSOLUTE address" - " in pass two"); - else { - abs_seg = reloc_seg(e); - abs_offset = reloc_value(e); - } - } else - report_error (ERR_PANIC, "invalid ABSOLUTE address " - "in pass two"); - in_abs_seg = TRUE; - location.segment = abs_seg; - break; - case 7: - p = value; - q = debugid; - validid = TRUE; - if (!isidstart(*p)) - validid = FALSE; - while (*p && !isspace(*p)) { - if (!isidchar(*p)) - validid = FALSE; - *q++ = *p++; - } - *q++ = 0; - if (!validid) { - report_error (ERR_PANIC, - "identifier expected after DEBUG in pass 2"); - break; - } - while (*p && isspace(*p)) - p++; - ofmt->current_dfmt->debug_directive (debugid, p); - break; - default: - if (!ofmt->directive (line+1, value, 2)) - report_error (ERR_PANIC, "invalid directive on pass two"); - break; - } - } - else /* not a directive */ - { - parse_line (2, line, &output_ins, - report_error, evaluate, redefine_label); - if (forwref != NULL && globallineno == forwref->lineno) { - output_ins.forw_ref = TRUE; - do { - output_ins.oprs[forwref->operand].opflags|= OPFLAG_FORWARD; - forwref = saa_rstruct (forwrefs); - } while (forwref != NULL && forwref->lineno == globallineno); - } else - output_ins.forw_ref = FALSE; - - /* - * Hack to prevent phase error in the code - * rol ax,x - * x equ 1 - * - * If the second operand is a forward reference, - * the UNITY property of the number 1 in that - * operand is cancelled. Otherwise the above - * sequence will cause a phase error. - * - * This hack means that the above code will - * generate 286+ code. - * - * The forward reference will mean that the - * operand will not have the UNITY property on - * the first pass, so the pass behaviours will - * be consistent. - */ - - if (output_ins.forw_ref && - output_ins.operands >= 2 && - (output_ins.oprs[1].opflags & OPFLAG_FORWARD)) - { - output_ins.oprs[1].type &= ~ONENESS; - } + pass1 = pass < pass_max ? 1 : 2; /* seq is 1, 1, 1,..., 1, 2 */ + pass2 = pass > 1 ? 2 : 1; /* seq is 1, 2, 2,..., 2, 2 */ + def_label = pass > 1 ? redefine_label : define_label; + - if (output_ins.opcode == I_EQU) - { - /* - * Special `..' EQUs get processed here, except - * `..@' macro processor EQUs which are done above. - */ - if (output_ins.label[0] == '.' && - output_ins.label[1] == '.' && - output_ins.label[2] != '@') - { - if (output_ins.operands == 1 && - (output_ins.oprs[0].type & IMMEDIATE)) { - define_label (output_ins.label, - output_ins.oprs[0].segment, - output_ins.oprs[0].offset, - NULL, FALSE, FALSE, ofmt, report_error); - } - else if (output_ins.operands == 2 && - (output_ins.oprs[0].type & IMMEDIATE) && - (output_ins.oprs[0].type & COLON) && - output_ins.oprs[0].segment == NO_SEG && - (output_ins.oprs[1].type & IMMEDIATE) && - output_ins.oprs[1].segment == NO_SEG) - { - define_label (output_ins.label, - output_ins.oprs[0].offset | SEG_ABS, - output_ins.oprs[1].offset, - NULL, FALSE, FALSE, ofmt, report_error); - } - else - report_error(ERR_NONFATAL, "bad syntax for EQU"); - } - } - offs += assemble (location.segment, offs, sb, - &output_ins, ofmt, report_error, &nasmlist); - cleanup_insn (&output_ins); - set_curr_ofs (offs); - } + sb = cmd_sb; /* set 'bits' to command line default */ + cpu = cmd_cpu; + if (pass == pass_max) { + if (*listname) + nasmlist.init(listname, report_error); + } + in_abs_seg = FALSE; + global_offset_changed = FALSE; /* set by redefine_label */ + location.segment = ofmt->section(NULL, pass2, &sb); + if (pass > 1) { + saa_rewind (forwrefs); + forwref = saa_rstruct (forwrefs); + raa_free (offsets); + offsets = raa_init(); + } + preproc->reset(fname, pass1, report_error, evaluate, &nasmlist); + globallineno = 0; + if (pass == 1) location.known = TRUE; + location.offset = offs = GET_CURR_OFFS; - nasm_free (line); + while ( (line = preproc->getline()) ) + { + globallineno++; + + /* here we parse our directives; this is not handled by the 'real' + * parser. */ + if ( (i = getkw (line, &value)) ) + { + switch (i) { + case 1: /* [SEGMENT n] */ + seg = ofmt->section (value, pass2, &sb); + if (seg == NO_SEG) { + report_error (pass1==1 ? ERR_NONFATAL : ERR_PANIC, + "segment name `%s' not recognised", + value); + } else { + in_abs_seg = FALSE; + location.segment = seg; + } + break; + case 2: /* [EXTERN label:special] */ + if (pass == pass_max) { + q = value; + while (*q && *q != ':') + q++; + if (*q == ':') { + *q++ = '\0'; + ofmt->symdef(value, 0L, 0L, 3, q); + } + } else if (pass == 1) { /* pass == 1 */ + if (*value == '$') + value++; /* skip initial $ if present */ + q = value; + validid = TRUE; + if (!isidstart(*q)) + validid = FALSE; + while (*q && *q != ':') { + if (!isidchar(*q)) + validid = FALSE; + q++; + } + if (!validid) { + report_error (ERR_NONFATAL, + "identifier expected after EXTERN"); + break; + } + if (*q == ':') { + *q++ = '\0'; + special = q; + } else + special = NULL; + if (!is_extern(value)) { /* allow re-EXTERN to be ignored */ + declare_as_global (value, special, report_error); + define_label (value, seg_alloc(), 0L, NULL, FALSE, TRUE, + ofmt, report_error); + } + } /* else pass == 1 */ + break; + case 3: /* [BITS bits] */ + sb = get_bits(value); + break; + case 4: /* [GLOBAL symbol:special] */ + if (pass == pass_max) { /* pass 2 */ + q = value; + while (*q && *q != ':') + q++; + if (*q == ':') { + *q++ = '\0'; + ofmt->symdef(value, 0L, 0L, 3, q); + } + } else if (pass == 1) { /* pass == 1 */ + if (*value == '$') + value++; /* skip initial $ if present */ + q = value; + validid = TRUE; + if (!isidstart(*q)) + validid = FALSE; + while (*q && *q != ':') { + if (!isidchar(*q)) + validid = FALSE; + q++; + } + if (!validid) { + report_error (ERR_NONFATAL, + "identifier expected after GLOBAL"); + break; + } + if (*q == ':') { + *q++ = '\0'; + special = q; + } else + special = NULL; + declare_as_global (value, special, report_error); + } /* pass == 1 */ + break; + case 5: /* [COMMON symbol size:special] */ + if (pass == 1) { + p = value; + validid = TRUE; + if (!isidstart(*p)) + validid = FALSE; + while (*p && !isspace(*p)) { + if (!isidchar(*p)) + validid = FALSE; + p++; + } + if (!validid) { + report_error (ERR_NONFATAL, + "identifier expected after COMMON"); + break; + } + if (*p) { + long size; + + while (*p && isspace(*p)) + *p++ = '\0'; + q = p; + while (*q && *q != ':') + q++; + if (*q == ':') { + *q++ = '\0'; + special = q; + } else + special = NULL; + size = readnum (p, &rn_error); + if (rn_error) + report_error (ERR_NONFATAL, "invalid size specified" + " in COMMON declaration"); + else + define_common (value, seg_alloc(), size, + special, ofmt, report_error); + } else + report_error (ERR_NONFATAL, "no size specified in" + " COMMON declaration"); + } else if (pass == pass_max) { /* pass == 2 */ + q = value; + while (*q && *q != ':') { + if (isspace(*q)) + *q = '\0'; + q++; + } + if (*q == ':') { + *q++ = '\0'; + ofmt->symdef(value, 0L, 0L, 3, q); + } + } + break; + case 6: /* [ABSOLUTE address] */ + stdscan_reset(); + stdscan_bufptr = value; + tokval.t_type = TOKEN_INVALID; + e = evaluate(stdscan, NULL, &tokval, NULL, pass2, report_error, + NULL); + if (e) { + if (!is_reloc(e)) + report_error (pass==1 ? ERR_NONFATAL : ERR_PANIC, + "cannot use non-relocatable expression as " + "ABSOLUTE address"); + else { + abs_seg = reloc_seg(e); + abs_offset = reloc_value(e); + } + } else + if (pass==1) abs_offset = 0x100;/* don't go near zero in case of / */ + else report_error (ERR_PANIC, "invalid ABSOLUTE address " + "in pass two"); + in_abs_seg = TRUE; + location.segment = abs_seg; + break; + case 7: /* DEBUG */ + p = value; + q = debugid; + validid = TRUE; + if (!isidstart(*p)) + validid = FALSE; + while (*p && !isspace(*p)) { + if (!isidchar(*p)) + validid = FALSE; + *q++ = *p++; + } + *q++ = 0; + if (!validid) { + report_error (pass==1 ? ERR_NONFATAL : ERR_PANIC, + "identifier expected after DEBUG"); + break; + } + while (*p && isspace(*p)) p++; + if (pass==pass_max) ofmt->current_dfmt->debug_directive (debugid, p); + break; + case 8: /* [WARNING {+|-}warn-name] */ + if (pass1 == 1) { + while (*value && isspace(*value)) + value++; + + if (*value == '+' || *value == '-') { + validid = (*value == '-') ? TRUE : FALSE; + value++; + } else + validid = FALSE; + + for (i=1; i<=ERR_WARN_MAX; i++) + if (!nasm_stricmp(value, suppressed_names[i])) + break; + if (i <= ERR_WARN_MAX) + suppressed[i] = validid; + else + report_error (ERR_NONFATAL, "invalid warning id in WARNING directive"); + } + break; + case 9: /* cpu */ + cpu = get_cpu (value); + break; + default: + if (!ofmt->directive (line+1, value, pass1)) + report_error (pass1==1 ? ERR_NONFATAL : ERR_PANIC, + "unrecognised directive [%s]", + line+1); + break; + } + } + else /* it isn't a directive */ + { + parse_line (pass2, line, &output_ins, + report_error, evaluate, + def_label); + + if (!optimizing && pass == 2) { + if (forwref != NULL && globallineno == forwref->lineno) { + output_ins.forw_ref = TRUE; + do { + output_ins.oprs[forwref->operand].opflags|= OPFLAG_FORWARD; + forwref = saa_rstruct (forwrefs); + } while (forwref != NULL && forwref->lineno == globallineno); + } else + output_ins.forw_ref = FALSE; + } + + + if (!optimizing && output_ins.forw_ref) + { + if (pass == 1) { + for(i = 0; i < output_ins.operands; i++) + { + if (output_ins.oprs[i].opflags & OPFLAG_FORWARD) + { + struct forwrefinfo *fwinf = + (struct forwrefinfo *)saa_wstruct(forwrefs); + fwinf->lineno = globallineno; + fwinf->operand = i; + } + } + } else { /* pass == 2 */ + /* + * Hack to prevent phase error in the code + * rol ax,x + * x equ 1 + * + * If the second operand is a forward reference, + * the UNITY property of the number 1 in that + * operand is cancelled. Otherwise the above + * sequence will cause a phase error. + * + * This hack means that the above code will + * generate 286+ code. + * + * The forward reference will mean that the + * operand will not have the UNITY property on + * the first pass, so the pass behaviours will + * be consistent. + */ + + if (output_ins.operands >= 2 && + (output_ins.oprs[1].opflags & OPFLAG_FORWARD)) + { + output_ins.oprs[1].type &= ~(ONENESS|BYTENESS); + } + + } /* pass == 2 */ + + } /* forw_ref */ + + + if (output_ins.opcode == I_EQU) { + if (pass1 == 1) + { + /* + * Special `..' EQUs get processed in pass two, + * except `..@' macro-processor EQUs which are done + * in the normal place. + */ + if (!output_ins.label) + report_error (ERR_NONFATAL, + "EQU not preceded by label"); + + else if (output_ins.label[0] != '.' || + output_ins.label[1] != '.' || + output_ins.label[2] == '@') + { + if (output_ins.operands == 1 && + (output_ins.oprs[0].type & IMMEDIATE) && + output_ins.oprs[0].wrt == NO_SEG) + { + int isext = output_ins.oprs[0].opflags & OPFLAG_EXTERN; + def_label (output_ins.label, + output_ins.oprs[0].segment, + output_ins.oprs[0].offset, + NULL, FALSE, isext, ofmt, report_error); + } + else if (output_ins.operands == 2 && + (output_ins.oprs[0].type & IMMEDIATE) && + (output_ins.oprs[0].type & COLON) && + output_ins.oprs[0].segment == NO_SEG && + output_ins.oprs[0].wrt == NO_SEG && + (output_ins.oprs[1].type & IMMEDIATE) && + output_ins.oprs[1].segment == NO_SEG && + output_ins.oprs[1].wrt == NO_SEG) + { + def_label (output_ins.label, + output_ins.oprs[0].offset | SEG_ABS, + output_ins.oprs[1].offset, + NULL, FALSE, FALSE, ofmt, report_error); + } + else + report_error(ERR_NONFATAL, "bad syntax for EQU"); + } + } else { /* pass == 2 */ + /* + * Special `..' EQUs get processed here, except + * `..@' macro processor EQUs which are done above. + */ + if (output_ins.label[0] == '.' && + output_ins.label[1] == '.' && + output_ins.label[2] != '@') + { + if (output_ins.operands == 1 && + (output_ins.oprs[0].type & IMMEDIATE)) { + define_label (output_ins.label, + output_ins.oprs[0].segment, + output_ins.oprs[0].offset, + NULL, FALSE, FALSE, ofmt, report_error); + } + else if (output_ins.operands == 2 && + (output_ins.oprs[0].type & IMMEDIATE) && + (output_ins.oprs[0].type & COLON) && + output_ins.oprs[0].segment == NO_SEG && + (output_ins.oprs[1].type & IMMEDIATE) && + output_ins.oprs[1].segment == NO_SEG) + { + define_label (output_ins.label, + output_ins.oprs[0].offset | SEG_ABS, + output_ins.oprs[1].offset, + NULL, FALSE, FALSE, ofmt, report_error); + } + else + report_error(ERR_NONFATAL, "bad syntax for EQU"); + } + } /* pass == 2 */ + } else { /* instruction isn't an EQU */ + + if (pass1 == 1) { + long l = insn_size (location.segment, offs, sb, cpu, + &output_ins, report_error); + if (using_debug_info && output_ins.opcode != -1) { + /* this is done here so we can do debug type info */ + long typeinfo = TYS_ELEMENTS(output_ins.operands); + switch (output_ins.opcode) { + case I_RESB: + typeinfo = TYS_ELEMENTS(output_ins.oprs[0].offset) | TY_BYTE; + break; + case I_RESW: + typeinfo = TYS_ELEMENTS(output_ins.oprs[0].offset) | TY_WORD; + break; + case I_RESD: + typeinfo = TYS_ELEMENTS(output_ins.oprs[0].offset) | TY_DWORD; + break; + case I_RESQ: + typeinfo = TYS_ELEMENTS(output_ins.oprs[0].offset) | TY_QWORD; + break; + case I_REST: + typeinfo = TYS_ELEMENTS(output_ins.oprs[0].offset) | TY_TBYTE; + break; + case I_DB: + typeinfo |= TY_BYTE; + break; + case I_DW: + typeinfo |= TY_WORD; + break; + case I_DD: + if (output_ins.eops_float) + typeinfo |= TY_FLOAT; + else + typeinfo |= TY_DWORD; + break; + case I_DQ: + typeinfo |= TY_QWORD; + break; + case I_DT: + typeinfo |= TY_TBYTE; + break; + default: + typeinfo = TY_LABEL; + } + ofmt->current_dfmt->debug_typevalue(typeinfo); + } + if (l != -1) { + offs += l; + SET_CURR_OFFS (offs); + } + /* + * else l == -1 => invalid instruction, which will be + * flagged as an error on pass 2 + */ + + } else { /* pass == 2 */ + offs += assemble (location.segment, offs, sb, cpu, + &output_ins, ofmt, report_error, &nasmlist); + SET_CURR_OFFS (offs); + + } + } /* not an EQU */ + cleanup_insn (&output_ins); + } + nasm_free (line); + location.offset = offs = GET_CURR_OFFS; + } /* end while (line = preproc->getline... */ + + if (pass1==2 && global_offset_changed) + report_error(ERR_NONFATAL, "phase error detected at end of assembly."); + + if (pass1 == 1) preproc->cleanup(); + + if (pass1==1 && terminate_after_phase) { + fclose(ofile); + remove(outname); + if (want_usage) + usage(); + exit (1); + } + pass_cnt++; + if (pass>1 && !global_offset_changed && pass<pass_max) pass = pass_max-1; + } /* for (pass=1; pass<=2; pass++) */ - location.offset = offs = get_curr_ofs; - } + nasmlist.cleanup(); +#if 1 + if (optimizing) + fprintf(error_file, + "info:: assembly required 1+%d+1 passes\n", pass_cnt-2); +#endif +} /* exit from assemble_file (...) */ - preproc->cleanup(); - nasmlist.cleanup(); -} static int getkw (char *buf, char **value) { @@ -1164,22 +1153,28 @@ static int getkw (char *buf, char **value) while (*buf!=']') buf++; *buf++ = '\0'; } +#if 0 for (q=p; *q; q++) *q = tolower(*q); - if (!strcmp(p, "segment") || !strcmp(p, "section")) +#endif + if (!nasm_stricmp(p, "segment") || !nasm_stricmp(p, "section")) return 1; - if (!strcmp(p, "extern")) + if (!nasm_stricmp(p, "extern")) return 2; - if (!strcmp(p, "bits")) + if (!nasm_stricmp(p, "bits")) return 3; - if (!strcmp(p, "global")) + if (!nasm_stricmp(p, "global")) return 4; - if (!strcmp(p, "common")) + if (!nasm_stricmp(p, "common")) return 5; - if (!strcmp(p, "absolute")) + if (!nasm_stricmp(p, "absolute")) return 6; - if (!strcmp(p, "debug")) + if (!nasm_stricmp(p, "debug")) return 7; + if (!nasm_stricmp(p, "warning")) + return 8; + if (!nasm_stricmp(p, "cpu")) + return 9; return -1; } @@ -1211,11 +1206,19 @@ static void report_error (int severity, char *fmt, ...) nasm_free (currentfile); } - if ( (severity & ERR_MASK) == ERR_WARNING) - fputs ("warning: ", error_file); - else if ( (severity & ERR_MASK) == ERR_PANIC) - fputs ("panic: ", error_file); - + switch (severity & ERR_MASK) { + case ERR_WARNING: + fputs ("warning: ", error_file); break; + case ERR_NONFATAL: + fputs ("error: ", error_file); break; + case ERR_FATAL: + fputs ("fatal: ", error_file); break; + case ERR_PANIC: + fputs ("panic: ", error_file); break; + case ERR_DEBUG: + fputs("debug: ", error_file); break; + } + va_start (ap, fmt); vfprintf (error_file, fmt, ap); fputc ('\n', error_file); @@ -1224,7 +1227,7 @@ static void report_error (int severity, char *fmt, ...) want_usage = TRUE; switch (severity & ERR_MASK) { - case ERR_WARNING: + case ERR_WARNING: case ERR_DEBUG: /* no further action, by definition */ break; case ERR_NONFATAL: @@ -1241,7 +1244,8 @@ static void report_error (int severity, char *fmt, ...) break; /* placate silly compilers */ case ERR_PANIC: fflush(NULL); - abort(); /* halt, catch fire, and dump core */ +/* abort(); */ /* halt, catch fire, and dump core */ + exit(3); break; } } @@ -1342,3 +1346,47 @@ static void no_pp_cleanup (void) { fclose(no_pp_fp); } + +static unsigned long get_cpu (char *value) +{ + + if (!strcmp(value, "8086")) return IF_8086; + if (!strcmp(value, "186")) return IF_186; + if (!strcmp(value, "286")) return IF_286; + if (!strcmp(value, "386")) return IF_386; + if (!strcmp(value, "486")) return IF_486; + if (!strcmp(value, "586") || + !nasm_stricmp(value, "pentium") ) return IF_PENT; + if (!strcmp(value, "686") || + !nasm_stricmp(value, "ppro") || + !nasm_stricmp(value, "p2") ) return IF_P6; + if (!nasm_stricmp(value, "p3") || + !nasm_stricmp(value, "katmai") ) return IF_KATMAI; + + report_error (pass ? ERR_NONFATAL : ERR_FATAL, "unknown 'cpu' type"); + + return IF_PLEVEL; /* the maximum level */ +} + + +static int get_bits (char *value) +{ + int i; + + if ((i = atoi(value)) == 16) return i; /* set for a 16-bit segment */ + else if (i == 32) { + if (cpu < IF_386) { + report_error(ERR_NONFATAL, + "cannot specify 32-bit segment on processor below a 386"); + i = 16; + } + } else { + report_error(pass ? ERR_NONFATAL : ERR_FATAL, + "`%s' is not a valid segment size; must be 16 or 32", + value); + i = 16; + } + return i; +} + +/* end of nasm.c */ @@ -13,7 +13,7 @@ #define NASM_MAJOR_VER 0 #define NASM_MINOR_VER 98 -#define NASM_VER "0.98" +#define NASM_VER "0.98.03" #ifndef NULL #define NULL 0 @@ -64,26 +64,28 @@ typedef void (*efunc) (int severity, char *fmt, ...); * argument to an efunc. */ -#define ERR_WARNING 0 /* warn only: no further action */ -#define ERR_NONFATAL 1 /* terminate assembly after phase */ -#define ERR_FATAL 2 /* instantly fatal: exit with error */ -#define ERR_PANIC 3 /* internal error: panic instantly +#define ERR_DEBUG 0x00000008 /* put out debugging message */ +#define ERR_WARNING 0x00000000 /* warn only: no further action */ +#define ERR_NONFATAL 0x00000001 /* terminate assembly after phase */ +#define ERR_FATAL 0x00000002 /* instantly fatal: exit with error */ +#define ERR_PANIC 0x00000003 /* internal error: panic instantly * and dump core for reference */ -#define ERR_MASK 0x0F /* mask off the above codes */ -#define ERR_NOFILE 0x10 /* don't give source file name/line */ -#define ERR_USAGE 0x20 /* print a usage message */ -#define ERR_PASS1 0x80 /* only print this error on pass one */ +#define ERR_MASK 0x0000000F /* mask off the above codes */ +#define ERR_NOFILE 0x00000010 /* don't give source file name/line */ +#define ERR_USAGE 0x00000020 /* print a usage message */ +#define ERR_PASS1 0x00000040 /* only print this error on pass one */ /* * These codes define specific types of suppressible warning. */ -#define ERR_WARN_MNP 0x0100 /* macro-num-parameters warning */ -#define ERR_WARN_OL 0x0200 /* orphan label (no colon, and +#define ERR_WARN_MNP 0x00000100 /* macro-num-parameters warning */ +#define ERR_WARN_MSR 0x00000200 /* macro self-reference */ +#define ERR_WARN_OL 0x00000300 /* orphan label (no colon, and * alone on line) */ -#define ERR_WARN_NOV 0x0300 /* numeric overflow */ -#define ERR_WARN_MASK 0xFF00 /* the mask for this feature */ +#define ERR_WARN_NOV 0x00000400 /* numeric overflow */ +#define ERR_WARN_MASK 0x0000FF00 /* the mask for this feature */ #define ERR_WARN_SHR 8 /* how far to shift right */ -#define ERR_WARN_MAX 3 /* the highest numbered one */ +#define ERR_WARN_MAX 4 /* the highest numbered one */ /* * ----------------------- @@ -250,8 +252,8 @@ struct eval_hints { * defined before use", whereas if `critical' is 2, the error will * be "symbol undefined". * - * If `critical' has bit 4 set (in addition to its main value: 0x11 - * and 0x12 correspond to 1 and 2) then an extended expression + * If `critical' has bit 8 set (in addition to its main value: 0x101 + * and 0x102 correspond to 1 and 2) then an extended expression * syntax is recognised, in which relational operators such as =, < * and >= are accepted, as well as low-precedence logical operators * &&, ^^ and ||. @@ -259,6 +261,7 @@ struct eval_hints { * If `hints' is non-NULL, it gets filled in with some hints as to * the base register in complex effective addresses. */ +#define CRITICAL 0x100 typedef expr *(*evalfunc) (scanner sc, void *scprivate, struct tokenval *tv, int *fwref, int critical, efunc error, struct eval_hints *hints); @@ -411,7 +414,9 @@ enum { /* special type of immediate operand */ #define ONENESS 0x00800000L /* so UNITY == IMMEDIATE | ONENESS */ #define UNITY 0x00802000L /* for shift/rotate instructions */ - +#define BYTENESS 0x80000000L /* so SBYTE == IMMEDIATE | BYTENESS */ +#define SBYTE 0x80002000L /* for op r16/32,immediate instrs. */ + /* * Next, the codes returned from the parser, for registers and * instructions. @@ -125,29 +125,33 @@ char *nasm_strndup (char *s, size_t len) return p; } +#if !defined(stricmp) && !defined(strcasecmp) int nasm_stricmp (const char *s1, const char *s2) { - while (*s1 && toupper(*s1) == toupper(*s2)) + while (*s1 && tolower(*s1) == tolower(*s2)) s1++, s2++; if (!*s1 && !*s2) return 0; - else if (toupper(*s1) < toupper(*s2)) + else if (tolower(*s1) < tolower(*s2)) return -1; else return 1; } +#endif +#if !defined(strnicmp) && !defined(strncasecmp) int nasm_strnicmp (const char *s1, const char *s2, int n) { - while (n > 0 && *s1 && toupper(*s1) == toupper(*s2)) + while (n > 0 && *s1 && tolower(*s1) == tolower(*s2)) s1++, s2++, n--; if ((!*s1 && !*s2) || n==0) return 0; - else if (toupper(*s1) < toupper(*s2)) + else if (tolower(*s1) < tolower(*s2)) return -1; else return 1; } +#endif #define lib_isnumchar(c) ( isalnum(c) || (c) == '$') #define numvalue(c) ((c)>='a' ? (c)-'a'+10 : (c)>='A' ? (c)-'A'+10 : (c)-'0') @@ -51,8 +51,25 @@ char *nasm_strndup_log (char *, int, char *, size_t); * ANSI doesn't guarantee the presence of `stricmp' or * `strcasecmp'. */ +#if defined(stricmp) || defined(strcasecmp) +#if defined(stricmp) +#define nasm_stricmp stricmp +#else +#define nasm_stricmp strcasecmp +#endif +#else int nasm_stricmp (const char *, const char *); +#endif + +#if defined(strnicmp) || defined(strncasecmp) +#if defined(strnicmp) +#define nasm_strnicmp strnicmp +#else +#define nasm_strnicmp strncasecmp +#endif +#else int nasm_strnicmp (const char *, const char *, int); +#endif /* * Convert a string into a number, using NASM number rules. Sets @@ -76,7 +76,7 @@ * next operation. */ -#define RECORD_MAX 1024 /* maximum size of _any_ record */ +#define RECORD_MAX 1024-3 /* maximal size of any record except type+reclen */ #define OBJ_PARMS 3 /* maximum .parm used by any .ori routine */ #define FIX_08_LOW 0x8000 /* location type for various fixup subrecords */ @@ -103,6 +103,7 @@ enum RecordID { /* record ID codes */ LEDATA = 0xA0, /* logical enumerated data */ FIXUPP = 0x9C, /* fixups (relocations) */ + FIXU32 = 0x9D, /* 32-bit fixups (relocations) */ MODEND = 0x8A /* module end */ }; @@ -139,8 +140,6 @@ static void ori_ledata(ObjRecord *orp); static void ori_pubdef(ObjRecord *orp); static void ori_null(ObjRecord *orp); static ObjRecord *obj_commit(ObjRecord *orp); -static void obj_write_fixup (ObjRecord *orp, int bytes, - int segrel, long seg, long wrt); static int obj_uppercase; /* Flag: all names in uppercase */ @@ -949,6 +948,10 @@ static void obj_deflabel (char *name, long segment, " for this symbol type"); } +/* forward declaration */ +static void obj_write_fixup (ObjRecord *orp, int bytes, + int segrel, long seg, long wrt, struct Segment *segto); + static void obj_out (long segto, void *data, unsigned long type, long segment, long wrt) { @@ -1049,7 +1052,7 @@ static void obj_out (long segto, void *data, unsigned long type, if (segment != NO_SEG) obj_write_fixup (orp, rsize, (realtype == OUT_ADDRESS ? 0x4000 : 0), - segment, wrt); + segment, wrt, seg); seg->currentpos += size; } else if (realtype == OUT_RESERVE) { if (orp->committed) @@ -1060,7 +1063,7 @@ static void obj_out (long segto, void *data, unsigned long type, } static void obj_write_fixup (ObjRecord *orp, int bytes, - int segrel, long seg, long wrt) + int segrel, long seg, long wrt, struct Segment *segto) { int locat, method; int base; @@ -1080,6 +1083,11 @@ static void obj_write_fixup (ObjRecord *orp, int bytes, if (forp == NULL) { orp->child = forp = obj_new(); forp->up = &(orp->child); + /* We should choose between FIXUPP and FIXU32 record type */ + /* If we're targeting a 32-bit segment, use a FIXU32 record */ + if (segto->use32) + forp->type = FIXU32; + else forp->type = FIXUPP; } @@ -647,8 +647,13 @@ insn *parse_line (int pass, char *buffer, insn *result, result->oprs[operand].offset = reloc_value(value); result->oprs[operand].segment = reloc_seg(value); result->oprs[operand].wrt = reloc_wrt(value); - if (is_simple(value) && reloc_value(value)==1) - result->oprs[operand].type |= UNITY; + if (is_simple(value)) { + if (reloc_value(value)==1) + result->oprs[operand].type |= UNITY; + if (reloc_value(value) >= -128 && + reloc_value(value) <= 127) + result->oprs[operand].type |= SBYTE; + } } else /* it's a register */ { @@ -34,6 +34,7 @@ */ #include <stdio.h> +#include <stdarg.h> #include <stdlib.h> #include <stddef.h> #include <string.h> @@ -100,6 +101,7 @@ struct MMacro { Token *iline; /* invocation line */ int nparam, rotate, *paramlen; unsigned long unique; + int lineno; /* Current line number on expansion */ }; /* @@ -267,8 +269,9 @@ static char *directives[] = { "%endrep", "%error", "%exitrep", "%iassign", "%idefine", "%if", "%ifctx", "%ifdef", "%ifid", "%ifidn", "%ifidni", "%ifnctx", "%ifndef", "%ifnid", "%ifnidn", "%ifnidni", "%ifnnum", - "%ifnstr", "%ifnum", "%ifstr", "%imacro", "%include", "%line", - "%macro", "%pop", "%push", "%rep", "%repl", "%rotate", "%undef" + "%ifnstr", "%ifnum", "%ifstr", "%imacro", "%include", "%ixdefine", + "%line", "%macro", "%pop", "%push", "%rep", "%repl", "%rotate", + "%undef", "%xdefine" }; enum { PP_ASSIGN, PP_CLEAR, PP_DEFINE, PP_ELIF, PP_ELIFCTX, PP_ELIFDEF, @@ -278,8 +281,9 @@ enum { PP_ENDREP, PP_ERROR, PP_EXITREP, PP_IASSIGN, PP_IDEFINE, PP_IF, PP_IFCTX, PP_IFDEF, PP_IFID, PP_IFIDN, PP_IFIDNI, PP_IFNCTX, PP_IFNDEF, PP_IFNID, PP_IFNIDN, PP_IFNIDNI, PP_IFNNUM, - PP_IFNSTR, PP_IFNUM, PP_IFSTR, PP_IMACRO, PP_INCLUDE, PP_LINE, - PP_MACRO, PP_POP, PP_PUSH, PP_REP, PP_REPL, PP_ROTATE, PP_UNDEF + PP_IFNSTR, PP_IFNUM, PP_IFSTR, PP_IMACRO, PP_INCLUDE, PP_IXDEFINE, + PP_LINE, PP_MACRO, PP_POP, PP_PUSH, PP_REP, PP_REPL, PP_ROTATE, + PP_UNDEF, PP_XDEFINE }; @@ -287,7 +291,7 @@ static Context *cstk; static Include *istk; static IncPath *ipath = NULL; -static efunc error; +static efunc __error; /* Pointer to client-provided error reporting function */ static evalfunc evaluate; static int pass; /* HACK: pass 0 = generate dependencies only */ @@ -345,7 +349,10 @@ int any_extrastdmac; */ static Token *expand_mmac_params (Token *tline); static Token *expand_smacro (Token *tline); +static Token *expand_id (Token *tline); +static Context *get_ctx (char *name, int all_contexts); static void make_tok_num(Token *tok, long val); +static void error (int severity, char *fmt, ...); /* * Macros for safe checking of token pointers, avoid *(NULL) @@ -586,8 +593,10 @@ static Token *tokenise (char *line) while (*line) { p = line; - if (*p == '%' && ( isdigit(p[1]) || - ((p[1] == '-' || p[1] == '+') && isdigit(p[2])))) + if (*p == '%' && + (isdigit(p[1]) || + ((p[1] == '-' || p[1] == '+') && isdigit(p[2])) || + ((p[1] == '+') && (isspace (p[2]) || !p[2])))) { p++; do { @@ -702,8 +711,10 @@ static Token *tokenise (char *line) /* * Convert a line of tokens back into text. + * If expand_locals is not zero, identifiers of the form "%$*xxx" + * will be transformed into ..@ctxnum.xxx */ -char *detoken (Token *tlist) +static char *detoken (Token *tlist, int expand_locals) { Token *t; int len; @@ -719,6 +730,24 @@ char *detoken (Token *tlist) else t->text = NULL; } + /* Expand local macros here and not during preprocessing */ + if (expand_locals && + t->type == TOK_PREPROC_ID && t->text && + t->text[0] == '%' && t->text [1] == '$') { + Context *ctx = get_ctx (t->text, FALSE); + if (ctx) { + char buffer [40]; + char *p, *q = t->text + 2; + + q += strspn (q, "$"); + sprintf (buffer, "..@%lu.", ctx->number); + p = nasm_malloc (strlen(buffer)+strlen(q)+1); + strcpy (p, buffer); + strcat (p, q); + nasm_free (t->text); + t->text = p; + } + } if (t->text) len += strlen(t->text); } @@ -827,43 +856,62 @@ static int ppscan(void *private_data, struct tokenval *tokval) } /* + * Compare a string to the name of an existing macro; this is a + * simple wrapper which calls either strcmp or nasm_stricmp + * depending on the value of the `casesense' parameter. + */ +static int mstrcmp(char *p, char *q, int casesense) +{ + return casesense ? strcmp(p,q) : nasm_stricmp(p,q); +} + +/* * Return the Context structure associated with a %$ token. Return * NULL, having _already_ reported an error condition, if the * context stack isn't deep enough for the supplied number of $ * signs. + * If all_contexts == TRUE, contexts that enclose current are + * also scanned for such smacro, until it is found; if not - + * only the context that directly results from the number of $'s + * in variable's name. */ -static Context *get_ctx (char *name) +static Context *get_ctx (char *name, int all_contexts) { Context *ctx; + SMacro *m; int i; + if (!name || name[0] != '%' || name[1] != '$') + return NULL; + if (!cstk) { error (ERR_NONFATAL, "`%s': context stack is empty", name); return NULL; } - i = 1; - ctx = cstk; - while (name[i+1] == '$') { - i++; + for (i = strspn (name+2, "$"), ctx = cstk; (i > 0) && ctx; i--) { ctx = ctx->next; + i--; + } if (!ctx) { error (ERR_NONFATAL, "`%s': context stack is only" " %d level%s deep", name, i-1, (i==2 ? "" : "s")); return NULL; } - } + if (!all_contexts) return ctx; -} -/* - * Compare a string to the name of an existing macro; this is a - * simple wrapper which calls either strcmp or nasm_stricmp - * depending on the value of the `casesense' parameter. - */ -static int mstrcmp(char *p, char *q, int casesense) -{ - return casesense ? strcmp(p,q) : nasm_stricmp(p,q); + do { + /* Search for this smacro in found context */ + m = ctx->localmac; + while (m) { + if (!mstrcmp(m->name, name, m->casesense)) + return ctx; + m = m->next; + } + ctx = ctx->next; + } while (ctx); + return NULL; } /* @@ -922,27 +970,30 @@ static FILE *inc_fopen(char *file) * * Note that this is also called with nparam zero to resolve * `ifdef'. + * + * If you already know which context macro belongs to, you can pass + * the context pointer as first parameter; if you won't but name begins + * with %$ the context will be automatically computed. If all_contexts + * is true, macro will be searched in outer contexts as well. */ -static int smacro_defined (char *name, int nparam, SMacro **defn, int nocase) +static int smacro_defined (Context *ctx, char *name, int nparam, SMacro **defn, + int nocase) { SMacro *m; - Context *ctx; - char *p; - if (name[0] == '%' && name[1] == '$') { - ctx = get_ctx (name); + if (ctx) + m = ctx->localmac; + else if (name[0] == '%' && name[1] == '$') { + if (cstk) + ctx = get_ctx (name, FALSE); if (!ctx) return FALSE; /* got to return _something_ */ m = ctx->localmac; - p = name+1; - p += strspn(p, "$"); - } else { + } else m = smacros[hash(name)]; - p = name; - } while (m) { - if (!mstrcmp(m->name, p, m->casesense & nocase) && + if (!mstrcmp(m->name, name, m->casesense && nocase) && (nparam <= 0 || m->nparam == 0 || nparam == m->nparam)) { if (defn) { if (nparam == m->nparam || nparam == -1) @@ -954,6 +1005,7 @@ static int smacro_defined (char *name, int nparam, SMacro **defn, int nocase) } m = m->next; } + return FALSE; } @@ -1021,10 +1073,7 @@ static int if_condition (Token *tline, int i) case PP_IFCTX: case PP_ELIFCTX: case PP_IFNCTX: case PP_ELIFNCTX: j = FALSE; /* have we matched yet? */ - if (!cstk) - error(ERR_FATAL, - "`%s': context stack is empty", directives[i]); - else while (tline) { + while (cstk && tline) { skip_white_(tline); if (!tline || tline->type != TOK_ID) { error(ERR_NONFATAL, @@ -1055,7 +1104,7 @@ static int if_condition (Token *tline, int i) free_tlist (origline); return -1; } - if (smacro_defined(tline->text, 0, NULL, 1)) + if (smacro_defined (NULL, tline->text, 0, NULL, 1)) j = TRUE; tline = tline->next; } @@ -1143,7 +1192,7 @@ static int if_condition (Token *tline, int i) tptr = &t; tokval.t_type = TOKEN_INVALID; evalresult = evaluate (ppscan, tptr, &tokval, - NULL, pass | 0x10, error, NULL); + NULL, pass | CRITICAL, error, NULL); free_tlist (tline); if (!evalresult) return -1; @@ -1167,6 +1216,18 @@ static int if_condition (Token *tline, int i) } /* + * Expand macros in a string. Used in %error and %include directives. + * First tokenise the string, apply "expand_smacro" and then de-tokenise back. + * The returned variable should ALWAYS be freed after usage. + */ +void expand_macros_in_string (char **p) +{ + Token *line = tokenise (*p); + line = expand_smacro (line); + *p = detoken (line, FALSE); +} + +/* * Find out if a line contains a preprocessor directive, and deal * with it if so. * @@ -1303,11 +1364,12 @@ static int do_directive (Token *tline) p[strlen(p)-1] = '\0'; /* remove the trailing quote */ } else p = tline->text; /* internal_string is easier */ + expand_macros_in_string (&p); inc = nasm_malloc(sizeof(Include)); inc->next = istk; inc->conds = NULL; inc->fp = inc_fopen(p); - inc->fname = src_set_fname(nasm_strdup(p)); + inc->fname = src_set_fname (p); inc->lineno = src_set_linnum(0); inc->lineinc = 1; inc->expansion = NULL; @@ -1320,6 +1382,7 @@ static int do_directive (Token *tline) case PP_PUSH: tline = tline->next; skip_white_(tline); + tline = expand_id (tline); if (!tok_type_(tline, TOK_ID)) { error(ERR_NONFATAL, "`%%push' expects a context identifier"); @@ -1341,6 +1404,7 @@ static int do_directive (Token *tline) case PP_REPL: tline = tline->next; skip_white_(tline); + tline = expand_id (tline); if (!tok_type_(tline, TOK_ID)) { error(ERR_NONFATAL, "`%%repl' expects a context identifier"); @@ -1379,10 +1443,12 @@ static int do_directive (Token *tline) if (tok_type_(tline, TOK_STRING)) { p = tline->text+1; /* point past the quote to the name */ p[strlen(p)-1] = '\0'; /* remove the trailing quote */ - error(ERR_NONFATAL, "user error: %s", p); + expand_macros_in_string (&p); + error (ERR_NONFATAL, "%s", p); + nasm_free (p); } else { - p = detoken(tline); - error(ERR_WARNING, "user error: %s", p); + p = detoken(tline, FALSE); + error (ERR_WARNING, "%s", p); nasm_free(p); } free_tlist (origline); @@ -1409,15 +1475,7 @@ static int do_directive (Token *tline) j = if_condition(tline->next, i); tline->next = NULL; /* it got freed */ free_tlist (origline); - if (j < 0) - /* - * Bogus expression in %if, but we should pretend - * it was OK anyway, so that we don't get an error - * cascade on the subsequent %else / %endif. - */ - j = COND_NEVER; - else - j = j ? COND_IF_TRUE : COND_IF_FALSE; + j = j < 0 ? COND_NEVER : j ? COND_IF_TRUE : COND_IF_FALSE; } cond = nasm_malloc(sizeof(Cond)); cond->next = istk->conds; @@ -1449,14 +1507,7 @@ static int do_directive (Token *tline) j = if_condition(expand_mmac_params(tline->next), i); tline->next = NULL; /* it got freed */ free_tlist (origline); - if (j < 0) - /* - * The expression was bogus, but let's make - * %endif not complain about missing %if - */ - j = COND_NEVER; - else - istk->conds->state = j ? COND_IF_TRUE : COND_IF_FALSE; + istk->conds->state = j < 0 ? COND_NEVER : j ? COND_IF_TRUE : COND_IF_FALSE; } return (istk->conds->state == COND_IF_TRUE ? 5 : 1); @@ -1495,6 +1546,7 @@ static int do_directive (Token *tline) (i == PP_IMACRO ? "i" : "")); tline = tline->next; skip_white_(tline); + tline = expand_id (tline); if (!tok_type_(tline, TOK_ID)) { error (ERR_NONFATAL, "`%%%smacro' expects a macro name", @@ -1508,7 +1560,7 @@ static int do_directive (Token *tline) defining->nolist = FALSE; defining->in_progress = FALSE; defining->rep_nest = NULL; - tline = tline->next; + tline = expand_smacro (tline->next); skip_white_(tline); if (!tok_type_(tline, TOK_NUMBER)) { error (ERR_NONFATAL, @@ -1717,36 +1769,38 @@ static int do_directive (Token *tline) free_tlist (origline); return 1; + case PP_XDEFINE: + case PP_IXDEFINE: case PP_DEFINE: case PP_IDEFINE: tline = tline->next; skip_white_(tline); + tline = expand_id (tline); if (!tline || (tline->type != TOK_ID && (tline->type != TOK_PREPROC_ID || tline->text[1] != '$'))) { error (ERR_NONFATAL, - "`%%%sdefine' expects a macro identifier", - (i == PP_IDEFINE ? "i" : "")); + "`%%%s%sdefine' expects a macro identifier", + ((i == PP_IDEFINE || i == PP_IXDEFINE) ? "i" : ""), + ((i == PP_XDEFINE || i == PP_IXDEFINE) ? "x" : "")); free_tlist (origline); return 3; } - mname = tline->text; - if (tline->type == TOK_ID) { - p = tline->text; - smhead = &smacros[hash(mname)]; - } else { - ctx = get_ctx (tline->text); - if (ctx == NULL) - return 3; - else { - p = tline->text+1; - p += strspn(p, "$"); + + ctx = get_ctx (tline->text, FALSE); + if (!ctx) + smhead = &smacros[hash(tline->text)]; + else smhead = &ctx->localmac; - } - } + mname = tline->text; last = tline; param_start = tline = tline->next; nparam = 0; + + /* Expand the macro definition now for %xdefine and %ixdefine */ + if ((i == PP_XDEFINE) || (i == PP_IXDEFINE)) + tline = expand_smacro (tline); + if (tok_is_(tline, "(")) { /* * This macro has parameters. @@ -1811,7 +1865,7 @@ static int do_directive (Token *tline) * carefully re-terminated after chopping off the expansion * from the end). */ - if (smacro_defined (mname, nparam, &smac, i==PP_DEFINE)) { + if (smacro_defined (ctx, mname, nparam, &smac, i == PP_DEFINE)) { if (!smac) { error (ERR_WARNING, "single-line macro `%s' defined both with and" @@ -1833,8 +1887,8 @@ static int do_directive (Token *tline) smac->next = *smhead; *smhead = smac; } - smac->name = nasm_strdup(p); - smac->casesense = (i == PP_DEFINE); + smac->name = nasm_strdup(mname); + smac->casesense = ((i == PP_DEFINE) || (i == PP_XDEFINE)); smac->nparam = nparam; smac->expansion = macro_start; smac->in_progress = FALSE; @@ -1844,6 +1898,7 @@ static int do_directive (Token *tline) case PP_UNDEF: tline = tline->next; skip_white_(tline); + tline = expand_id (tline); if (!tline || (tline->type != TOK_ID && (tline->type != TOK_PREPROC_ID || tline->text[1] != '$'))) { @@ -1852,33 +1907,26 @@ static int do_directive (Token *tline) free_tlist (origline); return 3; } - mname = tline->text; - if (tline->type == TOK_ID) { - p = tline->text; - smhead = &smacros[hash(mname)]; - } else { - ctx = get_ctx (tline->text); - if (ctx == NULL) { - free_tlist (origline); - return 3; - } else { - p = tline->text+1; - p += strspn(p, "$"); - smhead = &ctx->localmac; - } + if (tline->next) { + error (ERR_WARNING, + "trailing garbage after macro name ignored"); } + + /* Find the context that symbol belongs to */ + ctx = get_ctx (tline->text, FALSE); + if (!ctx) + smhead = &smacros[hash(tline->text)]; + else + smhead = &ctx->localmac; + + mname = tline->text; last = tline; - tline = tline->next; last->next = NULL; - if (tline) - error(ERR_WARNING, - "trailing garbage after macro name ignored"); - /* * We now have a macro name... go hunt for it. */ - while (smacro_defined (mname, -1, &smac, 1)) { + while (smacro_defined (ctx, mname, -1, &smac, 1)) { /* Defined, so we need to find its predecessor and nuke it */ SMacro **s; for ( s = smhead ; *s && *s != smac ; s = &(*s)->next ); @@ -1889,12 +1937,14 @@ static int do_directive (Token *tline) nasm_free(smac); } } + free_tlist (origline); return 3; case PP_ASSIGN: case PP_IASSIGN: tline = tline->next; skip_white_(tline); + tline = expand_id (tline); if (!tline || (tline->type != TOK_ID && (tline->type != TOK_PREPROC_ID || tline->text[1] != '$'))) { @@ -1904,26 +1954,16 @@ static int do_directive (Token *tline) free_tlist (origline); return 3; } - mname = tline->text; - if (tline->type == TOK_ID) { - p = tline->text; - smhead = &smacros[hash(mname)]; - } else { - ctx = get_ctx (tline->text); - if (ctx == NULL) { - free_tlist (origline); - return 3; - } else { - p = tline->text+1; - p += strspn(p, "$"); + ctx = get_ctx (tline->text, FALSE); + if (!ctx) + smhead = &smacros[hash(tline->text)]; + else smhead = &ctx->localmac; - } - } + mname = tline->text; last = tline; - tline = tline->next; + tline = expand_smacro (tline->next); last->next = NULL; - tline = expand_smacro (tline); t = tline; tptr = &t; tokval.t_type = TOKEN_INVALID; @@ -1956,7 +1996,7 @@ static int do_directive (Token *tline) * zero, and a numeric token to use as an expansion. Create * and store an SMacro. */ - if (smacro_defined (mname, 0, &smac, i==PP_ASSIGN)) { + if (smacro_defined (ctx, mname, 0, &smac, i == PP_ASSIGN)) { if (!smac) error (ERR_WARNING, "single-line macro `%s' defined both with and" @@ -1976,7 +2016,7 @@ static int do_directive (Token *tline) smac->next = *smhead; *smhead = smac; } - smac->name = nasm_strdup(p); + smac->name = nasm_strdup(mname); smac->casesense = (i == PP_ASSIGN); smac->nparam = 0; smac->expansion = macro_start; @@ -2013,7 +2053,7 @@ static int do_directive (Token *tline) src_set_linnum(k); istk->lineinc = m; if (tline) { - nasm_free ( src_set_fname ( detoken(tline) ) ); + nasm_free (src_set_fname (detoken (tline, FALSE))); } free_tlist (origline); return 5; @@ -2077,7 +2117,7 @@ static Token *expand_mmac_params (Token *tline) while (tline) { if (tline->type == TOK_PREPROC_ID && - (tline->text[1] == '+' || tline->text[1] == '-' || + (((tline->text[1] == '+' || tline->text[1] == '-') && tline->text [2]) || tline->text[1] == '%' || (tline->text[1] >= '0' && tline->text[1] <= '9'))) { char *text = NULL; @@ -2244,26 +2284,38 @@ static Token *expand_smacro (Token *tline) SMacro *head = NULL, *m; Token **params; int *paramsize; - int nparam, sparam, brackets; - char *p; + int nparam, sparam, brackets, rescan; + Token *org_tline = tline; + Context *ctx; + char *mname; + + /* + * Trick: we should avoid changing the start token pointer since it can + * be contained in "next" field of other token. Because of this + * we allocate a copy of first token and work with it; at the end of + * routine we copy it back + */ + if (org_tline) + { + tline = nasm_malloc (sizeof (Token)); + *tline = *org_tline; + } +again: tail = &thead; thead = NULL; while (tline) { /* main token loop */ - p = NULL; - if (tline->type == TOK_ID) { - head = smacros[hash(tline->text)]; - p = tline->text; - } else if (tline->type == TOK_PREPROC_ID && tline->text[1] == '$') { - Context *ctx = get_ctx (tline->text); - if (ctx) { + if ((mname = tline->text)) { + /* if this token is a local macro, look in local context */ + if (tline->type == TOK_ID || tline->type == TOK_PREPROC_ID) + ctx = get_ctx (mname, TRUE); + else + ctx = NULL; + if (!ctx) + head = smacros[hash(mname)]; + else head = ctx->localmac; - p = tline->text+2; - p += strspn(p, "$"); - } - } - if (p) { /* * We've hit an identifier. As in is_mmacro below, we first * check whether the identifier is a single-line macro at @@ -2271,7 +2323,7 @@ static Token *expand_smacro (Token *tline) * necessary. */ for (m = head; m; m = m->next) - if (!mstrcmp(m->name, p, m->casesense)) + if (!mstrcmp(m->name, mname, m->casesense)) break; if (m) { mstart = tline; @@ -2303,8 +2355,7 @@ static Token *expand_smacro (Token *tline) nasm_free (t); continue; } - } - else { + } else { /* * Complicated case: at least one macro with this name * exists and takes parameters. We must find the @@ -2393,7 +2444,7 @@ static Token *expand_smacro (Token *tline) } /* parameter loop */ nparam++; while (m && (m->nparam != nparam || - mstrcmp(m->name, p, m->casesense))) + mstrcmp(m->name, mname, m->casesense))) m = m->next; if (!m) error (ERR_WARNING|ERR_WARN_MNP, @@ -2415,8 +2466,7 @@ static Token *expand_smacro (Token *tline) nasm_free (params); nasm_free (paramsize); tline = mstart; - } - else { + } else { /* * Expand the macro: we are placed on the last token of the * call, so that we can easily split the call from the @@ -2485,27 +2535,138 @@ static Token *expand_smacro (Token *tline) t->mac = NULL; t->next = NULL; tail = &t->next; - if (t->type == TOK_PREPROC_ID && t->text[1] == '$') { - Context *c = get_ctx (t->text); - char *p, *q, buffer[40]; - - t->type = TOK_ID; - if (c) { - q = t->text+1; - q += strspn(q, "$"); - sprintf(buffer, "..@%lu.", c->number); - p = nasm_strcat (buffer,q); + } + } + + /* + * Now scan the entire line and look for successive TOK_IDs that resulted + * after expansion (they can't be produced by tokenise()). The successive + * TOK_IDs should be concatenated. + * Also we look for %+ tokens and concatenate the tokens before and after + * them (without white spaces in between). + */ + t = thead; + rescan = 0; + while (t) { + while (t && t->type != TOK_ID && t->type != TOK_PREPROC_ID) + t = t->next; + if (!t || !t->next) + break; + if (t->next->type == TOK_ID || + t->next->type == TOK_PREPROC_ID || + t->next->type == TOK_NUMBER) { + Token *next = t->next->next; + char *p = nasm_malloc (strlen (t->text) + strlen (t->next->text) + 1); + strcpy (p, t->text); + strcat (p, t->next->text); nasm_free (t->text); + nasm_free (t->next->text); + nasm_free (t->next); + t->next = next; t->text = p; + rescan = 1; + } else if (t->next->type == TOK_WHITESPACE && t->next->next && + t->next->next->type == TOK_PREPROC_ID && + strcmp (t->next->next->text, "%+") == 0) { + /* free the next whitespace, the %+ token and next whitespace */ + int i; + for (i = 1; i <= 3; i++) + { + Token *next; + if (!t->next || (i != 2 && t->next->type != TOK_WHITESPACE)) + break; + next = t->next->next; + nasm_free (t->next->text); + nasm_free (t->next); + t->next = next; + } /* endfor */ + } else + t = t->next; } + /* If we concatenaded something, re-scan the line for macros */ + if (rescan) { + tline = thead; + goto again; } - } + + if (org_tline) + { + if (thead) { + *org_tline = *thead; + nasm_free (thead); + } else + { + /* the expression expanded to empty line; + we can't return NULL for some reasons + we just set the line to a single WHITESPACE token. */ + memset (org_tline, 0, sizeof (*org_tline)); + org_tline->text = nasm_strdup (" "); + org_tline->type = TOK_WHITESPACE; + } + thead = org_tline; } return thead; } /* + * Similar to expand_smacro but used exclusively with macro identifiers + * right before they are fetched in. The reason is that there can be + * identifiers consisting of several subparts. We consider that if there + * are more than one element forming the name, user wants a expansion, + * otherwise it will be left as-is. Example: + * + * %define %$abc cde + * + * the identifier %$abc will be left as-is so that the handler for %define + * will suck it and define the corresponding value. Other case: + * + * %define _%$abc cde + * + * In this case user wants name to be expanded *before* %define starts + * working, so we'll expand %$abc into something (if it has a value; + * otherwise it will be left as-is) then concatenate all successive + * PP_IDs into one. + */ +static Token *expand_id (Token *tline) +{ + Token *cur, *oldnext = NULL; + + if (!tline || + !tline->next) + return tline; + + cur = tline; + while (cur->next && + (cur->next->type == TOK_ID || + cur->next->type == TOK_PREPROC_ID || + cur->next->type == TOK_NUMBER)) + cur = cur->next; + + /* If identifier consists of just one token, don't expand */ + if (cur == tline) + return tline; + + if (cur) { + oldnext = cur->next; /* Detach the tail past identifier */ + cur->next = NULL; /* so that expand_smacro stops here */ + } + + tline = expand_smacro (tline); + + if (cur) { + /* expand_smacro possibly changhed tline; re-scan for EOL */ + cur = tline; + while (cur && cur->next) + cur = cur->next; + if (cur) + cur->next = oldnext; + } + + return tline; +} + +/* * Determine whether the given line constitutes a multi-line macro * call, and return the MMacro structure called if so. Doesn't have * to check for an initial label - that's taken care of in @@ -2709,6 +2870,7 @@ static int expand_mmacro (Token *tline) m->rotate = 0; m->paramlen = paramlen; m->unique = unique++; + m->lineno = 0; m->next_active = istk->mstk; istk->mstk = m; @@ -2745,7 +2907,7 @@ static int expand_mmacro (Token *tline) * If we had a label, push it on as the first line of * the macro expansion. */ - if (label) + if (label) { if (dont_prepend<0) free_tlist(startline); else { @@ -2764,18 +2926,45 @@ static int expand_mmacro (Token *tline) tt->text = nasm_strdup(":"); } } + } list->uplevel (m->nolist ? LIST_MACRO_NOLIST : LIST_MACRO); return 1; } +/* + * Since preprocessor always operate only on the line that didn't + * arrived yet, we should always use ERR_OFFBY1. Also since user + * won't want to see same error twice (preprocessing is done once + * per pass) we will want to show errors only during pass one. + */ +static void error (int severity, char *fmt, ...) +{ + va_list arg; + char buff [1024]; + + /* If we're in a dead branch of IF or something like it, ignore the error */ + if (istk->conds && !emitting(istk->conds->state)) + return; + + va_start (arg, fmt); + vsprintf (buff, fmt, arg); + va_end (arg); + + if (istk->mstk && istk->mstk->name) + __error (severity|ERR_PASS1, "(%s:%d) %s", istk->mstk->name, + istk->mstk->lineno, buff); + else + __error (severity|ERR_PASS1, "%s", buff); +} + static void pp_reset (char *file, int apass, efunc errfunc, evalfunc eval, ListGen *listgen) { int h; - error = errfunc; + __error = errfunc; cstk = NULL; istk = nasm_malloc(sizeof(Include)); istk->next = NULL; @@ -2903,10 +3092,12 @@ static char *pp_getline (void) if (istk->expansion) { /* from a macro expansion */ char *p; Line *l = istk->expansion; + if (istk->mstk) + istk->mstk->lineno++; tline = l->first; istk->expansion = l->next; nasm_free (l); - p = detoken(tline); + p = detoken (tline, FALSE); list->line (LIST_MACRO, p); nasm_free(p); break; @@ -2994,7 +3185,7 @@ static char *pp_getline (void) /* * De-tokenise the line again, and emit it. */ - line = detoken(tline); + line = detoken(tline, TRUE); free_tlist (tline); break; } else { diff --git a/rdoff/Makefile.in b/rdoff/Makefile.in index c55851d..37cc111 100644 --- a/rdoff/Makefile.in +++ b/rdoff/Makefile.in @@ -29,7 +29,7 @@ LDRDFLIBS = rdoff.o nasmlib.o symtab.o collectn.o rdlib.o segtab.o hash.o RDXLIBS = rdoff.o rdfload.o symtab.o collectn.o hash.o .c.o: - $(CC) -c $(CFLAGS) $< + $(CC) -c $(CFLAGS) -o $@ $< all: rdfdump ldrdf rdx rdflib rdf2bin rdf2com diff --git a/standard.mac b/standard.mac index 5f86298..05905d6 100644 --- a/standard.mac +++ b/standard.mac @@ -71,6 +71,13 @@ __SECT__ [bits %1] %endmacro +%imacro use16 0.nolist +[bits 16] +%endmacro +%imacro use32 0.nolist +[bits 32] +%endmacro + %imacro global 1-*.nolist %rep %0 [global %1] @@ -84,3 +91,8 @@ __SECT__ %rotate 1 %endrep %endmacro + +%imacro cpu 1+.nolist +[cpu %1] +%endmacro + diff --git a/test/test1.asm b/test/test1.asm new file mode 100644 index 0000000..ce24ca1 --- /dev/null +++ b/test/test1.asm @@ -0,0 +1,62 @@ + segment text + bits 16 + + imul edx,[addr],10 + imul eax,20 + imul edx,eax,130 + + push 0x40 + push word 0x40 + push word 4095 + push byte 0x40 + push dword 0x40 + push dword 4095 + + add ax,1 + add bx,1 + cmp cx,0 + sub dx,3 + sbb si,-1 + xor ax,0xffff + xor ax,-1 + xor bx,0xffff + xor bx,-1 + + + adc bx,add1 + adc bx,-7 + adc bx,-128 + adc bx,-129 + adc bx,addr + adc bx,byte -7 +add1: adc bx,word -7 + adc bx,add1 + resb 256 +addr: nop + adc bx,addr + adc eax,5 + adc eax,500 + adc eax,byte 5 + adc ax,4 + adc ebx,7 + adc ebx,700 + adc ebx,byte 7 + adc ecx,1 + adc eax,1 + + shr edx,mmm + shr edx,one + adc ebx,byte mmm +m1: adc ebx,mmm +mmm equ 9 +m2: adc ebx,mmm +one equ 1 + shr edx,mmm + shr edx,one + shr edx,1 +tend dw tend + + segment data + db 'abc' + db '', 12, 13, 0 + diff --git a/test/test2.asm b/test/test2.asm new file mode 100644 index 0000000..5bbb034 --- /dev/null +++ b/test/test2.asm @@ -0,0 +1,18 @@ + USE16 + CPU 386 + +debugdump001: +goo: jmp foo + jc near foo + mov ax,[si+5] + mov ax,[si-7] + mov ax,[si+n] + nop + resb 10 +foo: jmp goo + jc goo + jmp short goo +debugdump002: push 0 +n equ 3 + + diff --git a/test/test2a.asm b/test/test2a.asm new file mode 100644 index 0000000..2ed09a7 --- /dev/null +++ b/test/test2a.asm @@ -0,0 +1,22 @@ + use32 + cpu P3 + +debugdump001: +goo: jmp foo +; cpu 386 + jc near foo + mov ax,[si+5] + mov ax,[si-7] + mov ax,[si+n] + align 16 +; cpu 486 + bswap edx +; cpu 186 + resb 10 +foo: jmp goo + jc goo + jmp short goo +debugdump002: push 0 +n equ 3 + + diff --git a/test/test3.asm b/test/test3.asm new file mode 100644 index 0000000..457ed44 --- /dev/null +++ b/test/test3.asm @@ -0,0 +1,45 @@ +debugdump001: + jc baker + jmp able - 20 + jmp able +baker: nop + times 125 nop +able: jmp baker + jmp baker + 20 + times 122 nop + jmp able +loc: nop + jc able+20 + + jmp able1 - 20 + jmp able1 +baker1: nop + times 126 nop +able1: jmp near baker1 + jmp baker1 + 20 + times 122 nop + jmp able1 +loc1: nop + +able2: jmp baker2 + times 124 nop + jmp able2 + nop +baker2: nop + + + +able3: jmp baker3 + times 124 nop + jmp able3 + nop + nop +baker3: nop +debugdump099: nop + + + + + + + diff --git a/test/test4.asm b/test/test4.asm new file mode 100644 index 0000000..357553e --- /dev/null +++ b/test/test4.asm @@ -0,0 +1,16 @@ + cpu 186 + +start: jmp able + xor ax,ax + jc start + jnc able + jc charlie + times 100 nop +able: jc start + times 100 nop +baker: jc start + times 100 nop +charlie: jc baker + jnc able + jmp start +end: db 0 diff --git a/test/test4a.asm b/test/test4a.asm new file mode 100644 index 0000000..bbf85a3 --- /dev/null +++ b/test/test4a.asm @@ -0,0 +1,16 @@ + cpu 386 + +start: jmp able + xor ax,ax + jc start + jnc able + jc charlie + times 100 nop +able: jc start + times 100 nop +baker: jc start + times 100 nop +charlie: jc baker + jnc able + jmp start +end: db 0 diff --git a/test/test4b.asm b/test/test4b.asm new file mode 100644 index 0000000..6344881 --- /dev/null +++ b/test/test4b.asm @@ -0,0 +1,17 @@ + use32 + cpu 186 + +start: jmp able + xor ax,ax + jc start + jnc able + jc charlie + times 100 nop +able: jc start + times 100 nop +baker: jc start + times 100 nop +charlie: jc baker + jnc able + jmp start +end: db 0 diff --git a/test/test4c.asm b/test/test4c.asm new file mode 100644 index 0000000..5d87349 --- /dev/null +++ b/test/test4c.asm @@ -0,0 +1,17 @@ + use32 + cpu 386 + +start: jmp able + xor ax,ax + jc start + jnc able + jc charlie + times 100 nop +able: jc start + times 100 nop +baker: jc start + times 100 nop +charlie: jc baker + jnc able + jmp start +end: db 0 diff --git a/test/test5.asm b/test/test5.asm new file mode 100644 index 0000000..12b0ee4 --- /dev/null +++ b/test/test5.asm @@ -0,0 +1,43 @@ +%macro pushm 1-* +%rep %0 +%rotate -1 +push %1 +%endrep +%endmacro + +%macro popm 1-* +%rep %0 +pop %1 +%rotate 1 +%endrep +%endmacro + +%macro pusha 0 +push ax +push cx +push dx +push bx +push bp +mov bp,sp +lea bp,[bp+10] +xchg bp,[bp-10] +push bp +push si +push di +%endmacro + +%macro popa 0 +pop di +pop si +pop bp +pop bx +pop bx +pop dx +pop cx +pop ax +%endmacro + + pushm ax,bx,cx,dx + popm ax,bx,cx,dx + pusha + popa diff --git a/test/test6.asm b/test/test6.asm new file mode 100644 index 0000000..cf6dca0 --- /dev/null +++ b/test/test6.asm @@ -0,0 +1,9 @@ +; test6.asm +; assemble with; nasm -O2 ... +; +%rep 20000 + jmp forward +%endrep +forward: dd forward + +
\ No newline at end of file @@ -954,11 +954,12 @@ static void ieee_write_file (int debuginfo) { ieee_putascii("ASI%X,R%X,%lX,+.\r\n", i, pub->index,pub->offset); else ieee_putascii("ASI%X,%lX,%lX,+.\r\n", i, pub->segment*16,pub->offset); - if (debuginfo) + if (debuginfo) { if (pub->type >= 0x100) ieee_putascii("ATI%X,T%X.\r\n", i, pub->type - 0x100); else ieee_putascii("ATI%X,%X.\r\n", i, pub->type); + } i++; } } @@ -972,11 +973,12 @@ static void ieee_write_file (int debuginfo) { ieee_putascii("ASI%X,R%X,%lX,+.\r\n", i, pub->index,pub->offset); else ieee_putascii("ASI%X,%lX,%lX,+.\r\n", i, pub->segment*16,pub->offset); - if (debuginfo) + if (debuginfo) { if (pub->type >= 0x100) ieee_putascii("ATI%X,T%X.\r\n", i, pub->type - 0x100); else ieee_putascii("ATI%X,%X.\r\n", i, pub->type); + } i++; pub = pub->next; } @@ -1019,11 +1021,12 @@ static void ieee_write_file (int debuginfo) { ieee_putascii("ASN%X,R%X,%lX,+.\r\n", i, loc->index,loc->offset); else ieee_putascii("ASN%X,%lX,%lX,+.\r\n", i, loc->segment*16,loc->offset); - if (debuginfo) + if (debuginfo) { if (loc->type >= 0x100) ieee_putascii("ATN%X,T%X.\r\n", i, loc->type - 0x100); else ieee_putascii("ATN%X,%X.\r\n", i, loc->type); + } i++; } } |