NASM 0.98.03
authorH. Peter Anvin <hpa@zytor.com>
Tue, 30 Apr 2002 20:59:21 +0000 (20:59 +0000)
committerH. Peter Anvin <hpa@zytor.com>
Tue, 30 Apr 2002 20:59:21 +0000 (20:59 +0000)
31 files changed:
Makefile.in
Mkfiles/Makefile.dj
README03.txt [new file with mode: 0644]
assemble.c
assemble.h
eval.c
insns.dat
insns.h
labels.c
macros.c
makedist.sh
nasm.c
nasm.h
nasmlib.c
nasmlib.h
outobj.c
parser.c
preproc.c
rdoff/Makefile.in
standard.mac
test/test1.asm [new file with mode: 0644]
test/test2.asm [new file with mode: 0644]
test/test2a.asm [new file with mode: 0644]
test/test3.asm [new file with mode: 0644]
test/test4.asm [new file with mode: 0644]
test/test4a.asm [new file with mode: 0644]
test/test4b.asm [new file with mode: 0644]
test/test4c.asm [new file with mode: 0644]
test/test5.asm [new file with mode: 0644]
test/test6.asm [new file with mode: 0644]
zoutieee.c

index 3a94ae3..3d31f56 100644 (file)
@@ -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
index 7cb2399..fb33748 100644 (file)
@@ -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 (file)
index 0000000..8d35390
--- /dev/null
@@ -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
index fef2ab7..21c5729 100644 (file)
  * \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;
 }
 
index 2ead91f..b08ceb1 100644 (file)
@@ -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);
 
diff --git a/eval.c b/eval.c
index a44ff7b..d97127c 100644 (file)
--- a/eval.c
+++ b/eval.c
@@ -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;
index 2df9893..08bb711 100644 (file)
--- a/insns.dat
+++ b/insns.dat
@@ -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
 
diff --git a/insns.h b/insns.h
index af911ee..294dd27 100644 (file)
--- a/insns.h
+++ b/insns.h
@@ -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 */
index 6259986..c47d34c 100644 (file)
--- a/labels.c
+++ b/labels.c
  */
 #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
 #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++;
index ed70a75..8a47c80 100644 (file)
--- a/macros.c
+++ b/macros.c
@@ -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
 };
index 5b7abfc..78f078a 100755 (executable)
@@ -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
diff --git a/nasm.c b/nasm.c
index 3c5327a..841640c 100644 (file)
--- a/nasm.c
+++ b/nasm.c
@@ -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 */
diff --git a/nasm.h b/nasm.h
index 240d2d4..75202aa 100644 (file)
--- a/nasm.h
+++ b/nasm.h
@@ -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.
index 86ed6c4..64f2b7f 100644 (file)
--- a/nasmlib.c
+++ b/nasmlib.c
@@ -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')
index d2997b1..0f9af79 100644 (file)
--- a/nasmlib.h
+++ b/nasmlib.h
@@ -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
index 0a7544d..f4619d9 100644 (file)
--- a/outobj.c
+++ b/outobj.c
@@ -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;
     }
 
index 1a9c9e4..0a85c9e 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -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 */
            {
index 5286dd0..5753cf2 100644 (file)
--- a/preproc.c
+++ b/preproc.c
@@ -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 {
index c55851d..37cc111 100644 (file)
@@ -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
 
index 5f86298..05905d6 100644 (file)
@@ -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 (file)
index 0000000..ce24ca1
--- /dev/null
@@ -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 (file)
index 0000000..5bbb034
--- /dev/null
@@ -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 (file)
index 0000000..2ed09a7
--- /dev/null
@@ -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 (file)
index 0000000..457ed44
--- /dev/null
@@ -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 (file)
index 0000000..357553e
--- /dev/null
@@ -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 (file)
index 0000000..bbf85a3
--- /dev/null
@@ -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 (file)
index 0000000..6344881
--- /dev/null
@@ -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 (file)
index 0000000..5d87349
--- /dev/null
@@ -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 (file)
index 0000000..12b0ee4
--- /dev/null
@@ -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 (file)
index 0000000..cf6dca0
--- /dev/null
@@ -0,0 +1,9 @@
+; test6.asm
+;   assemble with;   nasm -O2 ...
+;
+%rep 20000
+       jmp     forward
+%endrep
+forward:  dd   forward
+
+       
\ No newline at end of file
index 8475e95..0bcdb5c 100644 (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++;
         }
     }