NASM 0.98p3
authorH. Peter Anvin <hpa@zytor.com>
Tue, 30 Apr 2002 20:53:55 +0000 (20:53 +0000)
committerH. Peter Anvin <hpa@zytor.com>
Tue, 30 Apr 2002 20:53:55 +0000 (20:53 +0000)
34 files changed:
Changes
Wishlist
assemble.c
disasm.c
eval.c
eval.h
float.c
insns.dat
labels.c
labels.h
listing.c
names.c
nasm.c
nasm.h
nasmlib.c
nasmlib.h
ndisasm.c
outaout.c
outas86.c
outbin.c
outcoff.c
outdbg.c
outelf.c
outform.c
outform.h
outforms.h [new file with mode: 0644]
outobj.c
outrdf.c
outrdf2.c [new file with mode: 0644]
parser.c
parser.h
preproc.c
sync.c
zoutieee.c [new file with mode: 0644]

diff --git a/Changes b/Changes
index 24f4bfe..57584bd 100644 (file)
--- a/Changes
+++ b/Changes
@@ -442,3 +442,97 @@ corruption at ends of long PUBDEF records.
 
 Separated DOS archives into main-program and documentation to reduce
 download size.
+
+0.98 not released yet
+---------------------
+
+Fixed a bug whereby STRUC didn't work at all in RDF.
+
+Fixed a problem with group specification in PUBDEFs in OBJ.
+
+Improved ease of adding new output formats. Contribution due to
+Fox Cutter.
+
+Fixed a bug in relocations in the `bin' format: was showing up when
+a relocatable reference crossed an 8192-byte boundary in any output
+section.
+
+Fixed a bug in local labels: local-label lookups were inconsistent
+between passes one and two if an EQU occurred between the definition
+of a global label and the subsequent use of a local label local to
+that global.
+
+Fixed a seg-fault in the preprocessor (again) which happened when
+you use a blank line as the first line of a multi-line macro
+definition and then defined a label on the same line as a call to
+that macro.
+
+Fixed a stale-pointer bug in the handling of the NASM environment
+variable. Thanks to Thomas McWilliams.
+
+ELF had a hard limit on the number of sections which caused
+segfaults when transgressed. Fixed.
+
+Added ability for ndisasm to read from stdin by using `-' as the
+filename.
+
+ndisasm wasn't outputting the TO keyword. Fixed.
+
+Fixed error cascade on bogus expression in %if - an error in
+evaluation was causing the entire %if to be discarded, thus creating
+trouble later when the %else or %endif was encountered.
+
+Forward reference tracking was instruction-granular not operand-
+granular, which was causing 286-specific code to be generated
+needlessly on code of the form `shr word [forwardref],1'. Thanks to
+Jim Hague for sending a patch.
+
+All messages now appear on stdout, as sending them to stderr serves
+no useful purpose other than to make redirection difficult.
+
+Fixed the problem with EQUs pointing to an external symbol - this
+now generates an error message.
+
+Allowed multiple size prefixes to an operand, of which only the first
+is taken into account.
+
+Incorporated John Fine's changes, including fixes of a large number
+of preprocessor bugs, some small problems in OBJ, and a reworking of
+label handling to define labels before their line is assembled, rather
+than after.
+
+Reformatted a lot of the source code to be more readable. Included
+'coding.txt' as a guideline for how to format code for contributors.
+
+Stopped nested %reps causing a panic - they now cause a slightly more
+friendly error message instead.
+
+Fixed floating point constant problems (patch by Pedro Gimeno)
+
+Fixed the return value of insn_size() not being checked for -1, indicating
+an error.
+
+Incorporated 3D now instructions.
+
+Fixed the 'mov eax, eax + ebx' bug.
+
+Fixed the GLOBAL EQU bug in ELF. Released developers release 3.
+
+Incorporated John Fine's command line parsing changes
+
+Incorporated David Lindauer's OMF debug support
+
+Made changes for LCC 4.0 support (__NASM_CDecl__, removed register size
+specification warning when sizes agree).
+
+Released NASM 0.98 Pre-release 1
+
+fixed bug in outcoff.c to do with truncating section names longer
+than 8 characters, referencing beyond end of string; 0.98 pre-release 2
+
+added response file support, improved command line handling, new layout
+help screen
+
+fixed limit checking bug, 'OUT byte nn, reg' bug, and a couple of rdoff
+related bugs, updated Wishlist; 0.98 Prerelease 3.
+
index 197b113..b1529bf 100644 (file)
--- a/Wishlist
+++ b/Wishlist
 NASM Wishlist
 =============
 
-- forward-reference tracking is instruction-granular not operand-
-  granular. Bummer.
+Numbers on right hand side are version numbers that it would be nice to
+have this done by. ? means I haven't looked at it yet.
 
-- see if BITS can be made to do anything sensible in obj (eg set the
+- Create a binary RDF tools distribution. Should probably be distributed 0.98
+  seperately.
+
+- Check misc/ide.cfg into RCS as Watcom IDE enhancement thingy.                0.98
+  (nop@dlc.fi)
+
+- Package the Linux Assembler HOWTO.                                   0.98
+
+- AMD 3dNow extensions need documenting.                               0.98
+
+- prototypes of lrotate don't match in test/*. Fix.                    0.98
+
+- Build djgpp binaries for 0.98 onwards. Look into PMODE/W as a stub   0.98
+  - it might be a lot better than CWSDPMI. It's in PMW133.ZIP.
+
+- Fix `%error' giving error messages twice.                            0.99
+  Not especially important, as changes planned for 1.1x below will make
+  the preprocessor be only called once.
+
+- Sort out problems with OBJ:                                          0.99
+  * TLINK32 doesn't seem to like SEGDEF32 et al. So for that, we
+    should avoid xxx32 records wherever we can.
+  * However, didn't we change _to_ using xxx32 at some stage? Try
+    to remember why and when.
+  * Apparently Delphi's linker has trouble with two or more
+    globals being defined inside a PUBDEF32. Don't even know if it
+    _can_ cope with a PUBDEF16.
+  * Might need extra flags. *sigh*
+
+- Symbol table output may possibly be useful.                          0.99
+  Ken Martwick (kenm@efn.org) wants the following format:
+       labelname       type    offset(hex)     repetition count
+  Possibly include xref addresses after repetition count?
+
+- There are various other bugs in outelf.c that make certain kinds     0.99
+  of relocation not work. See zbrown.asm. Looks like we may have to do
+  a major rewrite of parts of it. Compare some NASM code output with
+  equivalent GAS code output. Look at the ELF spec. Generally fix things.
+
+- NASM is currently using a kludge in ELF that involves defining       0.99
+  a symbol at a zero absolute offset. This isn't needed, as the
+  documented solution to the problem that this solves is to use
+  SHN_UNDEF.
+
+- Debug information, in all formats it can be usefully done in.                0.99
+  * including line-number record support.
+  * "George C. Lindauer" <gclind01@starbase.spd.louisville.edu>
+    wants to have some say in how this goes through.
+  * Andrew Crabtree <andrewc@rosemail.rose.hp.com> wants to help out.
+
+- Think about a line-continuation character.                           0.99
+
+- Consider allowing declaration of two labels on the same line,
+  syntax 'label1[:] label2[:] ... instruction'. Need to investigate
+  feasibility.                                                         0.99
+
+- Quoting of quotes by doubling them, in string and char constants.    0.99
+
+- Two-operand syntax for SEGMENT/SECTION macro to avoid warnings       0.99
+  of ignored section parameters on reissue of __SECT__.
+  Or maybe skip the warning if the given parameters are identical to
+  what was actually stored. Investigate.                               
+
+- Apparently we are not missing a PSRAQ instruction, because it
+  doesn't exist.  Check that it doesn't exist as an undocumented
+  instruction, or something stupid like that.                          0.99
+
+- Any assembled form starting 0x80 can also start 0x82. ndisasm                1.00
+  should know this. New special code in instruction encodings,
+  probably.
+
+- Pointing an EQU at an external symbol now generates an error. There  1.05
+  may be a better way of handling this; we should look into it.
+  Ideally, the label mechanism should be changed to cope with one
+  label being declared relative to another - that may work, but could be
+  a pain to implement (or is it? it may be easy enough that you just
+  need to declare a new offset in the same segment...) This should be done
+  before v1.0 is released. There is a comment regarding this in labels.c,
+  towards the end of the file, which discusses ways of fixing this.
+
+- nested %rep used to cause a panic. Now a more informative error      1.10
+  message is produced. This problem whould be fixed before v1.0.
+  See comment in switch() statement block for PP_REP in do_directive()
+  in preproc.c (line 1585, or thereabouts)
+
+- Contribution: zgraeme.tar contains improved hash table routines      ?
+  contributed by Graeme Defty <graeme@HK.Super.NET> for use in the
+  label manager.
+
+- Contribution: zsyntax.zip contains a syntax-highlighting mode for    ?
+  NASM, for use with the Aurora text editor (??).
+
+- Contribution: zvim.zip contains a syntax-highlighting mode for       ?
+  NASM, for use with vim.
+
+- Contribution: zkendal1.zip and zkendal2.zip contain Kendall          ?
+  Bennett's (<KendallB@scitechsoft.com>) alternative syntax stuff,
+  providing an alternative syntax mode for NASM which allows a macro
+  set to be written that allows the same source files to be
+  assembled with NASM and TASM.
+
+- Add the UD2 instruction.                                             ?
+
+- Add the four instructions documented in 24368901.pdf (Intel's own    ?
+  document).
+
+- Some means of avoiding MOV memoffs,EAX which apparently the          1.10?
+  Pentium pairing detector thinks modifies EAX. Similar means of
+  choosing instruction encodings where necessary.
+
+- The example of ..@ makes it clear that a ..@ label isn't just                ?
+  local, but doesn't make it clear that it isn't just global either.
+
+- hpa wants an evaluator operator for ceil(log2(x)).                   ?
+
+- Extra reloc types in ELF: R_386_16 type 20, PC16 is 21, 8 is 22, PC8 is 23.
+  Add support for the 16s at least.                                    ?
+
+
+- Lazy section creation or selective section output, in COFF/win32     ?
+  at least and probably other formats: don't bother to emit a section
+  if it contains no data. Particularly the default auto-created
+  section. We believe zero-length sections crash at least WLINK (in
+  win32).
+
+- Make the flags field in `struct itemplate' in insns.h a long         ?
+  instead of an int.
+
+- Implement %ifref to check whether a single-line macro has ever been  ?
+  expanded since (last re) definition. Or maybe not. We'll see.
+
+- add pointer to \k{insLEAVE} and \k{insENTER} in chapters about       ?
+  mixed-language programming.
+
+- Some equivalent to TASM's GLOBAL directive, ie something which       ?
+  defines a symbol as external if it doesn't end up being defined
+  but defines it as public if it does end up being defined.
+
+- Documentation doesn't explain about C++ name mangling.               ?
+
+- see if BITS can be made to do anything sensible in obj (eg set the   ?
   default new-segment property to Use32).
 
-- __DATE__, __TIME__, and text variants of __NASM_MAJOR__ and
+- OBJ: coalesce consecutive offset and segment fixups for the same     ?
+  location into full-32bit-pointer fixups. This is apparently
+  necessary because some twazzock in the PowerBASIC development
+  team didn't deign to support the OMF spec the way the rest of the
+  world sees it.
+
+- Allow % to be separated from the rest of a preproc directive, for    ?
+  alternative directive indentation styles.
+
+- __DATE__, __TIME__, and text variants of __NASM_MAJOR__ and          ?
   __NASM_MINOR__.
 
-- Warn on TIMES combined with multi-line macros. TIMES gets applied
+- Warn on TIMES combined with multi-line macros. TIMES gets applied    1.00
   to first line only - should bring to users' attention.
 
-- Add support for lcc 4.0.
-  * If-when this happens, remember to bump the `supported lcc
-    version' number in Readme.
-
-- Re-work the evaluator, again, with a per-object-format fixup
+- Re-work the evaluator, again, with a per-object-format fixup         1.10
   routine, so as to be able to cope with section offsets "really"
   being pure numbers; should be able to allow at _least_ the two
   common idioms
@@ -28,17 +173,33 @@ NASM Wishlist
   had to. (_Always_ returning UNKNOWN on pass one, though a lovely
   clean design, breaks the first of the above examples.)
 
-- Preprocessor identifier concatenation?
+- Preprocessor identifier concatenation?                               1.10
 
-- Arbitrary section names in `bin'.
+- Arbitrary section names in `bin'.                                    ?
+  Is this necessary? Is it even desirable?
 
-- Ability to read from a pipe. Obviously not useful under dos, so
+- Ability to read from a pipe. Obviously not useful under dos, so      1.10
   memory problems with storing entire input file aren't a problem
   either.
 
-- Subsection support?
+  Related topic: file caching under DOS/32 bit...                      1.10?
+  maybe even implement discardable buffers that get thrown away
+  when we get a NULL returned from malloc(). Only really useful under
+  DOS. Think about it.
+
+  Another related topic: possibly spool out the pre-processed          1.10?
+  stuff to a file, to avoid having to re-process it. Possible problems
+  with preprocessor values not known on pass 1? Have a look...
+
+  Or maybe we can spool out a pre-parsed version...?                   1.10
+  Need to investigate feasibility. Does the results from the parser
+  change from pass 1 to pass 2? Would it be feasible to alter it so that
+  the parser returns an invariant result, and this is then processed
+  afterwards to resolve label references, etc?
 
-- A good ALIGN mechanism, similar to GAS's. GAS pads out space by
+- Subsection support?                                                  ?
+
+- A good ALIGN mechanism, similar to GAS's. GAS pads out space by      1.10?
   means of the following (32-bit) instructions:
           8DB42600000000    lea esi,[esi+0x0]
           8DB600000000      lea esi,[esi+0x0]
@@ -55,7 +216,7 @@ NASM Wishlist
     Also re-work the macro form so that when given one argument in a
   code section it calls this feature.
 
-- Possibly a means whereby FP constants can be specified as
+- Possibly a means whereby FP constants can be specified as            ?
   immediate operands to non-FP instructions.
   * Possible syntax: MOV EAX,FLOAT 1.2 to get a single-precision FP
     constant. Then maybe MOV EAX,HI_FLOAT 1.2 and MOV EAX,LO_FLOAT
@@ -67,37 +228,41 @@ NASM Wishlist
     chunks, one-byte chunks, even stranger chunks, and pieces of
     ten-byte reals to be bandied around as well.
 
-- A UNION macro might be quite cool, now that ABSOLUTE is sane
+- A UNION macro might be quite cool, now that ABSOLUTE is sane         ?
   enough to be able to handle it.
 
-- An equivalent to gcc's ## stringify operator, plus string
+- An equivalent to gcc's ## stringify operator, plus string            ?
   concatenation, somehow implemented without undue ugliness, so as
   to be able to do `%include "/my/path/%1"' in a macro, or something
   similar...
 
-- Actually _do_ something with the processor, privileged and
-  undocumented flags in the instruction table.
+- Actually _do_ something with the processor, privileged and           1.10
+  undocumented flags in the instruction table. When this happens,
+  consider allowing PMULHRW to map to either of the Cyrix or AMD
+  versions?
 
-- Maybe NEC V20/V30 instructions?
+- Maybe NEC V20/V30 instructions?                                      ?
 
 - Yet more object formats.
-  * Possibly direct support for .EXE files?
-
-- Debug information, in all formats it can be usefully done in.
-  * including line-number record support.
+  * Possibly direct support for .EXE files?                            1.10
 
-- Symbol map in binary format. Format-specific options...
+- Symbol map in binary format. Format-specific options...              1.10?
 
-- REDESIGN: Think about EQU dependency, and about start-point
+- REDESIGN: Think about EQU dependency, and about start-point          1.20?
   specification in OBJ. Possibly re-think directive support.
 
-- Think about a wrapper program like gcc? Possibly invent a _patch_
+- Think about a wrapper program like gcc? Possibly invent a _patch_    2.00?
   for gcc so that it can take .asm files on the command line?
 
-- If a wrapper happens, think about adding an option to cause the
+- If a wrapper happens, think about adding an option to cause the      ?
   resulting executable file to be executed immediately, thus
   allowing NASM source files to have #!... (probably silly)
 
-- Multi-platform support? If so: definitely Alpha; possibly Java
+- Multi-platform support? If so: definitely Alpha; possibly Java       ?
   byte code; probably ARM/StrongARM; maybe Sparc; maybe Mips; maybe
   Vax. Perhaps Z80 and 6502, just for a laugh?
+
+- Consider a 'verbose' option that prints information about the resulting ?
+  object file onto stdout.
+
+
index 8d14412..65bcea3 100644 (file)
@@ -72,10 +72,10 @@ static ListGen *list;
 
 static long calcsize (long, long, int, insn *, char *);
 static void gencode (long, long, int, insn *, char *, long);
-static int regval (operand *o);
-static int matches (struct itemplate *, insn *);
-static ea *process_ea (operand *, ea *, int, int, int);
-static int chsize (operand *, int);
+static int  regval (operand *o);
+static int  matches (struct itemplate *, insn *);
+static ea * process_ea (operand *, ea *, int, int, int);
+static int  chsize (operand *, int);
 
 /*
  * This routine wrappers the real output format's output routine,
@@ -83,7 +83,11 @@ static int chsize (operand *, int);
  * generator at the same time.
  */
 static void out (long offset, long segto, void *data, unsigned long type,
-                long segment, long wrt) {
+                long segment, long wrt) 
+{
+    static long lineno;
+    static char *lnfname;
+
     if ((type & OUT_TYPMASK) == OUT_ADDRESS) {
        if (segment != NO_SEG || wrt != NO_SEG) {
            /*
@@ -91,7 +95,8 @@ static void out (long offset, long segto, void *data, unsigned long type,
             * OUT_ADDRESS, so there's no work to be done here.
             */
            list->output (offset, data, type);
-       } else {
+       } 
+       else {
            unsigned char p[4], *q = p;
            /*
             * This is a non-relocated address, and we're going to
@@ -100,90 +105,105 @@ static void out (long offset, long segto, void *data, unsigned long type,
            if ((type & OUT_SIZMASK) == 4) {
                WRITELONG (q, * (long *) data);
                list->output (offset, p, OUT_RAWDATA+4);
-           } else {
+           } 
+           else {
                WRITESHORT (q, * (long *) data);
                list->output (offset, p, OUT_RAWDATA+2);
            }
        }
-    } else if ((type & OUT_TYPMASK) == OUT_RAWDATA) {
+    } 
+    else if ((type & OUT_TYPMASK) == OUT_RAWDATA) {
        list->output (offset, data, type);
-    } else if ((type & OUT_TYPMASK) == OUT_RESERVE) {
+    } 
+    else if ((type & OUT_TYPMASK) == OUT_RESERVE) {
        list->output (offset, NULL, type);
-    } else if ((type & OUT_TYPMASK) == OUT_REL2ADR ||
+    } 
+    else if ((type & OUT_TYPMASK) == OUT_REL2ADR ||
               (type & OUT_TYPMASK) == OUT_REL4ADR) {
        list->output (offset, data, type);
     }
 
+    if (src_get(&lineno,&lnfname))
+       outfmt->current_dfmt->linenum(lnfname,lineno,segto);
+
     outfmt->output (segto, data, type, segment, wrt);
 }
 
 long assemble (long segment, long offset, int bits,
               insn *instruction, struct ofmt *output, efunc error,
-              ListGen *listgen) {
-    int j, size_prob;
-    long insn_end, itimes;
-    long start = offset;
+              ListGen *listgen) 
+{
     struct itemplate *temp;
+    int    j;
+    int    size_prob;
+    long   insn_end;
+    long   itimes;
+    long   start = offset;
+    long   wsize = 0;                 /* size for DB etc. */
 
     errfunc = error;                  /* to pass to other functions */
     outfmt = output;                  /* likewise */
     list = listgen;                   /* and again */
 
-    if (instruction->opcode == -1)
-       return 0;
-
-    if (instruction->opcode == I_DB ||
-       instruction->opcode == I_DW ||
-       instruction->opcode == I_DD ||
-       instruction->opcode == I_DQ ||
-       instruction->opcode == I_DT) {
-       extop *e;
-       long wsize = 0;                /* placate gcc */
-       long t = instruction->times;
-
-       switch (instruction->opcode) {
-         case I_DB: wsize = 1; break;
-         case I_DW: wsize = 2; break;
-         case I_DD: wsize = 4; break;
-         case I_DQ: wsize = 8; break;
-         case I_DT: wsize = 10; break;
-       }
+    switch (instruction->opcode) 
+    {
+       case   -1: return 0;
+       case I_DB: wsize = 1; break;
+       case I_DW: wsize = 2; break;
+       case I_DD: wsize = 4; break;
+       case I_DQ: wsize = 8; break;
+       case I_DT: wsize = 10; break;
+    }
 
-       while (t--) {
-           for (e = instruction->eops; e; e = e->next) {
-               if (e->type == EOT_DB_NUMBER) {
+    if (wsize) {
+       extop  * e;
+       long   t = instruction->times;
+       if (t < 0)
+           errfunc(ERR_PANIC, "instruction->times < 0 (%ld) in assemble()",t);
+
+       while (t--)                    /* repeat TIMES times */
+       {
+           for (e = instruction->eops; e; e = e->next) 
+           {
+               if (e->type == EOT_DB_NUMBER) 
+               {
                    if (wsize == 1) {
                        if (e->segment != NO_SEG)
                            errfunc (ERR_NONFATAL,
                                     "one-byte relocation attempted");
                        else {
-                           unsigned char c = e->offset;
-                           out (offset, segment, &c, OUT_RAWDATA+1,
+                           out (offset, segment, &e->offset, OUT_RAWDATA+1,
                                 NO_SEG, NO_SEG);
                        }
-                   } else if (wsize > 5) {
+                   } 
+                   else if (wsize > 5) {
                        errfunc (ERR_NONFATAL, "integer supplied to a D%c"
                                 " instruction", wsize==8 ? 'Q' : 'T');
-                   } else
+                   } 
+                   else
                        out (offset, segment, &e->offset,
                             OUT_ADDRESS+wsize, e->segment,
                             e->wrt);
                    offset += wsize;
-               } else if (e->type == EOT_DB_STRING) {
+               } 
+               else if (e->type == EOT_DB_STRING) 
+               {
                    int align;
 
-                   align = (-e->stringlen) % wsize;
-                   if (align < 0)
-                       align += wsize;
                    out (offset, segment, e->stringval,
                         OUT_RAWDATA+e->stringlen, NO_SEG, NO_SEG);
-                   if (align)
-                       out (offset, segment, "\0\0\0\0",
+                   align = e->stringlen % wsize;
+
+                   if (align) {
+                       align = wsize - align;
+                       out (offset, segment, "\0\0\0\0\0\0\0\0",
                             OUT_RAWDATA+align, NO_SEG, NO_SEG);
+                       }
                    offset += e->stringlen + align;
                }
            }
-           if (t > 0 && t == instruction->times-1) {
+           if (t > 0 && t == instruction->times-1) 
+           {
                /*
                 * Dummy call to list->output to give the offset to the
                 * listing module.
@@ -197,29 +217,33 @@ long assemble (long segment, long offset, int bits,
        return offset - start;
     }
 
-    if (instruction->opcode == I_INCBIN) {
+    if (instruction->opcode == I_INCBIN) 
+    {
        static char fname[FILENAME_MAX];
-       FILE *fp;
-       long len;
+       FILE        * fp;
+       long        len;
 
        len = FILENAME_MAX-1;
        if (len > instruction->eops->stringlen)
            len = instruction->eops->stringlen;
        strncpy (fname, instruction->eops->stringval, len);
        fname[len] = '\0';
-       if (!(fp = fopen(fname, "rb")))
+
+       if ( (fp = fopen(fname, "rb")) == NULL)
            error (ERR_NONFATAL, "`incbin': unable to open file `%s'", fname);
        else if (fseek(fp, 0L, SEEK_END) < 0)
            error (ERR_NONFATAL, "`incbin': unable to seek on file `%s'",
                   fname);
-       else {
+       else 
+       {
            static char buf[2048];
            long t = instruction->times;
-           long l;
+           long base = 0;
 
            len = ftell (fp);
            if (instruction->eops->next) {
-               len -= instruction->eops->next->offset;
+               base = instruction->eops->next->offset;
+               len -= base;
                if (instruction->eops->next->next &&
                    len > instruction->eops->next->next->offset)
                    len = instruction->eops->next->next->offset;
@@ -230,11 +254,11 @@ long assemble (long segment, long offset, int bits,
             */
            list->output (offset, NULL, OUT_RAWDATA);
            list->uplevel(LIST_INCBIN);
-           while (t--) {
-               fseek (fp, 
-                      (instruction->eops->next ?
-                       instruction->eops->next->offset : 0),
-                      SEEK_SET);               
+           while (t--) 
+           {
+               long l;
+
+               fseek (fp, base, SEEK_SET);             
                l = len;
                while (l > 0) {
                    long m = fread (buf, 1, (l>sizeof(buf)?sizeof(buf):l),
@@ -247,7 +271,8 @@ long assemble (long segment, long offset, int bits,
                         */
                        error (ERR_NONFATAL, "`incbin': unexpected EOF while"
                               " reading file `%s'", fname);
-                       return 0;      /* it doesn't much matter... */
+                       t=0;  /* Try to exit cleanly */
+                       break;
                    }
                    out (offset, segment, buf, OUT_RAWDATA+m,
                         NO_SEG, NO_SEG);
@@ -274,7 +299,9 @@ long assemble (long segment, long offset, int bits,
     temp = nasm_instructions[instruction->opcode];
     while (temp->opcode != -1) {
        int m = matches (temp, instruction);
-       if (m == 100) {                /* matches! */
+
+       if (m == 100)                  /* matches! */
+       {
            char *codes = temp->code;
            long insn_size = calcsize(segment, offset, bits,
                                      instruction, codes);
@@ -284,7 +311,7 @@ long assemble (long segment, long offset, int bits,
            else while (itimes--) {
                insn_end = offset + insn_size;
                for (j=0; j<instruction->nprefix; j++) {
-                   unsigned char c;
+                   unsigned char c=0;
                    switch (instruction->prefixes[j]) {
                      case P_LOCK:
                        c = 0xF0; break;
@@ -299,37 +326,30 @@ long assemble (long segment, long offset, int bits,
                      case R_GS: c = 0x65; break;
                      case R_SS: c = 0x36; break;
                      case P_A16:
-                       if (bits == 16)
-                           c = 0;     /* no prefix */
-                       else
+                       if (bits != 16)
                            c = 0x67;
                        break;
                      case P_A32:
-                       if (bits == 32)
-                           c = 0;     /* no prefix */
-                       else
+                       if (bits != 32)
                            c = 0x67;
                        break;
                      case P_O16:
-                       if (bits == 16)
-                           c = 0;     /* no prefix */
-                       else
+                       if (bits != 16)
                            c = 0x66;
                        break;
                      case P_O32:
-                       if (bits == 32)
-                           c = 0;     /* no prefix */
-                       else
+                       if (bits != 32)
                            c = 0x66;
                        break;
                      default:
                        error (ERR_PANIC,
                               "invalid instruction prefix");
                    }
-                   if (c != 0)
+                   if (c != 0) {
                        out (offset, segment, &c, OUT_RAWDATA+1,
                             NO_SEG, NO_SEG);
-                   offset++;
+                       offset++;
+                   }
                }
                gencode (segment, offset, bits, instruction, codes, insn_end);
                offset += insn_size;
@@ -350,6 +370,7 @@ long assemble (long segment, long offset, int bits,
        }
        temp++;
     }
+
     if (temp->opcode == -1) {         /* didn't match any instruction */
        if (size_prob == 1)            /* would have matched, but for size */
            error (ERR_NONFATAL, "operation size not specified");
@@ -363,7 +384,8 @@ long assemble (long segment, long offset, int bits,
 }
 
 long insn_size (long segment, long offset, int bits,
-               insn *instruction, efunc error) {
+               insn *instruction, efunc error) 
+{
     struct itemplate *temp;
 
     errfunc = error;                  /* to pass to other functions */
@@ -375,12 +397,14 @@ long insn_size (long segment, long offset, int bits,
        instruction->opcode == I_DW ||
        instruction->opcode == I_DD ||
        instruction->opcode == I_DQ ||
-       instruction->opcode == I_DT) {
+       instruction->opcode == I_DT) 
+    {
        extop *e;
        long isize, osize, wsize = 0;  /* placate gcc */
 
        isize = 0;
-       switch (instruction->opcode) {
+       switch (instruction->opcode) 
+       {
          case I_DB: wsize = 1; break;
          case I_DW: wsize = 2; break;
          case I_DD: wsize = 4; break;
@@ -388,7 +412,8 @@ long insn_size (long segment, long offset, int bits,
          case I_DT: wsize = 10; break;
        }
 
-       for (e = instruction->eops; e; e = e->next) {
+       for (e = instruction->eops; e; e = e->next) 
+       {
            long align;
 
            osize = 0;
@@ -405,29 +430,34 @@ long insn_size (long segment, long offset, int bits,
        return isize * instruction->times;
     }
 
-    if (instruction->opcode == I_INCBIN) {
-       char fname[FILENAME_MAX];
-       FILE *fp;
-       long len;
+    if (instruction->opcode == I_INCBIN) 
+    {
+       char  fname[FILENAME_MAX];
+       FILE  * fp;
+       long  len;
 
        len = FILENAME_MAX-1;
        if (len > instruction->eops->stringlen)
            len = instruction->eops->stringlen;
        strncpy (fname, instruction->eops->stringval, len);
        fname[len] = '\0';
-       if (!(fp = fopen(fname, "rb")))
+       if ( (fp = fopen(fname, "rb")) == NULL )
            error (ERR_NONFATAL, "`incbin': unable to open file `%s'", fname);
        else if (fseek(fp, 0L, SEEK_END) < 0)
            error (ERR_NONFATAL, "`incbin': unable to seek on file `%s'",
                   fname);
-       else {
+       else 
+       {
            len = ftell (fp);
            fclose (fp);
-           if (instruction->eops->next) {
+           if (instruction->eops->next) 
+           {
                len -= instruction->eops->next->offset;
                if (instruction->eops->next->next &&
                    len > instruction->eops->next->next->offset)
+               {
                    len = instruction->eops->next->next->offset;
+               }
            }
            return instruction->times * len;
        }
@@ -438,19 +468,22 @@ long insn_size (long segment, long offset, int bits,
     while (temp->opcode != -1) {
        if (matches(temp, instruction) == 100) {
            /* we've matched an instruction. */
-           long isize;
-           char *codes = temp->code;
-           int j;
+           long  isize;
+           char  * codes = temp->code;
+           int   j;
 
            isize = calcsize(segment, offset, bits, instruction, codes);
            if (isize < 0)
                return -1;
-           for (j = 0; j < instruction->nprefix; j++) {
+           for (j = 0; j < instruction->nprefix; j++) 
+           {
                if ((instruction->prefixes[j] != P_A16 &&
                     instruction->prefixes[j] != P_O16 && bits==16) ||
                    (instruction->prefixes[j] != P_A32 &&
                     instruction->prefixes[j] != P_O32 && bits==32))
+               {
                    isize++;
+               }
            }
            return isize * instruction->times;
        }
@@ -460,9 +493,13 @@ long insn_size (long segment, long offset, int bits,
 }
 
 static long calcsize (long segment, long offset, int bits,
-                     insn *ins, char *codes) {
-    long length = 0;
-    unsigned char c;
+                     insn *ins, char *codes) 
+{
+    long           length = 0;
+    unsigned char  c;
+
+    (void) segment;  /* Don't warn that this parameter is unused */
+    (void) offset;   /* Don't warn that this parameter is unused */
 
     while (*codes) switch (c = *codes++) {
       case 01: case 02: case 03:
@@ -542,304 +579,353 @@ static long calcsize (long segment, long offset, int bits,
 }
 
 static void gencode (long segment, long offset, int bits,
-                    insn *ins, char *codes, long insn_end) {
+                    insn *ins, char *codes, long insn_end) 
+{
     static char condval[] = { /* conditional opcodes */
        0x7, 0x3, 0x2, 0x6, 0x2, 0x4, 0xF, 0xD, 0xC, 0xE, 0x6, 0x2,
        0x3, 0x7, 0x3, 0x5, 0xE, 0xC, 0xD, 0xF, 0x1, 0xB, 0x9, 0x5,
        0x0, 0xA, 0xA, 0xB, 0x8, 0x4
     };
-    unsigned char c, bytes[4];
-    long data, size;
-
-    while (*codes) switch (c = *codes++) {
-      case 01: case 02: case 03:
-       out (offset, segment, codes, OUT_RAWDATA+c, NO_SEG, NO_SEG);
-       codes += c;
-       offset += c;
-       break;
-      case 04: case 06:
-       switch (ins->oprs[0].basereg) {
-         case R_CS: bytes[0] = 0x0E + (c == 0x04 ? 1 : 0); break;
-         case R_DS: bytes[0] = 0x1E + (c == 0x04 ? 1 : 0); break;
-         case R_ES: bytes[0] = 0x06 + (c == 0x04 ? 1 : 0); break;
-         case R_SS: bytes[0] = 0x16 + (c == 0x04 ? 1 : 0); break;
-         default:
-           errfunc (ERR_PANIC, "bizarre 8086 segment register received");
-       }
-       out (offset, segment, bytes, OUT_RAWDATA+1, NO_SEG, NO_SEG);
-       offset++;
-       break;
-      case 05: case 07:
-       switch (ins->oprs[0].basereg) {
-         case R_FS: bytes[0] = 0xA0 + (c == 0x05 ? 1 : 0); break;
-         case R_GS: bytes[0] = 0xA8 + (c == 0x05 ? 1 : 0); break;
-         default:
-           errfunc (ERR_PANIC, "bizarre 386 segment register received");
-       }
-       out (offset, segment, bytes, OUT_RAWDATA+1, NO_SEG, NO_SEG);
-       offset++;
-       break;
-      case 010: case 011: case 012:
-       bytes[0] = *codes++ + regval(&ins->oprs[c-010]);
-       out (offset, segment, bytes, OUT_RAWDATA+1, NO_SEG, NO_SEG);
-       offset += 1;
-       break;
-      case 017:
-       bytes[0] = 0;
-       out (offset, segment, bytes, OUT_RAWDATA+1, NO_SEG, NO_SEG);
-       offset += 1;
-       break;
-      case 014: case 015: case 016:
-       if (ins->oprs[c-014].offset < -128 || ins->oprs[c-014].offset > 127)
-           errfunc (ERR_WARNING, "signed byte value exceeds bounds");
-       if (ins->oprs[c-014].segment != NO_SEG) {
-           data = ins->oprs[c-014].offset;
-           out (offset, segment, &data, OUT_ADDRESS+1,
-                ins->oprs[c-014].segment, ins->oprs[c-014].wrt);
-       } else {
-           bytes[0] = ins->oprs[c-014].offset;
+    unsigned char c;
+    unsigned char bytes[4];
+    long          data, size;
+
+    while (*codes)
+       switch (c = *codes++) 
+       {
+       case 01: case 02: case 03:
+           out (offset, segment, codes, OUT_RAWDATA+c, NO_SEG, NO_SEG);
+           codes += c;
+           offset += c;
+           break;
+
+       case 04: case 06:
+           switch (ins->oprs[0].basereg) 
+           {
+           case R_CS: 
+               bytes[0] = 0x0E + (c == 0x04 ? 1 : 0); break;
+           case R_DS: 
+               bytes[0] = 0x1E + (c == 0x04 ? 1 : 0); break;
+           case R_ES: 
+               bytes[0] = 0x06 + (c == 0x04 ? 1 : 0); break;
+           case R_SS: 
+               bytes[0] = 0x16 + (c == 0x04 ? 1 : 0); break;
+           default:
+               errfunc (ERR_PANIC, "bizarre 8086 segment register received");
+           }
            out (offset, segment, bytes, OUT_RAWDATA+1, NO_SEG, NO_SEG);
-       }
-       offset += 1;
-       break;
-      case 020: case 021: case 022:
-       if (ins->oprs[c-020].offset < -256 || ins->oprs[c-020].offset > 255)
-           errfunc (ERR_WARNING, "byte value exceeds bounds");
-       if (ins->oprs[c-020].segment != NO_SEG) {
-           data = ins->oprs[c-020].offset;
-           out (offset, segment, &data, OUT_ADDRESS+1,
-                ins->oprs[c-020].segment, ins->oprs[c-020].wrt);
-       } else {
-           bytes[0] = ins->oprs[c-020].offset;
+           offset++;
+           break;
+
+       case 05: case 07:
+           switch (ins->oprs[0].basereg) {
+           case R_FS: bytes[0] = 0xA0 + (c == 0x05 ? 1 : 0); break;
+           case R_GS: bytes[0] = 0xA8 + (c == 0x05 ? 1 : 0); break;
+           default:
+               errfunc (ERR_PANIC, "bizarre 386 segment register received");
+           }
            out (offset, segment, bytes, OUT_RAWDATA+1, NO_SEG, NO_SEG);
-       }
-       offset += 1;
-       break;
-      case 024: case 025: case 026:
-       if (ins->oprs[c-024].offset < 0 || ins->oprs[c-024].offset > 255)
-           errfunc (ERR_WARNING, "unsigned byte value exceeds bounds");
-       if (ins->oprs[c-024].segment != NO_SEG) {
-           data = ins->oprs[c-024].offset;
-           out (offset, segment, &data, OUT_ADDRESS+1,
-                ins->oprs[c-024].segment, ins->oprs[c-024].wrt);
-       } else {
-           bytes[0] = ins->oprs[c-024].offset;
+           offset++;
+           break;
+
+       case 010: case 011: case 012:
+           bytes[0] = *codes++ + regval(&ins->oprs[c-010]);
            out (offset, segment, bytes, OUT_RAWDATA+1, NO_SEG, NO_SEG);
-       }
-       offset += 1;
-       break;
-      case 030: case 031: case 032:
-       if (ins->oprs[c-030].segment == NO_SEG &&
-           ins->oprs[c-030].wrt == NO_SEG &&
-           (ins->oprs[c-030].offset < -65536L ||
-           ins->oprs[c-030].offset > 65535L))
-           errfunc (ERR_WARNING, "word value exceeds bounds");
-       data = ins->oprs[c-030].offset;
-       out (offset, segment, &data, OUT_ADDRESS+2,
-                       ins->oprs[c-030].segment, ins->oprs[c-030].wrt);
-       offset += 2;
-       break;
-      case 034: case 035: case 036:
-       data = ins->oprs[c-034].offset;
-       size = ((ins->oprs[c-034].addr_size ?
-                ins->oprs[c-034].addr_size : bits) == 16 ? 2 : 4);
-       if (size==16 && (data < -65536L || data > 65535L))
-           errfunc (ERR_WARNING, "word value exceeds bounds");
-       out (offset, segment, &data, OUT_ADDRESS+size,
-            ins->oprs[c-034].segment, ins->oprs[c-034].wrt);
-       offset += size;
-       break;
-      case 037:
-       if (ins->oprs[0].segment == NO_SEG)
-           errfunc (ERR_NONFATAL, "value referenced by FAR is not"
-                    " relocatable");
-       data = 0L;
-       out (offset, segment, &data, OUT_ADDRESS+2,
-            outfmt->segbase(1+ins->oprs[0].segment),
-                       ins->oprs[0].wrt);
-       offset += 2;
-       break;
-      case 040: case 041: case 042:
-       data = ins->oprs[c-040].offset;
-       out (offset, segment, &data, OUT_ADDRESS+4,
-            ins->oprs[c-040].segment, ins->oprs[c-040].wrt);
-       offset += 4;
-       break;
-      case 050: case 051: case 052:
-       if (ins->oprs[c-050].segment != segment)
-           errfunc (ERR_NONFATAL, "short relative jump outside segment");
-       data = ins->oprs[c-050].offset - insn_end;
-       if (data > 127 || data < -128)
-           errfunc (ERR_NONFATAL, "short jump is out of range");
-       bytes[0] = data;
-       out (offset, segment, bytes, OUT_RAWDATA+1, NO_SEG, NO_SEG);
-       offset += 1;
-       break;
-      case 060: case 061: case 062:
-       if (ins->oprs[c-060].segment != segment) {
-           data = ins->oprs[c-060].offset;
-           out (offset, segment, &data, OUT_REL2ADR+insn_end-offset,
-                ins->oprs[c-060].segment, ins->oprs[c-060].wrt);
-       } else {
-           data = ins->oprs[c-060].offset - insn_end;
-           out (offset, segment, &data,
-                OUT_ADDRESS+2, NO_SEG, NO_SEG);
-       }
-       offset += 2;
-       break;
-      case 064: case 065: case 066:
-       size = ((ins->oprs[c-064].addr_size ?
-                ins->oprs[c-064].addr_size : bits) == 16 ? 2 : 4);
-       if (ins->oprs[c-064].segment != segment) {
-           data = ins->oprs[c-064].offset;
-           size = (bits == 16 ? OUT_REL2ADR : OUT_REL4ADR);
-           out (offset, segment, &data, size+insn_end-offset,
-                ins->oprs[c-064].segment, ins->oprs[c-064].wrt);
-           size = (bits == 16 ? 2 : 4);
-       } else {
-           data = ins->oprs[c-064].offset - insn_end;
-           out (offset, segment, &data,
-                OUT_ADDRESS+size, NO_SEG, NO_SEG);
-       }
-       offset += size;
-       break;
-      case 070: case 071: case 072:
-       if (ins->oprs[c-070].segment != segment) {
-           data = ins->oprs[c-070].offset;
-           out (offset, segment, &data, OUT_REL4ADR+insn_end-offset,
-                ins->oprs[c-070].segment, ins->oprs[c-070].wrt);
-       } else {
-           data = ins->oprs[c-070].offset - insn_end;
-           out (offset, segment, &data,
-                OUT_ADDRESS+4, NO_SEG, NO_SEG);
-       }
-       offset += 4;
-       break;
-      case 0300: case 0301: case 0302:
-       if (chsize (&ins->oprs[c-0300], bits)) {
-           *bytes = 0x67;
-           out (offset, segment, bytes,
-                OUT_RAWDATA+1, NO_SEG, NO_SEG);
            offset += 1;
-       } else
-           offset += 0;
-       break;
-      case 0310:
-       if (bits==32) {
-           *bytes = 0x67;
-           out (offset, segment, bytes,
-                OUT_RAWDATA+1, NO_SEG, NO_SEG);
+           break;
+
+       case 017:
+           bytes[0] = 0;
+           out (offset, segment, bytes, OUT_RAWDATA+1, NO_SEG, NO_SEG);
            offset += 1;
-       } else
-           offset += 0;
-       break;
-      case 0311:
-       if (bits==16) {
-           *bytes = 0x67;
-           out (offset, segment, bytes,
-                OUT_RAWDATA+1, NO_SEG, NO_SEG);
+           break;
+
+       case 014: case 015: case 016:
+           if (ins->oprs[c-014].offset < -128 
+               || ins->oprs[c-014].offset > 127)
+           {
+               errfunc (ERR_WARNING, "signed byte value exceeds bounds");
+           }
+
+           if (ins->oprs[c-014].segment != NO_SEG) 
+           {
+               data = ins->oprs[c-014].offset;
+               out (offset, segment, &data, OUT_ADDRESS+1,
+                    ins->oprs[c-014].segment, ins->oprs[c-014].wrt);
+           } 
+           else {
+               bytes[0] = ins->oprs[c-014].offset;
+               out (offset, segment, bytes, OUT_RAWDATA+1, NO_SEG, NO_SEG);
+           }
            offset += 1;
-       } else
-           offset += 0;
-       break;
-      case 0312:
-       break;
-      case 0320:
-       if (bits==32) {
-           *bytes = 0x66;
-           out (offset, segment, bytes,
-                OUT_RAWDATA+1, NO_SEG, NO_SEG);
+           break;
+
+       case 020: case 021: case 022:
+           if (ins->oprs[c-020].offset < -256 
+               || ins->oprs[c-020].offset > 255)
+           {
+               errfunc (ERR_WARNING, "byte value exceeds bounds");
+           }
+           if (ins->oprs[c-020].segment != NO_SEG) {
+               data = ins->oprs[c-020].offset;
+               out (offset, segment, &data, OUT_ADDRESS+1,
+                    ins->oprs[c-020].segment, ins->oprs[c-020].wrt);
+           } 
+           else {
+               bytes[0] = ins->oprs[c-020].offset;
+               out (offset, segment, bytes, OUT_RAWDATA+1, NO_SEG, NO_SEG);
+           }
            offset += 1;
-       } else
-           offset += 0;
-       break;
-      case 0321:
-       if (bits==16) {
-           *bytes = 0x66;
-           out (offset, segment, bytes,
-                OUT_RAWDATA+1, NO_SEG, NO_SEG);
+           break;
+       
+       case 024: case 025: case 026:
+           if (ins->oprs[c-024].offset < 0 || ins->oprs[c-024].offset > 255)
+               errfunc (ERR_WARNING, "unsigned byte value exceeds bounds");
+           if (ins->oprs[c-024].segment != NO_SEG) {
+               data = ins->oprs[c-024].offset;
+               out (offset, segment, &data, OUT_ADDRESS+1,
+                    ins->oprs[c-024].segment, ins->oprs[c-024].wrt);
+           }
+           else {
+               bytes[0] = ins->oprs[c-024].offset;
+               out (offset, segment, bytes, OUT_RAWDATA+1, NO_SEG, NO_SEG);
+           }
            offset += 1;
-       } else
-           offset += 0;
-       break;
-      case 0322:
-       break;
-      case 0330:
-       *bytes = *codes++ + condval[ins->condition];
-       out (offset, segment, bytes,
-            OUT_RAWDATA+1, NO_SEG, NO_SEG);
-       offset += 1;
-       break;
-      case 0340: case 0341: case 0342:
-       if (ins->oprs[0].segment != NO_SEG)
-           errfunc (ERR_PANIC, "non-constant BSS size in pass two");
-       else {
-           long size = ins->oprs[0].offset << (c-0340);
-           if (size > 0)
-               out (offset, segment, NULL,
-                    OUT_RESERVE+size, NO_SEG, NO_SEG);
+           break;
+
+       case 030: case 031: case 032:
+           if (ins->oprs[c-030].segment == NO_SEG &&
+               ins->oprs[c-030].wrt == NO_SEG &&
+               (ins->oprs[c-030].offset < -65536L ||
+                ins->oprs[c-030].offset > 65535L))
+           {
+               errfunc (ERR_WARNING, "word value exceeds bounds");
+           }
+           data = ins->oprs[c-030].offset;
+           out (offset, segment, &data, OUT_ADDRESS+2,
+                ins->oprs[c-030].segment, ins->oprs[c-030].wrt);
+           offset += 2;
+           break;
+
+       case 034: case 035: case 036:
+           data = ins->oprs[c-034].offset;
+           size = ((ins->oprs[c-034].addr_size ?
+                    ins->oprs[c-034].addr_size : bits) == 16 ? 2 : 4);
+           if (size==16 && (data < -65536L || data > 65535L))
+               errfunc (ERR_WARNING, "word value exceeds bounds");
+           out (offset, segment, &data, OUT_ADDRESS+size,
+                ins->oprs[c-034].segment, ins->oprs[c-034].wrt);
            offset += size;
-       }
-       break;
-      default:                        /* can't do it by 'case' statements */
-       if (c>=0100 && c<=0277) {      /* it's an EA */
-           ea ea_data;
-           int rfield;
-           unsigned char *p;
-           long s;
-
-           if (c<=0177)               /* pick rfield from operand b */
-               rfield = regval (&ins->oprs[c&7]);
-           else                       /* rfield is constant */
-               rfield = c & 7;
-           if (!process_ea (&ins->oprs[(c>>3)&7], &ea_data, bits, rfield,
-                            ins->forw_ref))
-               errfunc (ERR_NONFATAL, "invalid effective address");
+           break;
+
+       case 037:
+           if (ins->oprs[0].segment == NO_SEG)
+               errfunc (ERR_NONFATAL, "value referenced by FAR is not"
+                        " relocatable");
+           data = 0L;
+           out (offset, segment, &data, OUT_ADDRESS+2,
+                outfmt->segbase(1+ins->oprs[0].segment),
+                ins->oprs[0].wrt);
+           offset += 2;
+               break;
 
-           p = bytes;
-           *p++ = ea_data.modrm;
-           if (ea_data.sib_present)
-               *p++ = ea_data.sib;
-           /*
-            * the cast in the next line is to placate MS C...
-            */
-           out (offset, segment, bytes, OUT_RAWDATA+(long)(p-bytes),
-                NO_SEG, NO_SEG);
-           s = p-bytes;
+       case 040: case 041: case 042:
+           data = ins->oprs[c-040].offset;
+           out (offset, segment, &data, OUT_ADDRESS+4,
+                ins->oprs[c-040].segment, ins->oprs[c-040].wrt);
+           offset += 4;
+           break;
+
+       case 050: case 051: case 052:
+           if (ins->oprs[c-050].segment != segment)
+               errfunc (ERR_NONFATAL, "short relative jump outside segment");
+           data = ins->oprs[c-050].offset - insn_end;
+           if (data > 127 || data < -128)
+               errfunc (ERR_NONFATAL, "short jump is out of range");
+           bytes[0] = data;
+           out (offset, segment, bytes, OUT_RAWDATA+1, NO_SEG, NO_SEG);
+           offset += 1;
+           break;
 
-           switch (ea_data.bytes) {
-             case 0:
-               break;
-             case 1:
-               if (ins->oprs[(c>>3)&7].segment != NO_SEG) {
-                   data = ins->oprs[(c>>3)&7].offset;
-                   out (offset, segment, &data, OUT_ADDRESS+1,
-                        ins->oprs[(c>>3)&7].segment,
-                        ins->oprs[(c>>3)&7].wrt);
-               } else {
-                   *bytes = ins->oprs[(c>>3)&7].offset;
-                   out (offset, segment, bytes, OUT_RAWDATA+1,
-                        NO_SEG, NO_SEG);
-               }
-               s++;
-               break;
-             case 2:
-             case 4:
-               data = ins->oprs[(c>>3)&7].offset;
+       case 060: case 061: case 062:
+           if (ins->oprs[c-060].segment != segment) {
+               data = ins->oprs[c-060].offset;
+               out (offset, segment, &data, OUT_REL2ADR+insn_end-offset,
+                    ins->oprs[c-060].segment, ins->oprs[c-060].wrt);
+           } else {
+               data = ins->oprs[c-060].offset - insn_end;
                out (offset, segment, &data,
-                    OUT_ADDRESS+ea_data.bytes,
-                    ins->oprs[(c>>3)&7].segment, ins->oprs[(c>>3)&7].wrt);
-               s += ea_data.bytes;
-               break;
+                    OUT_ADDRESS+2, NO_SEG, NO_SEG);
            }
-           offset += s;
-       } else
-           errfunc (ERR_PANIC, "internal instruction table corrupt"
+           offset += 2;
+           break;
+
+       case 064: case 065: case 066:
+           size = ((ins->oprs[c-064].addr_size ?
+                    ins->oprs[c-064].addr_size : bits) == 16 ? 2 : 4);
+           if (ins->oprs[c-064].segment != segment) {
+               data = ins->oprs[c-064].offset;
+               size = (bits == 16 ? OUT_REL2ADR : OUT_REL4ADR);
+               out (offset, segment, &data, size+insn_end-offset,
+                    ins->oprs[c-064].segment, ins->oprs[c-064].wrt);
+               size = (bits == 16 ? 2 : 4);
+           } else {
+               data = ins->oprs[c-064].offset - insn_end;
+               out (offset, segment, &data,
+                    OUT_ADDRESS+size, NO_SEG, NO_SEG);
+           }
+           offset += size;
+           break;
+
+       case 070: case 071: case 072:
+           if (ins->oprs[c-070].segment != segment) {
+               data = ins->oprs[c-070].offset;
+               out (offset, segment, &data, OUT_REL4ADR+insn_end-offset,
+                    ins->oprs[c-070].segment, ins->oprs[c-070].wrt);
+           } else {
+               data = ins->oprs[c-070].offset - insn_end;
+               out (offset, segment, &data,
+                    OUT_ADDRESS+4, NO_SEG, NO_SEG);
+           }
+           offset += 4;
+           break;
+
+       case 0300: case 0301: case 0302:
+           if (chsize (&ins->oprs[c-0300], bits)) {
+               *bytes = 0x67;
+               out (offset, segment, bytes,
+                    OUT_RAWDATA+1, NO_SEG, NO_SEG);
+               offset += 1;
+           } else
+               offset += 0;
+           break;
+
+       case 0310:
+           if (bits==32) {
+               *bytes = 0x67;
+               out (offset, segment, bytes,
+                    OUT_RAWDATA+1, NO_SEG, NO_SEG);
+               offset += 1;
+           } else
+               offset += 0;
+           break;
+
+       case 0311:
+           if (bits==16) {
+               *bytes = 0x67;
+               out (offset, segment, bytes,
+                    OUT_RAWDATA+1, NO_SEG, NO_SEG);
+               offset += 1;
+           } else
+               offset += 0;
+           break;
+
+       case 0312:
+           break;
+
+       case 0320:
+           if (bits==32) {
+               *bytes = 0x66;
+               out (offset, segment, bytes,
+                    OUT_RAWDATA+1, NO_SEG, NO_SEG);
+               offset += 1;
+           } else
+               offset += 0;
+           break;
+
+       case 0321:
+           if (bits==16) {
+               *bytes = 0x66;
+               out (offset, segment, bytes,
+                    OUT_RAWDATA+1, NO_SEG, NO_SEG);
+               offset += 1;
+           } else
+               offset += 0;
+           break;
+
+       case 0322:
+           break;
+
+       case 0330:
+           *bytes = *codes++ + condval[ins->condition];
+           out (offset, segment, bytes,
+                OUT_RAWDATA+1, NO_SEG, NO_SEG);
+           offset += 1;
+           break;
+
+       case 0340: case 0341: case 0342:
+           if (ins->oprs[0].segment != NO_SEG)
+               errfunc (ERR_PANIC, "non-constant BSS size in pass two");
+           else {
+               long size = ins->oprs[0].offset << (c-0340);
+               if (size > 0)
+                   out (offset, segment, NULL,
+                        OUT_RESERVE+size, NO_SEG, NO_SEG);
+               offset += size;
+           }
+           break;
+
+       default:                       /* can't do it by 'case' statements */
+           if (c>=0100 && c<=0277) {      /* it's an EA */
+               ea ea_data;
+               int rfield;
+               unsigned char *p;
+               long s;
+
+               if (c<=0177)           /* pick rfield from operand b */
+                   rfield = regval (&ins->oprs[c&7]);
+               else                   /* rfield is constant */
+                   rfield = c & 7;
+
+               if (!process_ea (&ins->oprs[(c>>3)&7], &ea_data, bits, rfield,
+                                ins->forw_ref))
+               {
+                   errfunc (ERR_NONFATAL, "invalid effective address");
+               }
+
+               p = bytes;
+               *p++ = ea_data.modrm;
+               if (ea_data.sib_present)
+                   *p++ = ea_data.sib;
+
+               s = p-bytes;
+               out (offset, segment, bytes, OUT_RAWDATA + s,
+                    NO_SEG, NO_SEG);
+
+               switch (ea_data.bytes) {
+               case 0:
+                   break;
+               case 1:
+                   if (ins->oprs[(c>>3)&7].segment != NO_SEG) {
+                       data = ins->oprs[(c>>3)&7].offset;
+                       out (offset, segment, &data, OUT_ADDRESS+1,
+                            ins->oprs[(c>>3)&7].segment,
+                            ins->oprs[(c>>3)&7].wrt);
+                   } else {
+                       *bytes = ins->oprs[(c>>3)&7].offset;
+                       out (offset, segment, bytes, OUT_RAWDATA+1,
+                            NO_SEG, NO_SEG);
+                   }
+                   s++;
+                   break;
+               case 2:
+               case 4:
+                   data = ins->oprs[(c>>3)&7].offset;
+                   out (offset, segment, &data,
+                        OUT_ADDRESS+ea_data.bytes,
+                        ins->oprs[(c>>3)&7].segment, ins->oprs[(c>>3)&7].wrt);
+                   s += ea_data.bytes;
+                   break;
+               }
+               offset += s;
+           } else
+               errfunc (ERR_PANIC, "internal instruction table corrupt"
                     ": instruction code 0x%02X given", c);
-    }
+       }
 }
 
-static int regval (operand *o) {
+static int regval (operand *o) 
+{
     switch (o->basereg) {
       case R_EAX: case R_AX: case R_AL: case R_ES: case R_CR0: case R_DR0:
       case R_ST0: case R_MM0:
@@ -871,7 +957,8 @@ static int regval (operand *o) {
     }
 }
 
-static int matches (struct itemplate *itemp, insn *instruction) {
+static int matches (struct itemplate *itemp, insn *instruction) 
+{
     int i, size, oprs, ret;
 
     ret = 100;
@@ -899,7 +986,8 @@ static int matches (struct itemplate *itemp, insn *instruction) {
     for (i=0; i<itemp->operands; i++)
        if (itemp->opd[i] & ~instruction->oprs[i].type ||
            ((itemp->opd[i] & SIZE_MASK) &&
-            ((itemp->opd[i] ^ instruction->oprs[i].type) & SIZE_MASK))) {
+            ((itemp->opd[i] ^ instruction->oprs[i].type) & SIZE_MASK)))
+       {
            if ((itemp->opd[i] & ~instruction->oprs[i].type & NON_SIZE) ||
                (instruction->oprs[i].type & SIZE_MASK))
                return 0;
@@ -939,7 +1027,8 @@ static int matches (struct itemplate *itemp, insn *instruction) {
 }
 
 static ea *process_ea (operand *input, ea *output, int addrbits, int rfield,
-                      int forw_ref) {
+                      int forw_ref) 
+{
     if (!(REGISTER & ~input->type)) {  /* it's a single register */
        static int regs[] = {
            R_MM0, R_EAX, R_AX, R_AL, R_MM1, R_ECX, R_CX, R_CL,
@@ -955,7 +1044,8 @@ static ea *process_ea (operand *input, ea *output, int addrbits, int rfield,
            output->sib_present = FALSE;/* no SIB necessary */
            output->bytes = 0;         /* no offset necessary either */
            output->modrm = 0xC0 | (rfield << 3) | (i/4);
-       } else
+       } 
+       else
            return NULL;
     } else {                          /* it's a memory reference */
        if (input->basereg==-1 && (input->indexreg==-1 || input->scale==0)) {
@@ -965,7 +1055,8 @@ static ea *process_ea (operand *input, ea *output, int addrbits, int rfield,
            output->sib_present = FALSE;
            output->bytes = (addrbits==32 ? 4 : 2);
            output->modrm = (addrbits==32 ? 5 : 6) | (rfield << 3);
-       } else {                       /* it's an indirection */
+       } 
+       else {                 /* it's an indirection */
            int i=input->indexreg, b=input->basereg, s=input->scale;
            long o=input->offset, seg=input->segment;
            int hb=input->hintbase, ht=input->hinttype;
@@ -1029,13 +1120,15 @@ static ea *process_ea (operand *input, ea *output, int addrbits, int rfield,
                             (o>=-128 && o<=127 && seg==NO_SEG && !forw_ref &&
                              !(input->eaflags & EAF_WORDOFFS))) {
                        mod = 1;
-                   } else
+                   } 
+                   else
                        mod = 2;
 
                    output->sib_present = FALSE;
                    output->bytes = (b==-1 || mod==2 ? 4 : mod);
                    output->modrm = (mod<<6) | (rfield<<3) | rm;
-               } else {               /* we need a SIB */
+               } 
+               else {         /* we need a SIB */
                    int mod, scale, index, base;
 
                    switch (b) {
@@ -1091,7 +1184,8 @@ static ea *process_ea (operand *input, ea *output, int addrbits, int rfield,
                    output->modrm = (mod<<6) | (rfield<<3) | 4;
                    output->sib = (scale<<6) | (index<<3) | base;
                }
-           } else {                   /* it's 16-bit */
+           } 
+           else {                     /* it's 16-bit */
                int mod, rm;
 
                /* check all registers are BX, BP, SI or DI */
@@ -1152,7 +1246,8 @@ static ea *process_ea (operand *input, ea *output, int addrbits, int rfield,
     return output;
 }
 
-static int chsize (operand *input, int addrbits) {
+static int chsize (operand *input, int addrbits) 
+{
     if (!(MEMORY & ~input->type)) {
        int i=input->indexreg, b=input->basereg;
 
@@ -1168,6 +1263,7 @@ static int chsize (operand *input, int addrbits) {
            return (addrbits==16);
        else
            return (addrbits==32);
-    } else
+    } 
+    else
        return 0;
 }
index 3dded0d..4764bc1 100644 (file)
--- a/disasm.c
+++ b/disasm.c
@@ -33,7 +33,8 @@ extern struct itemplate **itable[];
 #define SEG_NODISP 64
 #define SEG_SIGNED 128
 
-static int whichreg(long regflags, int regval) {
+static int whichreg(long regflags, int regval) 
+{
     static int reg32[] = {
        R_EAX, R_ECX, R_EDX, R_EBX, R_ESP, R_EBP, R_ESI, R_EDI };
     static int reg16[] = {
@@ -98,7 +99,8 @@ static int whichreg(long regflags, int regval) {
     return 0;
 }
 
-static char *whichcond(int condval) {
+static char *whichcond(int condval) 
+{
     static int conds[] = {
        C_O, C_NO, C_C, C_NC, C_Z, C_NZ, C_NA, C_A,
        C_S, C_NS, C_PE, C_PO, C_L, C_NL, C_NG, C_G
@@ -110,7 +112,8 @@ static char *whichcond(int condval) {
  * Process an effective address (ModRM) specification.
  */
 static unsigned char *do_ea (unsigned char *data, int modrm, int asize,
-                            int segsize, operand *op) {
+                            int segsize, operand *op) 
+{
     int mod, rm, scale, index, base;
 
     mod = (modrm >> 6) & 03;
@@ -249,11 +252,13 @@ static unsigned char *do_ea (unsigned char *data, int modrm, int asize,
  * stream in data. Return the number of bytes matched if so.
  */
 static int matches (unsigned char *r, unsigned char *data, int asize,
-                   int osize, int segsize, insn *ins) {
-    unsigned char *origdata = data;
-    int a_used = FALSE, o_used = FALSE;
+                   int osize, int segsize, insn *ins) 
+{
+    unsigned char * origdata = data;
+    int           a_used = FALSE, o_used = FALSE;
 
-    while (*r) {
+    while (*r) 
+    {
        int c = *r++;
        if (c >= 01 && c <= 03) {
            while (c--)
@@ -440,7 +445,8 @@ static int matches (unsigned char *r, unsigned char *data, int asize,
 }
 
 long disasm (unsigned char *data, char *output, int segsize, long offset,
-            int autosync) {
+            int autosync) 
+{
     struct itemplate **p;
     int length = 0;
     char *segover;
@@ -486,7 +492,8 @@ long disasm (unsigned char *data, char *output, int segsize, long offset,
     works = TRUE;
     for (p = itable[*data]; *p; p++)
        if ( (length = matches((unsigned char *)((*p)->code), data,
-                              asize, osize, segsize, &ins)) ) {
+                              asize, osize, segsize, &ins)) ) 
+       {
            works = TRUE;
            /*
             * Final check to make sure the types of r/m match up.
@@ -507,11 +514,17 @@ long disasm (unsigned char *data, char *output, int segsize, long offset,
                    ((((*p)->opd[i] & (REGISTER | FPUREG)) ||
                      (ins.oprs[i].segment & SEG_RMREG)) &&
                     !whichreg ((*p)->opd[i], ins.oprs[i].basereg)))
-
+               {
                    works = FALSE;
+                   /*
+                    * FIXME: can we do a break here?
+                    */
+               }
+
            if (works)
                break;
        }
+
     if (!length || !works)
        return 0;                      /* no instruction was matched */
 
@@ -570,9 +583,12 @@ long disasm (unsigned char *data, char *output, int segsize, long offset,
            colon = FALSE;
 
        if (((*p)->opd[i] & (REGISTER | FPUREG)) ||
-           (ins.oprs[i].segment & SEG_RMREG)) {
+           (ins.oprs[i].segment & SEG_RMREG)) 
+       {
            ins.oprs[i].basereg = whichreg ((*p)->opd[i],
                                            ins.oprs[i].basereg);
+           if ( (*p)->opd[i] & TO )
+               slen += sprintf(output+slen, "to ");
            slen += sprintf(output+slen, "%s",
                            reg_names[ins.oprs[i].basereg-EXPR_REG_START]);
        } else if (!(UNITY & ~(*p)->opd[i])) {
@@ -680,7 +696,8 @@ long disasm (unsigned char *data, char *output, int segsize, long offset,
     return length;
 }
 
-long eatbyte (unsigned char *data, char *output) {
+long eatbyte (unsigned char *data, char *output) 
+{
     sprintf(output, "db 0x%02X", *data);
     return 1;
 }
diff --git a/eval.c b/eval.c
index 0e81c92..6dd3f4d 100644 (file)
--- a/eval.c
+++ b/eval.c
 #include "nasm.h"
 #include "nasmlib.h"
 #include "eval.h"
+#include "labels.h"
 
-static expr **tempexprs = NULL;
-static int ntempexprs, tempexprs_size = 0;
 #define TEMPEXPRS_DELTA 128
-
-static expr *tempexpr;
-static int ntempexpr, tempexpr_size;
 #define TEMPEXPR_DELTA 8
 
-static scanner scan;
+static scanner scan;   /* Address of scanner routine */
+static efunc error;    /* Address of error reporting routine */
+static lfunc labelfunc;        /* Address of label routine */
+
+static struct ofmt *outfmt;  /* Structure of addresses of output routines */
+
+static expr **tempexprs = NULL;
+static int    ntempexprs;
+static int    tempexprs_size = 0;
+
+static expr  *tempexpr;
+static int   ntempexpr;
+static int   tempexpr_size;
+
+static struct tokenval *tokval;          /* The current token */
+static int i;                    /* The t_type of tokval */
+
 static void *scpriv;
-static struct tokenval *tokval;
-static efunc error;
-static int i;
-static int seg, ofs;
-static char *label = NULL, special_empty_string[] = "";
-static lfunc labelfunc;
-static struct ofmt *outfmt;
-static int *forward;
+static loc_t *location;                /* Pointer to current line's segment,offset */
+static int *opflags;
 
 static struct eval_hints *hint;
 
 /*
+ * Unimportant cleanup is done to avoid confusing people who are trying
+ * to debug real memory leaks
+ */
+void eval_cleanup(void) 
+{
+    while (ntempexprs)
+       nasm_free (tempexprs[--ntempexprs]);
+    nasm_free (tempexprs);
+}
+
+/*
  * Construct a temporary expression.
  */
-static void begintemp(void) {
+static void begintemp(void) 
+{
     tempexpr = NULL;
     tempexpr_size = ntempexpr = 0;
 }
 
-static void addtotemp(long type, long value) {
+static void addtotemp(long type, long value) 
+{
     while (ntempexpr >= tempexpr_size) {
        tempexpr_size += TEMPEXPR_DELTA;
        tempexpr = nasm_realloc(tempexpr,
@@ -57,7 +76,8 @@ static void addtotemp(long type, long value) {
     tempexpr[ntempexpr++].value = value;
 }
 
-static expr *finishtemp(void) {
+static expr *finishtemp(void) 
+{
     addtotemp (0L, 0L);                       /* terminate */
     while (ntempexprs >= tempexprs_size) {
        tempexprs_size += TEMPEXPRS_DELTA;
@@ -72,7 +92,8 @@ static expr *finishtemp(void) {
  * absolute segment types: we preserve them during addition _only_
  * if one of the segments is a truly pure scalar.
  */
-static expr *add_vectors(expr *p, expr *q) {
+static expr *add_vectors(expr *p, expr *q) 
+{
     int preserve;
 
     preserve = is_really_simple(p) || is_really_simple(q);
@@ -81,7 +102,8 @@ static expr *add_vectors(expr *p, expr *q) {
 
     while (p->type && q->type &&
           p->type < EXPR_SEGBASE+SEG_ABS &&
-          q->type < EXPR_SEGBASE+SEG_ABS) {
+          q->type < EXPR_SEGBASE+SEG_ABS)
+    {
        int lasttype;
 
        if (p->type > q->type) {
@@ -91,7 +113,9 @@ static expr *add_vectors(expr *p, expr *q) {
            addtotemp(p->type, p->value);
            lasttype = p++->type;
        } else {                       /* *p and *q have same type */
-           addtotemp(p->type, p->value + q->value);
+           long sum = p->value + q->value;
+           if (sum)
+               addtotemp(p->type, sum);
            lasttype = p->type;
            p++, q++;
        }
@@ -100,12 +124,14 @@ static expr *add_vectors(expr *p, expr *q) {
        }
     }
     while (p->type &&
-          (preserve || p->type < EXPR_SEGBASE+SEG_ABS)) {
+          (preserve || p->type < EXPR_SEGBASE+SEG_ABS)) 
+    {
        addtotemp(p->type, p->value);
        p++;
     }
     while (q->type &&
-          (preserve || q->type < EXPR_SEGBASE+SEG_ABS)) {
+          (preserve || q->type < EXPR_SEGBASE+SEG_ABS)) 
+    {
        addtotemp(q->type, q->value);
        q++;
     }
@@ -125,7 +151,8 @@ static expr *add_vectors(expr *p, expr *q) {
  * multiplied. This allows [eax*1+ebx] to hint EBX rather than EAX
  * as the base register.
  */
-static expr *scalar_mult(expr *vect, long scalar, int affect_hints) {
+static expr *scalar_mult(expr *vect, long scalar, int affect_hints) 
+{
     expr *p = vect;
 
     while (p->type && p->type < EXPR_SEGBASE+SEG_ABS) {
@@ -140,13 +167,15 @@ static expr *scalar_mult(expr *vect, long scalar, int affect_hints) {
     return vect;
 }
 
-static expr *scalarvect (long scalar) {
+static expr *scalarvect (long scalar) 
+{
     begintemp();
     addtotemp(EXPR_SIMPLE, scalar);
     return finishtemp();
 }
 
-static expr *unknown_expr (void) {
+static expr *unknown_expr (void) 
+{
     begintemp();
     addtotemp(EXPR_UNKNOWN, 1L);
     return finishtemp();
@@ -157,7 +186,8 @@ static expr *unknown_expr (void) {
  * value. Return NULL, as usual, if an error occurs. Report the
  * error too.
  */
-static expr *segment_part (expr *e) {
+static expr *segment_part (expr *e) 
+{
     long seg;
 
     if (is_unknown(e))
@@ -228,22 +258,27 @@ static expr *expr4(int), *expr5(int), *expr6(int);
 
 static expr *(*bexpr)(int);
 
-static expr *rexp0(int critical) {
+static expr *rexp0(int critical) 
+{
     expr *e, *f;
 
     e = rexp1(critical);
     if (!e)
        return NULL;
-    while (i == TOKEN_DBL_OR) {
+
+    while (i == TOKEN_DBL_OR) 
+    {  
        i = scan(scpriv, tokval);
        f = rexp1(critical);
        if (!f)
            return NULL;
        if (!(is_simple(e) || is_just_unknown(e)) ||
-           !(is_simple(f) || is_just_unknown(f))) {
-               error(ERR_NONFATAL, "`|' operator may only be applied to"
-                     " scalar values");
-           }
+           !(is_simple(f) || is_just_unknown(f))) 
+       {
+           error(ERR_NONFATAL, "`|' operator may only be applied to"
+                 " scalar values");
+       }
+
        if (is_just_unknown(e) || is_just_unknown(f))
            e = unknown_expr();
        else
@@ -252,22 +287,27 @@ static expr *rexp0(int critical) {
     return e;
 }
 
-static expr *rexp1(int critical) {
+static expr *rexp1(int critical) 
+{
     expr *e, *f;
 
     e = rexp2(critical);
     if (!e)
        return NULL;
-    while (i == TOKEN_DBL_XOR) {
+    
+    while (i == TOKEN_DBL_XOR) 
+    {
        i = scan(scpriv, tokval);
        f = rexp2(critical);
        if (!f)
            return NULL;
        if (!(is_simple(e) || is_just_unknown(e)) ||
-           !(is_simple(f) || is_just_unknown(f))) {
+           !(is_simple(f) || is_just_unknown(f))) 
+       {
            error(ERR_NONFATAL, "`^' operator may only be applied to"
                  " scalar values");
        }
+
        if (is_just_unknown(e) || is_just_unknown(f))
            e = unknown_expr();
        else
@@ -276,19 +316,22 @@ static expr *rexp1(int critical) {
     return e;
 }
 
-static expr *rexp2(int critical) {
+static expr *rexp2(int critical) 
+{
     expr *e, *f;
 
     e = rexp3(critical);
     if (!e)
        return NULL;
-    while (i == TOKEN_DBL_AND) {
+    while (i == TOKEN_DBL_AND) 
+    {
        i = scan(scpriv, tokval);
        f = rexp3(critical);
        if (!f)
            return NULL;
        if (!(is_simple(e) || is_just_unknown(e)) ||
-           !(is_simple(f) || is_just_unknown(f))) {
+           !(is_simple(f) || is_just_unknown(f))) 
+       {
            error(ERR_NONFATAL, "`&' operator may only be applied to"
                  " scalar values");
        }
@@ -300,22 +343,28 @@ static expr *rexp2(int critical) {
     return e;
 }
 
-static expr *rexp3(int critical) {
+static expr *rexp3(int critical) 
+{
     expr *e, *f;
     long v;
 
     e = expr0(critical);
     if (!e)
        return NULL;
+
     while (i == TOKEN_EQ || i == TOKEN_LT || i == TOKEN_GT ||
-          i == TOKEN_NE || i == TOKEN_LE || i == TOKEN_GE) {
+          i == TOKEN_NE || i == TOKEN_LE || i == TOKEN_GE) 
+    {
        int j = i;
        i = scan(scpriv, tokval);
        f = expr0(critical);
        if (!f)
            return NULL;
+
        e = add_vectors (e, scalar_mult(f, -1L, FALSE));
-       switch (j) {
+
+       switch (j) 
+       {
          case TOKEN_EQ: case TOKEN_NE:
            if (is_unknown(e))
                v = -1;                /* means unknown */
@@ -343,6 +392,7 @@ static expr *rexp3(int critical) {
            }
            break;
        }
+
        if (v == -1)
            e = unknown_expr();
        else
@@ -351,22 +401,26 @@ static expr *rexp3(int critical) {
     return e;
 }
 
-static expr *expr0(int critical) {
+static expr *expr0(int critical) 
+{
     expr *e, *f;
 
     e = expr1(critical);
     if (!e)
        return NULL;
-    while (i == '|') {
+
+    while (i == '|') 
+    {
        i = scan(scpriv, tokval);
        f = expr1(critical);
        if (!f)
            return NULL;
        if (!(is_simple(e) || is_just_unknown(e)) ||
-           !(is_simple(f) || is_just_unknown(f))) {
-               error(ERR_NONFATAL, "`|' operator may only be applied to"
-                     " scalar values");
-           }
+           !(is_simple(f) || is_just_unknown(f))) 
+       {
+           error(ERR_NONFATAL, "`|' operator may only be applied to"
+                 " scalar values");
+       }
        if (is_just_unknown(e) || is_just_unknown(f))
            e = unknown_expr();
        else
@@ -375,19 +429,22 @@ static expr *expr0(int critical) {
     return e;
 }
 
-static expr *expr1(int critical) {
+static expr *expr1(int critical) 
+{
     expr *e, *f;
 
     e = expr2(critical);
     if (!e)
        return NULL;
+
     while (i == '^') {
        i = scan(scpriv, tokval);
        f = expr2(critical);
        if (!f)
            return NULL;
        if (!(is_simple(e) || is_just_unknown(e)) ||
-           !(is_simple(f) || is_just_unknown(f))) {
+           !(is_simple(f) || is_just_unknown(f))) 
+       {
            error(ERR_NONFATAL, "`^' operator may only be applied to"
                  " scalar values");
        }
@@ -399,19 +456,22 @@ static expr *expr1(int critical) {
     return e;
 }
 
-static expr *expr2(int critical) {
+static expr *expr2(int critical) 
+{
     expr *e, *f;
 
     e = expr3(critical);
     if (!e)
        return NULL;
+
     while (i == '&') {
        i = scan(scpriv, tokval);
        f = expr3(critical);
        if (!f)
            return NULL;
        if (!(is_simple(e) || is_just_unknown(e)) ||
-           !(is_simple(f) || is_just_unknown(f))) {
+           !(is_simple(f) || is_just_unknown(f))) 
+       {
            error(ERR_NONFATAL, "`&' operator may only be applied to"
                  " scalar values");
        }
@@ -423,20 +483,24 @@ static expr *expr2(int critical) {
     return e;
 }
 
-static expr *expr3(int critical) {
+static expr *expr3(int critical) 
+{
     expr *e, *f;
 
     e = expr4(critical);
     if (!e)
        return NULL;
-    while (i == TOKEN_SHL || i == TOKEN_SHR) {
+
+    while (i == TOKEN_SHL || i == TOKEN_SHR) 
+    {
        int j = i;
        i = scan(scpriv, tokval);
        f = expr4(critical);
        if (!f)
            return NULL;
        if (!(is_simple(e) || is_just_unknown(e)) ||
-           !(is_simple(f) || is_just_unknown(f))) {
+           !(is_simple(f) || is_just_unknown(f))) 
+       {
            error(ERR_NONFATAL, "shift operator may only be applied to"
                  " scalar values");
        } else if (is_just_unknown(e) || is_just_unknown(f)) {
@@ -454,13 +518,15 @@ static expr *expr3(int critical) {
     return e;
 }
 
-static expr *expr4(int critical) {
+static expr *expr4(int critical) 
+{
     expr *e, *f;
 
     e = expr5(critical);
     if (!e)
        return NULL;
-    while (i == '+' || i == '-') {
+    while (i == '+' || i == '-') 
+    {
        int j = i;
        i = scan(scpriv, tokval);
        f = expr5(critical);
@@ -478,21 +544,24 @@ static expr *expr4(int critical) {
     return e;
 }
 
-static expr *expr5(int critical) {
+static expr *expr5(int critical) 
+{
     expr *e, *f;
 
     e = expr6(critical);
     if (!e)
        return NULL;
     while (i == '*' || i == '/' || i == '%' ||
-          i == TOKEN_SDIV || i == TOKEN_SMOD) {
+          i == TOKEN_SDIV || i == TOKEN_SMOD) 
+    {
        int j = i;
        i = scan(scpriv, tokval);
        f = expr6(critical);
        if (!f)
            return NULL;
        if (j != '*' && (!(is_simple(e) || is_just_unknown(e)) ||
-                        !(is_simple(f) || is_just_unknown(f)))) {
+                        !(is_simple(f) || is_just_unknown(f)))) 
+       {
            error(ERR_NONFATAL, "division operator may only be applied to"
                  " scalar values");
            return NULL;
@@ -548,7 +617,8 @@ static expr *expr5(int critical) {
     return e;
 }
 
-static expr *expr6(int critical) {
+static expr *expr6(int critical) 
+{
     long type;
     expr *e;
     long label_seg, label_ofs;
@@ -597,8 +667,10 @@ static expr *expr6(int critical) {
        }
        i = scan(scpriv, tokval);
        return e;
-    } else if (i == TOKEN_NUM || i == TOKEN_REG || i == TOKEN_ID ||
-              i == TOKEN_HERE || i == TOKEN_BASE) {
+    } 
+    else if (i == TOKEN_NUM || i == TOKEN_REG || i == TOKEN_ID ||
+            i == TOKEN_HERE || i == TOKEN_BASE) 
+    {
        begintemp();
        switch (i) {
          case TOKEN_NUM:
@@ -613,11 +685,11 @@ static expr *expr6(int critical) {
          case TOKEN_HERE:
          case TOKEN_BASE:
            /*
-            * If "label" begins with "%", this indicates that no
+            * If !location->known, this indicates that no
             * symbol, Here or Base references are valid because we
             * are in preprocess-only mode.
             */
-           if (*label == '%') {
+           if (!location->known) {
                error(ERR_NONFATAL,
                      "%s not supported in preprocess-only mode",
                      (i == TOKEN_ID ? "symbol references" :
@@ -641,11 +713,11 @@ static expr *expr6(int critical) {
             */
            type = EXPR_SIMPLE;        /* might get overridden by UNKNOWN */
            if (i == TOKEN_BASE) {
-               label_seg = seg;
+               label_seg = location->segment;
                label_ofs = 0;
-           } else if (i == TOKEN_HERE || !strcmp(tokval->t_charptr, label)) {
-               label_seg = seg;
-               label_ofs = ofs;
+           } else if (i == TOKEN_HERE) {
+               label_seg = location->segment;
+               label_ofs = location->offset;
            } else if (!labelfunc(tokval->t_charptr,&label_seg,&label_ofs)) {
                if (critical == 2) {
                    error (ERR_NONFATAL, "symbol `%s' undefined",
@@ -656,16 +728,19 @@ static expr *expr6(int critical) {
                           tokval->t_charptr);
                    return NULL;
                } else {
-                   if (forward)
-                       *forward = TRUE;
+                   if (opflags)
+                       *opflags |= 1;
                    type = EXPR_UNKNOWN;
                    label_seg = NO_SEG;
                    label_ofs = 1;
                }
            }
            addtotemp(type, label_ofs);
-           if (label_seg!=NO_SEG)
+           if (label_seg!=NO_SEG) {
                addtotemp(EXPR_SEGBASE + label_seg, 1L);
+               if (opflags && is_extern (tokval->t_charptr))
+                   *opflags |= OPFLAG_EXTERN;
+           }
            break;
        }
        i = scan(scpriv, tokval);
@@ -676,26 +751,17 @@ static expr *expr6(int critical) {
     }
 }
 
-void eval_global_info (struct ofmt *output, lfunc lookup_label) {
+void eval_global_info (struct ofmt *output, lfunc lookup_label, loc_t *locp) 
+{
     outfmt = output;
     labelfunc = lookup_label;
-}
-
-void eval_info (char *labelname, long segment, long offset) {
-    if (label != special_empty_string)
-       nasm_free (label);
-    if (labelname)
-       label = nasm_strdup(labelname);
-    else {
-       label = special_empty_string;
-       seg = segment;
-       ofs = offset;
-    }
+    location = locp;
 }
 
 expr *evaluate (scanner sc, void *scprivate, struct tokenval *tv,
                int *fwref, int critical, efunc report_error,
-               struct eval_hints *hints) {
+               struct eval_hints *hints) 
+{
     expr *e;
     expr *f = NULL;
 
@@ -713,7 +779,7 @@ expr *evaluate (scanner sc, void *scprivate, struct tokenval *tv,
     scpriv = scprivate;
     tokval = tv;
     error = report_error;
-    forward = fwref;
+    opflags = fwref;
 
     if (tokval->t_type == TOKEN_INVALID)
        i = scan(scpriv, tokval);
@@ -748,7 +814,8 @@ expr *evaluate (scanner sc, void *scprivate, struct tokenval *tv,
            value = reloc_seg(f);
            if (value == NO_SEG)
                value = reloc_value(f) | SEG_ABS;
-           else if (!(value & SEG_ABS) && !(value % 2) && critical) {
+           else if (!(value & SEG_ABS) && !(value % 2) && critical) 
+           {
                error(ERR_NONFATAL, "invalid right-hand operand to WRT");
                return NULL;
            }
diff --git a/eval.h b/eval.h
index 26bde15..a933cbf 100644 (file)
--- a/eval.h
+++ b/eval.h
  * providing segment-base details, and what function can be used to
  * look labels up.
  */
-void eval_global_info (struct ofmt *output, lfunc lookup_label);
-
-/*
- * Called to set the information the evaluator needs: the value of
- * $ is set from `segment' and `offset' if `labelname' is NULL, and
- * otherwise the name of the current line's label is set from
- * `labelname' instead.
- */
-void eval_info (char *labelname, long segment, long offset);
+void eval_global_info (struct ofmt *output, lfunc lookup_label, loc_t *locp);
 
 /*
  * The evaluator itself.
@@ -31,4 +23,6 @@ expr *evaluate (scanner sc, void *scprivate, struct tokenval *tv,
                int *fwref, int critical, efunc report_error,
                struct eval_hints *hints);
 
+void eval_cleanup(void);
+
 #endif
diff --git a/float.c b/float.c
index 1f66ca6..545ae77 100644 (file)
--- a/float.c
+++ b/float.c
  * => we only have to worry about _one_ bit shift to the left
  */
 
-static int multiply(unsigned short *to, unsigned short *from) {
+static int multiply(unsigned short *to, unsigned short *from) 
+{
     unsigned long temp[MANT_WORDS*2];
-    int i, j;
+    int           i, j;
 
     for (i=0; i<MANT_WORDS*2; i++)
        temp[i] = 0;
@@ -56,11 +57,14 @@ static int multiply(unsigned short *to, unsigned short *from) {
 }
 
 static void flconvert(char *string, unsigned short *mant, long *exponent,
-                     efunc error) {
-    char digits[MANT_DIGITS], *p, *q, *r;
-    unsigned short mult[MANT_WORDS], *m, bit;
-    long tenpwr, twopwr;
-    int extratwos, started, seendot;
+                     efunc error) 
+{
+    char           digits[MANT_DIGITS];
+    char           *p, *q, *r;
+    unsigned short mult[MANT_WORDS], bit;
+    unsigned short * m;
+    long           tenpwr, twopwr;
+    int            extratwos, started, seendot;
 
     p = digits;
     tenpwr = 0;
@@ -179,9 +183,10 @@ static void flconvert(char *string, unsigned short *mant, long *exponent,
 /*
  * Shift a mantissa to the right by i (i < 16) bits.
  */
-static void shr(unsigned short *mant, int i) {
+static void shr(unsigned short *mant, int i) 
+{
     unsigned short n = 0, m;
-    int j;
+    int            j;
 
     for (j=0; j<MANT_WORDS; j++) {
        m = (mant[j] << (16-i)) & 0xFFFF;
@@ -193,7 +198,8 @@ static void shr(unsigned short *mant, int i) {
 /*
  * Round a mantissa off after i words.
  */
-static int round(unsigned short *mant, int i) {
+static int round(unsigned short *mant, int i) 
+{
     if (mant[i] & 0x8000) {
        do {
            ++mant[--i];
@@ -207,7 +213,8 @@ static int round(unsigned short *mant, int i) {
 #define put(a,b) ( (*(a)=(b)), ((a)[1]=(b)>>8) )
 
 static int to_double(char *str, long sign, unsigned char *result,
-                    efunc error) {
+                    efunc error) 
+{
     unsigned short mant[MANT_WORDS];
     long exponent;
 
@@ -267,7 +274,8 @@ static int to_double(char *str, long sign, unsigned char *result,
 }
 
 static int to_float(char *str, long sign, unsigned char *result,
-                   efunc error) {
+                   efunc error) 
+{
     unsigned short mant[MANT_WORDS];
     long exponent;
 
@@ -320,7 +328,8 @@ static int to_float(char *str, long sign, unsigned char *result,
 }
 
 static int to_ldoub(char *str, long sign, unsigned char *result,
-                   efunc error) {
+                   efunc error) 
+{
     unsigned short mant[MANT_WORDS];
     long exponent;
 
@@ -379,7 +388,8 @@ static int to_ldoub(char *str, long sign, unsigned char *result,
 }
 
 int float_const (char *number, long sign, unsigned char *result, int bytes,
-                efunc error) {
+                efunc error) 
+{
     if (bytes == 4)
        return to_float (number, sign, result, error);
     else if (bytes == 8)
index 27436f1..4113a07 100644 (file)
--- a/insns.dat
+++ b/insns.dat
@@ -125,6 +125,7 @@ BTS       reg32,reg32         \321\300\2\x0F\xAB\101        386
 BTS       rm16,imm            \320\300\2\x0F\xBA\205\25     386
 BTS       rm32,imm            \321\300\2\x0F\xBA\205\25     386
 CALL      imm                 \322\1\xE8\64                 8086
+CALL      imm|near            \322\1\xE8\64                 8086
 CALL      imm|far             \322\1\x9A\34\37              8086,ND
 CALL      imm:imm             \322\1\x9A\35\30              8086
 CALL      imm16:imm           \320\1\x9A\31\30              8086
@@ -274,6 +275,7 @@ FDIVR     fpureg              \1\xD8\10\xF8                 8086,FPU
 FDIVR     fpu0,fpureg         \1\xD8\11\xF8                 8086,FPU
 FDIVRP    fpureg              \1\xDE\10\xF0                 8086,FPU
 FDIVRP    fpureg,fpu0         \1\xDE\10\xF0                 8086,FPU
+FEMMS     void                \2\x0F\x0E                    PENT,MMX,FPU
 FENI      void                \3\x9B\xDB\xE0                8086,FPU
 FFREE     fpureg              \1\xDD\10\xC0                 8086,FPU
 FIADD     mem32               \300\1\xDA\200                8086,FPU
@@ -447,6 +449,7 @@ JCXZ      imm                 \320\1\xE3\50                 8086
 JECXZ     imm                 \321\1\xE3\50                 386
 JMP       imm|short           \1\xEB\50                     8086
 JMP       imm                 \322\1\xE9\64                 8086
+JMP       imm|near            \322\1\xE9\64                 8086
 JMP       imm|far             \322\1\xEA\34\37              8086,ND
 JMP       imm:imm             \322\1\xEA\35\30              8086
 JMP       imm16:imm           \320\1\xEA\31\30              8086
@@ -619,9 +622,9 @@ OR        rm32,imm            \321\300\1\x81\201\41         386,SM
 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
-OUT       imm,reg_al          \1\xE6\24                     8086
-OUT       imm,reg_ax          \320\1\xE7\24                 8086
-OUT       imm,reg_eax         \321\1\xE7\24                 386
+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
 OUT       reg_dx,reg_al       \1\xEE                        8086
 OUT       reg_dx,reg_ax       \320\1\xEF                    8086
 OUT       reg_dx,reg_eax      \321\1\xEF                    386
@@ -656,6 +659,8 @@ PANDN     mmxreg,mem          \301\2\x0F\xDF\110            PENT,MMX,SM
 PANDN     mmxreg,mmxreg       \2\x0F\xDF\110                PENT,MMX
 PAVEB     mmxreg,mem          \301\2\x0F\x50\110            PENT,MMX,SM,CYRIX
 PAVEB     mmxreg,mmxreg       \2\x0F\x50\110                PENT,MMX,CYRIX
+PAVGUSB   mmxreg,mem          \301\2\x0F\x0F\110\01\xBF     PENT,MMX,SM,FPU
+PAVGUSB   mmxreg,mmxreg       \2\x0F\x0F\110\01\xBF         PENT,MMX,FPU
 PCMPEQB   mmxreg,mem          \301\2\x0F\x74\110            PENT,MMX,SM
 PCMPEQB   mmxreg,mmxreg       \2\x0F\x74\110                PENT,MMX
 PCMPEQD   mmxreg,mem          \301\2\x0F\x76\110            PENT,MMX,SM
@@ -669,15 +674,51 @@ PCMPGTD   mmxreg,mmxreg       \2\x0F\x66\110                PENT,MMX
 PCMPGTW   mmxreg,mem          \301\2\x0F\x65\110            PENT,MMX,SM
 PCMPGTW   mmxreg,mmxreg       \2\x0F\x65\110                PENT,MMX
 PDISTIB   mmxreg,mem          \301\2\x0F\x54\110            PENT,MMX,SM,CYRIX
+PF2ID     mmxreg,mem          \301\2\x0F\x0F\110\01\x1D     PENT,MMX,SM,FPU
+PF2ID     mmxreg,mmxreg       \2\x0F\x0F\110\01\x1D         PENT,MMX,FPU
+PFACC     mmxreg,mem          \301\2\x0F\x0F\110\01\xAE     PENT,MMX,SM,FPU
+PFACC     mmxreg,mmxreg       \2\x0F\x0F\110\01\xAE         PENT,MMX,FPU
+PFADD     mmxreg,mem          \301\2\x0F\x0F\110\01\x9E     PENT,MMX,SM,FPU
+PFADD     mmxreg,mmxreg       \2\x0F\x0F\110\01\x9E         PENT,MMX,FPU
+PFCMPEQ   mmxreg,mem          \301\2\x0F\x0F\110\01\xB0     PENT,MMX,SM,FPU
+PFCMPEQ   mmxreg,mmxreg       \2\x0F\x0F\110\01\xB0         PENT,MMX,FPU
+PFCMPGE   mmxreg,mem          \301\2\x0F\x0F\110\01\x90     PENT,MMX,SM,FPU
+PFCMPGE   mmxreg,mmxreg       \2\x0F\x0F\110\01\x90         PENT,MMX,FPU
+PFCMPGT   mmxreg,mem          \301\2\x0F\x0F\110\01\xA0     PENT,MMX,SM,FPU
+PFCMPGT   mmxreg,mmxreg       \2\x0F\x0F\110\01\xA0         PENT,MMX,FPU
+PFMAX     mmxreg,mem          \301\2\x0F\x0F\110\01\xA4     PENT,MMX,SM,FPU
+PFMAX     mmxreg,mmxreg       \2\x0F\x0F\110\01\xA4         PENT,MMX,FPU
+PFMIN     mmxreg,mem          \301\2\x0F\x0F\110\01\x94     PENT,MMX,SM,FPU
+PFMIN     mmxreg,mmxreg       \2\x0F\x0F\110\01\x94         PENT,MMX,FPU
+PFMUL     mmxreg,mem          \301\2\x0F\x0F\110\01\xB4     PENT,MMX,SM,FPU
+PFMUL     mmxreg,mmxreg       \2\x0F\x0F\110\01\xB4         PENT,MMX,FPU
+PFRCP     mmxreg,mem          \301\2\x0F\x0F\110\01\x96     PENT,MMX,SM,FPU
+PFRCP     mmxreg,mmxreg       \2\x0F\x0F\110\01\x96         PENT,MMX,FPU
+PFRCPIT1  mmxreg,mem          \301\2\x0F\x0F\110\01\xA6     PENT,MMX,SM,FPU
+PFRCPIT1  mmxreg,mmxreg       \2\x0F\x0F\110\01\xA6         PENT,MMX,FPU
+PFRCPIT2  mmxreg,mem          \301\2\x0F\x0F\110\01\xB6     PENT,MMX,SM,FPU
+PFRCPIT2  mmxreg,mmxreg       \2\x0F\x0F\110\01\xB6         PENT,MMX,FPU
+PFRSQIT1  mmxreg,mem          \301\2\x0F\x0F\110\01\xA7     PENT,MMX,SM,FPU
+PFRSQIT1  mmxreg,mmxreg       \2\x0F\x0F\110\01\xA7         PENT,MMX,FPU
+PFRSQRT   mmxreg,mem          \301\2\x0F\x0F\110\01\x97     PENT,MMX,SM,FPU
+PFRSQRT   mmxreg,mmxreg       \2\x0F\x0F\110\01\x97         PENT,MMX,FPU
+PFSUB     mmxreg,mem          \301\2\x0F\x0F\110\01\x9A     PENT,MMX,SM,FPU
+PFSUB     mmxreg,mmxreg       \2\x0F\x0F\110\01\x9A         PENT,MMX,FPU
+PFSUBR    mmxreg,mem          \301\2\x0F\x0F\110\01\xAA     PENT,MMX,SM,FPU
+PFSUBR    mmxreg,mmxreg       \2\x0F\x0F\110\01\xAA         PENT,MMX,FPU
+PI2FD     mmxreg,mem          \301\2\x0F\x0F\110\01\x0D     PENT,MMX,SM,FPU
+PI2FD     mmxreg,mmxreg       \2\x0F\x0F\110\01\x0D         PENT,MMX,FPU
 PMACHRIW  mmxreg,mem          \301\2\x0F\x5E\110            PENT,MMX,SM,CYRIX
 PMADDWD   mmxreg,mem          \301\2\x0F\xF5\110            PENT,MMX,SM
 PMADDWD   mmxreg,mmxreg       \2\x0F\xF5\110                PENT,MMX
 PMAGW     mmxreg,mem          \301\2\x0F\x52\110            PENT,MMX,SM,CYRIX
 PMAGW     mmxreg,mmxreg       \2\x0F\x52\110                PENT,MMX,CYRIX
-PMULHRW   mmxreg,mem          \301\2\x0F\x59\110            PENT,MMX,SM,CYRIX
-PMULHRW   mmxreg,mmxreg       \2\x0F\x59\110                PENT,MMX,CYRIX
 PMULHRIW  mmxreg,mem          \301\2\x0F\x5D\110            PENT,MMX,SM,CYRIX
 PMULHRIW  mmxreg,mmxreg       \2\x0F\x5D\110                PENT,MMX,CYRIX
+PMULHRWA  mmxreg,mem          \301\2\x0F\x0F\110\1\xB7      PENT,MMX,SM,FPU
+PMULHRWA  mmxreg,mmxreg       \2\x0F\x0F\110\1\xB7          PENT,MMX,FPU
+PMULHRWC  mmxreg,mem          \301\2\x0F\x59\110            PENT,MMX,SM,CYRIX
+PMULHRWC  mmxreg,mmxreg       \2\x0F\x59\110                PENT,MMX,CYRIX
 PMULHW    mmxreg,mem          \301\2\x0F\xE5\110            PENT,MMX,SM
 PMULHW    mmxreg,mmxreg       \2\x0F\xE5\110                PENT,MMX
 PMULLW    mmxreg,mem          \301\2\x0F\xD5\110            PENT,MMX,SM
@@ -701,6 +742,8 @@ POPFD     void                \321\1\x9D                    386
 POPFW     void                \320\1\x9D                    186
 POR       mmxreg,mem          \301\2\x0F\xEB\110            PENT,MMX,SM
 POR       mmxreg,mmxreg       \2\x0F\xEB\110                PENT,MMX
+PREFETCH  mem                 \2\x0F\x0D\200                PENT,MMX,SM,FPU
+PREFETCHW mem                 \2\x0F\x0D\201                PENT,MMX,SM,FPU
 PSLLD     mmxreg,mem          \301\2\x0F\xF2\110            PENT,MMX,SM
 PSLLD     mmxreg,mmxreg       \2\x0F\xF2\110                PENT,MMX
 PSLLD     mmxreg,imm          \2\x0F\x72\206\25             PENT,MMX
@@ -772,19 +815,19 @@ PXOR      mmxreg,mem          \301\2\x0F\xEF\110            PENT,MMX,SM
 PXOR      mmxreg,mmxreg       \2\x0F\xEF\110                PENT,MMX
 RCL       rm8,unity           \300\1\xD0\202                8086
 RCL       rm8,reg_cl          \300\1\xD2\202                8086
-RCL       rm8,imm             \300\1\xC0\202\25             286,SB
+RCL       rm8,imm             \300\1\xC0\202\25             186,SB
 RCL       rm16,unity          \320\300\1\xD1\202            8086
 RCL       rm16,reg_cl         \320\300\1\xD3\202            8086
-RCL       rm16,imm            \320\300\1\xC1\202\25         286,SB
+RCL       rm16,imm            \320\300\1\xC1\202\25         186,SB
 RCL       rm32,unity          \321\300\1\xD1\202            386
 RCL       rm32,reg_cl         \321\300\1\xD3\202            386
 RCL       rm32,imm            \321\300\1\xC1\202\25         386,SB
 RCR       rm8,unity           \300\1\xD0\203                8086
 RCR       rm8,reg_cl          \300\1\xD2\203                8086
-RCR       rm8,imm             \300\1\xC0\203\25             286,SB
+RCR       rm8,imm             \300\1\xC0\203\25             186,SB
 RCR       rm16,unity          \320\300\1\xD1\203            8086
 RCR       rm16,reg_cl         \320\300\1\xD3\203            8086
-RCR       rm16,imm            \320\300\1\xC1\203\25         286,SB
+RCR       rm16,imm            \320\300\1\xC1\203\25         186,SB
 RCR       rm32,unity          \321\300\1\xD1\203            386
 RCR       rm32,reg_cl         \321\300\1\xD3\203            386
 RCR       rm32,imm            \321\300\1\xC1\203\25         386,SB
@@ -804,19 +847,19 @@ RETN      void                \1\xC3                        8086
 RETN      imm                 \1\xC2\30                     8086
 ROL       rm8,unity           \300\1\xD0\200                8086
 ROL       rm8,reg_cl          \300\1\xD2\200                8086
-ROL       rm8,imm             \300\1\xC0\200\25             286,SB
+ROL       rm8,imm             \300\1\xC0\200\25             186,SB
 ROL       rm16,unity          \320\300\1\xD1\200            8086
 ROL       rm16,reg_cl         \320\300\1\xD3\200            8086
-ROL       rm16,imm            \320\300\1\xC1\200\25         286,SB
+ROL       rm16,imm            \320\300\1\xC1\200\25         186,SB
 ROL       rm32,unity          \321\300\1\xD1\200            386
 ROL       rm32,reg_cl         \321\300\1\xD3\200            386
 ROL       rm32,imm            \321\300\1\xC1\200\25         386,SB
 ROR       rm8,unity           \300\1\xD0\201                8086
 ROR       rm8,reg_cl          \300\1\xD2\201                8086
-ROR       rm8,imm             \300\1\xC0\201\25             286,SB
+ROR       rm8,imm             \300\1\xC0\201\25             186,SB
 ROR       rm16,unity          \320\300\1\xD1\201            8086
 ROR       rm16,reg_cl         \320\300\1\xD3\201            8086
-ROR       rm16,imm            \320\300\1\xC1\201\25         286,SB
+ROR       rm16,imm            \320\300\1\xC1\201\25         186,SB
 ROR       rm32,unity          \321\300\1\xD1\201            386
 ROR       rm32,reg_cl         \321\300\1\xD3\201            386
 ROR       rm32,imm            \321\300\1\xC1\201\25         386,SB
@@ -824,20 +867,20 @@ RSM       void                \2\x0F\xAA                    PENT
 SAHF      void                \1\x9E                        8086
 SAL       rm8,unity           \300\1\xD0\204                8086,ND
 SAL       rm8,reg_cl          \300\1\xD2\204                8086,ND
-SAL       rm8,imm             \300\1\xC0\204\25             286,ND,SB
+SAL       rm8,imm             \300\1\xC0\204\25             186,ND,SB
 SAL       rm16,unity          \320\300\1\xD1\204            8086,ND
 SAL       rm16,reg_cl         \320\300\1\xD3\204            8086,ND
-SAL       rm16,imm            \320\300\1\xC1\204\25         286,ND,SB
+SAL       rm16,imm            \320\300\1\xC1\204\25         186,ND,SB
 SAL       rm32,unity          \321\300\1\xD1\204            386,ND
 SAL       rm32,reg_cl         \321\300\1\xD3\204            386,ND
 SAL       rm32,imm            \321\300\1\xC1\204\25         386,ND,SB
 SALC      void                \1\xD6                        8086,UNDOC
 SAR       rm8,unity           \300\1\xD0\207                8086
 SAR       rm8,reg_cl          \300\1\xD2\207                8086
-SAR       rm8,imm             \300\1\xC0\207\25             286,SB
+SAR       rm8,imm             \300\1\xC0\207\25             186,SB
 SAR       rm16,unity          \320\300\1\xD1\207            8086
 SAR       rm16,reg_cl         \320\300\1\xD3\207            8086
-SAR       rm16,imm            \320\300\1\xC1\207\25         286,SB
+SAR       rm16,imm            \320\300\1\xC1\207\25         186,SB
 SAR       rm32,unity          \321\300\1\xD1\207            386
 SAR       rm32,reg_cl         \321\300\1\xD3\207            386
 SAR       rm32,imm            \321\300\1\xC1\207\25         386,SB
@@ -870,10 +913,10 @@ SCASW     void                \320\1\xAF                    8086
 SGDT      mem                 \300\2\x0F\x01\200            286,PRIV
 SHL       rm8,unity           \300\1\xD0\204                8086
 SHL       rm8,reg_cl          \300\1\xD2\204                8086
-SHL       rm8,imm             \300\1\xC0\204\25             286,SB
+SHL       rm8,imm             \300\1\xC0\204\25             186,SB
 SHL       rm16,unity          \320\300\1\xD1\204            8086
 SHL       rm16,reg_cl         \320\300\1\xD3\204            8086
-SHL       rm16,imm            \320\300\1\xC1\204\25         286,SB
+SHL       rm16,imm            \320\300\1\xC1\204\25         186,SB
 SHL       rm32,unity          \321\300\1\xD1\204            386
 SHL       rm32,reg_cl         \321\300\1\xD3\204            386
 SHL       rm32,imm            \321\300\1\xC1\204\25         386,SB
@@ -887,10 +930,10 @@ SHLD      mem,reg32,reg_cl    \300\321\2\x0F\xA5\101        386,SM
 SHLD      reg32,reg32,reg_cl  \300\321\2\x0F\xA5\101        386
 SHR       rm8,unity           \300\1\xD0\205                8086
 SHR       rm8,reg_cl          \300\1\xD2\205                8086
-SHR       rm8,imm             \300\1\xC0\205\25             286,SB
+SHR       rm8,imm             \300\1\xC0\205\25             186,SB
 SHR       rm16,unity          \320\300\1\xD1\205            8086
 SHR       rm16,reg_cl         \320\300\1\xD3\205            8086
-SHR       rm16,imm            \320\300\1\xC1\205\25         286,SB
+SHR       rm16,imm            \320\300\1\xC1\205\25         186,SB
 SHR       rm32,unity          \321\300\1\xD1\205            386
 SHR       rm32,reg_cl         \321\300\1\xD3\205            386
 SHR       rm32,imm            \321\300\1\xC1\205\25         386,SB
@@ -948,6 +991,9 @@ TEST      mem,reg16           \320\300\1\x85\101            8086,SM
 TEST      reg16,reg16         \320\300\1\x85\101            8086
 TEST      mem,reg32           \321\300\1\x85\101            386,SM
 TEST      reg32,reg32         \321\300\1\x85\101            386
+TEST      reg8,mem            \301\1\x84\110                8086,SM
+TEST      reg16,mem           \320\301\1\x85\110            8086,SM
+TEST      reg32,mem           \321\301\1\x85\110            386,SM
 TEST      reg_al,imm          \1\xA8\21                     8086,SM
 TEST      reg_ax,imm          \320\1\xA9\31                 8086,SM
 TEST      reg_eax,imm         \321\1\xA9\41                 386,SM
index 2c17c7c..dc7e075 100644 (file)
--- a/labels.c
+++ b/labels.c
@@ -43,7 +43,7 @@ union label {                        /* actual label structures */
     struct {
        long segment, offset;
         char *label, *special;
-       int is_global;
+       int is_global, is_norm;
     } defn;
     struct {
        long movingon, dummy;
@@ -74,7 +74,8 @@ static int initialised = FALSE;
  * given label name. Creates a new one, if it isn't found, and if
  * `create' is TRUE.
  */
-static union label *find_label (char *label, int create) {
+static union label *find_label (char *label, int create) 
+{
     int hash = 0;
     char *p, *prev;
     int prevlen;
@@ -117,11 +118,13 @@ static union label *find_label (char *label, int create) {
        lfree[hash]->defn.special = NULL;
        lfree[hash]->defn.is_global = NOT_DEFINED_YET;
        return lfree[hash]++;
-    } else
+    } 
+    else
        return NULL;
 }
 
-int lookup_label (char *label, long *segment, long *offset) {
+int lookup_label (char *label, long *segment, long *offset) 
+{
     union label *lptr;
 
     if (!initialised)
@@ -132,11 +135,13 @@ int lookup_label (char *label, long *segment, long *offset) {
        *segment = lptr->defn.segment;
        *offset = lptr->defn.offset;
        return 1;
-    } else
+    } 
+    else
        return 0;
 }
 
-int is_extern (char *label) {
+int is_extern (char *label) 
+{
     union label *lptr;
 
     if (!initialised)
@@ -149,22 +154,48 @@ int is_extern (char *label) {
        return 0;
 }
 
-void define_label_stub (char *label, efunc error) {
+void redefine_label (char *label, long segment, long offset, char *special,
+                  int is_norm, int isextrn, struct ofmt *ofmt, efunc error) 
+{
     union label *lptr;
 
+    /* This routine possibly ought to check for phase errors.  Most assemblers
+     * check for phase errors at this point.  I don't know whether phase errors
+     * are even possible, nor whether they are checked somewhere else
+     */
+
+    (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 (!strncmp(label, "debugdump", 9))
+       fprintf(stderr, "debug: redefine_label (%s, %ld, %08lx, %s, %d, %d)\n",
+               label, segment, offset, special, is_norm, isextrn);
+#endif
+
     if (!islocal(label)) {
        lptr = find_label (label, 1);
        if (!lptr)
            error (ERR_PANIC, "can't find label `%s' on pass two", label);
-       if (*label != '.')
+       if (*label != '.' && lptr->defn.is_norm)
            prevlabel = lptr->defn.label;
     }
 }
 
 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 (!strncmp(label, "debugdump", 9))
+       fprintf(stderr, "debug: define_label (%s, %ld, %08lx, %s, %d, %d)\n",
+               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);
@@ -182,14 +213,19 @@ void define_label (char *label, long segment, long offset, char *special,
 
     lptr->defn.segment = segment;
     lptr->defn.offset = offset;
+    lptr->defn.is_norm = (label[0] != '.' && is_norm);
 
     ofmt->symdef (lptr->defn.label, segment, offset,
                  !!(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);
 }
 
 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);
@@ -210,9 +246,12 @@ void define_common (char *label, long segment, long size, char *special,
 
     ofmt->symdef (lptr->defn.label, segment, size, 2,
                  special ? special : lptr->defn.special);
+    ofmt->current_dfmt->debug_deflabel(lptr->defn.label, segment, size, 2,
+                 special ? special : lptr->defn.special);
 }
 
-void declare_as_global (char *label, char *special, efunc error) {
+void declare_as_global (char *label, char *special, efunc error) 
+{
     union label *lptr;
 
     if (islocal(label)) {
@@ -237,7 +276,8 @@ void declare_as_global (char *label, char *special, efunc error) {
     }
 }
 
-int init_labels (void) {
+int init_labels (void) 
+{
     int i;
 
     for (i=0; i<LABEL_HASHES; i++) {
@@ -248,7 +288,9 @@ int init_labels (void) {
        lfree[i] = ltab[i];
     }
 
-    perm_head = perm_tail = (struct permts *) nasm_malloc (sizeof(struct permts));
+    perm_head = 
+       perm_tail = (struct permts *) nasm_malloc (sizeof(struct permts));
+
     if (!perm_head)
        return -1;
 
@@ -263,7 +305,8 @@ int init_labels (void) {
     return 0;
 }
 
-void cleanup_labels (void) {
+void cleanup_labels (void) 
+{
     int i;
 
     initialised = FALSE;
@@ -288,7 +331,8 @@ void cleanup_labels (void) {
     }
 }
 
-static void init_block (union label *blk) {
+static void init_block (union label *blk) 
+{
     int j;
 
     for (j=0; j<LABEL_BLOCK-1; j++)
@@ -297,7 +341,8 @@ static void init_block (union label *blk) {
     blk[LABEL_BLOCK-1].admin.next = NULL;
 }
 
-static char *perm_copy (char *string1, char *string2) {
+static char *perm_copy (char *string1, char *string2) 
+{
     char *p, *q;
     int len = strlen(string1)+strlen(string2)+1;
 
@@ -310,8 +355,46 @@ static char *perm_copy (char *string1, char *string2) {
     }
     p = q = perm_tail->data + perm_tail->usage;
     while ( (*q = *string1++) ) q++;
-    while ( (*q++ = *string2++) );
+    while ( (*q++ = *string2++) ) ;
     perm_tail->usage = q - perm_tail->data;
 
     return p;
 }
+
+/*
+ * Notes regarding bug involving redefinition of external segments.
+ *
+ * Up to and including v0.97, the following code didn't work. From 0.97
+ * developers release 2 onwards, it will generate an error.
+ *
+ * EXTERN extlabel
+ * newlabel EQU extlabel + 1
+ *
+ * The results of allowing this code through are that two import records
+ * are generated, one for 'extlabel' and one for 'newlabel'.
+ *
+ * The reason for this is an inadequacy in the defined interface between
+ * the label manager and the output formats. The problem lies in how the
+ * output format driver tells that a label is an external label for which
+ * a label import record must be produced. Most (all except bin?) produce
+ * the record if the segment number of the label is not one of the internal
+ * segments that the output driver is producing.
+ *
+ * A simple fix to this would be to make the output formats keep track of
+ * which symbols they've produced import records for, and make them not
+ * produce import records for segments that are already defined.
+ *
+ * The best way, which is slightly harder but reduces duplication of code
+ * and should therefore make the entire system smaller and more stable is
+ * to change the interface between assembler, define_label(), and
+ * the output module. The changes that are needed are:
+ *
+ * The semantics of the 'isextern' flag passed to define_label() need
+ * examining. This information may or may not tell us what we need to
+ * know (ie should we be generating an import record at this point for this
+ * label). If these aren't the semantics, the semantics should be changed
+ * to this.
+ *
+ * The output module interface needs changing, so that the `isextern' flag
+ * is passed to the module, so that it can be easily tested for.
+ */
index 111104b..b78c856 100644 (file)
--- a/labels.h
+++ b/labels.h
@@ -10,9 +10,10 @@ int lookup_label (char *label, long *segment, long *offset);
 int is_extern (char *label);
 void define_label (char *label, long segment, long offset, char *special,
                   int is_norm, int isextrn, struct ofmt *ofmt, efunc error);
+void redefine_label (char *label, long segment, long offset, char *special,
+                  int is_norm, int isextrn, struct ofmt *ofmt, efunc error);
 void define_common (char *label, long segment, long size, char *special,
                    struct ofmt *ofmt, efunc error);
-void define_label_stub (char *label, efunc error);
 void declare_as_global (char *label, char *special, efunc error);
 int init_labels (void);
 void cleanup_labels (void);
index 89b722a..af8a9bf 100644 (file)
--- a/listing.c
+++ b/listing.c
@@ -50,31 +50,39 @@ static int listlevel, listlevel_e;
 
 static FILE *listfp;
 
-static void list_emit (void) {
+static void list_emit (void) 
+{
     if (!listlinep && !listdata[0])
        return;
+
     fprintf(listfp, "%6ld ", ++listlineno);
+
     if (listdata[0])
        fprintf(listfp, "%08lX %-*s", listoffset, LIST_HEXBIT+1, listdata);
     else
        fprintf(listfp, "%*s", LIST_HEXBIT+10, "");
+
     if (listlevel_e)
        fprintf(listfp, "%s<%d>", (listlevel < 10 ? " " : ""), listlevel_e);
     else if (listlinep)
        fprintf(listfp, "    ");
+
     if (listlinep)
        fprintf(listfp, " %s", listline);
+
     fputc('\n', listfp);
     listlinep = FALSE;
     listdata[0] = '\0';
 }
 
-static void list_init (char *fname, efunc error) {
+static void list_init (char *fname, efunc error) 
+{
     listfp = fopen (fname, "w");
     if (!listfp) {
        error (ERR_NONFATAL, "unable to open listing file `%s'", fname);
        return;
     }
+
     *listline = '\0';
     listlineno = 0;
     listp = TRUE;
@@ -86,19 +94,23 @@ static void list_init (char *fname, efunc error) {
     mistack->inhibiting = TRUE;
 }
 
-static void list_cleanup (void) {
+static void list_cleanup (void) 
+{
     if (!listp)
        return;
+
     while (mistack) {
        MacroInhibit *temp = mistack;
        mistack = temp->next;
        nasm_free (temp);
     }
+
     list_emit();
     fclose (listfp);
 }
 
-static void list_out (long offset, char *str) {
+static void list_out (long offset, char *str) 
+{
     if (strlen(listdata) + strlen(str) > LIST_HEXBIT) {
        strcat(listdata, "-");
        list_emit();
@@ -108,7 +120,8 @@ static void list_out (long offset, char *str) {
     strcat(listdata, str);
 }
 
-static void list_output (long offset, void *data, unsigned long type) {
+static void list_output (long offset, void *data, unsigned long type) 
+{
     long typ, size;
 
     if (!listp || suppress)
@@ -117,20 +130,25 @@ static void list_output (long offset, void *data, unsigned long type) {
     typ = type & OUT_TYPMASK;
     size = type & OUT_SIZMASK;
 
-    if (typ == OUT_RAWDATA) {
+    if (typ == OUT_RAWDATA) 
+    {
        unsigned char *p = data;
        char q[3];
-       while (size--) {
+       while (size--) 
+       {
            HEX (q, *p);
            q[2] = '\0';
            list_out (offset++, q);
            p++;
        }
-    } else if (typ == OUT_ADDRESS) {
+    } 
+    else if (typ == OUT_ADDRESS) 
+    {
        unsigned long d = *(long *)data;
        char q[11];
        unsigned char p[4], *r = p;
-       if (size == 4) {
+       if (size == 4) 
+       {
            q[0] = '['; q[9] = ']'; q[10] = '\0';
            WRITELONG (r, d);
            HEX (q+1, p[0]);
@@ -138,14 +156,17 @@ static void list_output (long offset, void *data, unsigned long type) {
            HEX (q+5, p[2]);
            HEX (q+7, p[3]);
            list_out (offset, q);
-       } else {
+       } 
+       else {
            q[0] = '['; q[5] = ']'; q[6] = '\0';
            WRITESHORT (r, d);
            HEX (q+1, p[0]);
            HEX (q+3, p[1]);
            list_out (offset, q);
        }
-    } else if (typ == OUT_REL2ADR) {
+    } 
+    else if (typ == OUT_REL2ADR) 
+    {
        unsigned long d = *(long *)data;
        char q[11];
        unsigned char p[4], *r = p;
@@ -154,7 +175,9 @@ static void list_output (long offset, void *data, unsigned long type) {
        HEX (q+1, p[0]);
        HEX (q+3, p[1]);
        list_out (offset, q);
-    } else if (typ == OUT_REL4ADR) {
+    } 
+    else if (typ == OUT_REL4ADR) 
+    {
        unsigned long d = *(long *)data;
        char q[11];
        unsigned char p[4], *r = p;
@@ -165,17 +188,22 @@ static void list_output (long offset, void *data, unsigned long type) {
        HEX (q+5, p[2]);
        HEX (q+7, p[3]);
        list_out (offset, q);
-    } else if (typ == OUT_RESERVE) {
+    } 
+    else if (typ == OUT_RESERVE) 
+    {
        char q[20];
        sprintf(q, "<res %08lX>", size);
        list_out (offset, q);
     }
 }
 
-static void list_line (int type, char *line) {
+static void list_line (int type, char *line) 
+{
     if (!listp)
        return;
-    if (mistack && mistack->inhibiting) {
+
+    if (mistack && mistack->inhibiting) 
+    {
        if (type == LIST_MACRO)
            return;
        else {                         /* pop the m i stack */
@@ -191,22 +219,29 @@ static void list_line (int type, char *line) {
     listlevel_e = listlevel;
 }
 
-static void list_uplevel (int type) {
+static void list_uplevel (int type) 
+{
     if (!listp)
        return;
-    if (type == LIST_INCBIN || type == LIST_TIMES) {
+    if (type == LIST_INCBIN || type == LIST_TIMES) 
+    {
        suppress |= (type == LIST_INCBIN ? 1 : 2);
        list_out (listoffset, type == LIST_INCBIN ? "<incbin>" : "<rept>");
        return;
     }
+
     listlevel++;
-    if (mistack && mistack->inhibiting && type == LIST_INCLUDE) {
+
+    if (mistack && mistack->inhibiting && type == LIST_INCLUDE) 
+    {
        MacroInhibit *temp = nasm_malloc(sizeof(MacroInhibit));
        temp->next = mistack;
        temp->level = listlevel;
        temp->inhibiting = FALSE;
        mistack = temp;
-    } else if (type == LIST_MACRO_NOLIST) {
+    } 
+    else if (type == LIST_MACRO_NOLIST) 
+    {
        MacroInhibit *temp = nasm_malloc(sizeof(MacroInhibit));
        temp->next = mistack;
        temp->level = listlevel;
@@ -215,15 +250,20 @@ static void list_uplevel (int type) {
     }
 }
 
-static void list_downlevel (int type) {
+static void list_downlevel (int type) 
+{
     if (!listp)
        return;
-    if (type == LIST_INCBIN || type == LIST_TIMES) {
+
+    if (type == LIST_INCBIN || type == LIST_TIMES) 
+    {
        suppress &= ~(type == LIST_INCBIN ? 1 : 2);
        return;
     }
+
     listlevel--;
-    while (mistack && mistack->level > listlevel) {
+    while (mistack && mistack->level > listlevel) 
+    {
        MacroInhibit *temp = mistack;
        mistack = temp->next;
        nasm_free (temp);
diff --git a/names.c b/names.c
index 218ce5a..cc16845 100644 (file)
--- a/names.c
+++ b/names.c
@@ -28,7 +28,9 @@ static char *insn_names[] = {        /* instruction names, as strings */
     "fcmovbe", "fcmove", "fcmovnb", "fcmovnbe", "fcmovne",
     "fcmovnu", "fcmovu", "fcom", "fcomi", "fcomip", "fcomp",
     "fcompp", "fcos", "fdecstp", "fdisi", "fdiv", "fdivp", "fdivr",
-    "fdivrp", "feni", "ffree", "fiadd", "ficom", "ficomp", "fidiv",
+    "fdivrp", 
+    "femms",
+    "feni", "ffree", "fiadd", "ficom", "ficomp", "fidiv",
     "fidivr", "fild", "fimul", "fincstp", "finit", "fist", "fistp",
     "fisub", "fisubr", "fld", "fld1", "fldcw", "fldenv", "fldl2e",
     "fldl2t", "fldlg2", "fldln2", "fldpi", "fldz", "fmul", "fmulp",
@@ -40,7 +42,7 @@ static char *insn_names[] = {        /* instruction names, as strings */
     "fucomi", "fucomip", "fucomp", "fucompp", "fxam", "fxch",
     "fxtract", "fyl2x", "fyl2xp1", "hlt", "ibts", "icebp", "idiv",
     "imul", "in", "inc", "incbin", "insb", "insd", "insw", "int",
-    "int1", "int01", "int3", "into", "invd", "invlpg", "iret",
+    "int01", "int1", "int3", "into", "invd", "invlpg", "iret",
     "iretd", "iretw", "jcxz", "jecxz", "jmp", "lahf", "lar", "lds",
     "lea", "leave", "les", "lfs", "lgdt", "lgs", "lidt", "lldt",
     "lmsw", "loadall", "loadall286", "lodsb", "lodsd", "lodsw",
@@ -49,12 +51,18 @@ static char *insn_names[] = {              /* instruction names, as strings */
     "movsx", "movzx", "mul", "neg", "nop", "not", "or", "out",
     "outsb", "outsd", "outsw", "packssdw", "packsswb", "packuswb",
     "paddb", "paddd", "paddsb", "paddsiw", "paddsw", "paddusb",
-    "paddusw", "paddw", "pand", "pandn", "paveb", "pcmpeqb",
+    "paddusw", "paddw", "pand", "pandn", "paveb", 
+    "pavgusb", "pcmpeqb",
     "pcmpeqd", "pcmpeqw", "pcmpgtb", "pcmpgtd", "pcmpgtw",
-    "pdistib", "pmachriw", "pmaddwd", "pmagw", "pmulhrw",
-    "pmulhriw", "pmulhw", "pmullw", "pmvgezb", "pmvlzb", "pmvnzb",
+    "pdistib", 
+    "pf2id", "pfacc", "pfadd", "pfcmpeq", "pfcmpge", "pfcmpgt",
+    "pfmax", "pfmin", "pfmul", "pfrcp", "pfrcpit1", "pfrcpit2",
+    "pfrsqit1", "pfrsqrt", "pfsub", "pfsubr", "pi2fd",
+    "pmachriw", "pmaddwd", "pmagw", "pmulhriw", "pmulhrwa", "pmulhrwc",
+    "pmulhw", "pmullw", "pmvgezb", "pmvlzb", "pmvnzb",
     "pmvzb", "pop", "popa", "popad", "popaw", "popf", "popfd",
-    "popfw", "por", "pslld", "psllq", "psllw", "psrad", "psraw",
+    "popfw", "por", 
+    "prefetch", "prefetchw", "pslld", "psllq", "psllw", "psrad", "psraw",
     "psrld", "psrlq", "psrlw", "psubb", "psubd", "psubsb",
     "psubsiw", "psubsw", "psubusb", "psubusw", "psubw", "punpckhbw",
     "punpckhdq", "punpckhwd", "punpcklbw", "punpckldq", "punpcklwd",
diff --git a/nasm.c b/nasm.c
index a1e4dd8..1404db1 100644 (file)
--- a/nasm.c
+++ b/nasm.c
 #include "outform.h"
 #include "listing.h"
 
+struct forwrefinfo {                  /* info held on forward refs. */
+    int lineno;
+    int operand;
+};
+
 static void report_error (int, char *, ...);
 static void parse_cmdline (int, char **);
 static void assemble_file (char *);
@@ -29,12 +34,11 @@ static int getkw (char *buf, char **value);
 static void register_output_formats(void);
 static void usage(void);
 
-static char *obuf;
+static int using_debug_info;
+
 static char inname[FILENAME_MAX];
 static char outname[FILENAME_MAX];
 static char listname[FILENAME_MAX];
-static int lineno;                    /* for error reporting */
-static int lineinc;                   /* set by [LINE] or [ONELINE] */
 static int globallineno;              /* for forward-reference tracking */
 static int pass;
 static struct ofmt *ofmt = NULL;
@@ -42,27 +46,27 @@ static struct ofmt *ofmt = NULL;
 static FILE *ofile = NULL;
 static int sb = 16;                   /* by default */
 
-static int use_stdout = FALSE;        /* by default, errors to stderr */
+static loc_t location;
+int          in_abs_seg;              /* Flag we are in ABSOLUTE seg */
+static long  abs_seg;
 
-static long current_seg, abs_seg;
 static struct RAA *offsets;
 static long abs_offset;
 
 static struct SAA *forwrefs;          /* keep track of forward references */
-static int forwline;
+static struct forwrefinfo *forwref;
 
 static Preproc *preproc;
 static int preprocess_only;
 
 /* used by error function to report location */
-static char currentfile[FILENAME_MAX];
 
 /*
  * Which of the suppressible warnings are suppressed. Entry zero
  * doesn't do anything. Initial defaults are given here.
  */
 static char suppressed[1+ERR_WARN_MAX] = {
-    0, FALSE, TRUE, FALSE
+    0, TRUE, TRUE, FALSE
 };
 
 /*
@@ -101,20 +105,30 @@ static Preproc no_pp = {
 /*
  * get/set current offset...
  */
-#define get_curr_ofs (current_seg==NO_SEG?abs_offset:\
-                     raa_read(offsets,current_seg))
-#define set_curr_ofs(x) (current_seg==NO_SEG?(void)(abs_offset=(x)):\
-                        (void)(offsets=raa_write(offsets,current_seg,(x))))
+#define get_curr_ofs (in_abs_seg?abs_offset:\
+                     raa_read(offsets,location.segment))
+#define set_curr_ofs(x) (in_abs_seg?(void)(abs_offset=(x)):\
+                        (void)(offsets=raa_write(offsets,location.segment,(x))))
 
 static int want_usage;
 static int terminate_after_phase;
 
-int main(int argc, char **argv) {
+static void nasm_fputs(char *line, FILE *ofile) 
+{
+    if (ofile) {
+       fputs(line, ofile);
+       fputc('\n', ofile);
+    } else
+       puts(line);
+}
+
+int main(int argc, char **argv) 
+{
     want_usage = terminate_after_phase = FALSE;
 
     nasm_set_malloc_error (report_error);
     offsets = raa_init();
-    forwrefs = saa_init ((long)sizeof(int));
+    forwrefs = saa_init ((long)sizeof(struct forwrefinfo));
 
     preproc = &nasmpp;
     preprocess_only = FALSE;
@@ -125,7 +139,8 @@ int main(int argc, char **argv) {
 
     parse_cmdline(argc, argv);
 
-    if (terminate_after_phase) {
+    if (terminate_after_phase) 
+    {
        if (want_usage)
            usage();
        return 1;
@@ -133,10 +148,15 @@ int main(int argc, char **argv) {
 
     if (ofmt->stdmac)
        pp_extra_stdmac (ofmt->stdmac);
-    eval_global_info (ofmt, lookup_label);
+    parser_global_info (ofmt, &location);
+    eval_global_info (ofmt, lookup_label, &location);
 
-    if (preprocess_only) {
+    if (preprocess_only) 
+    {
        char *line;
+       char *file_name = NULL;
+       long  prior_linnum=0;
+       int   lineinc=0;
 
        if (*outname) {
            ofile = fopen(outname, "w");
@@ -146,41 +166,37 @@ int main(int argc, char **argv) {
        } else
            ofile = NULL;
 
-       eval_info ("%", 0L, 0L);       /* disallow labels, $ or $$ in exprs */
+       location.known = FALSE;
 
        preproc->reset (inname, 2, report_error, evaluate, &nasmlist);
-       strcpy(currentfile,inname);
-       lineno = 0;
-       lineinc = 1;
        while ( (line = preproc->getline()) ) {
-           int ln, li;
-           char buf[FILENAME_MAX];
-
-           lineno += lineinc;
            /*
-            * We must still check for %line directives, so that we
-            * can report errors accurately.
+            * We generate %line directives if needed for later programs
             */
-           if (!strncmp(line, "%line", 5) &&
-               sscanf(line, "%%line %d+%d %s", &ln, &li, buf) == 3) {
-               lineno = ln - li;
-               lineinc = li;
-               strncpy (currentfile, buf, FILENAME_MAX-1);
-               currentfile[FILENAME_MAX-1] = '\0';
+           long linnum = prior_linnum += lineinc;
+           int  altline = src_get(&linnum, &file_name);
+           if (altline) {
+               if (altline==1 && lineinc==1)
+                  nasm_fputs("", ofile);
+               else {
+                  lineinc = (altline != -1 || lineinc!=1);
+                  fprintf(ofile ? ofile : stdout, "%%line %ld+%d %s\n",
+                          linnum, lineinc, file_name);
+               }
+               prior_linnum = linnum;
            }
-           if (ofile) {
-               fputs(line, ofile);
-               fputc('\n', ofile);
-           } else
-               puts(line);
+           nasm_fputs(line, ofile);
            nasm_free (line);
        }
+       nasm_free(file_name);
        preproc->cleanup();
        if (ofile)
            fclose(ofile);
        if (ofile && terminate_after_phase)
            remove(outname);
-    } else {
+    } 
+    else       /* NOT preprocess only */
+    {
        /*
         * We must call ofmt->filename _anyway_, even if the user
         * has specified their own output file, because some
@@ -195,25 +211,31 @@ int main(int argc, char **argv) {
            report_error (ERR_FATAL | ERR_NOFILE,
                          "unable to open output file `%s'", outname);
        }
+
        /*
         * We must call init_labels() before ofmt->init() since
         * some object formats will want to define labels in their
         * init routines. (eg OS/2 defines the FLAT group)
         */
        init_labels ();
+
        ofmt->init (ofile, report_error, define_label, evaluate);
+
        assemble_file (inname);
+
        if (!terminate_after_phase) {
-           ofmt->cleanup ();
+           ofmt->cleanup (using_debug_info);
            cleanup_labels ();
        }
-       /*
-        * We had an fclose on the output file here, but we
-        * actually do that in all the object file drivers as well,
-        * so we're leaving out the one here.
-        *     fclose (ofile);
-        */
-       if (terminate_after_phase) {
+       else {
+
+           /*
+            * We had an fclose on the output file here, but we
+            * actually do that in all the object file drivers as well,
+            * so we're leaving out the one here.
+            *     fclose (ofile);
+            */
+
            remove(outname);
            if (listname[0])
                remove(listname);
@@ -222,8 +244,11 @@ int main(int argc, char **argv) {
 
     if (want_usage)
        usage();
+
     raa_free (offsets);
     saa_free (forwrefs);
+    eval_cleanup ();
+    nasmlib_cleanup ();
 
     if (terminate_after_phase)
        return 1;
@@ -231,43 +256,70 @@ int main(int argc, char **argv) {
        return 0;
 }
 
-static int process_arg (char *p, char *q) {
+
+/*
+ * Get a parameter for a command line option.
+ * First arg must be in the form of e.g. -f...
+ */
+static char *get_param (char *p, char *q, int *advance)
+{
+    *advance = 0;
+    if (p[2])                         /* the parameter's in the option */
+    {
+       p += 2;
+       while (isspace(*p))
+           p++;
+       return p;
+    }
+    if (q && q[0])
+    {
+       *advance = 1;
+       return q;
+    }
+    report_error (ERR_NONFATAL | ERR_NOFILE | ERR_USAGE,
+                 "option `-%c' requires an argument",
+                 p[1]);
+    return NULL;
+}
+
+int stopoptions = 0;
+static int process_arg (char *p, char *q)
+{
     char *param;
-    int i;
-    int advance = 0;
+    int  i, advance = 0;
 
     if (!p || !p[0])
        return 0;
 
-    if (p[0]=='-') {
+    if (p[0]=='-' && ! stopoptions) 
+    {
        switch (p[1]) {
-         case 's':
-           use_stdout = TRUE;
-           break;
+         case '-':                     /* -- => stop processing options */
+             stopoptions = 1;
+             break;
+         case 's':                    /* silently ignored for compatibility */
+             break;
          case 'o':                    /* these parameters take values */
          case 'f':
          case 'p':
          case 'd':
          case 'i':
          case 'l':
-           if (p[2])                  /* the parameter's in the option */
-               param = p+2;
-           else if (!q) {
-               report_error (ERR_NONFATAL | ERR_NOFILE | ERR_USAGE,
-                             "option `-%c' requires an argument",
-                             p[1]);
+         case 'F':
+           if ( !(param = get_param (p, q, &advance)) )
                break;
-           } else
-               advance = 1, param = q;
            if (p[1]=='o') {           /* output file */
                strcpy (outname, param);
            } else if (p[1]=='f') {    /* output format */
                ofmt = ofmt_find(param);
                if (!ofmt) {
                    report_error (ERR_FATAL | ERR_NOFILE | ERR_USAGE,
-                                 "unrecognised output format `%s'",
+                                 "unrecognised output format `%s' - "
+                                 "use -hf for a list",
                                  param);
                }
+               else
+                   ofmt->current_dfmt = ofmt->debug_formats[0];
            } else if (p[1]=='p') {    /* pre-include */
                pp_pre_include (param);
            } else if (p[1]=='d') {    /* pre-define */
@@ -276,40 +328,63 @@ static int process_arg (char *p, char *q) {
                pp_include_path (param);
            } else if (p[1]=='l') {    /* listing file */
                strcpy (listname, param);
-           }
+           } else if (p[1] == 'F') {  /* specify debug format */
+               ofmt->current_dfmt = dfmt_find(ofmt, param);
+               if (!ofmt->current_dfmt) {
+                   report_error (ERR_FATAL | ERR_NOFILE | ERR_USAGE,
+                                 "unrecognized debug format `%s' for"
+                                 " output format `%s'",
+                                 param, ofmt->shortname);
+                }
+            }
+           break;
+         case 'g':
+           using_debug_info = TRUE;
            break;
          case 'h':
-           fprintf(use_stdout ? stdout : stderr,
-                   "usage: nasm [-o outfile] [-f format] [-l listfile]"
-                   " [options...] filename\n");
-           fprintf(use_stdout ? stdout : stderr,
-                   "    or nasm -r   for version info\n\n");
-           fprintf(use_stdout ? stdout : stderr,
-                   "    -e means preprocess only; "
-                   "-a means don't preprocess\n");
-           fprintf(use_stdout ? stdout : stderr,
-                   "    -s means send errors to stdout not stderr\n");
-           fprintf(use_stdout ? stdout : stderr,
-                   "    -i<path> adds a pathname to the include file"
-                   " path\n    -p<file> pre-includes a file;"
-                   " -d<macro>[=<value] pre-defines a macro\n");
-           fprintf(use_stdout ? stdout : stderr,
-                   "    -w+foo enables warnings about foo; "
-                   "-w-foo disables them\n  where foo can be:\n");
+           printf("usage: nasm [-@ response file] [-o outfile] [-f format] "
+                  "[-l listfile]\n"
+                  "            [options...] [--] filename\n");
+           printf("    or nasm -r   for version info\n\n");
+           printf("    -e          preprocess only (writes output to "
+                  "stdout by default)\n"
+                  "    -a          don't preprocess\n\n");
+           printf("    -g          enable debug info\n"
+                  "    -F format   select a debugging format\n\n");
+           printf("    -i<path>    adds a pathname to the include file path\n"
+                  "    -p<file>    pre-includes a file\n"
+                  "    -d<macro>[=<value>] pre-defines a macro\n");
+           printf("    -w+foo      enables warnings about foo; "
+                  "-w-foo disables them\n  where foo can be:\n");
            for (i=1; i<=ERR_WARN_MAX; i++)
-               fprintf(use_stdout ? stdout : stderr,
-                       "    %-16s%s (default %s)\n",
-                       suppressed_names[i], suppressed_what[i],
-                       suppressed[i] ? "off" : "on");
-           fprintf(use_stdout ? stdout : stderr,
-                   "\nvalid output formats for -f are"
-                   " (`*' denotes default):\n");
-           ofmt_list(ofmt, use_stdout ? stdout : stderr);
+               printf("    %-16s%s (default %s)\n",
+                      suppressed_names[i], suppressed_what[i],
+                      suppressed[i] ? "off" : "on");
+           printf ("\nresponse files should contain command line parameters"
+                   ", one per line.\n");
+           if (p[2] == 'f') {
+               printf("\nvalid output formats for -f are"
+                      " (`*' denotes default):\n");
+               ofmt_list(ofmt, stdout);
+           }
+           else {
+               printf ("\nFor a list of valid output formats, use -hf.\n");
+               printf ("For a list of debug formats, use -f <form> -y.\n");
+           }
            exit (0);                  /* never need usage message here */
            break;
+          case 'y':
+           printf("\nvalid debug formats for '%s' output format are"
+                  " ('*' denotes default):\n",
+               ofmt->shortname);
+           dfmt_list(ofmt, stdout);
+           exit(0);
+           break;
          case 'r':
-           fprintf(use_stdout ? stdout : stderr,
-                   "NASM version %s\n", NASM_VER);
+           printf("NASM version %s\n", NASM_VER);
+#ifdef DEBUG
+           printf("Compiled with -DDEBUG on " __DATE__ "\n");
+#endif
            exit (0);                  /* never need usage message here */
            break;
          case 'e':                    /* preprocess only */
@@ -334,12 +409,15 @@ static int process_arg (char *p, char *q) {
            }
            break;
          default:
-           report_error (ERR_NONFATAL | ERR_NOFILE | ERR_USAGE,
+           if (!ofmt->setinfo(GI_SWITCH,&p))
+               report_error (ERR_NONFATAL | ERR_NOFILE | ERR_USAGE,
                          "unrecognised option `-%c'",
                          p[1]);
            break;
        }
-    } else {
+    } 
+    else 
+    {
        if (*inname) {
            report_error (ERR_NONFATAL | ERR_NOFILE | ERR_USAGE,
                          "more than one input file specified");
@@ -350,8 +428,73 @@ static int process_arg (char *p, char *q) {
     return advance;
 }
 
-static void parse_cmdline(int argc, char **argv) {
-    char *envreal, *envcopy, *p, *q, *arg, *prevarg;
+#define ARG_BUF_DELTA 128
+
+static void process_respfile (FILE *rfile)
+{
+    char *buffer, *p, *q, *prevarg;
+    int bufsize, prevargsize;
+
+    bufsize = prevargsize = ARG_BUF_DELTA;
+    buffer = nasm_malloc(ARG_BUF_DELTA);
+    prevarg = nasm_malloc(ARG_BUF_DELTA);
+    prevarg[0] = '\0';
+
+    while (1) {   /* Loop to handle all lines in file */
+
+       p = buffer;
+       while (1) {  /* Loop to handle long lines */
+           q = fgets(p, bufsize-(p-buffer), rfile);
+           if (!q)
+               break;
+           p += strlen(p);
+           if (p > buffer && p[-1] == '\n')
+               break;
+           if (p-buffer > bufsize-10) {
+               int offset;
+               offset = p - buffer;
+               bufsize += ARG_BUF_DELTA;
+               buffer = nasm_realloc(buffer, bufsize);
+               p = buffer + offset;
+           }
+       }
+
+       if (!q && p == buffer) {
+           if (prevarg[0])
+               process_arg (prevarg, NULL);
+           nasm_free (buffer);
+           nasm_free (prevarg);
+           return;
+       }
+
+       /*
+        * Play safe: remove CRs, LFs and any spurious ^Zs, if any of
+        * them are present at the end of the line.
+        */
+       *(p = &buffer[strcspn(buffer, "\r\n\032")]) = '\0';
+
+       while (p > buffer && isspace(p[-1]))
+           *--p = '\0';
+
+       p = buffer;
+       while (isspace(*p))
+           p++;
+
+       if (process_arg (prevarg, p))
+           *p = '\0';
+
+       if (strlen(p) > prevargsize-10) {
+           prevargsize += ARG_BUF_DELTA;
+           prevarg = nasm_realloc(prevarg, prevargsize);
+       }
+       strcpy (prevarg, p);
+    }
+}
+
+static void parse_cmdline(int argc, char **argv)
+{
+    FILE *rfile;
+    char *envreal, *envcopy=NULL, *p, *q, *arg, *prevarg;
     char separator = ' ';
 
     *inname = *outname = *listname = '\0';
@@ -375,18 +518,28 @@ static void parse_cmdline(int argc, char **argv) {
            if (process_arg (prevarg, arg))
                arg = NULL;
        }
+       if (arg)
+           process_arg (arg, NULL);
        nasm_free (envcopy);
     }
-    if (arg)
-       process_arg (arg, NULL);
 
     /*
      * Now process the actual command line.
      */
-    while (--argc) {
+    while (--argc)
+    {
        int i;
        argv++;
-       i = process_arg (argv[0], argc > 1 ? argv[1] : NULL);
+       if (!stopoptions && argv[0][0] == '-' && argv[0][1] == '@') {
+           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;
     }
 
@@ -395,56 +548,34 @@ static void parse_cmdline(int argc, char **argv) {
                      "no input file specified");
 }
 
-static void assemble_file (char *fname) {
-    char *value, *p, *q, *special, *line;
-    insn output_ins;
-    int i, rn_error, validid;
-    long seg, offs;
+static void assemble_file (char *fname)
+{
+    char   * value, * p, * q, * special, * line, debugid[80];
+    insn   output_ins;
+    int    i, rn_error, validid;
+    long   seg, offs;
     struct tokenval tokval;
-    expr *e;
+    expr   * e;
 
-    /* pass one */
+    /*
+     * pass one 
+     */
     pass = 1;
-    current_seg = ofmt->section(NULL, pass, &sb);
+    in_abs_seg = FALSE;
+    location.segment = ofmt->section(NULL, pass, &sb);
     preproc->reset(fname, 1, report_error, evaluate, &nasmlist);
-    strcpy(currentfile,fname);
-    lineno = 0;
-    lineinc = 1;
     globallineno = 0;
-    offs = get_curr_ofs;
-    eval_info (NULL, current_seg, offs);   /* set $ */
-    while ( (line = preproc->getline()) ) {
-       lineno += lineinc;
-       globallineno++;
+    location.known = TRUE;
+    location.offset = offs = get_curr_ofs;
 
-       if (line[0] == '%') {
-           int ln, li;
-           char buf[FILENAME_MAX];
-
-           /*
-            * This will be a line number directive. They come
-            * straight from the preprocessor, so we'll subject
-            * them to only minimal error checking.
-            */
-           if (strncmp(line, "%line", 5)) {
-               if (preproc == &no_pp)
-                   report_error (ERR_WARNING, "unknown `%%' directive in "
-                                 " preprocessed source");
-           } else if (sscanf(line, "%%line %d+%d %s", &ln, &li, buf) != 3) {
-               report_error (ERR_WARNING, "bogus line number directive in"
-                             " preprocessed source");
-           } else {
-               lineno = ln - li;
-               lineinc = li;
-               strncpy (currentfile, buf, FILENAME_MAX-1);
-               currentfile[FILENAME_MAX-1] = '\0';
-           }
-           continue;
-       }
+    while ( (line = preproc->getline()) ) 
+    {
+       globallineno++;
 
        /* here we parse our directives; this is not handled by the 'real'
         * parser. */
-       if ( (i = getkw (line, &value)) ) {
+       if ( (i = getkw (line, &value)) ) 
+       {
            switch (i) {
              case 1:          /* [SEGMENT n] */
                seg = ofmt->section (value, pass, &sb);
@@ -453,7 +584,8 @@ static void assemble_file (char *fname) {
                                  "segment name `%s' not recognised",
                                  value);
                } else {
-                   current_seg = seg;
+                   in_abs_seg = FALSE;
+                   location.segment = seg;
                }
                break;
              case 2:          /* [EXTERN label:special] */
@@ -561,7 +693,6 @@ static void assemble_file (char *fname) {
                                  " COMMON declaration");
                break;
              case 6:                  /* [ABSOLUTE address] */
-               current_seg = NO_SEG;
                stdscan_reset();
                stdscan_bufptr = value;
                tokval.t_type = TOKEN_INVALID;
@@ -578,6 +709,25 @@ static void assemble_file (char *fname) {
                    }
                } 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))
@@ -585,31 +735,28 @@ static void assemble_file (char *fname) {
                                  line+1);
                break;
            }
-       } else {
+       }
+       else    /* it isn't a directive */
+       {
            parse_line (1, line, &output_ins,
-                       report_error, evaluate, eval_info);
-           if (output_ins.forw_ref)
-               *(int *)saa_wstruct(forwrefs) = globallineno;
-
-           /*
-            * Hack to prevent phase error in the code
-            *   rol ax,x
-            *   x equ 1
-            *
-            * We rule that the presence of a forward reference
-            * cancels out the UNITY property of the number 1. This
-            * isn't _strictly_ necessary in pass one, since the
-            * problem occurs in pass two, but for the sake of
-            * having the passes as near to identical as we can
-            * manage, we do it like this.
-            */
-           if (output_ins.forw_ref) {
-               int i;
-               for (i=0; i<output_ins.operands; i++)
-                   output_ins.oprs[i].type &= ~ONENESS;
+                       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 (output_ins.opcode == I_EQU) {
+           if (output_ins.opcode == I_EQU) 
+           {
                /*
                 * Special `..' EQUs get processed in pass two,
                 * except `..@' macro-processor EQUs which are done
@@ -618,46 +765,111 @@ static void assemble_file (char *fname) {
                if (!output_ins.label)
                    report_error (ERR_NONFATAL,
                                  "EQU not preceded by label");
+
+               /* 
+                * EQU cannot be used to declare a label relative to
+                * an external symbol.
+                */
+               else if ((output_ins.oprs[0].opflags & OPFLAG_EXTERN) 
+                        || (output_ins.operands > 1 
+                            && (output_ins.oprs[1].opflags & OPFLAG_EXTERN)))
+               {
+                   report_error (ERR_NONFATAL,
+                                 "EQU used relative to external symbol");
+               }
+
                else if (output_ins.label[0] != '.' ||
                         output_ins.label[1] != '.' ||
-                        output_ins.label[2] == '@') {
+                        output_ins.label[2] == '@') 
+               {
                    if (output_ins.operands == 1 &&
                        (output_ins.oprs[0].type & IMMEDIATE) &&
-                       output_ins.oprs[0].wrt == NO_SEG) {
+                       output_ins.oprs[0].wrt == NO_SEG) 
+                   {
                        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 &&
+                   } 
+                   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) {
+                              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
+                   } 
+                   else
                        report_error(ERR_NONFATAL, "bad syntax for EQU");
                }
-           } else {
-               if (output_ins.label)
-                   define_label (output_ins.label,
-                                 current_seg==NO_SEG ? abs_seg : current_seg,
-                                 offs, NULL, TRUE, FALSE, ofmt, report_error);
-               offs += insn_size (current_seg, offs, sb,
+           } 
+           else  /* instruction isn't an EQU */
+           {
+               long l = insn_size (location.segment, offs, sb,
                                   &output_ins, report_error);
-               set_curr_ofs (offs);
+               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);
-       offs = get_curr_ofs;
-       eval_info (NULL, current_seg, offs);   /* set $ */
+       location.offset = offs = get_curr_ofs;
     }
+
     preproc->cleanup();
 
     if (terminate_after_phase) {
@@ -668,50 +880,26 @@ static void assemble_file (char *fname) {
        exit (1);
     }
 
-    /* pass two */
+    /*
+     * pass two 
+     */
+
     pass = 2;
     saa_rewind (forwrefs);
     if (*listname)
        nasmlist.init(listname, report_error);
-    {
-       int *p = saa_rstruct (forwrefs);
-       if (p)
-           forwline = *p;
-       else
-           forwline = -1;
-    }
-    current_seg = ofmt->section(NULL, pass, &sb);
+    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);
-    strcpy(currentfile,fname);
-    lineno = 0;
-    lineinc = 1;
     globallineno = 0;
-    offs = get_curr_ofs;
-    eval_info (NULL, current_seg, offs);   /* set $ */
-    while ( (line = preproc->getline()) ) {
-       lineno += lineinc;
-       globallineno++;
-
-       if (line[0] == '%') {
-           int ln, li;
-           char buf[FILENAME_MAX];
+    location.offset = offs = get_curr_ofs;
 
-           /*
-            * This will be a line number directive. They come
-            * straight from the preprocessor, so we'll subject
-            * them to only minimal error checking.
-            */
-           if (!strncmp(line, "%line", 5) &&
-               sscanf(line, "%%line %d+%d %s", &ln, &li, buf) == 3) {
-               lineno = ln - li;
-               lineinc = li;
-               strncpy (currentfile, buf, FILENAME_MAX-1);
-               currentfile[FILENAME_MAX-1] = '\0';
-           }
-           continue;
-       }
+    while ( (line = preproc->getline()) ) 
+    {
+       globallineno++;
 
        /* here we parse our directives; this is not handled by
         * the 'real' parser. */
@@ -723,7 +911,8 @@ static void assemble_file (char *fname) {
                    report_error (ERR_PANIC,
                                  "invalid segment name on pass two");
                } else
-                   current_seg = seg;
+                   in_abs_seg = FALSE;
+                   location.segment = seg;
                break;
              case 2:          /* [EXTERN label] */
                q = value;
@@ -769,7 +958,6 @@ static void assemble_file (char *fname) {
                }
                break;
              case 6:                  /* [ABSOLUTE addr] */
-               current_seg = NO_SEG;
                stdscan_reset();
                stdscan_bufptr = value;
                tokval.t_type = TOKEN_INVALID;
@@ -786,22 +974,46 @@ static void assemble_file (char *fname) {
                } 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 {
+       } 
+       else            /* not a directive */
+       {
            parse_line (2, line, &output_ins,
-                       report_error, evaluate, eval_info);
-           if (globallineno == forwline) {
-               int *p = saa_rstruct (forwrefs);
-               if (p)
-                   forwline = *p;
-               else
-                   forwline = -1;
+                       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;
 
@@ -809,68 +1021,92 @@ static void assemble_file (char *fname) {
             * 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) {
-               int i;
-               for (i=0; i<output_ins.operands; i++)
-                   output_ins.oprs[i].type &= ~ONENESS;
+
+           if (output_ins.forw_ref &&
+               output_ins.operands >= 2 &&
+               (output_ins.oprs[1].opflags & OPFLAG_FORWARD)) 
+           {
+                   output_ins.oprs[1].type &= ~ONENESS;
            }
 
-           obuf = line;
-           if (output_ins.label)
-               define_label_stub (output_ins.label, report_error);
-           if (output_ins.opcode == I_EQU) {
+           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] != '@') {
+                   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 &&
+                   } 
+                   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) {
+                              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
+                   } 
+                   else
                        report_error(ERR_NONFATAL, "bad syntax for EQU");
                }
            }
-           offs += assemble (current_seg, offs, sb,
+           offs += assemble (location.segment, offs, sb,
                              &output_ins, ofmt, report_error, &nasmlist);
            cleanup_insn (&output_ins);
            set_curr_ofs (offs);
        }
+
        nasm_free (line);
 
-       offs = get_curr_ofs;
-       eval_info (NULL, current_seg, offs);   /* set $ */
+       location.offset = offs = get_curr_ofs;
     }
+
     preproc->cleanup();
     nasmlist.cleanup();
 }
 
-static int getkw (char *buf, char **value) {
+static int getkw (char *buf, char **value) 
+{
     char *p, *q;
 
     if (*buf!='[')
        return 0;
+
     p = buf;
+
     while (*p && *p != ']') p++;
+
     if (!*p)
        return 0;
+
     q = p++;
+
     while (*p && *p != ';') {
        if (!isspace(*p))
            return 0;
@@ -905,10 +1141,13 @@ static int getkw (char *buf, char **value) {
        return 5;
     if (!strcmp(p, "absolute"))
        return 6;
+    if (!strcmp(p, "debug"))
+       return 7;
     return -1;
 }
 
-static void report_error (int severity, char *fmt, ...) {
+static void report_error (int severity, char *fmt, ...) 
+{
     va_list ap;
 
     /*
@@ -926,19 +1165,23 @@ static void report_error (int severity, char *fmt, ...) {
        return;
 
     if (severity & ERR_NOFILE)
-       fputs ("nasm: ", use_stdout ? stdout : stderr);
-    else
-       fprintf (use_stdout ? stdout : stderr, "%s:%d: ", currentfile,
-                lineno + (severity & ERR_OFFBY1 ? lineinc : 0));
+       fputs ("nasm: ", stdout);
+    else {
+       char * currentfile = NULL;
+       long lineno = 0;
+       src_get (&lineno, &currentfile);
+       fprintf (stdout, "%s:%ld: ", currentfile, lineno);
+       nasm_free (currentfile);
+    }
 
     if ( (severity & ERR_MASK) == ERR_WARNING)
-       fputs ("warning: ", use_stdout ? stdout : stderr);
+       fputs ("warning: ", stdout);
     else if ( (severity & ERR_MASK) == ERR_PANIC)
-       fputs ("panic: ", use_stdout ? stdout : stderr);
+       fputs ("panic: ", stdout);
 
     va_start (ap, fmt);
-    vfprintf (use_stdout ? stdout : stderr, fmt, ap);
-    fputc ('\n', use_stdout ? stdout : stderr);
+    vfprintf (stdout, fmt, ap);
+    fputc ('\n', stdout);
 
     if (severity & ERR_USAGE)
        want_usage = TRUE;
@@ -965,80 +1208,14 @@ static void report_error (int severity, char *fmt, ...) {
     }
 }
 
-static void usage(void) {
-    fputs("type `nasm -h' for help\n", use_stdout ? stdout : stderr);
+static void usage(void) 
+{
+    fputs("type `nasm -h' for help\n", stdout);
 }
 
-static void register_output_formats(void) {
-    /* Flat-form binary format */
-#ifdef OF_BIN
-    extern struct ofmt of_bin;
-#endif
-    /* Unix formats: a.out, COFF, ELF */
-#ifdef OF_AOUT
-    extern struct ofmt of_aout;
-#endif
-#ifdef OF_AOUTB
-    extern struct ofmt of_aoutb;
-#endif
-#ifdef OF_COFF
-    extern struct ofmt of_coff;
-#endif
-#ifdef OF_ELF
-    extern struct ofmt of_elf;
-#endif
-    /* Linux strange format: as86 */
-#ifdef OF_AS86
-    extern struct ofmt of_as86;
-#endif
-    /* DOS and DOS-ish formats: OBJ, OS/2, Win32 */
-#ifdef OF_OBJ
-    extern struct ofmt of_obj;
-#endif
-#ifdef OF_WIN32
-    extern struct ofmt of_win32;
-#endif
-#ifdef OF_RDF
-    extern struct ofmt of_rdf;
-#endif
-#ifdef OF_DBG     /* debug format must be included specifically */
-    extern struct ofmt of_dbg;
-#endif
-
-#ifdef OF_BIN
-    ofmt_register (&of_bin);
-#endif
-#ifdef OF_AOUT
-    ofmt_register (&of_aout);
-#endif
-#ifdef OF_AOUTB
-    ofmt_register (&of_aoutb);
-#endif
-#ifdef OF_COFF
-    ofmt_register (&of_coff);
-#endif
-#ifdef OF_ELF
-    ofmt_register (&of_elf);
-#endif
-#ifdef OF_AS86
-    ofmt_register (&of_as86);
-#endif
-#ifdef OF_OBJ
-    ofmt_register (&of_obj);
-#endif
-#ifdef OF_WIN32
-    ofmt_register (&of_win32);
-#endif
-#ifdef OF_RDF
-    ofmt_register (&of_rdf);
-#endif
-#ifdef OF_DBG
-    ofmt_register (&of_dbg);
-#endif
-    /*
-     * set the default format
-     */
-    ofmt = &OF_DEFAULT;
+static void register_output_formats(void) 
+{
+    ofmt = ofmt_register (report_error);
 }
 
 #define BUF_DELTA 512
@@ -1046,9 +1223,14 @@ static void register_output_formats(void) {
 static FILE *no_pp_fp;
 static efunc no_pp_err;
 static ListGen *no_pp_list;
+static long no_pp_lineinc;
 
 static void no_pp_reset (char *file, int pass, efunc error, evalfunc eval,
-                        ListGen *listgen) {
+                        ListGen *listgen) 
+{
+    src_set_fname(nasm_strdup(file));
+    src_set_linnum(0);
+    no_pp_lineinc = 1;
     no_pp_err = error;
     no_pp_fp = fopen(file, "r");
     if (!no_pp_fp)
@@ -1059,49 +1241,66 @@ static void no_pp_reset (char *file, int pass, efunc error, evalfunc eval,
     (void) eval;                      /* placate compilers */
 }
 
-static char *no_pp_getline (void) {
+static char *no_pp_getline (void) 
+{
     char *buffer, *p, *q;
     int bufsize;
 
     bufsize = BUF_DELTA;
     buffer = nasm_malloc(BUF_DELTA);
-    p = buffer;
-    while (1) {
-       q = fgets(p, bufsize-(p-buffer), no_pp_fp);
-       if (!q)
-           break;
-       p += strlen(p);
-       if (p > buffer && p[-1] == '\n')
-           break;
-       if (p-buffer > bufsize-10) {
-           bufsize += BUF_DELTA;
-           buffer = nasm_realloc(buffer, bufsize);
-       }
-    }
+    src_set_linnum(src_get_linnum() + no_pp_lineinc);
 
-    if (!q && p == buffer) {
-       nasm_free (buffer);
-       return NULL;
-    }
+    while (1) {   /* Loop to handle %line */
 
-    /*
-     * Play safe: remove CRs as well as LFs, if any of either are
-     * present at the end of the line.
-     */
-    while (p > buffer && (p[-1] == '\n' || p[-1] == '\r'))
-       *--p = '\0';
+       p = buffer;
+       while (1) {  /* Loop to handle long lines */
+           q = fgets(p, bufsize-(p-buffer), no_pp_fp);
+           if (!q)
+               break;
+           p += strlen(p);
+           if (p > buffer && p[-1] == '\n')
+               break;
+           if (p-buffer > bufsize-10) {
+               int offset;
+               offset = p - buffer;
+               bufsize += BUF_DELTA;
+               buffer = nasm_realloc(buffer, bufsize);
+               p = buffer + offset;
+           }
+       }
 
-    /*
-     * Handle spurious ^Z, which may be inserted into source files
-     * by some file transfer utilities.
-     */
-    buffer[strcspn(buffer, "\032")] = '\0';
+       if (!q && p == buffer) {
+           nasm_free (buffer);
+           return NULL;
+       }
+
+       /*
+        * Play safe: remove CRs, LFs and any spurious ^Zs, if any of
+        * them are present at the end of the line.
+        */
+       buffer[strcspn(buffer, "\r\n\032")] = '\0';
+
+       if (!strncmp(buffer, "%line", 5)) {
+           long ln;
+           int  li;
+           char *nm = nasm_malloc(strlen(buffer));
+           if (sscanf(buffer+5, "%ld+%d %s", &ln, &li, nm) == 3) {
+               nasm_free( src_set_fname(nm) );
+               src_set_linnum(ln);
+               no_pp_lineinc = li;
+               continue;
+           }
+           nasm_free(nm);
+       }
+       break;
+    }
 
     no_pp_list->line (LIST_READ, buffer);
 
     return buffer;
 }
 
-static void no_pp_cleanup (void) {
+static void no_pp_cleanup (void) 
+{
     fclose(no_pp_fp);
 }
diff --git a/nasm.h b/nasm.h
index 8dafac5..aabe568 100644 (file)
--- a/nasm.h
+++ b/nasm.h
@@ -12,8 +12,8 @@
 #define NASM_NASM_H
 
 #define NASM_MAJOR_VER 0
-#define NASM_MINOR_VER 97
-#define NASM_VER "0.97"
+#define NASM_MINOR_VER 98
+#define NASM_VER "0.98 pre-release 3"
 
 #ifndef NULL
 #define NULL 0
@@ -72,9 +72,6 @@ typedef void (*efunc) (int severity, char *fmt, ...);
 #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_OFFBY1 0x40                       /* report error as being on the line 
-                                       * we're just _about_ to read, not
-                                       * the one we've just read */
 #define ERR_PASS1 0x80                /* only print this error on pass one */
 
 /*
@@ -205,6 +202,12 @@ enum {                                    /* token types, other than chars */
     TOKEN_FLOAT                               /* floating-point constant */
 };
 
+typedef struct {
+    long segment;
+    long offset;
+    int  known;
+} loc_t;
+
 /*
  * Expression-evaluator datatype. Expressions, within the
  * evaluator, are stored as an array of these beasts, terminated by
@@ -261,13 +264,6 @@ typedef expr *(*evalfunc) (scanner sc, void *scprivate, struct tokenval *tv,
                           struct eval_hints *hints);
 
 /*
- * There's also an auxiliary routine through which the evaluator
- * needs to hear about the value of $ and the label (if any)
- * defined on the current line.
- */
-typedef void (*evalinfofunc) (char *labelname, long segment, long offset);
-
-/*
  * Special values for expr->type. ASSUMPTION MADE HERE: the number
  * of distinct register names (i.e. possible "type" fields for an
  * expr structure) does not exceed 124 (EXPR_REG_START through
@@ -311,11 +307,13 @@ typedef struct {
  * ----------------------------------------------------------------
  */
 
-/* isidstart matches any character that may start an identifier, and isidchar
+/*
+ * isidstart matches any character that may start an identifier, and isidchar
  * matches any character that may appear at places other than the start of an
  * identifier. E.g. a period may only appear at the start of an identifier
  * (for local labels), whereas a number may appear anywhere *but* at the
- * start. */
+ * start. 
+ */
 
 #define isidstart(c) ( isalpha(c) || (c)=='_' || (c)=='.' || (c)=='?' \
                                   || (c)=='@' )
@@ -439,7 +437,9 @@ enum {                                     /* instruction names */
     I_FCMOVBE, I_FCMOVE, I_FCMOVNB, I_FCMOVNBE, I_FCMOVNE,
     I_FCMOVNU, I_FCMOVU, I_FCOM, I_FCOMI, I_FCOMIP, I_FCOMP,
     I_FCOMPP, I_FCOS, I_FDECSTP, I_FDISI, I_FDIV, I_FDIVP, I_FDIVR,
-    I_FDIVRP, I_FENI, I_FFREE, I_FIADD, I_FICOM, I_FICOMP, I_FIDIV,
+    I_FDIVRP,
+    I_FEMMS,
+    I_FENI, I_FFREE, I_FIADD, I_FICOM, I_FICOMP, I_FIDIV,
     I_FIDIVR, I_FILD, I_FIMUL, I_FINCSTP, I_FINIT, I_FIST, I_FISTP,
     I_FISUB, I_FISUBR, I_FLD, I_FLD1, I_FLDCW, I_FLDENV, I_FLDL2E,
     I_FLDL2T, I_FLDLG2, I_FLDLN2, I_FLDPI, I_FLDZ, I_FMUL, I_FMULP,
@@ -451,7 +451,7 @@ enum {                                     /* instruction names */
     I_FUCOMI, I_FUCOMIP, I_FUCOMP, I_FUCOMPP, I_FXAM, I_FXCH,
     I_FXTRACT, I_FYL2X, I_FYL2XP1, I_HLT, I_IBTS, I_ICEBP, I_IDIV,
     I_IMUL, I_IN, I_INC, I_INCBIN, I_INSB, I_INSD, I_INSW, I_INT,
-    I_INT1, I_INT01, I_INT3, I_INTO, I_INVD, I_INVLPG, I_IRET,
+    I_INT01, I_INT1, I_INT3, I_INTO, I_INVD, I_INVLPG, I_IRET,
     I_IRETD, I_IRETW, I_JCXZ, I_JECXZ, I_JMP, I_LAHF, I_LAR, I_LDS,
     I_LEA, I_LEAVE, I_LES, I_LFS, I_LGDT, I_LGS, I_LIDT, I_LLDT,
     I_LMSW, I_LOADALL, I_LOADALL286, I_LODSB, I_LODSD, I_LODSW,
@@ -460,12 +460,18 @@ enum {                                   /* instruction names */
     I_MOVSX, I_MOVZX, I_MUL, I_NEG, I_NOP, I_NOT, I_OR, I_OUT,
     I_OUTSB, I_OUTSD, I_OUTSW, I_PACKSSDW, I_PACKSSWB, I_PACKUSWB,
     I_PADDB, I_PADDD, I_PADDSB, I_PADDSIW, I_PADDSW, I_PADDUSB,
-    I_PADDUSW, I_PADDW, I_PAND, I_PANDN, I_PAVEB, I_PCMPEQB,
+    I_PADDUSW, I_PADDW, I_PAND, I_PANDN, I_PAVEB, 
+    I_PAVGUSB, I_PCMPEQB,
     I_PCMPEQD, I_PCMPEQW, I_PCMPGTB, I_PCMPGTD, I_PCMPGTW,
-    I_PDISTIB, I_PMACHRIW, I_PMADDWD, I_PMAGW, I_PMULHRW,
-    I_PMULHRIW, I_PMULHW, I_PMULLW, I_PMVGEZB, I_PMVLZB, I_PMVNZB,
+    I_PDISTIB,
+    I_PF2ID, I_PFACC, I_PFADD, I_PFCMPEQ, I_PFCMPGE, I_PFCMPGT,
+    I_PFMAX, I_PFMIN, I_PFMUL, I_PFRCP, I_PFRCPIT1, I_PFRCPIT2,
+    I_PFRSQIT1, I_PFRSQRT, I_PFSUB, I_PFSUBR, I_PI2FD,
+    I_PMACHRIW, I_PMADDWD, I_PMAGW,  I_PMULHRIW, I_PMULHRWA,
+    I_PMULHRWC, I_PMULHW, I_PMULLW, I_PMVGEZB, I_PMVLZB, I_PMVNZB,
     I_PMVZB, I_POP, I_POPA, I_POPAD, I_POPAW, I_POPF, I_POPFD,
-    I_POPFW, I_POR, I_PSLLD, I_PSLLQ, I_PSLLW, I_PSRAD, I_PSRAW,
+    I_POPFW, I_POR, I_PREFETCH, I_PREFETCHW,
+    I_PSLLD, I_PSLLQ, I_PSLLW, I_PSRAD, I_PSRAW,
     I_PSRLD, I_PSRLQ, I_PSRLW, I_PSUBB, I_PSUBD, I_PSUBSB,
     I_PSUBSIW, I_PSUBSW, I_PSUBUSB, I_PSUBUSW, I_PSUBW, I_PUNPCKHBW,
     I_PUNPCKHDQ, I_PUNPCKHWD, I_PUNPCKLBW, I_PUNPCKLDQ, I_PUNPCKLWD,
@@ -480,6 +486,8 @@ enum {                                     /* instruction names */
     I_XOR, I_CMOVcc, I_Jcc, I_SETcc
 };
 
+#define MAX_KEYWORD 9  /* max length of any instruction, register name etc. */
+
 enum {                                /* condition code names */
     C_A, C_AE, C_B, C_BE, C_C, C_E, C_G, C_GE, C_L, C_LE, C_NA, C_NAE,
     C_NB, C_NBE, C_NC, C_NE, C_NG, C_NGE, C_NL, C_NLE, C_NO, C_NP,
@@ -522,8 +530,12 @@ typedef struct {                  /* operand to an instruction */
     long offset;                      /* any immediate number */
     long wrt;                         /* segment base it's relative to */
     int eaflags;                      /* special EA flags */
+    int opflags;                      /* see OPFLAG_* defines below */
 } operand;
 
+#define OPFLAG_FORWARD         1      /* operand is a forward reference */
+#define OPFLAG_EXTERN          2      /* operand is an external reference */
+
 typedef struct extop {                /* extended operand */
     struct extop *next;                       /* linked list */
     long type;                        /* defined above */
@@ -542,13 +554,16 @@ typedef struct {                 /* an instruction itself */
     int nprefix;                      /* number of entries in above */
     int opcode;                               /* the opcode - not just the string */
     int condition;                    /* the condition code, if Jcc/SETcc */
-    int operands;                     /* how many operands? 0-3 */
+    int operands;                     /* how many operands? 0-3 
+                                        * (more if db et al) */
     operand oprs[3];                  /* the operands, defined as above */
     extop *eops;                      /* extended operands */
+    int eops_float;                    /* true if DD and floating */
     long times;                               /* repeat count (TIMES prefix) */
     int forw_ref;                     /* is there a forward reference? */
 } insn;
 
+enum geninfo { GI_SWITCH };
 /*
  * ------------------------------------------------------------
  * The data structure defining an output format driver, and the
@@ -569,6 +584,27 @@ struct ofmt {
     char *shortname;
 
     /*
+     * this is reserved for out module specific help.
+     * It is set to NULL in all the out modules but is not implemented
+     * in the main program
+     */
+    char *helpstring;
+
+    /*
+     * this is a pointer to the first element of the debug information
+     */
+    struct dfmt **debug_formats;
+
+    /*
+     * and a pointer to the element that is being used
+     * note: this is set to the default at compile time and changed if the
+     * -F option is selected.  If developing a set of new debug formats for
+     * an output format, be sure to set this to whatever default you want
+     *
+     */
+    struct dfmt *current_dfmt;
+
+    /*
      * This, if non-NULL, is a NULL-terminated list of `char *'s
      * pointing to extra standard macros supplied by the object
      * format (e.g. a sensible initial default value of __SECT__,
@@ -587,6 +623,15 @@ struct ofmt {
     void (*init) (FILE *fp, efunc error, ldfunc ldef, evalfunc eval);
 
     /*
+     * This procedure is called to pass generic information to the
+     * object file.  The first parameter gives the information type
+     * (currently only command line switches)
+     * and the second parameter gives the value.  This function returns
+     * 1 if recognized, 0 if unrecognized
+     */
+    int (*setinfo)(enum geninfo type, char **string);
+
+    /*
      * This procedure is called by assemble() to write actual
      * generated code or data to the object file. Typically it
      * doesn't have to actually _write_ it, just store it for
@@ -705,7 +750,7 @@ struct ofmt {
      * One thing the cleanup routine should always do is to close
      * the output file pointer.
      */
-    void (*cleanup) (void);
+    void (*cleanup) (int debuginfo);
 };
 
 /*
@@ -735,6 +780,103 @@ struct ofmt {
 #define OUT_SIZMASK 0x0FFFFFFFUL
 
 /*
+ * ------------------------------------------------------------
+ * The data structure defining a debug format driver, and the
+ * interfaces to the functions therein.
+ * ------------------------------------------------------------
+ */
+
+struct dfmt {
+    
+    /*
+     * This is a short (one-liner) description of the type of
+     * output generated by the driver.
+     */
+    char *fullname;
+
+    /*
+     * This is a single keyword used to select the driver.
+     */
+    char *shortname;
+
+
+    /*
+     * init - called initially to set up local pointer to object format, 
+     * void pointer to implementation defined data, file pointer (which
+     * probably won't be used, but who knows?), and error function.
+     */
+    void (*init) (struct ofmt * of, void * id, FILE * fp, efunc error);
+
+    /*
+     * linenum - called any time there is output with a change of
+     * line number or file.
+     */
+    void (*linenum) (const char * filename, long linenumber, long segto);
+
+    /*
+     * debug_deflabel - called whenever a label is defined. Parameters
+     * are the same as to 'symdef()' in the output format. This function
+     * would be called before the output format version.
+     */
+
+    void (*debug_deflabel) (char * name, long segment, long offset,
+                            int is_global, char * special);
+    /*
+     * debug_directive - called whenever a DEBUG directive other than 'LINE'
+     * is encountered. 'directive' contains the first parameter to the
+     * DEBUG directive, and params contains the rest. For example,
+     * 'DEBUG VAR _somevar:int' would translate to a call to this
+     * function with 'directive' equal to "VAR" and 'params' equal to 
+     * "_somevar:int".
+     */
+    void (*debug_directive) (const char * directive, const char * params);
+
+    /*
+     * typevalue - called whenever the assembler wishes to register a type
+     * for the last defined label.  This routine MUST detect if a type was
+     * already registered and not re-register it.
+     */
+    void (*debug_typevalue) (long type);
+
+    /*
+     * debug_output - called whenever output is required
+     * 'type' is the type of info required, and this is format-specific
+     */
+    void (*debug_output) (int type, void *param);
+
+    /*
+     * cleanup - called after processing of file is complete
+     */
+    void (*cleanup) (void);
+
+};
+/*
+ * The type definition macros
+ * for debugging
+ *
+ * low 3 bits: reserved
+ * next 5 bits: type
+ * next 24 bits: number of elements for arrays (0 for labels)
+ */
+
+#define TY_UNKNOWN 0x00
+#define TY_LABEL   0x08
+#define TY_BYTE    0x10
+#define TY_WORD    0x18
+#define TY_DWORD   0x20
+#define TY_FLOAT   0x28
+#define TY_QWORD   0x30
+#define TY_TBYTE   0x38
+#define TY_COMMON  0xE0
+#define TY_SEG     0xE8
+#define TY_EXTERN  0xF0
+#define TY_EQU     0xF8
+
+#define TYM_TYPE(x) ((x) & 0xF8)
+#define TYM_ELEMENTS(x) (((x) & 0xFFFFFF00) >> 8)
+
+#define TYS_ELEMENTS(x)  ((x) << 8)
+/*
  * -----
  * Other
  * -----
index 4508fec..86ed6c4 100644 (file)
--- a/nasmlib.c
+++ b/nasmlib.c
@@ -20,7 +20,8 @@ static efunc nasm_malloc_error;
 static FILE *logfp;
 #endif
 
-void nasm_set_malloc_error (efunc error) {
+void nasm_set_malloc_error (efunc error) 
+{
     nasm_malloc_error = error;
 #ifdef LOGALLOC
     logfp = fopen ("malloc.log", "w");
@@ -124,7 +125,8 @@ char *nasm_strndup (char *s, size_t len)
     return p;
 }
 
-int nasm_stricmp (char *s1, char *s2) {
+int nasm_stricmp (const char *s1, const char *s2) 
+{
     while (*s1 && toupper(*s1) == toupper(*s2))
        s1++, s2++;
     if (!*s1 && !*s2)
@@ -135,7 +137,8 @@ int nasm_stricmp (char *s1, char *s2) {
        return 1;
 }
 
-int nasm_strnicmp (char *s1, char *s2, int n) {
+int nasm_strnicmp (const char *s1, const char *s2, int n) 
+{
     while (n > 0 && *s1 && toupper(*s1) == toupper(*s2))
        s1++, s2++, n--;
     if ((!*s1 && !*s2) || n==0)
@@ -149,15 +152,29 @@ int nasm_strnicmp (char *s1, char *s2, int n) {
 #define lib_isnumchar(c)   ( isalnum(c) || (c) == '$')
 #define numvalue(c)  ((c)>='a' ? (c)-'a'+10 : (c)>='A' ? (c)-'A'+10 : (c)-'0')
 
-long readnum (char *str, int *error) {
+long readnum (char *str, int *error) 
+{
     char *r = str, *q;
     long radix;
     unsigned long result, checklimit;
+    int digit, last;
     int warn = FALSE;
+    int sign = 1;
 
     *error = FALSE;
 
     while (isspace(*r)) r++;          /* find start of number */
+
+    /*
+     * If the number came from make_tok_num (as a result of an %assign), it
+     * might have a '-' built into it (rather than in a preceeding token).
+     */
+    if (*r == '-')
+    {
+       r++;
+       sign = -1;
+    }
+
     q = r;
 
     while (lib_isnumchar(*q)) q++;     /* find end of number */
@@ -199,15 +216,26 @@ long readnum (char *str, int *error) {
      */
     checklimit = 0x80000000UL / (radix>>1);
 
+    /*
+     * Calculate the highest allowable value for the last digit
+     * of a 32 bit constant... in radix 10, it is 6, otherwise it is 0
+     */
+    last = (radix == 10 ? 6 : 0);
+
     result = 0;
     while (*r && r < q) {
-       if (*r<'0' || (*r>'9' && *r<'A') || numvalue(*r)>=radix) {
+       if (*r<'0' || (*r>'9' && *r<'A') || (digit = numvalue(*r)) >= radix) 
+       {
            *error = TRUE;
            return 0;
        }
-       if (result >= checklimit)
+       if (result > checklimit ||
+           (result == checklimit && digit >= last))
+       {
            warn = TRUE;
-       result = radix * result + numvalue(*r);
+       }
+
+       result = radix * result + digit;
        r++;
     }
 
@@ -216,25 +244,46 @@ long readnum (char *str, int *error) {
                           "numeric constant %s does not fit in 32 bits",
                           str);
 
-    return result;
+    return result*sign;
+}
+
+long readstrnum (char *str, int length, int *warn) 
+{
+    long charconst = 0;
+    int i;
+
+    *warn = FALSE;
+
+    str += length;
+    for (i=0; i<length; i++) {
+       if (charconst & 0xff000000UL) {
+           *warn = TRUE;
+       }
+       charconst = (charconst<<8) + (unsigned char) *--str;
+    }
+    return charconst;
 }
 
 static long next_seg;
 
-void seg_init(void) {
+void seg_init(void) 
+{
     next_seg = 0;
 }
 
-long seg_alloc(void) {
+long seg_alloc(void) 
+{
     return (next_seg += 2) - 2;
 }
 
-void fwriteshort (int data, FILE *fp) {
+void fwriteshort (int data, FILE *fp) 
+{
     fputc ((int) (data & 255), fp);
     fputc ((int) ((data >> 8) & 255), fp);
 }
 
-void fwritelong (long data, FILE *fp) {
+void fwritelong (long data, FILE *fp) 
+{
     fputc ((int) (data & 255), fp);
     fputc ((int) ((data >> 8) & 255), fp);
     fputc ((int) ((data >> 16) & 255), fp);
@@ -242,7 +291,8 @@ void fwritelong (long data, FILE *fp) {
 }
 
 void standard_extension (char *inname, char *outname, char *extension,
-                        efunc error) {
+                        efunc error) 
+{
     char *p, *q;
 
     if (*outname)                     /* file name already exists, */
@@ -268,47 +318,13 @@ void standard_extension (char *inname, char *outname, char *extension,
        strcpy(p, extension);
 }
 
-#define RAA_BLKSIZE 4096              /* this many longs allocated at once */
-#define RAA_LAYERSIZE 1024            /* this many _pointers_ allocated */
-
-typedef struct RAA RAA;
-typedef union RAA_UNION RAA_UNION;
-typedef struct RAA_LEAF RAA_LEAF;
-typedef struct RAA_BRANCH RAA_BRANCH;
-
-struct RAA {
-    /*
-     * Number of layers below this one to get to the real data. 0
-     * means this structure is a leaf, holding RAA_BLKSIZE real
-     * data items; 1 and above mean it's a branch, holding
-     * RAA_LAYERSIZE pointers to the next level branch or leaf
-     * structures.
-     */
-    int layers;
-    /*
-     * Number of real data items spanned by one position in the
-     * `data' array at this level. This number is 1, trivially, for
-     * a leaf (level 0): for a level 1 branch it should be
-     * RAA_BLKSIZE, and for a level 2 branch it's
-     * RAA_LAYERSIZE*RAA_BLKSIZE.
-     */
-    long stepsize;
-    union RAA_UNION {
-       struct RAA_LEAF {
-           long data[RAA_BLKSIZE];
-       } l;
-       struct RAA_BRANCH {
-           struct RAA *data[RAA_LAYERSIZE];
-       } b;
-    } u;
-};
-
 #define LEAFSIZ (sizeof(RAA)-sizeof(RAA_UNION)+sizeof(RAA_LEAF))
 #define BRANCHSIZ (sizeof(RAA)-sizeof(RAA_UNION)+sizeof(RAA_BRANCH))
 
 #define LAYERSIZ(r) ( (r)->layers==0 ? RAA_BLKSIZE : RAA_LAYERSIZE )
 
-static struct RAA *real_raa_init (int layers) {
+static struct RAA *real_raa_init (int layers) 
+{
     struct RAA *r;
 
     if (layers == 0) {
@@ -327,11 +343,13 @@ static struct RAA *real_raa_init (int layers) {
     return r;
 }
 
-struct RAA *raa_init (void) {
+struct RAA *raa_init (void) 
+{
     return real_raa_init (0);
 }
 
-void raa_free (struct RAA *r) {
+void raa_free (struct RAA *r) 
+{
     if (r->layers == 0)
        nasm_free (r);
     else {
@@ -342,7 +360,8 @@ void raa_free (struct RAA *r) {
     }
 }
 
-long raa_read (struct RAA *r, long posn) {
+long raa_read (struct RAA *r, long posn) 
+{
     if (posn > r->stepsize * LAYERSIZ(r))
        return 0L;
     while (r->layers > 0) {
@@ -356,7 +375,8 @@ long raa_read (struct RAA *r, long posn) {
     return r->u.l.data[posn];
 }
 
-struct RAA *raa_write (struct RAA *r, long posn, long value) {
+struct RAA *raa_write (struct RAA *r, long posn, long value) 
+{
     struct RAA *result;
 
     if (posn < 0)
@@ -396,17 +416,8 @@ struct RAA *raa_write (struct RAA *r, long posn, long value) {
 
 #define SAA_MAXLEN 8192
 
-struct SAA {
-    /*
-     * members `end' and `elem_len' are only valid in first link in
-     * list; `rptr' and `rpos' are used for reading
-     */
-    struct SAA *next, *end, *rptr;
-    long elem_len, length, posn, start, rpos;
-    char *data;
-};
-
-struct SAA *saa_init (long elem_len) {
+struct SAA *saa_init (long elem_len) 
+{
     struct SAA *s;
 
     if (elem_len > SAA_MAXLEN)
@@ -423,7 +434,8 @@ struct SAA *saa_init (long elem_len) {
     return s;
 }
 
-void saa_free (struct SAA *s) {
+void saa_free (struct SAA *s) 
+{
     struct SAA *t;
 
     while (s) {
@@ -434,7 +446,8 @@ void saa_free (struct SAA *s) {
     }
 }
 
-void *saa_wstruct (struct SAA *s) {
+void *saa_wstruct (struct SAA *s) 
+{
     void *p;
 
     if (s->end->length - s->end->posn < s->elem_len) {
@@ -452,7 +465,8 @@ void *saa_wstruct (struct SAA *s) {
     return p;
 }
 
-void saa_wbytes (struct SAA *s, void *data, long len) {
+void saa_wbytes (struct SAA *s, void *data, long len) 
+{
     char *d = data;
 
     while (len > 0) {
@@ -480,12 +494,14 @@ void saa_wbytes (struct SAA *s, void *data, long len) {
     }
 }
 
-void saa_rewind (struct SAA *s) {
+void saa_rewind (struct SAA *s) 
+{
     s->rptr = s;
     s->rpos = 0L;
 }
 
-void *saa_rstruct (struct SAA *s) {
+void *saa_rstruct (struct SAA *s) 
+{
     void *p;
 
     if (!s->rptr)
@@ -503,7 +519,8 @@ void *saa_rstruct (struct SAA *s) {
     return p;
 }
 
-void *saa_rbytes (struct SAA *s, long *len) {
+void *saa_rbytes (struct SAA *s, long *len) 
+{
     void *p;
 
     if (!s->rptr)
@@ -516,7 +533,8 @@ void *saa_rbytes (struct SAA *s, long *len) {
     return p;
 }
 
-void saa_rnbytes (struct SAA *s, void *data, long len) {
+void saa_rnbytes (struct SAA *s, void *data, long len) 
+{
     char *d = data;
 
     while (len > 0) {
@@ -541,26 +559,27 @@ void saa_rnbytes (struct SAA *s, void *data, long len) {
     }
 }
 
-void saa_fread (struct SAA *s, long posn, void *data, long len) {
+void saa_fread (struct SAA *s, long posn, void *data, long len) 
+{
     struct SAA *p;
     long pos;
     char *cdata = data;
 
-    if (!s->rptr || posn > s->rptr->start + s->rpos)
+    if (!s->rptr || posn < s->rptr->start)
        saa_rewind (s);
-    while (posn >= s->rptr->start + s->rptr->posn) {
-       s->rptr = s->rptr->next;
-       if (!s->rptr)
+    p = s->rptr;
+    while (posn >= p->start + p->posn) {
+       p = p->next;
+       if (!p)
            return;                    /* what else can we do?! */
     }
 
-    p = s->rptr;
-    pos = posn - s->rptr->start;
+    pos = posn - p->start;
     while (len) {
-       long l = s->rptr->posn - pos;
+       long l = p->posn - pos;
        if (l > len)
            l = len;
-       memcpy (cdata, s->rptr->data+pos, l);
+       memcpy (cdata, p->data+pos, l);
        len -= l;
        cdata += l;
        p = p->next;
@@ -568,28 +587,30 @@ void saa_fread (struct SAA *s, long posn, void *data, long len) {
            return;
        pos = 0L;
     }
+    s->rptr = p;
 }
 
-void saa_fwrite (struct SAA *s, long posn, void *data, long len) {
+void saa_fwrite (struct SAA *s, long posn, void *data, long len) 
+{
     struct SAA *p;
     long pos;
     char *cdata = data;
 
-    if (!s->rptr || posn > s->rptr->start + s->rpos)
+    if (!s->rptr || posn < s->rptr->start)
        saa_rewind (s);
-    while (posn >= s->rptr->start + s->rptr->posn) {
-       s->rptr = s->rptr->next;
-       if (!s->rptr)
+    p = s->rptr;
+    while (posn >= p->start + p->posn) {
+       p = p->next;
+       if (!p)
            return;                    /* what else can we do?! */
     }
 
-    p = s->rptr;
-    pos = posn - s->rptr->start;
+    pos = posn - p->start;
     while (len) {
-       long l = s->rptr->posn - pos;
+       long l = p->posn - pos;
        if (l > len)
            l = len;
-       memcpy (s->rptr->data+pos, cdata, l);
+       memcpy (p->data+pos, cdata, l);
        len -= l;
        cdata += l;
        p = p->next;
@@ -597,9 +618,11 @@ void saa_fwrite (struct SAA *s, long posn, void *data, long len) {
            return;
        pos = 0L;
     }
+    s->rptr = p;
 }
 
-void saa_fpwrite (struct SAA *s, FILE *fp) {
+void saa_fpwrite (struct SAA *s, FILE *fp) 
+{
     char *data;
     long len;
 
@@ -632,16 +655,29 @@ static char **stdscan_tempstorage = NULL;
 static int stdscan_tempsize = 0, stdscan_templen = 0;
 #define STDSCAN_TEMP_DELTA 256
 
-static void stdscan_pop(void) {
+static void stdscan_pop(void) 
+{
     nasm_free (stdscan_tempstorage[--stdscan_templen]);
 }
 
-void stdscan_reset(void) {
+void stdscan_reset(void) 
+{
     while (stdscan_templen > 0)
        stdscan_pop();
 }
 
-static char *stdscan_copy(char *p, int len) {
+/*
+ * Unimportant cleanup is done to avoid confusing people who are trying
+ * to debug real memory leaks
+ */
+void nasmlib_cleanup (void) 
+{
+    stdscan_reset();
+    nasm_free (stdscan_tempstorage);
+}
+
+static char *stdscan_copy(char *p, int len) 
+{
     char *text;
 
     text = nasm_malloc(len+1);
@@ -659,8 +695,11 @@ static char *stdscan_copy(char *p, int len) {
 }
 
 char *stdscan_bufptr = NULL;
-int stdscan (void *private_data, struct tokenval *tv) {
-    char ourcopy[256], *r, *s;
+int stdscan (void *private_data, struct tokenval *tv) 
+{
+    char ourcopy[MAX_KEYWORD+1], *r, *s;
+
+    (void) private_data;  /* Don't warn that this parameter is unused */
 
     while (isspace(*stdscan_bufptr)) stdscan_bufptr++;
     if (!*stdscan_bufptr)
@@ -682,11 +721,12 @@ int stdscan (void *private_data, struct tokenval *tv) {
        while (isidchar(*stdscan_bufptr)) stdscan_bufptr++;
        tv->t_charptr = stdscan_copy(r, stdscan_bufptr - r);
 
+       if (is_sym || stdscan_bufptr-r > MAX_KEYWORD)
+           return tv->t_type = TOKEN_ID;/* bypass all other checks */
+    
        for (s=tv->t_charptr, r=ourcopy; *s; s++)
            *r++ = tolower (*s);
        *r = '\0';
-       if (is_sym)
-           return tv->t_type = TOKEN_ID;/* bypass all other checks */
        /* right, so we have an identifier sitting in temp storage. now,
         * is it actually a register or instruction name, or what? */
        if ((tv->t_integer=bsi(ourcopy, reg_names,
@@ -743,7 +783,10 @@ int stdscan (void *private_data, struct tokenval *tv) {
             * a floating point constant
             */
            stdscan_bufptr++;
-           while (isnumchar(*stdscan_bufptr)) {
+           while (isnumchar(*stdscan_bufptr) ||
+                  ((stdscan_bufptr[-1] == 'e' || stdscan_bufptr[-1] == 'E')
+                   && (*stdscan_bufptr == '-' || *stdscan_bufptr == '+')) ) 
+           {
                stdscan_bufptr++;
            }
            tv->t_charptr = stdscan_copy(r, stdscan_bufptr - r);
@@ -759,16 +802,15 @@ int stdscan (void *private_data, struct tokenval *tv) {
     } else if (*stdscan_bufptr == '\'' ||
               *stdscan_bufptr == '"') {/* a char constant */
        char quote = *stdscan_bufptr++, *r;
+       int rn_warn;
        r = tv->t_charptr = stdscan_bufptr;
        while (*stdscan_bufptr && *stdscan_bufptr != quote) stdscan_bufptr++;
        tv->t_inttwo = stdscan_bufptr - r;      /* store full version */
        if (!*stdscan_bufptr)
            return tv->t_type = TOKEN_ERRNUM;       /* unmatched quotes */
-       tv->t_integer = 0;
-       r = stdscan_bufptr++;                  /* skip over final quote */
-       while (quote != *--r) {
-           tv->t_integer = (tv->t_integer<<8) + (unsigned char) *r;
-       }
+       stdscan_bufptr++;                       /* skip over final quote */
+       tv->t_integer = readstrnum(r, tv->t_inttwo, &rn_warn);
+       /* FIXME: rn_warn is not checked! */
        return tv->t_type = TOKEN_NUM;
     } else if (*stdscan_bufptr == ';') {  /* a comment has happened - stay */
        return tv->t_type = 0;
@@ -816,7 +858,8 @@ int stdscan (void *private_data, struct tokenval *tv) {
  * Return TRUE if the argument is a simple scalar. (Or a far-
  * absolute, which counts.)
  */
-int is_simple (expr *vect) {
+int is_simple (expr *vect) 
+{
     while (vect->type && !vect->value)
        vect++;
     if (!vect->type)
@@ -834,7 +877,8 @@ int is_simple (expr *vect) {
  * Return TRUE if the argument is a simple scalar, _NOT_ a far-
  * absolute.
  */
-int is_really_simple (expr *vect) {
+int is_really_simple (expr *vect) 
+{
     while (vect->type && !vect->value)
        vect++;
     if (!vect->type)
@@ -852,7 +896,8 @@ int is_really_simple (expr *vect) {
  * Return TRUE if the argument is relocatable (i.e. a simple
  * scalar, plus at most one segment-base, plus possibly a WRT).
  */
-int is_reloc (expr *vect) {
+int is_reloc (expr *vect) 
+{
     while (vect->type && !vect->value) /* skip initial value-0 terms */
        vect++;
     if (!vect->type)                  /* trivially return TRUE if nothing */
@@ -886,7 +931,8 @@ int is_reloc (expr *vect) {
 /*
  * Return TRUE if the argument contains an `unknown' part.
  */
-int is_unknown(expr *vect) {
+int is_unknown(expr *vect) 
+{
     while (vect->type && vect->type < EXPR_UNKNOWN)
        vect++;
     return (vect->type == EXPR_UNKNOWN);
@@ -896,7 +942,8 @@ int is_unknown(expr *vect) {
  * Return TRUE if the argument contains nothing but an `unknown'
  * part.
  */
-int is_just_unknown(expr *vect) {
+int is_just_unknown(expr *vect) 
+{
     while (vect->type && !vect->value)
        vect++;
     return (vect->type == EXPR_UNKNOWN);
@@ -906,7 +953,8 @@ int is_just_unknown(expr *vect) {
  * Return the scalar part of a relocatable vector. (Including
  * simple scalar vectors - those qualify as relocatable.)
  */
-long reloc_value (expr *vect) {
+long reloc_value (expr *vect) 
+{
     while (vect->type && !vect->value)
        vect++;
     if (!vect->type) return 0;
@@ -920,7 +968,8 @@ long reloc_value (expr *vect) {
  * Return the segment number of a relocatable vector, or NO_SEG for
  * simple scalars.
  */
-long reloc_seg (expr *vect) {
+long reloc_seg (expr *vect) 
+{
     while (vect->type && (vect->type == EXPR_WRT || !vect->value))
        vect++;
     if (vect->type == EXPR_SIMPLE) {
@@ -938,7 +987,8 @@ long reloc_seg (expr *vect) {
  * Return the WRT segment number of a relocatable vector, or NO_SEG
  * if no WRT part is present.
  */
-long reloc_wrt (expr *vect) {
+long reloc_wrt (expr *vect) 
+{
     while (vect->type && vect->type < EXPR_WRT)
        vect++;
     if (vect->type == EXPR_WRT) {
@@ -950,7 +1000,8 @@ long reloc_wrt (expr *vect) {
 /*
  * Binary search.
  */
-int bsi (char *string, char **array, int size) {
+int bsi (char *string, char **array, int size) 
+{
     int i = -1, j = size;             /* always, i < index < j */
     while (j-i >= 2) {
        int k = (i+j)/2;
@@ -964,3 +1015,88 @@ int bsi (char *string, char **array, int size) {
     }
     return -1;                        /* we haven't got it :( */
 }
+
+static char *file_name = NULL;
+static long line_number = 0;
+
+char *src_set_fname(char *newname) 
+{
+    char *oldname = file_name;
+    file_name = newname;
+    return oldname;
+}
+
+long src_set_linnum(long newline) 
+{
+    long oldline = line_number;
+    line_number = newline;
+    return oldline;
+}
+
+long src_get_linnum(void) 
+{
+    return line_number;
+}
+
+int src_get(long *xline, char **xname) 
+{
+    if (!file_name || !*xname || strcmp(*xname, file_name)) 
+    {
+       nasm_free(*xname);
+       *xname = file_name ? nasm_strdup(file_name) : NULL;
+       *xline = line_number;
+       return -2;
+    }
+    if (*xline != line_number) 
+    {
+       long tmp = line_number - *xline;
+       *xline = line_number;
+       return tmp;
+    }
+    return 0;
+}
+
+void nasm_quote(char **str) 
+{
+    int ln=strlen(*str);
+    char q=(*str)[0];
+    char *p;
+    if (ln>1 && (*str)[ln-1]==q && (q=='"' || q=='\''))
+       return;
+    q = '"';
+    if (strchr(*str,q))
+       q = '\'';
+    p = nasm_malloc(ln+3);
+    strcpy(p+1, *str);
+    nasm_free(*str);
+    p[ln+1] = p[0] = q;
+    p[ln+2] = 0;
+    *str = p;
+}
+    
+char *nasm_strcat(char *one, char *two) 
+{
+    char *rslt;
+    int l1=strlen(one);
+    rslt = nasm_malloc(l1+strlen(two)+1);
+    strcpy(rslt, one);
+    strcpy(rslt+l1, two);
+    return rslt;
+}
+
+void null_debug_routine()
+{
+}
+struct dfmt null_debug_form = {
+    "Null debug format",
+    "null",
+    null_debug_routine,
+    null_debug_routine,
+    null_debug_routine,
+    null_debug_routine,
+    null_debug_routine,
+    null_debug_routine,
+    null_debug_routine,
+};
+
+struct dfmt *null_debug_arr[2] = { &null_debug_form, NULL };
index 9168f18..d2997b1 100644 (file)
--- a/nasmlib.h
+++ b/nasmlib.h
@@ -1,4 +1,4 @@
-/* nasmlib.c   header file for nasmlib.h
+/* nasmlib.h   header file for nasmlib.c
  *
  * The Netwide Assembler is copyright (C) 1996 Simon Tatham and
  * Julian Hall. All rights reserved. The software is
@@ -51,8 +51,8 @@ char *nasm_strndup_log (char *, int, char *, size_t);
  * ANSI doesn't guarantee the presence of `stricmp' or
  * `strcasecmp'.
  */
-int nasm_stricmp (char *, char *);
-int nasm_strnicmp (char *, char *, int);
+int nasm_stricmp (const char *, const char *);
+int nasm_strnicmp (const char *, const char *, int);
 
 /*
  * Convert a string into a number, using NASM number rules. Sets
@@ -61,6 +61,14 @@ int nasm_strnicmp (char *, char *, int);
 long readnum(char *str, int *error);
 
 /*
+ * Convert a character constant into a number. Sets
+ * `*warn' to TRUE if an overflow occurs, and FALSE otherwise.
+ * str points to and length covers the middle of the string,
+ * without the quotes.
+ */
+long readstrnum(char *str, int length, int *warn);
+
+/*
  * seg_init: Initialise the segment-number allocator.
  * seg_alloc: allocate a hitherto unused segment number.
  */
@@ -108,7 +116,41 @@ void fwritelong (long data, FILE *fp);
  * chunk.
  */
 
-struct RAA;
+#define RAA_BLKSIZE 4096              /* this many longs allocated at once */
+#define RAA_LAYERSIZE 1024            /* this many _pointers_ allocated */
+
+typedef struct RAA RAA;
+typedef union RAA_UNION RAA_UNION;
+typedef struct RAA_LEAF RAA_LEAF;
+typedef struct RAA_BRANCH RAA_BRANCH;
+
+struct RAA {
+    /*
+     * Number of layers below this one to get to the real data. 0
+     * means this structure is a leaf, holding RAA_BLKSIZE real
+     * data items; 1 and above mean it's a branch, holding
+     * RAA_LAYERSIZE pointers to the next level branch or leaf
+     * structures.
+     */
+    int layers;
+    /*
+     * Number of real data items spanned by one position in the
+     * `data' array at this level. This number is 1, trivially, for
+     * a leaf (level 0): for a level 1 branch it should be
+     * RAA_BLKSIZE, and for a level 2 branch it's
+     * RAA_LAYERSIZE*RAA_BLKSIZE.
+     */
+    long stepsize;
+    union RAA_UNION {
+       struct RAA_LEAF {
+           long data[RAA_BLKSIZE];
+       } l;
+       struct RAA_BRANCH {
+           struct RAA *data[RAA_LAYERSIZE];
+       } b;
+    } u;
+};
+
 
 struct RAA *raa_init (void);
 void raa_free (struct RAA *);
@@ -125,7 +167,15 @@ struct RAA *raa_write (struct RAA *r, long posn, long value);
  * of a given size.
  */
 
-struct SAA;
+struct SAA {
+    /*
+     * members `end' and `elem_len' are only valid in first link in
+     * list; `rptr' and `rpos' are used for reading
+     */
+    struct SAA *next, *end, *rptr;
+    long elem_len, length, posn, start, rpos;
+    char *data;
+};
 
 struct SAA *saa_init (long elem_len);  /* 1 == byte */
 void saa_free (struct SAA *);
@@ -169,4 +219,23 @@ long reloc_wrt(expr *);
  */
 int bsi (char *string, char **array, int size);
 
+
+char *src_set_fname(char *newname);
+long src_set_linnum(long newline);
+long src_get_linnum(void);
+/*
+ * src_get may be used if you simply want to know the source file and line.
+ * It is also used if you maintain private status about the source location
+ * It return 0 if the information was the same as the last time you
+ * checked, -1 if the name changed and (new-old) if just the line changed.
+ */
+int src_get(long *xline, char **xname);
+
+void nasm_quote(char **str);
+char *nasm_strcat(char *one, char *two);
+void nasmlib_cleanup(void);
+
+void null_debug_routine();
+extern struct dfmt null_debug_form;
+extern struct dfmt *null_debug_arr[2];
 #endif
index 90639e9..a07a278 100644 (file)
--- a/ndisasm.c
+++ b/ndisasm.c
@@ -33,7 +33,8 @@ static const char *help =
 static void output_ins (unsigned long, unsigned char *, int, char *);
 static void skip (unsigned long dist, FILE *fp);
 
-int main(int argc, char **argv) {
+int main(int argc, char **argv) 
+{
     unsigned char buffer[INSN_MAX * 2], *p, *q;
     char outbuf[256];
     char *pname = *argv;
@@ -52,7 +53,7 @@ int main(int argc, char **argv) {
 
     while (--argc) {
        char *v, *vv, *p = *++argv;
-       if (*p == '-') {
+       if (*p == '-' && p[1]) {
            p++;
            while (*p) switch (tolower(*p)) {
              case 'a':                /* auto or intelligent sync */
@@ -170,12 +171,16 @@ int main(int argc, char **argv) {
        return 0;
     }
 
-    fp = fopen(filename, "rb");
-    if (!fp) {
-       fprintf(stderr, "%s: unable to open `%s': %s\n",
-               pname, filename, strerror(errno));
-       return 1;
-    }
+    if (strcmp(filename, "-")) {
+       fp = fopen(filename, "rb");
+       if (!fp) {
+           fprintf(stderr, "%s: unable to open `%s': %s\n",
+                   pname, filename, strerror(errno));
+           return 1;
+       }
+    } else
+       fp = stdin;
+
     if (initskip > 0)
        skip (initskip, fp);
 
@@ -191,9 +196,12 @@ int main(int argc, char **argv) {
        unsigned long to_read = buffer+sizeof(buffer)-p;
        if (to_read > nextsync-offset-(p-q))
            to_read = nextsync-offset-(p-q);
-       lenread = fread (p, 1, to_read, fp);
-       if (lenread == 0)
-           eof = TRUE;                /* help along systems with bad feof */
+       if (to_read) {
+           lenread = fread (p, 1, to_read, fp);
+           if (lenread == 0)
+               eof = TRUE;            /* help along systems with bad feof */
+       } else
+           lenread = 0;
        p += lenread;
        if (offset == nextsync) {
            if (synclen) {
@@ -222,12 +230,16 @@ int main(int argc, char **argv) {
            q = buffer;
        }
     } while (lenread > 0 || !(eof || feof(fp)));
-    fclose (fp);
+
+    if (fp != stdin)
+       fclose (fp);
+
     return 0;
 }
 
 static void output_ins (unsigned long offset, unsigned char *data,
-                       int datalen, char *insn) {
+                       int datalen, char *insn) 
+{
     int bytes;
     printf("%08lX  ", offset);
 
@@ -256,7 +268,8 @@ static void output_ins (unsigned long offset, unsigned char *data,
  * Skip a certain amount of data in a file, either by seeking if
  * possible, or if that fails then by reading and discarding.
  */
-static void skip (unsigned long dist, FILE *fp) {
+static void skip (unsigned long dist, FILE *fp) 
+{
     char buffer[256];                 /* should fit on most stacks :-) */
 
     /*
index e4c7610..b82109a 100644 (file)
--- a/outaout.c
+++ b/outaout.c
@@ -116,7 +116,8 @@ static long aout_gotpc_sect, aout_gotoff_sect;
 static long aout_got_sect, aout_plt_sect;
 static long aout_sym_sect;
 
-static void aoutg_init(FILE *fp, efunc errfunc, ldfunc ldef, evalfunc eval) {
+static void aoutg_init(FILE *fp, efunc errfunc, ldfunc ldef, evalfunc eval) 
+{
     aoutfp = fp;
     error = errfunc;
     evaluate = eval;
@@ -140,7 +141,8 @@ static void aoutg_init(FILE *fp, efunc errfunc, ldfunc ldef, evalfunc eval) {
 
 #ifdef OF_AOUT
 
-static void aout_init(FILE *fp, efunc errfunc, ldfunc ldef, evalfunc eval) {
+static void aout_init(FILE *fp, efunc errfunc, ldfunc ldef, evalfunc eval) 
+{
     bsd = FALSE;
     aoutg_init (fp, errfunc, ldef, eval);
 
@@ -154,7 +156,8 @@ static void aout_init(FILE *fp, efunc errfunc, ldfunc ldef, evalfunc eval) {
 
 extern struct ofmt of_aoutb;
 
-static void aoutb_init(FILE *fp, efunc errfunc, ldfunc ldef, evalfunc eval) {
+static void aoutb_init(FILE *fp, efunc errfunc, ldfunc ldef, evalfunc eval) 
+{
     bsd = TRUE;
     aoutg_init (fp, errfunc, ldef, eval);
 
@@ -174,9 +177,12 @@ static void aoutb_init(FILE *fp, efunc errfunc, ldfunc ldef, evalfunc eval) {
 
 #endif
 
-static void aout_cleanup(void) {
+static void aout_cleanup(int debuginfo) 
+{
     struct Reloc *r;
 
+    (void) debuginfo;
+
     aout_pad_sections();
     aout_fixup_relocs(&stext);
     aout_fixup_relocs(&sdata);
@@ -199,7 +205,8 @@ static void aout_cleanup(void) {
     saa_free (strs);
 }
 
-static long aout_section_names (char *name, int pass, int *bits) {
+static long aout_section_names (char *name, int pass, int *bits) 
+{
     /*
      * Default to 32 bits.
      */
@@ -220,7 +227,8 @@ static long aout_section_names (char *name, int pass, int *bits) {
 }
 
 static void aout_deflabel (char *name, long segment, long offset,
-                          int is_global, char *special) {
+                          int is_global, char *special) 
+{
     int pos = strslen+4;
     struct Symbol *sym;
     int special_used = FALSE;
@@ -384,7 +392,8 @@ static void aout_deflabel (char *name, long segment, long offset,
 }
 
 static void aout_add_reloc (struct Section *sect, long segment,
-                           int reltype, int bytes) {
+                           int reltype, int bytes) 
+{
     struct Reloc *r;
 
     r = *sect->tail = nasm_malloc(sizeof(struct Reloc));
@@ -429,7 +438,8 @@ static void aout_add_reloc (struct Section *sect, long segment,
  */
 static long aout_add_gsym_reloc (struct Section *sect,
                                 long segment, long offset,
-                                int type, int bytes, int exact) {
+                                int type, int bytes, int exact) 
+{
     struct Symbol *sym, *sm, *shead;
     struct Reloc *r;
 
@@ -500,7 +510,8 @@ static long aout_add_gsym_reloc (struct Section *sect,
  * offset from the `asym' symbol rather than the section.
  */
 static long aout_add_gotoff_reloc (struct Section *sect, long segment,
-                                  long offset, int bytes) {
+                                  long offset, int bytes) 
+{
     struct Reloc *r;
     struct Symbol *asym;
 
@@ -534,7 +545,8 @@ static long aout_add_gotoff_reloc (struct Section *sect, long segment,
 }
 
 static void aout_out (long segto, void *data, unsigned long type,
-                     long segment, long wrt) {
+                     long segment, long wrt) 
+{
     struct Section *s;
     long realbytes = type & OUT_SIZMASK;
     long addr;
@@ -695,7 +707,8 @@ static void aout_out (long segto, void *data, unsigned long type,
     }
 }
 
-static void aout_pad_sections(void) {
+static void aout_pad_sections(void) 
+{
     static unsigned char pad[] = { 0x90, 0x90, 0x90, 0x90 };
     /*
      * Pad each of the text and data sections with NOPs until their
@@ -716,7 +729,8 @@ static void aout_pad_sections(void) {
  * the relocation table, _after_ the final size of each section is
  * known, and fix up the relocations pointed to.
  */
-static void aout_fixup_relocs(struct Section *sect) {
+static void aout_fixup_relocs(struct Section *sect) 
+{
     struct Reloc *r;
 
     saa_rewind (sect->data);
@@ -748,7 +762,8 @@ static void aout_fixup_relocs(struct Section *sect) {
     }
 }
 
-static void aout_write(void) {
+static void aout_write(void) 
+{
     /*
      * Emit the a.out header.
      */
@@ -786,7 +801,8 @@ static void aout_write(void) {
     saa_fpwrite (strs, aoutfp);
 }
 
-static void aout_write_relocs (struct Reloc *r) {
+static void aout_write_relocs (struct Reloc *r) 
+{
     while (r) {
        unsigned long word2;
 
@@ -805,7 +821,8 @@ static void aout_write_relocs (struct Reloc *r) {
     }
 }
 
-static void aout_write_syms (void) {
+static void aout_write_syms (void) 
+{
     int i;
 
     saa_rewind (syms);
@@ -835,28 +852,38 @@ static void aout_write_syms (void) {
 }
 
 static void aout_sect_write (struct Section *sect,
-                            unsigned char *data, unsigned long len) {
+                            unsigned char *data, unsigned long len) 
+{
     saa_wbytes (sect->data, data, len);
     sect->len += len;
 }
 
-static long aout_segbase (long segment) {
+static long aout_segbase (long segment) 
+{
     return segment;
 }
 
-static int aout_directive (char *directive, char *value, int pass) {
+static int aout_directive (char *directive, char *value, int pass) 
+{
     return 0;
 }
 
-static void aout_filename (char *inname, char *outname, efunc error) {
+static void aout_filename (char *inname, char *outname, efunc error) 
+{
     standard_extension (inname, outname, ".o", error);
 }
 
 static char *aout_stdmac[] = {
     "%define __SECT__ [section .text]",
+    "%macro __NASM_CDecl__ 1",
+    "%endmacro",
     NULL
 };
 
+static int aout_set_info(enum geninfo type, char **val)
+{
+    return 0;
+}
 #endif /* OF_AOUT || OF_AOUTB */
 
 #ifdef OF_AOUT
@@ -864,8 +891,12 @@ static char *aout_stdmac[] = {
 struct ofmt of_aout = {
     "Linux a.out object files",
     "aout",
+    NULL,
+    null_debug_arr,
+    &null_debug_form,
     aout_stdmac,
     aout_init,
+    aout_set_info,
     aout_out,
     aout_deflabel,
     aout_section_names,
@@ -882,8 +913,12 @@ struct ofmt of_aout = {
 struct ofmt of_aoutb = {
     "NetBSD/FreeBSD a.out object files",
     "aoutb",
+    NULL,
+    null_debug_arr,
+    &null_debug_form,
     aout_stdmac,
     aoutb_init,
+    aout_set_info,
     aout_out,
     aout_deflabel,
     aout_section_names,
index f214d86..eb02186 100644 (file)
--- a/outas86.c
+++ b/outas86.c
@@ -80,7 +80,8 @@ static void as86_write_section (struct Section *, int);
 static int as86_add_string (char *name);
 static void as86_sect_write(struct Section *, unsigned char *, unsigned long);
 
-static void as86_init(FILE *fp, efunc errfunc, ldfunc ldef, evalfunc eval) {
+static void as86_init(FILE *fp, efunc errfunc, ldfunc ldef, evalfunc eval) 
+{
     as86fp = fp;
     error = errfunc;
     (void) ldef;                      /* placate optimisers */
@@ -105,9 +106,12 @@ static void as86_init(FILE *fp, efunc errfunc, ldfunc ldef, evalfunc eval) {
     as86_add_string (as86_module);
 }
 
-static void as86_cleanup(void) {
+static void as86_cleanup(int debuginfo) 
+{
     struct Piece *p;
 
+    (void) debuginfo;
+
     as86_write();
     fclose (as86fp);
     saa_free (stext.data);
@@ -127,7 +131,8 @@ static void as86_cleanup(void) {
     saa_free (strs);
 }
 
-static long as86_section_names (char *name, int pass, int *bits) {
+static long as86_section_names (char *name, int pass, int *bits) 
+{
     /*
      * Default is 16 bits.
      */
@@ -147,7 +152,8 @@ static long as86_section_names (char *name, int pass, int *bits) {
        return NO_SEG;
 }
 
-static int as86_add_string (char *name) {
+static int as86_add_string (char *name) 
+{
     int pos = strslen;
     int length = strlen(name);
 
@@ -158,7 +164,8 @@ static int as86_add_string (char *name) {
 }
 
 static void as86_deflabel (char *name, long segment, long offset,
-                          int is_global, char *special) {
+                          int is_global, char *special) 
+{
     struct Symbol *sym;
 
     if (special)
@@ -207,7 +214,8 @@ static void as86_deflabel (char *name, long segment, long offset,
 }
 
 static void as86_add_piece (struct Section *sect, int type, long offset,
-                           long segment, long bytes, int relative) {
+                           long segment, long bytes, int relative) 
+{
     struct Piece *p;
 
     sect->len += bytes;
@@ -237,7 +245,8 @@ static void as86_add_piece (struct Section *sect, int type, long offset,
 }
 
 static void as86_out (long segto, void *data, unsigned long type,
-                     long segment, long wrt) {
+                     long segment, long wrt) 
+{
     struct Section *s;
     long realbytes = type & OUT_SIZMASK;
     long offset;
@@ -339,7 +348,8 @@ static void as86_out (long segto, void *data, unsigned long type,
     }
 }
 
-static void as86_write(void) {
+static void as86_write(void) 
+{
     int i;
     long symlen, seglen, segsize;
 
@@ -430,7 +440,8 @@ static void as86_write(void) {
     fputc (0, as86fp);                /* termination */
 }
 
-static void as86_set_rsize (int size) {
+static void as86_set_rsize (int size) 
+{
     if (as86_reloc_size != size) {
        switch (as86_reloc_size = size) {
          case 1: fputc (0x01, as86fp); break;
@@ -441,7 +452,8 @@ static void as86_set_rsize (int size) {
     }
 }
 
-static void as86_write_section (struct Section *sect, int index) {
+static void as86_write_section (struct Section *sect, int index) 
+{
     struct Piece *p;
     unsigned long s;
     long length;
@@ -512,20 +524,24 @@ static void as86_write_section (struct Section *sect, int index) {
 }
 
 static void as86_sect_write (struct Section *sect,
-                            unsigned char *data, unsigned long len) {
+                            unsigned char *data, unsigned long len) 
+{
     saa_wbytes (sect->data, data, len);
     sect->datalen += len;
 }
 
-static long as86_segbase (long segment) {
+static long as86_segbase (long segment) 
+{
     return segment;
 }
 
-static int as86_directive (char *directive, char *value, int pass) {
+static int as86_directive (char *directive, char *value, int pass) 
+{
     return 0;
 }
 
-static void as86_filename (char *inname, char *outname, efunc error) {
+static void as86_filename (char *inname, char *outname, efunc error) 
+{
     char *p;
 
     if ( (p = strrchr (inname, '.')) != NULL) {
@@ -539,16 +555,30 @@ static void as86_filename (char *inname, char *outname, efunc error) {
 
 static char *as86_stdmac[] = {
     "%define __SECT__ [section .text]",
+    "%macro __NASM_CDecl__ 1",
+    "%endmacro",
     NULL
 };
 
+static int as86_set_info(enum geninfo type, char **val)
+{
+    return 0;
+}
+void as86_linenumber (char *name, long segment, long offset, int is_main,
+                    int lineno)
+{
+}
 struct ofmt of_as86 = {
     "Linux as86 (bin86 version 0.3) object files",
     "as86",
+    NULL,
+    null_debug_arr,
+    &null_debug_form,
     as86_stdmac,
     as86_init,
+    as86_set_info,
     as86_out,
-    as86_deflabel,
+    as86_deflabel, 
     as86_section_names,
     as86_segbase,
     as86_directive,
index 3540739..a3289cf 100644 (file)
--- a/outbin.c
+++ b/outbin.c
@@ -42,7 +42,8 @@ static long data_align, bss_align;
 static long start_point;
 
 static void add_reloc (struct Section *s, long bytes, long secref,
-                      long secrel) {
+                      long secrel) 
+{
     struct Reloc *r;
 
     r = *reloctail = nasm_malloc(sizeof(struct Reloc));
@@ -55,9 +56,12 @@ static void add_reloc (struct Section *s, long bytes, long secref,
     r->target = s;
 }
 
-static void bin_init (FILE *afp, efunc errfunc, ldfunc ldef, evalfunc eval) {
+static void bin_init (FILE *afp, efunc errfunc, ldfunc ldef, evalfunc eval) 
+{
     fp = afp;
 
+    (void) eval;   /* Don't warn that this parameter is unused */
+
     error = errfunc;
     (void) ldef;                      /* placate optimisers */
 
@@ -74,10 +78,13 @@ static void bin_init (FILE *afp, efunc errfunc, ldfunc ldef, evalfunc eval) {
     data_align = bss_align = 4;
 }
 
-static void bin_cleanup (void) {
+static void bin_cleanup (int debuginfo) 
+{
     struct Reloc *r;
     long datapos, datagap, bsspos;
 
+    (void) debuginfo;
+
     datapos = start_point + textsect.length;
     datapos = (datapos + data_align-1) & ~(data_align-1);
     datagap = datapos - (start_point + textsect.length);
@@ -87,7 +94,8 @@ static void bin_cleanup (void) {
     saa_rewind (textsect.contents);
     saa_rewind (datasect.contents);
 
-    for (r = relocs; r; r = r->next) {
+    for (r = relocs; r; r = r->next) 
+    {
        unsigned char *p, *q, mydata[4];
        long l;
 
@@ -141,7 +149,8 @@ static void bin_cleanup (void) {
 }
 
 static void bin_out (long segto, void *data, unsigned long type,
-                    long segment, long wrt) {
+                    long segment, long wrt) 
+{
     unsigned char *p, mydata[4];
     struct Section *s;
     long realbytes;
@@ -221,8 +230,10 @@ static void bin_out (long segto, void *data, unsigned long type,
            s->length += type;
        } else
            bsslen += type;
-    } else if ((type & OUT_TYPMASK) == OUT_REL2ADR ||
-              (type & OUT_TYPMASK) == OUT_REL4ADR) {
+    } 
+    else if ((type & OUT_TYPMASK) == OUT_REL2ADR ||
+            (type & OUT_TYPMASK) == OUT_REL4ADR) 
+    {
        realbytes = ((type & OUT_TYPMASK) == OUT_REL4ADR ? 4 : 2);
        if (segment != NO_SEG &&
            segment != textsect.index &&
@@ -251,7 +262,11 @@ static void bin_out (long segto, void *data, unsigned long type,
 }
 
 static void bin_deflabel (char *name, long segment, long offset,
-                         int is_global, char *special) {
+                         int is_global, char *special) 
+{
+
+    (void) segment;   /* Don't warn that this parameter is unused */
+    (void) offset;    /* Don't warn that this parameter is unused */
 
     if (special)
        error (ERR_NONFATAL, "binary format does not support any"
@@ -268,11 +283,14 @@ static void bin_deflabel (char *name, long segment, long offset,
     }
 }
 
-static long bin_secname (char *name, int pass, int *bits) {
+static long bin_secname (char *name, int pass, int *bits) 
+{
     int sec_index;
     long *sec_align;
     char *p;
 
+    (void) pass;   /* Don't warn that this parameter is unused */
+
     /*
      * Default is 16 bits.
      */
@@ -318,13 +336,17 @@ static long bin_secname (char *name, int pass, int *bits) {
     return sec_index;
 }
 
-static long bin_segbase (long segment) {
+static long bin_segbase (long segment) 
+{
     return segment;
 }
 
-static int bin_directive (char *directive, char *value, int pass) {
+static int bin_directive (char *directive, char *value, int pass) 
+{
     int rn_error;
 
+    (void) pass;   /* Don't warn that this parameter is unused */
+
     if (!strcmp(directive, "org")) {
        start_point = readnum (value, &rn_error);
        if (rn_error)
@@ -334,7 +356,8 @@ static int bin_directive (char *directive, char *value, int pass) {
        return 0;
 }
 
-static void bin_filename (char *inname, char *outname, efunc error) {
+static void bin_filename (char *inname, char *outname, efunc error) 
+{
     standard_extension (inname, outname, "", error);
 }
 
@@ -343,14 +366,24 @@ static char *bin_stdmac[] = {
     "%imacro org 1+.nolist",
     "[org %1]",
     "%endmacro",
+    "%macro __NASM_CDecl__ 1",
+    "%endmacro",
     NULL
 };
 
+static int bin_set_info(enum geninfo type, char **val)
+{
+    return 0;
+}
 struct ofmt of_bin = {
     "flat-form binary files (e.g. DOS .COM, .SYS)",
     "bin",
+    NULL,
+    null_debug_arr,
+    &null_debug_form,
     bin_stdmac,
     bin_init,
+    bin_set_info,
     bin_out,
     bin_deflabel,
     bin_secname,
index 09e886c..f546a8e 100644 (file)
--- a/outcoff.c
+++ b/outcoff.c
@@ -127,21 +127,24 @@ static void coff_section_header (char *, long, long, long, long, int, long);
 static void coff_write_relocs (struct Section *);
 static void coff_write_symbols (void);
 
-static void coff_win32_init(FILE *fp, efunc errfunc,
-                           ldfunc ldef, evalfunc eval) {
+static void coff_win32_init(FILE *fp,  efunc errfunc,
+                           ldfunc ldef, evalfunc eval) 
+{
     win32 = TRUE;
     (void) ldef;                      /* placate optimisers */
     coff_gen_init(fp, errfunc);
 }
 
-static void coff_std_init(FILE *fp, efunc errfunc,
-                         ldfunc ldef, evalfunc eval) {
+static void coff_std_init(FILE *fp, efunc errfunc, ldfunc ldef, evalfunc eval) 
+{
     win32 = FALSE;
     (void) ldef;                      /* placate optimisers */
     coff_gen_init(fp, errfunc);
 }
 
-static void coff_gen_init(FILE *fp, efunc errfunc) {
+static void coff_gen_init(FILE *fp, efunc errfunc) 
+{
+
     coffp = fp;
     error = errfunc;
     sects = NULL;
@@ -155,10 +158,13 @@ static void coff_gen_init(FILE *fp, efunc errfunc) {
     def_seg = seg_alloc();
 }
 
-static void coff_cleanup(void) {
+static void coff_cleanup(int debuginfo) 
+{
     struct Reloc *r;
     int i;
 
+    (void) debuginfo;
+
     coff_write();
     fclose (coffp);
     for (i=0; i<nsects; i++) {
@@ -169,6 +175,7 @@ static void coff_cleanup(void) {
            sects[i]->head = sects[i]->head->next;
            nasm_free (r);
        }
+       nasm_free (sects[i]);
     }
     nasm_free (sects);
     saa_free (syms);
@@ -177,7 +184,8 @@ static void coff_cleanup(void) {
     saa_free (strs);
 }
 
-static int coff_make_section (char *name, unsigned long flags) {
+static int coff_make_section (char *name, unsigned long flags) 
+{
     struct Section *s;
 
     s = nasm_malloc (sizeof(*s));
@@ -205,7 +213,8 @@ static int coff_make_section (char *name, unsigned long flags) {
     return nsects-1;
 }
 
-static long coff_section_names (char *name, int pass, int *bits) {
+static long coff_section_names (char *name, int pass, int *bits) 
+{
     char *p;
     unsigned long flags, align_and = ~0L, align_or = 0L;
     int i;
@@ -225,7 +234,7 @@ static long coff_section_names (char *name, int pass, int *bits) {
     if (strlen(name) > 8) {
        error (ERR_WARNING, "COFF section names limited to 8 characters:"
               " truncating");
-       p[8] = '\0';
+       name[8] = '\0';
     }
     flags = 0;
 
@@ -306,7 +315,8 @@ static long coff_section_names (char *name, int pass, int *bits) {
 }
 
 static void coff_deflabel (char *name, long segment, long offset,
-                          int is_global, char *special) {
+                          int is_global, char *special) 
+{
     int pos = strslen+4;
     struct Symbol *sym;
 
@@ -363,7 +373,8 @@ static void coff_deflabel (char *name, long segment, long offset,
 }
 
 static long coff_add_reloc (struct Section *sect, long segment,
-                           int relative) {
+                           int relative) 
+{
     struct Reloc *r;
 
     r = *sect->tail = nasm_malloc(sizeof(struct Reloc));
@@ -399,7 +410,8 @@ static long coff_add_reloc (struct Section *sect, long segment,
 }
 
 static void coff_out (long segto, void *data, unsigned long type,
-                     long segment, long wrt) {
+                     long segment, long wrt) 
+{
     struct Section *s;
     long realbytes = type & OUT_SIZMASK;
     unsigned char mydata[4], *p;
@@ -506,16 +518,19 @@ static void coff_out (long segto, void *data, unsigned long type,
 }
 
 static void coff_sect_write (struct Section *sect,
-                            unsigned char *data, unsigned long len) {
+                            unsigned char *data, unsigned long len) 
+{
     saa_wbytes (sect->data, data, len);
     sect->len += len;
 }
 
-static int coff_directives (char *directive, char *value, int pass) {
+static int coff_directives (char *directive, char *value, int pass) 
+{
     return 0;
 }
 
-static void coff_write (void) {
+static void coff_write (void) 
+{
     long pos, sympos, vsize;
     int i;
 
@@ -579,7 +594,8 @@ static void coff_write (void) {
 
 static void coff_section_header (char *name, long vsize,
                                 long datalen, long datapos,
-                                long relpos, int nrelocs, long flags) {
+                                long relpos, int nrelocs, long flags) 
+{
     char padname[8];
 
     memset (padname, 0, 8);
@@ -596,7 +612,8 @@ static void coff_section_header (char *name, long vsize,
     fwritelong (flags, coffp);
 }
 
-static void coff_write_relocs (struct Section *s) {
+static void coff_write_relocs (struct Section *s) 
+{
     struct Reloc *r;
 
     for (r = s->head; r; r = r->next) {
@@ -615,7 +632,8 @@ static void coff_write_relocs (struct Section *s) {
 }
 
 static void coff_symbol (char *name, long strpos, long value,
-                        int section, int type, int aux) {
+                        int section, int type, int aux) 
+{
     char padname[8];
 
     if (name) {
@@ -633,7 +651,8 @@ static void coff_symbol (char *name, long strpos, long value,
     fputc (aux, coffp);
 }
 
-static void coff_write_symbols (void) {
+static void coff_write_symbols (void) 
+{
     char filename[18];
     int i;
 
@@ -674,34 +693,47 @@ static void coff_write_symbols (void) {
     }
 }
 
-static long coff_segbase (long segment) {
+static long coff_segbase (long segment) 
+{
     return segment;
 }
 
-static void coff_std_filename (char *inname, char *outname, efunc error) {
+static void coff_std_filename (char *inname, char *outname, efunc error) 
+{
     strcpy(coff_infile, inname);
     standard_extension (inname, outname, ".o", error);
 }
 
-static void coff_win32_filename (char *inname, char *outname, efunc error) {
+static void coff_win32_filename (char *inname, char *outname, efunc error) 
+{
     strcpy(coff_infile, inname);
     standard_extension (inname, outname, ".obj", error);
 }
 
-#endif /* defined(OF_COFF) || defined(OF_WIN32) */
-
 static char *coff_stdmac[] = {
     "%define __SECT__ [section .text]",
+    "%macro __NASM_CDecl__ 1",
+    "%endmacro",
     NULL
 };
 
+static int coff_set_info(enum geninfo type, char **val)
+{
+    return 0;
+}
+#endif /* defined(OF_COFF) || defined(OF_WIN32) */
+
 #ifdef OF_COFF
 
 struct ofmt of_coff = {
     "COFF (i386) object files (e.g. DJGPP for DOS)",
     "coff",
+    NULL,
+    null_debug_arr,
+    &null_debug_form,
     coff_stdmac,
     coff_std_init,
+    coff_set_info,
     coff_out,
     coff_deflabel,
     coff_section_names,
@@ -718,8 +750,12 @@ struct ofmt of_coff = {
 struct ofmt of_win32 = {
     "Microsoft Win32 (i386) object files",
     "win32",
+    NULL,
+    null_debug_arr,
+    &null_debug_form,
     coff_stdmac,
     coff_win32_init,
+    coff_set_info,
     coff_out,
     coff_deflabel,
     coff_section_names,
index b3d23a0..723e372 100644 (file)
--- a/outdbg.c
+++ b/outdbg.c
@@ -27,17 +27,24 @@ struct Section {
 FILE *dbgf;
 efunc dbgef;
 
+struct ofmt of_dbg;
 static void dbg_init(FILE *fp, efunc errfunc, ldfunc ldef, evalfunc eval)
 {
+    (void) eval;
+
     dbgf = fp;
     dbgef = errfunc;
     dbgsect = NULL;
     (void) ldef;
     fprintf(fp,"NASM Output format debug dump\n");
+    of_dbg.current_dfmt->init(&of_dbg,0,fp,errfunc);
+    
 }
 
-static void dbg_cleanup(void)
+static void dbg_cleanup(int debuginfo)
 {
+    (void) debuginfo;
+    of_dbg.current_dfmt->cleanup();
     while (dbgsect) {
        struct Section *tmp = dbgsect;
        dbgsect = dbgsect->next;
@@ -84,7 +91,8 @@ static long dbg_section_names (char *name, int pass, int *bits)
 }
 
 static void dbg_deflabel (char *name, long segment, long offset,
-                         int is_global, char *special) {
+                         int is_global, char *special) 
+{
     fprintf(dbgf,"deflabel %s := %08lx:%08lx %s (%d)%s%s\n",
            name, segment, offset,
            is_global == 2 ? "common" : is_global ? "global" : "local",
@@ -93,7 +101,8 @@ static void dbg_deflabel (char *name, long segment, long offset,
 }
 
 static void dbg_out (long segto, void *data, unsigned long type,
-                    long segment, long wrt) {
+                    long segment, long wrt) 
+{
     long realbytes = type & OUT_SIZMASK;
     long ldata;
     int id;
@@ -135,25 +144,99 @@ static void dbg_out (long segto, void *data, unsigned long type,
     }
 }
 
-static long dbg_segbase(long segment) {
+static long dbg_segbase(long segment) 
+{
     return segment;
 }
 
-static int dbg_directive (char *directive, char *value, int pass) {
+static int dbg_directive (char *directive, char *value, int pass) 
+{
     fprintf(dbgf, "directive [%s] value [%s] (pass %d)\n",
            directive, value, pass);
     return 1;
 }
 
-static void dbg_filename (char *inname, char *outname, efunc error) {
+static void dbg_filename (char *inname, char *outname, efunc error) 
+{
     standard_extension (inname, outname, ".dbg", error);
 }
 
+static int dbg_set_info(enum geninfo type, char **val)
+{
+    (void) type;
+    (void) val;
+    return 0;
+}
+char *types[] = { 
+       "unknown", "label", "byte","word","dword","float","qword","tbyte" 
+};
+void dbgdbg_init(struct ofmt * of, void * id, FILE * fp, efunc error)
+{
+    (void) of;
+    (void) id;
+    (void) fp;
+    (void) error;
+    fprintf(fp,"   With debug info\n");
+}
+static void dbgdbg_cleanup(void)
+{
+}
+
+static void dbgdbg_linnum (const char *lnfname, long lineno, long segto)
+{
+    fprintf(dbgf,"dbglinenum %s(%ld) := %08lx\n",
+       lnfname,lineno,segto);
+}
+static void dbgdbg_deflabel (char *name, long segment,
+                         long offset, int is_global, char *special) 
+{
+    fprintf(dbgf,"dbglabel %s := %08lx:%08lx %s (%d)%s%s\n",
+           name,
+            segment, offset,
+           is_global == 2 ? "common" : is_global ? "global" : "local",
+           is_global,
+           special ? ": " : "", special);
+}
+static void dbgdbg_define(const char *type, const char *params)
+{
+    fprintf(dbgf,"dbgdirective [%s] value [%s]\n",type, params);
+}
+static void dbgdbg_output (int output_type, void *param)
+{
+    (void) output_type;
+    (void) param;
+}
+static void dbgdbg_typevalue(long type)
+{
+       fprintf(dbgf,"new type: %s(%lX)\n",
+           types[TYM_TYPE(type) >> 3], TYM_ELEMENTS(type) );
+}
+static struct dfmt debug_debug_form = {
+    "Trace of all info passed to debug stage",
+    "debug",
+    dbgdbg_init,
+    dbgdbg_linnum,
+    dbgdbg_deflabel,
+    dbgdbg_define,
+    dbgdbg_typevalue,
+    dbgdbg_output,
+    dbgdbg_cleanup,
+};
+
+static struct dfmt *debug_debug_arr[3] = {
+       &debug_debug_form,
+       &null_debug_form,
+       NULL
+};
 struct ofmt of_dbg = {
     "Trace of all info passed to output stage",
     "dbg",
     NULL,
+    debug_debug_arr,
+    &null_debug_form,
+    NULL,
     dbg_init,
+    dbg_set_info,
     dbg_out,
     dbg_deflabel,
     dbg_section_names,
index 6f6c1be..0b77c01 100644 (file)
--- a/outelf.c
+++ b/outelf.c
@@ -117,7 +117,7 @@ static struct ELF_SECTDATA {
     void *data;
     long len;
     int is_saa;
-} elf_sects[ELF_MAX_SECTIONS];
+} *elf_sects;
 static int elf_nsect;
 static long elf_foffs;
 
@@ -139,7 +139,8 @@ static long elf_gotpc_sect, elf_gotoff_sect;
 static long elf_got_sect, elf_plt_sect;
 static long elf_sym_sect;
 
-static void elf_init(FILE *fp, efunc errfunc, ldfunc ldef, evalfunc eval) {
+static void elf_init(FILE *fp, efunc errfunc, ldfunc ldef, evalfunc eval) 
+{
     elffp = fp;
     error = errfunc;
     evaluate = eval;
@@ -173,10 +174,13 @@ static void elf_init(FILE *fp, efunc errfunc, ldfunc ldef, evalfunc eval) {
     def_seg = seg_alloc();
 }
 
-static void elf_cleanup(void) {
+static void elf_cleanup(int debuginfo) 
+{
     struct Reloc *r;
     int i;
 
+    (void) debuginfo;
+
     elf_write();
     fclose (elffp);
     for (i=0; i<nsects; i++) {
@@ -196,7 +200,8 @@ static void elf_cleanup(void) {
     saa_free (strs);
 }
 
-static void add_sectname (char *firsthalf, char *secondhalf) {
+static void add_sectname (char *firsthalf, char *secondhalf) 
+{
     int len = strlen(firsthalf)+strlen(secondhalf);
     while (shstrtablen + len + 1 > shstrtabsize)
        shstrtab = nasm_realloc (shstrtab, (shstrtabsize += SHSTR_DELTA));
@@ -205,7 +210,8 @@ static void add_sectname (char *firsthalf, char *secondhalf) {
     shstrtablen += len+1;
 }
 
-static int elf_make_section (char *name, int type, int flags, int align) {
+static int elf_make_section (char *name, int type, int flags, int align) 
+{
     struct Section *s;
 
     s = nasm_malloc (sizeof(*s));
@@ -235,18 +241,18 @@ static int elf_make_section (char *name, int type, int flags, int align) {
     return nsects-1;
 }
 
-static long elf_section_names (char *name, int pass, int *bits) {
+static long elf_section_names (char *name, int pass, int *bits) 
+{
     char *p;
     int flags_and, flags_or, type, align, i;
 
     /*
      * Default is 32 bits.
      */
-    if (!name)
+    if (!name) {
        *bits = 32;
-
-    if (!name)
        return def_seg;
+    }
 
     p = name;
     while (*p && !isspace(*p)) p++;
@@ -334,7 +340,8 @@ static long elf_section_names (char *name, int pass, int *bits) {
 }
 
 static void elf_deflabel (char *name, long segment, long offset,
-                          int is_global, char *special) {
+                          int is_global, char *special) 
+{
     int pos = strslen;
     struct Symbol *sym;
     int special_used = FALSE;
@@ -439,9 +446,29 @@ static void elf_deflabel (char *name, long segment, long offset,
        sym->value = (sym->section == SHN_UNDEF ? 0 : offset);
 
     if (sym->type == SYM_GLOBAL) {
+       /*
+        * There's a problem here that needs fixing. 
+        * If sym->section == SHN_ABS, then the first line of the
+        * else section causes a core dump, because its a reference
+        * beyond the end of the section array.
+        * This behaviour is exhibited by this code:
+        *     GLOBAL crash_nasm
+        *     crash_nasm equ 0
+        *
+        * I'm not sure how to procede, because I haven't got the
+        * first clue about how ELF works, so I don't know what to
+        * do with it. Furthermore, I'm not sure what the rest of this
+        * section of code does. Help?
+        *
+        * For now, I'll see if doing absolutely nothing with it will
+        * work...
+        */
        if (sym->section == SHN_UNDEF || sym->section == SHN_COMMON)
+       {
            bsym = raa_write (bsym, segment, nglobs);
-       else {
+       }
+       else if (sym->section != SHN_ABS) 
+       {
            /*
             * This is a global symbol; so we must add it to the linked
             * list of global symbols in its section. We'll push it on
@@ -505,7 +532,8 @@ static void elf_deflabel (char *name, long segment, long offset,
 }
 
 static void elf_add_reloc (struct Section *sect, long segment,
-                          int type) {
+                          int type) 
+{
     struct Reloc *r;
 
     r = *sect->tail = nasm_malloc(sizeof(struct Reloc));
@@ -553,7 +581,8 @@ static void elf_add_reloc (struct Section *sect, long segment,
  */
 static long elf_add_gsym_reloc (struct Section *sect,
                                long segment, long offset,
-                               int type, int exact) {
+                               int type, int exact) 
+{
     struct Reloc *r;
     struct Section *s;
     struct Symbol *sym, *sm;
@@ -617,7 +646,8 @@ static long elf_add_gsym_reloc (struct Section *sect,
 }
 
 static void elf_out (long segto, void *data, unsigned long type,
-                     long segment, long wrt) {
+                     long segment, long wrt) 
+{
     struct Section *s;
     long realbytes = type & OUT_SIZMASK;
     long addr;
@@ -744,7 +774,8 @@ static void elf_out (long segto, void *data, unsigned long type,
     }
 }
 
-static void elf_write(void) {
+static void elf_write(void) 
+{
     int nsections, align;
     char *p;
     int commlen;
@@ -819,6 +850,7 @@ static void elf_write(void) {
     align = ((elf_foffs+SEG_ALIGN_1) & ~SEG_ALIGN_1) - elf_foffs;
     elf_foffs += align;
     elf_nsect = 0;
+    elf_sects = nasm_malloc(sizeof(*elf_sects) * (2 * nsects + 10));
 
     elf_section_header (0, 0, 0, NULL, FALSE, 0L, 0, 0, 0, 0); /* SHN_UNDEF */
     p = shstrtab+1;
@@ -853,10 +885,12 @@ static void elf_write(void) {
      */
     elf_write_sections();
 
+    nasm_free (elf_sects);
     saa_free (symtab);
 }
 
-static struct SAA *elf_build_symtab (long *len, long *local) {
+static struct SAA *elf_build_symtab (long *len, long *local) 
+{
     struct SAA *s = saa_init(1L);
     struct Symbol *sym;
     unsigned char entry[16], *p;
@@ -968,7 +1002,8 @@ static struct SAA *elf_build_reltab (long *len, struct Reloc *r) {
 
 static void elf_section_header (int name, int type, int flags,
                                void *data, int is_saa, long datalen,
-                               int link, int info, int align, int eltsize) {
+                               int link, int info, int align, int eltsize) 
+{
     elf_sects[elf_nsect].data = data;
     elf_sects[elf_nsect].len = datalen;
     elf_sects[elf_nsect].is_saa = is_saa;
@@ -988,7 +1023,8 @@ static void elf_section_header (int name, int type, int flags,
     fwritelong ((long)eltsize, elffp);
 }
 
-static void elf_write_sections (void) {
+static void elf_write_sections (void) 
+{
     int i;
     for (i = 0; i < elf_nsect; i++)
        if (elf_sects[i].data) {
@@ -1004,34 +1040,49 @@ static void elf_write_sections (void) {
 }
 
 static void elf_sect_write (struct Section *sect,
-                            unsigned char *data, unsigned long len) {
+                            unsigned char *data, unsigned long len) 
+{
     saa_wbytes (sect->data, data, len);
     sect->len += len;
 }
 
-static long elf_segbase (long segment) {
+static long elf_segbase (long segment) 
+{
     return segment;
 }
 
-static int elf_directive (char *directive, char *value, int pass) {
+static int elf_directive (char *directive, char *value, int pass) 
+{
     return 0;
 }
 
-static void elf_filename (char *inname, char *outname, efunc error) {
+static void elf_filename (char *inname, char *outname, efunc error) 
+{
     strcpy(elf_module, inname);
     standard_extension (inname, outname, ".o", error);
 }
 
 static char *elf_stdmac[] = {
     "%define __SECT__ [section .text]",
+    "%macro __NASM_CDecl__ 1",
+    "%define $_%1 $%1",
+    "%endmacro",
     NULL
 };
+static int elf_set_info(enum geninfo type, char **val)
+{
+    return 0;
+}
 
 struct ofmt of_elf = {
     "ELF32 (i386) object files (e.g. Linux)",
     "elf",
+    NULL,
+    null_debug_arr,
+    &null_debug_form,
     elf_stdmac,
     elf_init,
+    elf_set_info,
     elf_out,
     elf_deflabel,
     elf_section_names,
index 09202de..c8b9532 100644 (file)
--- a/outform.c
+++ b/outform.c
 
 #include <stdio.h>
 #include <string.h>
+
+#define BUILD_DRIVERS_ARRAY
 #include "outform.h"
 
-static struct ofmt *drivers[MAX_OUTPUT_FORMATS];
 static int ndrivers = 0;
 
 struct ofmt *ofmt_find(char *name)     /* find driver */
@@ -26,17 +27,45 @@ struct ofmt *ofmt_find(char *name)     /* find driver */
 
     return NULL;
 }
+struct dfmt *dfmt_find(struct ofmt *ofmt, char *name)     /* find driver */
+{
+    struct dfmt **dfmt = ofmt->debug_formats;
+    while (*dfmt) {
+       if (!strcmp(name, (*dfmt)->shortname))
+               return (*dfmt);
+       dfmt++;
+    }
+    return NULL;
+}
 
 void ofmt_list(struct ofmt *deffmt, FILE *fp)
 {
     int i;
     for (i=0; i<ndrivers; i++)
-       fprintf(fp, "  %c %-7s%s\n",
+       fprintf(fp, "  %c %-10s%s\n",
                drivers[i] == deffmt ? '*' : ' ',
                drivers[i]->shortname,
                drivers[i]->fullname);
 }
+void dfmt_list(struct ofmt *ofmt, FILE *fp)
+{
+    struct dfmt ** drivers = ofmt->debug_formats;
+    while (*drivers) {
+       fprintf(fp, "  %c %-10s%s\n",
+               drivers[0] == ofmt->current_dfmt ? '*' : ' ',
+               drivers[0]->shortname,
+               drivers[0]->fullname);
+       drivers++;
+    }
+}
+struct ofmt *ofmt_register (efunc error) {
+    for (ndrivers=0; drivers[ndrivers] != NULL; ndrivers++);
+
+    if (ndrivers==0)
+    {
+        error(ERR_PANIC | ERR_NOFILE,
+             "No output drivers given at compile time");
+    }
 
-void ofmt_register (struct ofmt *info) {
-    drivers[ndrivers++] = info;
+    return (&OF_DEFAULT);
 }
index e23f3c7..2e7a32d 100644 (file)
--- a/outform.h
+++ b/outform.h
@@ -20,6 +20,9 @@
  * OF_UNIX                -- ensure that 'aout', 'aoutb', 'coff', 'elf' are in.
  * OF_OTHERS              -- ensure that 'bin', 'as86' & 'rdf' are in.
  * OF_ALL                 -- ensure that all formats are included.
+ *                           note that this doesn't include 'dbg', which is
+ *                           only really useful if you're doing development
+ *                           work on NASM. Define OF_DBG if you want this.
  *
  * OF_DEFAULT=of_name     -- ensure that 'name' is the default format.
  *
 
 #include "nasm.h"
 
-#define MAX_OUTPUT_FORMATS 16
-
-struct ofmt *ofmt_find(char *);
-void ofmt_list(struct ofmt *, FILE *);
-void ofmt_register (struct ofmt *);
-
 /* -------------- USER MODIFIABLE PART ---------------- */
 
 /*
@@ -60,7 +57,7 @@ void ofmt_register (struct ofmt *);
 
 /* ====configurable info begins here==== */
 /* formats configurable:
- * bin,obj,elf,aout,aoutb,coff,win32,as86,rdf */
+ * bin,obj,elf,aout,aoutb,coff,win32,as86,rdf,rdf2 */
 
 /* process options... */
 
@@ -95,8 +92,8 @@ void ofmt_register (struct ofmt *);
 #ifndef OF_AS86
 #define OF_AS86
 #endif
-#ifndef OF_RDF
-#define OF_RDF
+#ifndef OF_RDF2
+#define OF_RDF2
 #endif
 #endif /* OF_ALL */
 
@@ -138,6 +135,9 @@ void ofmt_register (struct ofmt *);
 #ifndef OF_RDF
 #define OF_RDF
 #endif
+#ifndef OF_RDF2
+#define OF_RDF2
+#endif
 #endif
 
 /* finally... override any format specifically specifed to be off */
@@ -168,9 +168,75 @@ void ofmt_register (struct ofmt *);
 #ifdef OF_NO_RDF
 #undef OF_RDF
 #endif
+#ifdef OF_NO_RDF2
+#undef OF_RDF
+#endif
 
 #ifndef OF_DEFAULT
 #define OF_DEFAULT of_bin
 #endif
 
+#ifdef BUILD_DRIVERS_ARRAY            /* only if included from outform.c */
+
+/* pull in the externs for the different formats, then make the *drivers
+ * array based on the above defines */
+
+extern struct ofmt of_bin;
+extern struct ofmt of_aout;
+extern struct ofmt of_aoutb;
+extern struct ofmt of_coff;
+extern struct ofmt of_elf;
+extern struct ofmt of_as86;
+extern struct ofmt of_obj;
+extern struct ofmt of_win32;
+extern struct ofmt of_rdf;
+extern struct ofmt of_rdf2;
+extern struct ofmt of_dbg;
+
+struct ofmt *drivers[]={
+#ifdef OF_BIN
+    &of_bin,
+#endif
+#ifdef OF_AOUT
+    &of_aout,
+#endif
+#ifdef OF_AOUTB
+    &of_aoutb,
+#endif
+#ifdef OF_COFF
+    &of_coff,
+#endif
+#ifdef OF_ELF
+    &of_elf,
+#endif
+#ifdef OF_AS86
+    &of_as86,
+#endif
+#ifdef OF_OBJ
+    &of_obj,
+#endif
+#ifdef OF_WIN32
+    &of_win32,
+#endif
+#ifdef OF_RDF
+    &of_rdf,
+#endif
+#ifdef OF_RDF2
+    &of_rdf2,
+#endif
+#ifdef OF_DBG
+    &of_dbg,
+#endif
+
+   NULL
+};
+
+#endif  /* BUILD_DRIVERS_ARRAY */
+
+struct ofmt *ofmt_find(char *);
+struct dfmt *dfmt_find(struct ofmt *, char *);
+void ofmt_list(struct ofmt *, FILE *);
+void dfmt_list(struct ofmt *ofmt, FILE *fp);
+struct ofmt *ofmt_register (efunc error);
+
 #endif  /* NASM_OUTFORM_H */
diff --git a/outforms.h b/outforms.h
new file mode 100644 (file)
index 0000000..2afbbe2
--- /dev/null
@@ -0,0 +1,223 @@
+/* outform.h   header file for binding output format drivers to the
+ *              remainder of the code in the Netwide Assembler
+ *
+ * The Netwide Assembler is copyright (C) 1996 Simon Tatham and
+ * Julian Hall. All rights reserved. The software is
+ * redistributable under the licence given in the file "Licence"
+ * distributed in the NASM archive.
+ */
+
+/*
+ * This header file allows configuration of which output formats
+ * get compiled into the NASM binary. You can configure by defining
+ * various preprocessor symbols beginning with "OF_", either on the
+ * compiler command line or at the top of this file.
+ *
+ * OF_ONLY                -- only include specified object formats
+ * OF_name                -- ensure that output format 'name' is included
+ * OF_NO_name             -- remove output format 'name'
+ * OF_DOS                 -- ensure that 'obj', 'bin' & 'win32' are included.
+ * OF_UNIX                -- ensure that 'aout', 'aoutb', 'coff', 'elf' are in.
+ * OF_OTHERS              -- ensure that 'bin', 'as86' & 'rdf' are in.
+ * OF_ALL                 -- ensure that all formats are included.
+ *
+ * OF_DEFAULT=of_name     -- ensure that 'name' is the default format.
+ *
+ * eg: -DOF_UNIX -DOF_ELF -DOF_DEFAULT=of_elf would be a suitable config
+ * for an average linux system.
+ *
+ * Default config = -DOF_ALL -DOF_DEFAULT=of_bin
+ *
+ * You probably only want to set these options while compiling 'nasm.c'. */
+
+#ifndef NASM_OUTFORMS_H
+#define NASM_OUTFORMS_H
+
+#include "nasm.h"
+
+/* -------------- USER MODIFIABLE PART ---------------- */
+
+/*
+ * Insert #defines here in accordance with the configuration
+ * instructions above.
+ *
+ * E.g.
+ *
+ * #define OF_ONLY
+ * #define OF_OBJ
+ * #define OF_BIN
+ *
+ * for a 16-bit DOS assembler with no extraneous formats.
+ */
+
+/* ------------ END USER MODIFIABLE PART -------------- */
+
+/* ====configurable info begins here==== */
+/* formats configurable:
+ * bin,obj,elf,aout,aoutb,coff,win32,as86,rdf */
+
+/* process options... */
+
+#ifndef OF_ONLY
+#ifndef OF_ALL
+#define OF_ALL      /* default is to have all formats */
+#endif
+#endif
+
+#ifdef OF_ALL      /* set all formats on... */
+#ifndef OF_BIN
+#define OF_BIN
+#endif
+#ifndef OF_OBJ
+#define OF_OBJ
+#endif
+#ifndef OF_ELF
+#define OF_ELF
+#endif
+#ifndef OF_COFF
+#define OF_COFF
+#endif
+#ifndef OF_AOUT
+#define OF_AOUT
+#endif
+#ifndef OF_AOUTB
+#define OF_AOUTB
+#endif
+#ifndef OF_WIN32
+#define OF_WIN32
+#endif
+#ifndef OF_AS86
+#define OF_AS86
+#endif
+#ifndef OF_RDF
+#define OF_RDF
+#endif
+#endif /* OF_ALL */
+
+/* turn on groups of formats specified.... */
+#ifdef OF_DOS
+#ifndef OF_OBJ
+#define OF_OBJ
+#endif
+#ifndef OF_BIN
+#define OF_BIN
+#endif
+#ifndef OF_WIN32
+#define OF_WIN32
+#endif
+#endif
+
+#ifdef OF_UNIX
+#ifndef OF_AOUT
+#define OF_AOUT
+#endif
+#ifndef OF_AOUTB
+#define OF_AOUTB
+#endif
+#ifndef OF_COFF
+#define OF_COFF
+#endif
+#ifndef OF_ELF
+#define OF_ELF
+#endif
+#endif
+
+#ifdef OF_OTHERS
+#ifndef OF_BIN
+#define OF_BIN
+#endif
+#ifndef OF_AS86
+#define OF_AS86
+#endif
+#ifndef OF_RDF
+#define OF_RDF
+#endif
+#endif
+
+/* finally... override any format specifically specifed to be off */
+#ifdef OF_NO_BIN
+#undef OF_BIN
+#endif
+#ifdef OF_NO_OBJ
+#undef OF_OBJ
+#endif
+#ifdef OF_NO_ELF
+#undef OF_ELF
+#endif
+#ifdef OF_NO_AOUT
+#undef OF_AOUT
+#endif
+#ifdef OF_NO_AOUTB
+#undef OF_AOUTB
+#endif
+#ifdef OF_NO_COFF
+#undef OF_COFF
+#endif
+#ifdef OF_NO_WIN32
+#undef OF_WIN32
+#endif
+#ifdef OF_NO_AS86
+#undef OF_AS86
+#endif
+#ifdef OF_NO_RDF
+#undef OF_RDF
+#endif
+
+#ifndef OF_DEFAULT
+#define OF_DEFAULT of_bin
+#endif
+
+#ifdef BUILD_DRIVERS_ARRAY            /* only if included from outform.c */
+
+/* pull in the externs for the different formats, then make the *drivers
+ * array based on the above defines */
+
+extern struct ofmt of_bin;
+extern struct ofmt of_aout;
+extern struct ofmt of_aoutb;
+extern struct ofmt of_coff;
+extern struct ofmt of_elf;
+extern struct ofmt of_as86;
+extern struct ofmt of_obj;
+extern struct ofmt of_win32;
+extern struct ofmt of_rdf;
+extern struct ofmt of_dbg;
+
+struct ofmt *drivers[]={
+#ifdef OF_BIN
+    &of_bin,
+#endif
+#ifdef OF_AOUT
+    &of_aout,
+#endif
+#ifdef OF_AOUTB
+    &of_aoutb,
+#endif
+#ifdef OF_COFF
+    &of_coff,
+#endif
+#ifdef OF_ELF
+    &of_elf,
+#endif
+#ifdef OF_AS86
+    &of_as86,
+#endif
+#ifdef OF_OBJ
+    &of_obj,
+#endif
+#ifdef OF_WIN32
+    &of_win32,
+#endif
+#ifdef OF_RDF
+    &of_rdf,
+#endif
+#ifdef OF_DBG
+    &of_dbg,
+#endif
+
+   NULL
+};
+
+#endif  /* BUILD_DRIVERS_ARRAY */
+
+#endif  /* NASM_OUTFORMS_H */
index f54d297..0a7544d 100644 (file)
--- a/outobj.c
+++ b/outobj.c
@@ -1,5 +1,5 @@
 /* outobj.c    output routines for the Netwide Assembler to produce
- *             Microsoft 16-bit .OBJ object files
+ *             .OBJ object files
  *
  * The Netwide Assembler is copyright (C) 1996 Simon Tatham and
  * Julian Hall. All rights reserved. The software is
 
 #ifdef OF_OBJ
 
+/*
+ * outobj.c is divided into two sections.  The first section is low level
+ * routines for creating obj records;  It has nearly zero NASM specific
+ * code.  The second section is high level routines for processing calls and
+ * data structures from the rest of NASM into obj format.
+ *
+ * It should be easy (though not zero work) to lift the first section out for
+ * use as an obj file writer for some other assembler or compiler.
+ */
+
+/*
+ * These routines are built around the ObjRecord data struture.  An ObjRecord
+ * holds an object file record that may be under construction or complete.
+ *
+ * A major function of these routines is to support continuation of an obj
+ * record into the next record when the maximum record size is exceeded.  The
+ * high level code does not need to worry about where the record breaks occur.
+ * It does need to do some minor extra steps to make the automatic continuation
+ * work.  Those steps may be skipped for records where the high level knows no
+ * continuation could be required.
+ *
+ * 1) An ObjRecord is allocated and cleared by obj_new, or an existing ObjRecord
+ *    is cleared by obj_clear.
+ *
+ * 2) The caller should fill in .type.
+ *
+ * 3) If the record is continuable and there is processing that must be done at
+ *    the start of each record then the caller should fill in .ori with the
+ *    address of the record initializer routine.
+ *
+ * 4) If the record is continuable and it should be saved (rather than emitted
+ *    immediately) as each record is done, the caller should set .up to be a
+ *    pointer to a location in which the caller keeps the master pointer to the
+ *    ObjRecord.  When the record is continued, the obj_bump routine will then
+ *    allocate a new ObjRecord structure and update the master pointer.
+ *
+ * 5) If the .ori field was used then the caller should fill in the .parm with
+ *    any data required by the initializer.
+ *
+ * 6) The caller uses the routines: obj_byte, obj_word, obj_rword, obj_dword,
+ *    obj_x, obj_index, obj_value and obj_name to fill in the various kinds of
+ *    data required for this record.
+ *
+ * 7) If the record is continuable, the caller should call obj_commit at each
+ *    point where breaking the record is permitted.
+ *
+ * 8) To write out the record, the caller should call obj_emit2.  If the
+ *    caller has called obj_commit for all data written then he can get slightly
+ *    faster code by calling obj_emit instead of obj_emit2.
+ *
+ * Most of these routines return an ObjRecord pointer.  This will be the input
+ * pointer most of the time and will be the new location if the ObjRecord
+ * moved as a result of the call.  The caller may ignore the return value in
+ * three cases:  It is a "Never Reallocates" routine;  or  The caller knows
+ * continuation is not possible;  or  The caller uses the master pointer for the
+ * next operation.
+ */
+
+#define RECORD_MAX 1024                /* maximum size of _any_ record */
+#define OBJ_PARMS  3           /* maximum .parm used by any .ori routine */
+
+#define FIX_08_LOW      0x8000 /* location type for various fixup subrecords */
+#define FIX_16_OFFSET   0x8400
+#define FIX_16_SELECTOR 0x8800
+#define FIX_32_POINTER  0x8C00
+#define FIX_08_HIGH     0x9000
+#define FIX_32_OFFSET   0xA400
+#define FIX_48_POINTER  0xAC00
+
+enum RecordID {                               /* record ID codes */
+
+    THEADR = 0x80,                    /* module header */
+    COMENT = 0x88,                    /* comment record */
+
+    LINNUM = 0x94,                     /* line number record */
+    LNAMES = 0x96,                    /* list of names */
+
+    SEGDEF = 0x98,                    /* segment definition */
+    GRPDEF = 0x9A,                    /* group definition */
+    EXTDEF = 0x8C,                    /* external definition */
+    PUBDEF = 0x90,                    /* public definition */
+    COMDEF = 0xB0,                    /* common definition */
+
+    LEDATA = 0xA0,                    /* logical enumerated data */
+    FIXUPP = 0x9C,                    /* fixups (relocations) */
+
+    MODEND = 0x8A                     /* module end */
+};
+
+enum ComentID {                        /* ID codes for comment records */
+
+     dEXTENDED = 0xA1,                 /* tells that we are using translator-specific extensions */
+     dLINKPASS = 0xA2,                 /* link pass 2 marker */
+     dTYPEDEF = 0xE3,                  /* define a type */
+     dSYM = 0xE6,                      /* symbol debug record */
+     dFILNAME = 0xE8,                  /* file name record */
+     dCOMPDEF = 0xEA                   /* compiler type info */
+
+};
+
+typedef struct ObjRecord ObjRecord;
+typedef void ORI(ObjRecord *orp);
+
+struct ObjRecord {
+    ORI           *ori;                        /* Initialization routine           */
+    int            used;               /* Current data size                */
+    int            committed;          /* Data size at last boundary       */
+    int            x_size;             /* (see obj_x)                      */
+    unsigned int   type;               /* Record type                      */
+    ObjRecord     *child;              /* Associated record below this one */
+    ObjRecord    **up;                 /* Master pointer to this ObjRecord */
+    ObjRecord     *back;               /* Previous part of this record     */
+    unsigned long  parm[OBJ_PARMS];    /* Parameters for ori routine       */
+    unsigned char  buf[RECORD_MAX];
+};
+
+static void obj_fwrite(ObjRecord *orp);
+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 */
+
+/*
+ * Clear an ObjRecord structure.  (Never reallocates).
+ * To simplify reuse of ObjRecord's, .type, .ori and .parm are not cleared.
+ */
+static ObjRecord *obj_clear(ObjRecord *orp) 
+{
+    orp->used = 0;
+    orp->committed = 0;
+    orp->x_size = 0;
+    orp->child = NULL;
+    orp->up = NULL;
+    orp->back = NULL;
+    return (orp);
+}
+
+/*
+ * Emit an ObjRecord structure.  (Never reallocates).
+ * The record is written out preceeded (recursively) by its previous part (if
+ * any) and followed (recursively) by its child (if any).
+ * The previous part and the child are freed.  The main ObjRecord is cleared,
+ * not freed.
+ */
+static ObjRecord *obj_emit(ObjRecord *orp) 
+{
+    if (orp->back) {
+       obj_emit(orp->back);
+       nasm_free(orp->back);
+    }
+
+    if (orp->committed)
+       obj_fwrite(orp);
+
+    if (orp->child) {
+       obj_emit(orp->child);
+       nasm_free(orp->child);
+    }
+
+    return (obj_clear(orp));
+}
+
+/*
+ * Commit and Emit a record.  (Never reallocates).
+ */
+static ObjRecord *obj_emit2(ObjRecord *orp) 
+{
+    obj_commit(orp);
+    return (obj_emit(orp));
+}
+
+/*
+ * Allocate and clear a new ObjRecord;  Also sets .ori to ori_null
+ */
+static ObjRecord *obj_new(void) 
+{
+    ObjRecord *orp;
+    
+    orp = obj_clear( nasm_malloc(sizeof(ObjRecord)) );
+    orp->ori = ori_null;
+    return (orp);
+}
+    
+/*
+ * Advance to the next record because the existing one is full or its x_size
+ * is incompatible.
+ * Any uncommited data is moved into the next record.
+ */
+static ObjRecord *obj_bump(ObjRecord *orp) 
+{
+    ObjRecord *nxt;
+    int used = orp->used;
+    int committed = orp->committed;
+
+    if (orp->up) {
+       *orp->up = nxt = obj_new();
+       nxt->ori = orp->ori;
+       nxt->type = orp->type;
+       nxt->up = orp->up;
+       nxt->back = orp;
+       memcpy( nxt->parm, orp->parm, sizeof(orp->parm));
+    } else
+       nxt = obj_emit(orp);
+
+    used -= committed;
+    if (used) {
+       nxt->committed = 1;
+       nxt->ori (nxt);
+       nxt->committed = nxt->used;
+       memcpy( nxt->buf + nxt->committed, orp->buf + committed, used);
+       nxt->used = nxt->committed + used;
+    }
+
+    return (nxt);
+}
+
+/*
+ * Advance to the next record if necessary to allow the next field to fit.
+ */
+static ObjRecord *obj_check(ObjRecord *orp, int size) 
+{
+    if (orp->used + size > RECORD_MAX)
+       orp = obj_bump(orp);
+
+    if (!orp->committed) {
+       orp->committed = 1;
+       orp->ori (orp);
+       orp->committed = orp->used;
+    }
+
+    return (orp);
+}
+
+/*
+ * All data written so far is commited to the current record (won't be moved to
+ * the next record in case of continuation).
+ */
+static ObjRecord *obj_commit(ObjRecord *orp) 
+{
+    orp->committed = orp->used;
+    return (orp);
+}
+
+/*
+ * Write a byte
+ */
+static ObjRecord *obj_byte(ObjRecord *orp, unsigned char val) 
+{
+    orp = obj_check(orp, 1);
+    orp->buf[orp->used] = val;
+    orp->used++;
+    return (orp);
+}
+
+/*
+ * Write a word
+ */
+static ObjRecord *obj_word(ObjRecord *orp, unsigned int val) 
+{
+    orp = obj_check(orp, 2);
+    orp->buf[orp->used] = val;
+    orp->buf[orp->used+1] = val >> 8;
+    orp->used += 2;
+    return (orp);
+}
+
+/*
+ * Write a reversed word
+ */
+static ObjRecord *obj_rword(ObjRecord *orp, unsigned int val) 
+{
+    orp = obj_check(orp, 2);
+    orp->buf[orp->used] = val >> 8;
+    orp->buf[orp->used+1] = val;
+    orp->used += 2;
+    return (orp);
+}
+
+/*
+ * Write a dword
+ */
+static ObjRecord *obj_dword(ObjRecord *orp, unsigned long val) 
+{
+    orp = obj_check(orp, 4);
+    orp->buf[orp->used] = val;
+    orp->buf[orp->used+1] = val >> 8;
+    orp->buf[orp->used+2] = val >> 16;
+    orp->buf[orp->used+3] = val >> 24;
+    orp->used += 4;
+    return (orp);
+}
+
+/*
+ * All fields of "size x" in one obj record must be the same size (either 16
+ * bits or 32 bits).  There is a one bit flag in each record which specifies
+ * which.
+ * This routine is used to force the current record to have the desired
+ * x_size.  x_size is normally automatic (using obj_x), so that this
+ * routine should be used outside obj_x, only to provide compatibility with
+ * linkers that have bugs in their processing of the size bit.
+ */
+
+static ObjRecord *obj_force(ObjRecord *orp, int x)
+{
+    if (orp->x_size == (x^48))
+       orp = obj_bump(orp);
+    orp->x_size = x;
+       return (orp);
+}
+
+/*
+ * This routine writes a field of size x.  The caller does not need to worry at
+ * all about whether 16-bits or 32-bits are required.
+ */
+static ObjRecord *obj_x(ObjRecord *orp, unsigned long val) 
+{
+    if (orp->type & 1)
+       orp->x_size = 32;
+    if (val > 0xFFFF)
+       orp = obj_force(orp, 32);
+    if (orp->x_size == 32)
+       return (obj_dword(orp, val));
+    orp->x_size = 16;
+    return (obj_word(orp, val));
+}
+
+/*
+ * Writes an index
+ */
+static ObjRecord *obj_index(ObjRecord *orp, unsigned int val) 
+{
+    if (val < 128)
+       return ( obj_byte(orp, val) );
+    return (obj_word(orp, (val>>8) | (val<<8) | 0x80));
+}
+
+/*
+ * Writes a variable length value
+ */
+static ObjRecord *obj_value(ObjRecord *orp, unsigned long val) 
+{
+    if (val <= 128)
+       return ( obj_byte(orp, val) );
+    if (val <= 0xFFFF) {
+       orp = obj_byte(orp, 129);
+       return ( obj_word(orp, val) );
+    }
+    if (val <= 0xFFFFFF)
+       return ( obj_dword(orp, (val<<8) + 132 ) );
+    orp = obj_byte(orp, 136);
+    return ( obj_dword(orp, val) );
+}
+
+/*
+ * Writes a counted string
+ */
+static ObjRecord *obj_name(ObjRecord *orp, char *name) 
+{
+    int len = strlen(name);
+    unsigned char *ptr;
+
+    orp = obj_check(orp, len+1);
+    ptr = orp->buf + orp->used;
+    *ptr++ = len;
+    orp->used += len+1;
+    if (obj_uppercase)
+       while (--len >= 0) {
+           *ptr++ = toupper(*name);
+           name++;
+    } else
+       memcpy(ptr, name, len);
+    return (orp);
+}
+
+/*
+ * Initializer for an LEDATA record.
+ * parm[0] = offset
+ * parm[1] = segment index
+ * During the use of a LEDATA ObjRecord, parm[0] is constantly updated to
+ * represent the offset that would be required if the record were split at the
+ * last commit point.
+ * parm[2] is a copy of parm[0] as it was when the current record was initted.
+ */
+static void ori_ledata(ObjRecord *orp) 
+{
+    obj_index (orp, orp->parm[1]);
+    orp->parm[2] = orp->parm[0];
+    obj_x (orp, orp->parm[0]);
+}
+
+/*
+ * Initializer for a PUBDEF record.
+ * parm[0] = group index
+ * parm[1] = segment index
+ * parm[2] = frame (only used when both indexes are zero)
+ */
+static void ori_pubdef(ObjRecord *orp) 
+{
+    obj_index (orp, orp->parm[0]);
+    obj_index (orp, orp->parm[1]);
+    if ( !(orp->parm[0] | orp->parm[1]) )
+       obj_word (orp, orp->parm[2]);
+}
+
+/*
+ * Initializer for a LINNUM record.
+ * parm[0] = group index
+ * parm[1] = segment index
+ */
+static void ori_linnum(ObjRecord *orp) 
+{
+    obj_index (orp, orp->parm[0]);
+    obj_index (orp, orp->parm[1]);
+}
+/*
+ * Initializer for a local vars record.
+ */
+static void ori_local(ObjRecord *orp) 
+{
+    obj_byte (orp, 0x40);
+    obj_byte (orp, dSYM);
+}
+
+/*
+ * Null initializer for records that continue without any header info
+ */
+static void ori_null(ObjRecord *orp) 
+{
+    (void) orp;  /* Do nothing */
+}
+
+/*
+ * This concludes the low level section of outobj.c
+ */
+
 static char obj_infile[FILENAME_MAX];
-static int obj_uppercase;
 
 static efunc error;
 static evalfunc evaluate;
@@ -27,24 +465,46 @@ static ldfunc deflabel;
 static FILE *ofp;
 static long first_seg;
 static int any_segs;
+static int passtwo;
+static int arrindex;
 
-#define LEDATA_MAX 1024                       /* maximum size of LEDATA record */
-#define RECORD_MAX 1024                       /* maximum size of _any_ record */
 #define GROUP_MAX 256                 /* we won't _realistically_ have more
                                        * than this many segs in a group */
 #define EXT_BLKSIZ 256                /* block size for externals list */
 
-static unsigned char record[RECORD_MAX], *recptr;
-
 struct Segment;                               /* need to know these structs exist */
 struct Group;
 
+struct LineNumber {
+    struct LineNumber *next;
+    struct Segment *segment;
+    long offset;
+    long lineno;
+};
+
+static struct FileName {
+    struct FileName *next;
+    char *name;
+    struct LineNumber *lnhead, **lntail;
+    int index;
+} *fnhead, **fntail;
+
+static struct Array {
+    struct Array *next;
+    unsigned size;
+    int basetype;
+} *arrhead, **arrtail;
+
+#define ARRAYBOT 31 /* magic number  for first array index */
+
+
 static struct Public {
     struct Public *next;
     char *name;
     long offset;
     long segment;                     /* only if it's far-absolute */
-} *fpubhead, **fpubtail;
+    int type;                          /* only for local debug syms */
+} *fpubhead, **fpubtail, *last_defined;
 
 static struct External {
     struct External *next;
@@ -78,7 +538,7 @@ static struct Segment {
     long index;                               /* the NASM segment id */
     long obj_index;                   /* the OBJ-file segment index */
     struct Group *grp;                /* the group it belongs to */
-    long currentpos;
+    unsigned long currentpos;
     long align;                               /* can be SEG_ABS + absolute addr */
     enum {
        CMB_PRIVATE = 0,
@@ -87,9 +547,10 @@ static struct Segment {
        CMB_COMMON = 6
     } combine;
     long use32;                               /* is this segment 32-bit? */
-    struct Public *pubhead, **pubtail;
+    struct Public *pubhead, **pubtail, *lochead, **loctail;
     char *name;
     char *segclass, *overlay;         /* `class' is a C++ keyword :-) */
+    ObjRecord *orp;
 } *seghead, **segtail, *obj_seg_needs_update;
 
 static struct Group {
@@ -105,16 +566,6 @@ static struct Group {
     } segs[GROUP_MAX];                /* ...in this */
 } *grphead, **grptail, *obj_grp_needs_update;
 
-static struct ObjData {
-    struct ObjData *next;
-    int nonempty;
-    struct Segment *seg;
-    long startpos;
-    int letype, ftype;
-    unsigned char ledata[LEDATA_MAX], *lptr;
-    unsigned char fixupp[RECORD_MAX], *fptr;
-} *datahead, *datacurr, **datatail;
-
 static struct ImpDef {
     struct ImpDef *next;
     char *extname;
@@ -138,46 +589,14 @@ static struct ExpDef {
 
 static long obj_entry_seg, obj_entry_ofs;
 
-enum RecordID {                               /* record ID codes */
-
-    THEADR = 0x80,                    /* module header */
-    COMENT = 0x88,                    /* comment record */
-
-    LNAMES = 0x96,                    /* list of names */
-
-    SEGDEF = 0x98,                    /* segment definition */
-    GRPDEF = 0x9A,                    /* group definition */
-    EXTDEF = 0x8C,                    /* external definition */
-    PUBDEF = 0x90,                    /* public definition */
-    COMDEF = 0xB0,                    /* common definition */
+struct ofmt of_obj;
 
-    LEDATA = 0xA0,                    /* logical enumerated data */
-    FIXUPP = 0x9C,                    /* fixups (relocations) */
-
-    MODEND = 0x8A                     /* module end */
-};
-
-extern struct ofmt of_obj;
-
-static long obj_ledata_space(struct Segment *);
-static int obj_fixup_free(struct Segment *);
-static void obj_ledata_new(struct Segment *);
-static void obj_ledata_commit(void);
-static void obj_write_fixup (struct ObjData *, int, int, long, long, long);
 static long obj_segment (char *, int, int *);
-static void obj_write_file(void);
-static unsigned char *obj_write_data(unsigned char *, unsigned char *, int);
-static unsigned char *obj_write_byte(unsigned char *, int);
-static unsigned char *obj_write_word(unsigned char *, int);
-static unsigned char *obj_write_dword(unsigned char *, long);
-static unsigned char *obj_write_rword(unsigned char *, int);
-static unsigned char *obj_write_name(unsigned char *, char *);
-static unsigned char *obj_write_index(unsigned char *, int);
-static unsigned char *obj_write_value(unsigned char *, unsigned long);
-static void obj_record(int, unsigned char *, unsigned char *);
+static void obj_write_file(int debuginfo);
 static int obj_directive (char *, char *, int);
 
-static void obj_init (FILE *fp, efunc errfunc, ldfunc ldef, evalfunc eval) {
+static void obj_init (FILE *fp, efunc errfunc, ldfunc ldef, evalfunc eval) 
+{
     ofp = fp;
     error = errfunc;
     evaluate = eval;
@@ -200,14 +619,24 @@ static void obj_init (FILE *fp, efunc errfunc, ldfunc ldef, evalfunc eval) {
     segtail = &seghead;
     grphead = obj_grp_needs_update = NULL;
     grptail = &grphead;
-    datahead = datacurr = NULL;
-    datatail = &datahead;
     obj_entry_seg = NO_SEG;
     obj_uppercase = FALSE;
+    passtwo = 0;
+
+    of_obj.current_dfmt->init (&of_obj,NULL,fp,errfunc);
 }
 
-static void obj_cleanup (void) {
-    obj_write_file();
+static int obj_set_info(enum geninfo type, char **val)
+{
+    (void) type;
+    (void) val;
+
+    return 0;
+}
+static void obj_cleanup (int debuginfo) 
+{
+    obj_write_file(debuginfo);
+    of_obj.current_dfmt->cleanup();
     fclose (ofp);
     while (seghead) {
        struct Segment *segtmp = seghead;
@@ -218,6 +647,8 @@ static void obj_cleanup (void) {
            nasm_free (pubtmp->name);
            nasm_free (pubtmp);
        }
+       nasm_free (segtmp->segclass);
+       nasm_free (segtmp->overlay);
        nasm_free (segtmp);
     }
     while (fpubhead) {
@@ -256,14 +687,10 @@ static void obj_cleanup (void) {
        grphead = grphead->next;
        nasm_free (grptmp);
     }
-    while (datahead) {
-       struct ObjData *datatmp = datahead;
-       datahead = datahead->next;
-       nasm_free (datatmp);
-    }
 }
 
-static void obj_ext_set_defwrt (struct External *ext, char *id) {
+static void obj_ext_set_defwrt (struct External *ext, char *id) 
+{
     struct Segment *seg;
     struct Group *grp;
 
@@ -290,7 +717,8 @@ static void obj_ext_set_defwrt (struct External *ext, char *id) {
 }
 
 static void obj_deflabel (char *name, long segment,
-                         long offset, int is_global, char *special) {
+                         long offset, int is_global, char *special) 
+{
     /*
      * We have three cases:
      *
@@ -376,19 +804,18 @@ static void obj_deflabel (char *name, long segment,
            error (ERR_PANIC, "strange segment conditions in OBJ driver");
     }
 
-    for (seg = seghead; seg; seg = seg->next)
+    for (seg = seghead; seg && is_global; seg = seg->next)
        if (seg->index == segment) {
+           struct Public *loc = nasm_malloc (sizeof(*loc));
            /*
             * Case (ii). Maybe MODPUB someday?
             */
-           if (is_global) {
-               struct Public *pub;
-               pub = *seg->pubtail = nasm_malloc(sizeof(*pub));
-               seg->pubtail = &pub->next;
-               pub->next = NULL;
-               pub->name = nasm_strdup(name);
-               pub->offset = offset;
-           }
+           *seg->pubtail = loc;
+           seg->pubtail = &loc->next;
+           loc->next = NULL;
+           loc->name = nasm_strdup(name);
+           loc->offset = offset;
+                  
            if (special)
                error(ERR_NONFATAL, "OBJ supports no special symbol features"
                      " for this symbol type");
@@ -398,16 +825,20 @@ static void obj_deflabel (char *name, long segment,
     /*
      * Case (iii).
      */
-    ext = *exttail = nasm_malloc(sizeof(*ext));
-    ext->next = NULL;
-    exttail = &ext->next;
-    ext->name = name;
-    ext->defwrt_type = DEFWRT_NONE;
-    if (is_global == 2) {
-       ext->commonsize = offset;
-       ext->commonelem = 1;           /* default FAR */
-    } else
-       ext->commonsize = 0;
+    if (is_global) {
+        ext = *exttail = nasm_malloc(sizeof(*ext));
+        ext->next = NULL;
+        exttail = &ext->next;
+        ext->name = name;
+        ext->defwrt_type = DEFWRT_NONE;
+        if (is_global == 2) {
+           ext->commonsize = offset;
+           ext->commonelem = 1;               /* default FAR */
+        } else
+           ext->commonsize = 0;
+    }
+    else
+       return;
 
     /*
      * Now process the special text, if any, to find default-WRT
@@ -519,11 +950,13 @@ static void obj_deflabel (char *name, long segment,
 }
 
 static void obj_out (long segto, void *data, unsigned long type,
-                    long segment, long wrt) {
+                    long segment, long wrt) 
+{
     long size, realtype;
     unsigned char *ucdata;
     long ldata;
     struct Segment *seg;
+    ObjRecord *orp;
 
     /*
      * handle absolute-assembly (structure definitions)
@@ -554,26 +987,29 @@ static void obj_out (long segto, void *data, unsigned long type,
     if (!seg)
        error (ERR_PANIC, "code directed to nonexistent segment?");
 
+    orp = seg->orp;
+    orp->parm[0] = seg->currentpos;
+
     size = type & OUT_SIZMASK;
     realtype = type & OUT_TYPMASK;
     if (realtype == OUT_RAWDATA) {
        ucdata = data;
        while (size > 0) {
-           long len = obj_ledata_space(seg);
-           if (len == 0) {
-               obj_ledata_new(seg);
-               len = obj_ledata_space(seg);
-           }
+           unsigned int len;
+           orp = obj_check(seg->orp, 1);
+           len = RECORD_MAX - orp->used;
            if (len > size)
                len = size;
-           datacurr->lptr = obj_write_data (datacurr->lptr, ucdata, len);
-           datacurr->nonempty = TRUE;
+           memcpy (orp->buf+orp->used, ucdata, len);
+           orp->committed = orp->used += len;
+           orp->parm[0] = seg->currentpos += len;
            ucdata += len;
            size -= len;
-           seg->currentpos += len;
        }
-    } else if (realtype == OUT_ADDRESS || realtype == OUT_REL2ADR ||
-              realtype == OUT_REL4ADR) {
+    }
+    else if (realtype == OUT_ADDRESS || realtype == OUT_REL2ADR ||
+            realtype == OUT_REL4ADR) 
+    {
        int rsize;
 
        if (segment == NO_SEG && realtype != OUT_ADDRESS)
@@ -591,13 +1027,10 @@ static void obj_out (long segto, void *data, unsigned long type,
            ldata += (size-4);
            size = 4;
        }
-       if (obj_ledata_space(seg) < 4 || !obj_fixup_free(seg))
-           obj_ledata_new(seg);
        if (size == 2)
-           datacurr->lptr = obj_write_word (datacurr->lptr, ldata);
+           orp = obj_word (orp, ldata);
        else
-           datacurr->lptr = obj_write_dword (datacurr->lptr, ldata);
-       datacurr->nonempty = TRUE;
+           orp = obj_dword (orp, ldata);
        rsize = size;
        if (segment < SEG_ABS && (segment != NO_SEG && segment % 2) &&
            size == 4) {
@@ -614,67 +1047,28 @@ static void obj_out (long segto, void *data, unsigned long type,
                      " dword-size segment base references");
        }
        if (segment != NO_SEG)
-           obj_write_fixup (datacurr, rsize,
-                            (realtype == OUT_REL2ADR ||
-                             realtype == OUT_REL4ADR ? 0 : 0x4000),
-                            segment, wrt,
-                            (seg->currentpos - datacurr->startpos));
+           obj_write_fixup (orp, rsize,
+                            (realtype == OUT_ADDRESS  ? 0x4000 : 0),
+                            segment, wrt);
        seg->currentpos += size;
     } else if (realtype == OUT_RESERVE) {
-       obj_ledata_commit();
+       if (orp->committed)
+           orp = obj_bump(orp);
        seg->currentpos += size;
     }
+    obj_commit(orp);
 }
 
-static long obj_ledata_space(struct Segment *segto) {
-    if (datacurr && datacurr->seg == segto)
-       return datacurr->ledata + LEDATA_MAX - datacurr->lptr;
-    else
-       return 0;
-}
-
-static int obj_fixup_free(struct Segment *segto) {
-    if (datacurr && datacurr->seg == segto)
-       return (datacurr->fixupp + RECORD_MAX - datacurr->fptr) > 8;
-    else
-       return 0;
-}
-
-static void obj_ledata_new(struct Segment *segto) {
-    datacurr = *datatail = nasm_malloc(sizeof(*datacurr));
-    datacurr->next = NULL;
-    datatail = &datacurr->next;
-    datacurr->nonempty = FALSE;
-    datacurr->lptr = datacurr->ledata;
-    datacurr->fptr = datacurr->fixupp;
-    datacurr->seg = segto;
-    if (segto->use32)
-       datacurr->letype = LEDATA+1;
-    else
-       datacurr->letype = LEDATA;
-    datacurr->startpos = segto->currentpos;
-    datacurr->ftype = FIXUPP;
-
-    datacurr->lptr = obj_write_index (datacurr->lptr, segto->obj_index);
-    if (datacurr->letype == LEDATA)
-       datacurr->lptr = obj_write_word (datacurr->lptr, segto->currentpos);
-    else
-       datacurr->lptr = obj_write_dword (datacurr->lptr, segto->currentpos);
-}
-
-static void obj_ledata_commit(void) {
-    datacurr = NULL;
-}
-
-static void obj_write_fixup (struct ObjData *data, int bytes,
-                            int segrel, long seg, long wrt,
-                            long offset) {
+static void obj_write_fixup (ObjRecord *orp, int bytes,
+                            int segrel, long seg, long wrt) 
+{
     int locat, method;
     int base;
     long tidx, fidx;
     struct Segment *s = NULL;
     struct Group *g = NULL;
     struct External *e = NULL;
+    ObjRecord *forp;
 
     if (bytes == 1) {
        error(ERR_NONFATAL, "`obj' output driver does not support"
@@ -682,24 +1076,34 @@ static void obj_write_fixup (struct ObjData *data, int bytes,
        return;
     }
 
-    locat = 0x8000 | segrel | offset;
+    forp = orp->child;
+    if (forp == NULL) {
+       orp->child = forp = obj_new();
+       forp->up = &(orp->child);
+       forp->type = FIXUPP;
+    }
+
     if (seg % 2) {
        base = TRUE;
-       locat |= 0x800;
+       locat = FIX_16_SELECTOR;
        seg--;
        if (bytes != 2)
            error(ERR_PANIC, "OBJ: 4-byte segment base fixup got"
                  " through sanity check");
-    } else {
+    }
+    else {
        base = FALSE;
-       if (bytes == 2)
-           locat |= 0x400;
-       else {
-           locat |= 0x2400;
-           data->ftype = FIXUPP+1;    /* need new-style FIXUPP record */
-       }
+       locat = (bytes == 2) ? FIX_16_OFFSET : FIX_32_OFFSET;
+       if (!segrel)
+           /*
+            * There is a bug in tlink that makes it process self relative
+            * fixups incorrectly if the x_size doesn't match the location
+            * size.
+            */
+           forp = obj_force(forp, bytes<<3);
     }
-    data->fptr = obj_write_rword (data->fptr, locat);
+
+    forp = obj_rword (forp, locat | segrel | (orp->parm[0]-orp->parm[2]));
 
     tidx = fidx = -1, method = 0;      /* placate optimisers */
 
@@ -796,13 +1200,15 @@ static void obj_write_fixup (struct ObjData *data, int bytes,
        }
     }
 
-    data->fptr = obj_write_byte (data->fptr, method);
+    forp = obj_byte (forp, method);
     if (fidx != -1)
-       data->fptr = obj_write_index (data->fptr, fidx);
-    data->fptr = obj_write_index (data->fptr, tidx);
+       forp = obj_index (forp, fidx);
+    forp = obj_index (forp, tidx);
+    obj_commit (forp);
 }
 
-static long obj_segment (char *name, int pass, int *bits) {
+static long obj_segment (char *name, int pass, int *bits) 
+{
     /*
      * We call the label manager here to define a name for the new
      * segment, and when our _own_ label-definition stub gets
@@ -876,6 +1282,13 @@ static long obj_segment (char *name, int pass, int *bits) {
        seg->segclass = seg->overlay = NULL;
        seg->pubhead = NULL;
        seg->pubtail = &seg->pubhead;
+       seg->lochead = NULL;
+       seg->loctail = &seg->lochead;
+       seg->orp = obj_new();
+       seg->orp->up = &(seg->orp);
+       seg->orp->ori = ori_ledata;
+       seg->orp->type = LEDATA;
+       seg->orp->parm[1] = obj_idx;
 
        /*
         * Process the segment attributes.
@@ -1014,6 +1427,7 @@ static long obj_segment (char *name, int pass, int *bits) {
        while (*extp) {
            if ((*extp)->defwrt_type == DEFWRT_STRING &&
                !strcmp((*extp)->defwrt_ptr.string, seg->name)) {
+               nasm_free((*extp)->defwrt_ptr.string);
                (*extp)->defwrt_type = DEFWRT_SEGMENT;
                (*extp)->defwrt_ptr.seg = seg;
                *extp = (*extp)->next_dws;
@@ -1029,7 +1443,8 @@ static long obj_segment (char *name, int pass, int *bits) {
     }
 }
 
-static int obj_directive (char *directive, char *value, int pass) {
+static int obj_directive (char *directive, char *value, int pass) 
+{
     if (!strcmp(directive, "group")) {
        char *p, *q, *v;
        if (pass == 1) {
@@ -1129,6 +1544,7 @@ static int obj_directive (char *directive, char *value, int pass) {
            while (*extp) {
                if ((*extp)->defwrt_type == DEFWRT_STRING &&
                    !strcmp((*extp)->defwrt_ptr.string, grp->name)) {
+                   nasm_free((*extp)->defwrt_ptr.string);
                    (*extp)->defwrt_type = DEFWRT_GROUP;
                    (*extp)->defwrt_ptr.grp = grp;
                    *extp = (*extp)->next_dws;
@@ -1268,7 +1684,8 @@ static int obj_directive (char *directive, char *value, int pass) {
     return 0;
 }
 
-static long obj_segbase (long segment) {
+static long obj_segbase (long segment) 
+{
     struct Segment *seg;
 
     /*
@@ -1301,7 +1718,7 @@ static long obj_segbase (long segment) {
                return e->defwrt_ptr.seg->index+1;
            else if (e->defwrt_type == DEFWRT_GROUP)
                return e->defwrt_ptr.grp->index+1;
-           else if (e->defwrt_type == DEFWRT_STRING)
+           else
                return NO_SEG;         /* can't tell what it is */
        }
 
@@ -1316,121 +1733,133 @@ static long obj_segbase (long segment) {
     return segment;                   /* no special treatment */
 }
 
-static void obj_filename (char *inname, char *outname, efunc error) {
+static void obj_filename (char *inname, char *outname, efunc error) 
+{
     strcpy(obj_infile, inname);
     standard_extension (inname, outname, ".obj", error);
 }
 
-static void obj_write_file (void) {
-    struct Segment *seg;
+static void obj_write_file (int debuginfo) 
+{
+    struct Segment *seg, *entry_seg_ptr = 0;
+    struct FileName *fn;
+    struct LineNumber *ln;
     struct Group *grp;
-    struct Public *pub;
+    struct Public *pub, *loc;
     struct External *ext;
-    struct ObjData *data;
     struct ImpDef *imp;
     struct ExpDef *export;
     static char boast[] = "The Netwide Assembler " NASM_VER;
-    int lname_idx, rectype;
+    int lname_idx;
+    ObjRecord *orp;
 
     /*
      * Write the THEADR module header.
      */
-    recptr = record;
-    recptr = obj_write_name (recptr, obj_infile);
-    obj_record (THEADR, record, recptr);
+    orp = obj_new();
+    orp->type = THEADR;
+    obj_name (orp, obj_infile);
+    obj_emit2 (orp);
 
     /*
      * Write the NASM boast comment.
      */
-    recptr = record;
-    recptr = obj_write_rword (recptr, 0);   /* comment type zero */
-    recptr = obj_write_name (recptr, boast);
-    obj_record (COMENT, record, recptr);
+    orp->type = COMENT;
+    obj_rword (orp, 0);   /* comment type zero */
+    obj_name (orp, boast);
+    obj_emit2 (orp);
 
+    orp->type = COMENT;
     /*
      * Write the IMPDEF records, if any.
      */
     for (imp = imphead; imp; imp = imp->next) {
-       recptr = record;
-       recptr = obj_write_rword (recptr, 0xA0);   /* comment class A0 */
-       recptr = obj_write_byte (recptr, 1);   /* subfunction 1: IMPDEF */
+       obj_rword (orp, 0xA0);   /* comment class A0 */
+       obj_byte (orp, 1);   /* subfunction 1: IMPDEF */
        if (imp->impname)
-           recptr = obj_write_byte (recptr, 0);   /* import by name */
+           obj_byte (orp, 0);   /* import by name */
        else
-           recptr = obj_write_byte (recptr, 1);   /* import by ordinal */
-       recptr = obj_write_name (recptr, imp->extname);
-       recptr = obj_write_name (recptr, imp->libname);
+           obj_byte (orp, 1);   /* import by ordinal */
+       obj_name (orp, imp->extname);
+       obj_name (orp, imp->libname);
        if (imp->impname)
-           recptr = obj_write_name (recptr, imp->impname);
+           obj_name (orp, imp->impname);
        else
-           recptr = obj_write_word (recptr, imp->impindex);
-       obj_record (COMENT, record, recptr);
+           obj_word (orp, imp->impindex);
+       obj_emit2 (orp);
     }
 
     /*
      * Write the EXPDEF records, if any.
      */
     for (export = exphead; export; export = export->next) {
-       recptr = record;
-       recptr = obj_write_rword (recptr, 0xA0);   /* comment class A0 */
-       recptr = obj_write_byte (recptr, 2);   /* subfunction 1: EXPDEF */
-       recptr = obj_write_byte (recptr, export->flags);
-       recptr = obj_write_name (recptr, export->extname);
-       recptr = obj_write_name (recptr, export->intname);
+       obj_rword (orp, 0xA0);   /* comment class A0 */
+       obj_byte (orp, 2);   /* subfunction 2: EXPDEF */
+       obj_byte (orp, export->flags);
+       obj_name (orp, export->extname);
+       obj_name (orp, export->intname);
        if (export->flags & EXPDEF_FLAG_ORDINAL)
-           recptr = obj_write_word (recptr, export->ordinal);
-       obj_record (COMENT, record, recptr);
+           obj_word (orp, export->ordinal);
+       obj_emit2 (orp);
+    }
+
+    /* we're using extended OMF if we put in debug info*/
+    if (debuginfo) {
+      orp->type = COMENT;
+      obj_byte (orp, 0x40);
+      obj_byte (orp, dEXTENDED);
+      obj_emit2 (orp);
     }
 
     /*
      * Write the first LNAMES record, containing LNAME one, which
      * is null. Also initialise the LNAME counter.
      */
-    recptr = record;
-    recptr = obj_write_name (recptr, "");
-    obj_record (LNAMES, record, recptr);
-    lname_idx = 2;
+    orp->type = LNAMES;
+    obj_byte (orp, 0);
+    lname_idx = 1;
+    /*
+     * Write some LNAMES for the segment names
+     */
+    for (seg = seghead; seg; seg = seg->next) {
+       orp = obj_name (orp, seg->name);
+       if (seg->segclass)
+           orp = obj_name (orp, seg->segclass);
+       if (seg->overlay)
+           orp = obj_name (orp, seg->overlay);
+       obj_commit (orp);
+    }
+    /*
+     * Write some LNAMES for the group names
+     */
+    for (grp = grphead; grp; grp = grp->next) {
+       orp = obj_name (orp, grp->name);
+       obj_commit (orp);
+    }
+    obj_emit (orp);
+
 
     /*
-     * Write the SEGDEF records. Each has an associated LNAMES
-     * record.
+     * Write the SEGDEF records.
      */
+    orp->type = SEGDEF;
     for (seg = seghead; seg; seg = seg->next) {
-       int new_segdef;                /* do we use the newer record type? */
        int acbp;
-       int sn, cn, on;                /* seg, class, overlay LNAME idx */
-
-       if (seg->use32 || seg->currentpos >= 0x10000L)
-           new_segdef = TRUE;
-       else
-           new_segdef = FALSE;
-
-       recptr = record;
-       recptr = obj_write_name (recptr, seg->name);
-       sn = lname_idx++;
-       if (seg->segclass) {
-           recptr = obj_write_name (recptr, seg->segclass);
-           cn = lname_idx++;
-       } else
-           cn = 1;
-       if (seg->overlay) {
-           recptr = obj_write_name (recptr, seg->overlay);
-           on = lname_idx++;
-       } else
-           on = 1;
-       obj_record (LNAMES, record, recptr);
+       unsigned long seglen = seg->currentpos;
 
        acbp = (seg->combine << 2);    /* C field */
 
-       if (seg->currentpos >= 0x10000L && !new_segdef)
-           acbp |= 0x02;              /* B bit */
-
        if (seg->use32)
            acbp |= 0x01;              /* P bit is Use32 flag */
+       else if (seglen == 0x10000L) {
+           seglen = 0;                /* This special case may be needed for old linkers */
+           acbp |= 0x02;              /* B bit */
+       }
+
 
        /* A field */
        if (seg->align >= SEG_ABS)
-           acbp |= 0x00;
+           /* acbp |= 0x00 */;
        else if (seg->align >= 4096) {
            if (seg->align > 4096)
                error(ERR_NONFATAL, "segment `%s' requires more alignment"
@@ -1447,43 +1876,22 @@ static void obj_write_file (void) {
        } else
            acbp |= 0x20;
 
-       recptr = record;
-       recptr = obj_write_byte (recptr, acbp);
+       obj_byte (orp, acbp);
        if (seg->align & SEG_ABS) {
-           recptr = obj_write_word (recptr, seg->align - SEG_ABS);
-           recptr = obj_write_byte (recptr, 0);
-       }
-       if (new_segdef)
-           recptr = obj_write_dword (recptr, seg->currentpos);
-       else
-           recptr = obj_write_word (recptr, seg->currentpos & 0xFFFF);
-       recptr = obj_write_index (recptr, sn);
-       recptr = obj_write_index (recptr, cn);
-       recptr = obj_write_index (recptr, on);
-       if (new_segdef)
-           obj_record (SEGDEF+1, record, recptr);
-       else
-           obj_record (SEGDEF, record, recptr);
-    }
-
-    /*
-     * Write some LNAMES for the group names. lname_idx is left
-     * alone here - it will catch up when we write the GRPDEFs.
-     */
-    recptr = record;
-    for (grp = grphead; grp; grp = grp->next) {
-       if (recptr - record + strlen(grp->name)+2 > 1024) {
-           obj_record (LNAMES, record, recptr);
-           recptr = record;
+           obj_x (orp, seg->align - SEG_ABS);  /* Frame */
+           obj_byte (orp, 0);  /* Offset */
        }
-       recptr = obj_write_name (recptr, grp->name);
+       obj_x (orp, seglen);
+       obj_index (orp, ++lname_idx);
+       obj_index (orp, seg->segclass ? ++lname_idx : 1);
+       obj_index (orp, seg->overlay ? ++lname_idx : 1);
+       obj_emit2 (orp);
     }
-    if (recptr > record)
-       obj_record (LNAMES, record, recptr);
 
     /*
      * Write the GRPDEF records.
      */
+    orp->type = GRPDEF;
     for (grp = grphead; grp; grp = grp->next) {
        int i;
 
@@ -1495,96 +1903,76 @@ static void obj_write_file (void) {
                grp->segs[i].name = NULL;
            }
        }
-       recptr = record;
-       recptr = obj_write_index (recptr, lname_idx++);
+       obj_index (orp, ++lname_idx);
        for (i = 0; i < grp->nindices; i++) {
-           recptr = obj_write_byte (recptr, 0xFF);
-           recptr = obj_write_index (recptr, grp->segs[i].index);
+           obj_byte (orp, 0xFF);
+           obj_index (orp, grp->segs[i].index);
        }
-       obj_record (GRPDEF, record, recptr);
+       obj_emit2 (orp);
     }
 
     /*
      * Write the PUBDEF records: first the ones in the segments,
      * then the far-absolutes.
      */
+    orp->type = PUBDEF;
+    orp->ori = ori_pubdef;
     for (seg = seghead; seg; seg = seg->next) {
-       int any;
-
-       recptr = record;
-       recptr = obj_write_index (recptr, seg->grp ? seg->grp->obj_index : 0);
-       recptr = obj_write_index (recptr, seg->obj_index);
-       any = FALSE;
-       if (seg->use32)
-           rectype = PUBDEF+1;
-       else
-           rectype = PUBDEF;
+       orp->parm[0] = seg->grp ? seg->grp->obj_index : 0;
+       orp->parm[1] = seg->obj_index;
        for (pub = seg->pubhead; pub; pub = pub->next) {
-           if (recptr - record + strlen(pub->name) + 7 > 1024) {
-               if (any)
-                   obj_record (rectype, record, recptr);
-               recptr = record;
-               recptr = obj_write_index (recptr, 0);
-               recptr = obj_write_index (recptr, seg->obj_index);
-           }
-           recptr = obj_write_name (recptr, pub->name);
-           if (seg->use32)
-               recptr = obj_write_dword (recptr, pub->offset);
-           else
-               recptr = obj_write_word (recptr, pub->offset);
-           recptr = obj_write_index (recptr, 0);
-           any = TRUE;
+           orp = obj_name (orp, pub->name);
+           orp = obj_x (orp, pub->offset);
+           orp = obj_byte (orp, 0);  /* type index */
+           obj_commit (orp);
        }
-       if (any)
-           obj_record (rectype, record, recptr);
+       obj_emit (orp);
     }
+    orp->parm[0] = 0;
+    orp->parm[1] = 0;
     for (pub = fpubhead; pub; pub = pub->next) {   /* pub-crawl :-) */
-       recptr = record;
-       recptr = obj_write_index (recptr, 0);   /* no group */
-       recptr = obj_write_index (recptr, 0);   /* no segment either */
-       recptr = obj_write_word (recptr, pub->segment);
-       recptr = obj_write_name (recptr, pub->name);
-       recptr = obj_write_word (recptr, pub->offset);
-       recptr = obj_write_index (recptr, 0);
-       obj_record (PUBDEF, record, recptr);
+       if (orp->parm[2] != pub->segment) {
+           obj_emit (orp);
+           orp->parm[2] = pub->segment;
+       }
+       orp = obj_name (orp, pub->name);
+       orp = obj_x (orp, pub->offset);
+       orp = obj_byte (orp, 0);  /* type index */
+       obj_commit (orp);
     }
+    obj_emit (orp);
 
     /*
      * Write the EXTDEF and COMDEF records, in order.
      */
-    recptr = record;
+    orp->ori = ori_null;
     for (ext = exthead; ext; ext = ext->next) {
        if (ext->commonsize == 0) {
-           /* dj@delorie.com: check for buffer overrun before we overrun it */
-           if (recptr - record + strlen(ext->name)+2 > RECORD_MAX) {
-               obj_record (EXTDEF, record, recptr);
-               recptr = record;
+           if (orp->type != EXTDEF) {
+               obj_emit (orp);
+               orp->type = EXTDEF;
            }
-           recptr = obj_write_name (recptr, ext->name);
-           recptr = obj_write_index (recptr, 0);
+           orp = obj_name (orp, ext->name);
+           orp = obj_index (orp, 0);
        } else {
-           if (recptr > record)
-               obj_record (EXTDEF, record, recptr);
-           recptr = record;
-           if (ext->commonsize) {
-               recptr = obj_write_name (recptr, ext->name);
-               recptr = obj_write_index (recptr, 0);
-               if (ext->commonelem) {
-                   recptr = obj_write_byte (recptr, 0x61);/* far communal */
-                   recptr = obj_write_value (recptr, (ext->commonsize /
-                                                      ext->commonelem));
-                   recptr = obj_write_value (recptr, ext->commonelem);
-               } else {
-                   recptr = obj_write_byte (recptr, 0x62);/* near communal */
-                   recptr = obj_write_value (recptr, ext->commonsize);
-               }
-               obj_record (COMDEF, record, recptr);
+           if (orp->type != COMDEF) {
+               obj_emit (orp);
+               orp->type = COMDEF;
+           }
+           orp = obj_name (orp, ext->name);
+           orp = obj_index (orp, 0);
+           if (ext->commonelem) {
+               orp = obj_byte (orp, 0x61);/* far communal */
+               orp = obj_value (orp, (ext->commonsize / ext->commonelem));
+               orp = obj_value (orp, ext->commonelem);
+           } else {
+               orp = obj_byte (orp, 0x62);/* near communal */
+               orp = obj_value (orp, ext->commonsize);
            }
-           recptr = record;
        }
+       obj_commit (orp);
     }
-    if (recptr > record)
-       obj_record (EXTDEF, record, recptr);
+    obj_emit (orp);
 
     /*
      * Write a COMENT record stating that the linker's first pass
@@ -1592,150 +1980,251 @@ static void obj_write_file (void) {
      * MODEND record specifies a start point, in which case,
      * according to some variants of the documentation, this COMENT
      * should be omitted. So we'll omit it just in case.
+     * But, TASM puts it in all the time so if we are using
+     * TASM debug stuff we are putting it in
      */
-    if (obj_entry_seg == NO_SEG) {
-       recptr = record;
-       recptr = obj_write_rword (recptr, 0x40A2);
-       recptr = obj_write_byte (recptr, 1);
-       obj_record (COMENT, record, recptr);
-    }
+    if (debuginfo || obj_entry_seg == NO_SEG) {
+       orp->type = COMENT;
+        obj_byte (orp, 0x40);
+        obj_byte (orp, dLINKPASS);
+       obj_byte (orp, 1);
+       obj_emit2 (orp);
+    } 
 
     /*
-     * Write the LEDATA/FIXUPP pairs.
+     * 1) put out the compiler type
+     * 2) Put out the type info.  The only type we are using is near label #19
+     */
+    if (debuginfo) {
+      int i;
+      struct Array *arrtmp = arrhead;
+      orp->type = COMENT;
+      obj_byte (orp, 0x40);
+      obj_byte (orp, dCOMPDEF);
+      obj_byte (orp, 4);
+      obj_byte (orp, 0);
+      obj_emit2 (orp);
+
+      obj_byte (orp, 0x40);
+      obj_byte (orp, dTYPEDEF);
+      obj_word (orp, 0x18); /* type # for linking */
+      obj_word (orp, 6);    /* size of type */
+      obj_byte (orp, 0x2a); /* absolute type for debugging */
+      obj_emit2 (orp);
+      obj_byte (orp, 0x40);
+      obj_byte (orp, dTYPEDEF);
+      obj_word (orp, 0x19); /* type # for linking */
+      obj_word (orp, 0);    /* size of type */
+      obj_byte (orp, 0x24); /* absolute type for debugging */
+      obj_byte (orp, 0);    /* near/far specifier */
+      obj_emit2 (orp);
+      obj_byte (orp, 0x40);
+      obj_byte (orp, dTYPEDEF);
+      obj_word (orp, 0x1A); /* type # for linking */
+      obj_word (orp, 0);    /* size of type */
+      obj_byte (orp, 0x24); /* absolute type for debugging */
+      obj_byte (orp, 1);    /* near/far specifier */
+      obj_emit2 (orp);
+      obj_byte (orp, 0x40);
+      obj_byte (orp, dTYPEDEF);
+      obj_word (orp, 0x1b); /* type # for linking */
+      obj_word (orp, 0);    /* size of type */
+      obj_byte (orp, 0x23); /* absolute type for debugging */
+      obj_byte (orp, 0);
+      obj_byte (orp, 0);
+      obj_byte (orp, 0);
+      obj_emit2 (orp);
+      obj_byte (orp, 0x40);
+      obj_byte (orp, dTYPEDEF);
+      obj_word (orp, 0x1c); /* type # for linking */
+      obj_word (orp, 0);    /* size of type */
+      obj_byte (orp, 0x23); /* absolute type for debugging */
+      obj_byte (orp, 0);
+      obj_byte (orp, 4);
+      obj_byte (orp, 0);
+      obj_emit2 (orp);
+      obj_byte (orp, 0x40);
+      obj_byte (orp, dTYPEDEF);
+      obj_word (orp, 0x1d); /* type # for linking */
+      obj_word (orp, 0);    /* size of type */
+      obj_byte (orp, 0x23); /* absolute type for debugging */
+      obj_byte (orp, 0);
+      obj_byte (orp, 1);
+      obj_byte (orp, 0);
+      obj_emit2 (orp);
+      obj_byte (orp, 0x40);
+      obj_byte (orp, dTYPEDEF);
+      obj_word (orp, 0x1e); /* type # for linking */
+      obj_word (orp, 0);    /* size of type */
+      obj_byte (orp, 0x23); /* absolute type for debugging */
+      obj_byte (orp, 0);
+      obj_byte (orp, 5);
+      obj_byte (orp, 0);
+      obj_emit2 (orp);
+
+      /* put out the array types */
+      for (i= ARRAYBOT; i < arrindex; i++) {
+        obj_byte (orp, 0x40);
+       obj_byte (orp, dTYPEDEF);
+       obj_word (orp, i ); /* type # for linking */
+       obj_word (orp, arrtmp->size);    /* size of type */
+       obj_byte (orp, 0x1A); /* absolute type for debugging (array)*/
+       obj_byte (orp, arrtmp->basetype ); /* base type */
+       obj_emit2 (orp);
+        arrtmp = arrtmp->next ;
+      }
+    }
+    /*
+     * write out line number info with a LINNUM record
+     * switch records when we switch segments, and output the
+     * file in a pseudo-TASM fashion.  The record switch is naive; that
+     * is that one file may have many records for the same segment
+     * if there are lots of segment switches
      */
-    for (data = datahead; data; data = data->next) {
-       if (data->nonempty) {
-           obj_record (data->letype, data->ledata, data->lptr);
-           if (data->fptr != data->fixupp)
-               obj_record (data->ftype, data->fixupp, data->fptr);
+    if (fnhead && debuginfo) {
+       seg = fnhead->lnhead->segment;
+
+       for (fn = fnhead; fn; fn = fn->next) {
+           /* write out current file name */
+            orp->type = COMENT;
+            orp->ori = ori_null;
+           obj_byte (orp, 0x40);
+           obj_byte (orp, dFILNAME);
+            obj_byte( orp,0);
+            obj_name( orp,fn->name);
+            obj_dword(orp, 0);
+           obj_emit2 (orp);
+
+           /* write out line numbers this file */
+
+            orp->type = LINNUM;
+            orp->ori = ori_linnum;
+           for (ln = fn->lnhead; ln; ln = ln->next) {
+               if (seg != ln->segment) {
+                   /* if we get here have to flush the buffer and start
+                     * a new record for a new segment
+                    */
+                   seg = ln->segment;
+                   obj_emit ( orp );
+               }
+               orp->parm[0] = seg->grp ? seg->grp->obj_index : 0;
+               orp->parm[1] = seg->obj_index;
+               orp = obj_word(orp, ln->lineno);
+                orp = obj_x(orp, ln->offset);
+               obj_commit (orp);
+           }
+           obj_emit (orp);
        }
     }
-
     /*
-     * Write the MODEND module end marker.
+     * we are going to locate the entry point segment now
+     * rather than wait until the MODEND record, because,
+     * then we can output a special symbol to tell where the
+     * entry point is.
+     *
      */
-    recptr = record;
-    rectype = MODEND;
     if (obj_entry_seg != NO_SEG) {
-       recptr = obj_write_byte (recptr, 0xC1);
-       /*
-        * Find the segment in the segment list.
-        */
        for (seg = seghead; seg; seg = seg->next) {
            if (seg->index == obj_entry_seg) {
-               if (seg->grp) {
-                   recptr = obj_write_byte (recptr, 0x10);
-                   recptr = obj_write_index (recptr, seg->grp->obj_index);
-               } else {
-                   recptr = obj_write_byte (recptr, 0x50);
-               }
-               recptr = obj_write_index (recptr, seg->obj_index);
-               if (seg->use32) {
-                   rectype = MODEND+1;
-                   recptr = obj_write_dword (recptr, obj_entry_ofs);
-               } else
-                   recptr = obj_write_word (recptr, obj_entry_ofs);
+                entry_seg_ptr = seg;
                break;
            }
        }
        if (!seg)
            error(ERR_NONFATAL, "entry point is not in this module");
-    } else
-       recptr = obj_write_byte (recptr, 0);
-    obj_record (rectype, record, recptr);
-}
-
-static unsigned char *obj_write_data(unsigned char *ptr,
-                                    unsigned char *data, int len) {
-    while (len--)
-       *ptr++ = *data++;
-    return ptr;
-}
-
-static unsigned char *obj_write_byte(unsigned char *ptr, int data) {
-    *ptr++ = data;
-    return ptr;
-}
-
-static unsigned char *obj_write_word(unsigned char *ptr, int data) {
-    *ptr++ = data & 0xFF;
-    *ptr++ = (data >> 8) & 0xFF;
-    return ptr;
-}
-
-static unsigned char *obj_write_dword(unsigned char *ptr, long data) {
-    *ptr++ = data & 0xFF;
-    *ptr++ = (data >> 8) & 0xFF;
-    *ptr++ = (data >> 16) & 0xFF;
-    *ptr++ = (data >> 24) & 0xFF;
-    return ptr;
-}
-
-static unsigned char *obj_write_rword(unsigned char *ptr, int data) {
-    *ptr++ = (data >> 8) & 0xFF;
-    *ptr++ = data & 0xFF;
-    return ptr;
-}
-
-static unsigned char *obj_write_name(unsigned char *ptr, char *data) {
-    *ptr++ = strlen(data);
-    if (obj_uppercase) {
-       while (*data) {
-           *ptr++ = (unsigned char) toupper(*data);
-           data++;
-       }
-    } else {
-       while (*data)
-           *ptr++ = (unsigned char) *data++;
     }
-    return ptr;
-}
 
-static unsigned char *obj_write_index(unsigned char *ptr, int data) {
-    if (data < 128)
-       *ptr++ = data;
-    else {
-       *ptr++ = 0x80 | ((data >> 8) & 0x7F);
-       *ptr++ = data & 0xFF;
+    /*
+     * get ready to put out symbol records
+     */
+    orp->type = COMENT;
+    orp->ori = ori_local;
+   
+    /*
+     * put out a symbol for the entry point
+     * no dots in this symbol, because, borland does
+     * not (officially) support dots in label names
+     * and I don't know what various versions of TLINK will do
+     */
+    if (debuginfo && obj_entry_seg != NO_SEG) {
+        orp = obj_name (orp,"start_of_program");
+       orp = obj_word (orp,0x19);  /* type: near label */
+       orp = obj_index (orp, seg->grp ? seg->grp->obj_index : 0);
+       orp = obj_index (orp, seg->obj_index);
+       orp = obj_x (orp, obj_entry_ofs);
+       obj_commit (orp);
+    } 
+    /*
+     * put out the local labels
+     */
+    for (seg = seghead; seg && debuginfo; seg = seg->next) {
+        /* labels this seg */
+        for (loc = seg->lochead; loc; loc = loc->next) {
+            orp = obj_name (orp,loc->name);
+           orp = obj_word (orp, loc->type);
+           orp = obj_index (orp, seg->grp ? seg->grp->obj_index : 0);
+           orp = obj_index (orp, seg->obj_index);
+           orp = obj_x (orp,loc->offset);
+           obj_commit (orp);
+        }
     }
-    return ptr;
-}
+    if (orp->used)
+       obj_emit (orp);
 
-static unsigned char *obj_write_value(unsigned char *ptr,
-                                     unsigned long data) {
-    if (data <= 128)
-       *ptr++ = data;
-    else if (data <= 0xFFFF) {
-       *ptr++ = 129;
-       *ptr++ = data & 0xFF;
-       *ptr++ = (data >> 8) & 0xFF;
-    } else if (data <= 0xFFFFFFL) {
-       *ptr++ = 132;
-       *ptr++ = data & 0xFF;
-       *ptr++ = (data >> 8) & 0xFF;
-       *ptr++ = (data >> 16) & 0xFF;
-    } else {
-       *ptr++ = 136;
-       *ptr++ = data & 0xFF;
-       *ptr++ = (data >> 8) & 0xFF;
-       *ptr++ = (data >> 16) & 0xFF;
-       *ptr++ = (data >> 24) & 0xFF;
+    /*
+     * Write the LEDATA/FIXUPP pairs.
+     */
+    for (seg = seghead; seg; seg = seg->next) {
+       obj_emit (seg->orp);
+       nasm_free (seg->orp);
     }
-    return ptr;
+
+    /*
+     * Write the MODEND module end marker.
+     */
+    orp->type = MODEND;
+    orp->ori = ori_null;
+    if (entry_seg_ptr) {
+       obj_byte (orp, 0xC1);
+       seg = entry_seg_ptr;
+       if (seg->grp) {
+           obj_byte (orp, 0x10);
+           obj_index (orp, seg->grp->obj_index);
+       } else {
+           /*
+            * the below changed to prevent TLINK crashing.
+            * Previous more efficient version read:
+            *
+            *  obj_byte (orp, 0x50);
+            */
+           obj_byte (orp, 0x00);
+           obj_index (orp, seg->obj_index);
+       }
+       obj_index (orp, seg->obj_index);
+       obj_x (orp, obj_entry_ofs);
+    } else
+       obj_byte (orp, 0);
+    obj_emit2 (orp);
+    nasm_free (orp);
 }
 
-static void obj_record(int type, unsigned char *start, unsigned char *end) {
-    unsigned long cksum, len;
+void obj_fwrite(ObjRecord *orp) 
+{
+    unsigned int cksum, len;
+    unsigned char *ptr;
 
-    cksum = type;
-    fputc (type, ofp);
-    len = end-start+1;
+    cksum = orp->type;
+    if (orp->x_size == 32)
+       cksum |= 1;
+    fputc (cksum, ofp);
+    len = orp->committed+1;
     cksum += (len & 0xFF) + ((len>>8) & 0xFF);
     fwriteshort (len, ofp);
-    fwrite (start, 1, end-start, ofp);
-    while (start < end)
-       cksum += *start++;
-    fputc ( (-(long)cksum) & 0xFF, ofp);
+    fwrite (orp->buf, 1, len-1, ofp);
+    for (ptr=orp->buf; --len; ptr++)
+       cksum += *ptr;
+    fputc ( (-cksum) & 0xFF, ofp);
 }
 
 static char *obj_stdmac[] = {
@@ -1743,7 +2232,7 @@ static char *obj_stdmac[] = {
     "%imacro group 1+.nolist",
     "[group %1]",
     "%endmacro",
-    "%imacro uppercase 1+.nolist",
+    "%imacro uppercase 0+.nolist",
     "[uppercase %1]",
     "%endmacro",
     "%imacro export 1+.nolist",
@@ -1752,14 +2241,243 @@ static char *obj_stdmac[] = {
     "%imacro import 1+.nolist",
     "[import %1]",
     "%endmacro",
+    "%macro __NASM_CDecl__ 1",
+    "%endmacro",
     NULL
 };
 
+void dbgbi_init(struct ofmt * of, void * id, FILE * fp, efunc error)
+{
+    (void) of;
+    (void) id;
+    (void) fp;
+    (void) error;
+
+    fnhead = NULL;
+    fntail = &fnhead;
+    arrindex = ARRAYBOT ;
+    arrhead = NULL;
+    arrtail = &arrhead;
+}
+static void dbgbi_cleanup(void)
+{
+    struct Segment *segtmp;
+    while (fnhead) {
+       struct FileName *fntemp = fnhead;
+       while (fnhead->lnhead) {
+           struct LineNumber *lntemp = fnhead->lnhead;
+           fnhead->lnhead = lntemp->next;
+           nasm_free( lntemp);
+       }
+       fnhead = fnhead->next;
+       nasm_free (fntemp->name);
+       nasm_free (fntemp);
+    }
+    for (segtmp=seghead; segtmp; segtmp=segtmp->next) {
+       while (segtmp->lochead) {
+           struct Public *loctmp = segtmp->lochead;
+           segtmp->lochead = loctmp->next;
+           nasm_free (loctmp->name);
+           nasm_free (loctmp);
+       }
+    }
+    while (arrhead) {
+       struct Array *arrtmp = arrhead;
+        arrhead = arrhead->next;
+        nasm_free (arrtmp);
+    }
+}
+
+static void dbgbi_linnum (const char *lnfname, long lineno, long segto)
+{
+    struct FileName *fn;
+    struct LineNumber *ln;
+    struct Segment *seg;
+
+    if (segto == NO_SEG)
+       return;
+
+    /*
+     * If `any_segs' is still FALSE, we must define a default
+     * segment.
+     */
+    if (!any_segs) {
+       int tempint;                   /* ignored */
+       if (segto != obj_segment("__NASMDEFSEG", 2, &tempint))
+           error (ERR_PANIC, "strange segment conditions in OBJ driver");
+    }
+
+    /*
+     * Find the segment we are targetting.
+     */
+    for (seg = seghead; seg; seg = seg->next)
+       if (seg->index == segto)
+           break;
+    if (!seg)
+       error (ERR_PANIC, "lineno directed to nonexistent segment?");
+
+    for (fn = fnhead; fn; fn = fnhead->next)
+       if (!nasm_stricmp(lnfname,fn->name))
+           break;
+    if (!fn) {
+       fn = nasm_malloc ( sizeof( *fn));
+       fn->name = nasm_malloc ( strlen(lnfname) + 1) ;
+        strcpy (fn->name,lnfname);
+       fn->lnhead = NULL;
+       fn->lntail = & fn->lnhead;
+       fn->next = NULL;
+       *fntail = fn;
+       fntail = &fn->next;
+    }
+    ln = nasm_malloc ( sizeof( *ln));
+    ln->segment = seg;
+    ln->offset = seg->currentpos;
+    ln->lineno = lineno;
+    ln->next = NULL;
+    *fn->lntail = ln;
+    fn->lntail = &ln->next;
+
+}
+static void dbgbi_deflabel (char *name, long segment,
+                         long offset, int is_global, char *special) 
+{
+    struct Segment *seg;
+
+    (void) special;
+
+    /*
+     * If it's a special-retry from pass two, discard it.
+     */
+    if (is_global == 3)
+       return;
+
+    /*
+     * First check for the double-period, signifying something
+     * unusual.
+     */
+    if (name[0] == '.' && name[1] == '.' && name[2] != '@') {
+       return;
+    }
+
+    /*
+     * Case (i):
+     */
+    if (obj_seg_needs_update) {
+       return;
+    } else if (obj_grp_needs_update) {
+       return;
+    }
+    if (segment < SEG_ABS && segment != NO_SEG && segment % 2)
+       return;
+
+    if (segment >= SEG_ABS || segment == NO_SEG) {
+       return;
+    }
+
+    /*
+     * If `any_segs' is still FALSE, we might need to define a
+     * default segment, if they're trying to declare a label in
+     * `first_seg'.  But the label should exist due to a prior
+     * call to obj_deflabel so we can skip that.
+     */
+
+    for (seg = seghead; seg; seg = seg->next)
+       if (seg->index == segment) {
+           struct Public *loc = nasm_malloc (sizeof(*loc));
+           /*
+            * Case (ii). Maybe MODPUB someday?
+            */
+           last_defined = *seg->loctail = loc;
+           seg->loctail = &loc->next;
+           loc->next = NULL;
+           loc->name = nasm_strdup(name);
+           loc->offset = offset;
+       }
+}
+static void dbgbi_typevalue (long type)
+{
+    int vsize;
+    int elem = TYM_ELEMENTS(type);
+    type = TYM_TYPE(type);
+
+    if (!last_defined)
+       return;
+
+    switch (type) {
+       case TY_BYTE:
+           last_defined->type = 8; /* unsigned char */
+           vsize = 1;
+           break;
+       case TY_WORD:
+           last_defined->type = 10; /* unsigned word */
+           vsize = 2;
+           break;
+       case TY_DWORD:
+           last_defined->type = 12; /* unsigned dword */
+           vsize = 4;
+           break;
+       case TY_FLOAT:
+           last_defined->type = 14; /* float */
+           vsize = 4;
+           break;
+       case TY_QWORD:
+           last_defined->type = 15; /* qword */
+           vsize = 8;
+           break;
+       case TY_TBYTE:
+           last_defined->type = 16; /* TBYTE */
+           vsize = 10;
+           break;
+       default:
+           last_defined->type = 0x19; /*label */
+           vsize = 0;
+           break;
+    }
+                
+    if (elem > 1) {
+        struct Array *arrtmp = nasm_malloc (sizeof(*arrtmp));
+        int vtype = last_defined->type;
+        arrtmp->size = vsize * elem;
+        arrtmp->basetype = vtype;
+        arrtmp->next = NULL;
+        last_defined->type = arrindex++;
+        *arrtail = arrtmp;
+        arrtail = & (arrtmp->next);
+    }
+    last_defined = NULL;
+}
+static void dbgbi_output (int output_type, void *param)
+{
+    (void) output_type;
+    (void) param;
+}
+static struct dfmt borland_debug_form = {
+    "Borland Debug Records",
+    "borland",
+    dbgbi_init,
+    dbgbi_linnum,
+    dbgbi_deflabel,
+    null_debug_routine,
+    dbgbi_typevalue,
+    dbgbi_output,
+    dbgbi_cleanup,
+};
+
+static struct dfmt *borland_debug_arr[3] = {
+       &borland_debug_form,
+       &null_debug_form,
+       NULL
+};
+
 struct ofmt of_obj = {
-    "Microsoft MS-DOS 16-bit OMF object files",
+    "MS-DOS 16-bit/32-bit OMF object files",
     "obj",
+    NULL,
+    borland_debug_arr,
+    &null_debug_form,
     obj_stdmac,
     obj_init,
+    obj_set_info,
     obj_out,
     obj_deflabel,
     obj_segment,
index cde1327..d9989e5 100644 (file)
--- a/outrdf.c
+++ b/outrdf.c
@@ -316,6 +316,12 @@ static void rdf_out (long segto, void *data, unsigned long type,
   struct RelocRec rr;
   unsigned char databuf[4],*pd;
 
+  if (segto == NO_SEG) {
+      if ((type & OUT_TYPMASK) != OUT_RESERVE)
+         error (ERR_NONFATAL, "attempt to assemble code in ABSOLUTE space");
+      return;
+  }
+
   segto >>= 1;    /* convert NASM segment no to RDF number */
 
   if (segto != 0 && segto != 1 && segto != 2) {
@@ -426,11 +432,13 @@ static void rdf_out (long segto, void *data, unsigned long type,
   }
 }
 
-static void rdf_cleanup (void) {
+static void rdf_cleanup (int debuginfo) {
   long         l;
   unsigned char b[4],*d;
   struct BSSRec        bs;
 
+    (void) debuginfo;
+
 
   /* should write imported & exported symbol declarations to header here */
 
@@ -496,14 +504,29 @@ static char *rdf_stdmac[] = {
     "%imacro library 1+.nolist",
     "[library %1]",
     "%endmacro",
+    "%macro __NASM_CDecl__ 1",
+    "%endmacro",
     NULL
 };
 
+static int rdf_set_info(enum geninfo type, char **val)
+{
+    return 0;
+}
+
 struct ofmt of_rdf = {
   "Relocatable Dynamic Object File Format v1.1",
+#ifdef OF_RDF2
+  "oldrdf",
+#else
   "rdf",
+#endif
+  NULL,
+  null_debug_arr,
+  &null_debug_form,
   rdf_stdmac,
   rdf_init,
+  rdf_set_info,
   rdf_out,
   rdf_deflabel,
   rdf_section_names,
diff --git a/outrdf2.c b/outrdf2.c
new file mode 100644 (file)
index 0000000..4ae6799
--- /dev/null
+++ b/outrdf2.c
@@ -0,0 +1,690 @@
+/* outrdf2.c   output routines for the Netwide Assembler to produce
+ *             RDOFF version 2 format object files (which are intended
+ *             mainly for use in proprietary projects, as the code to 
+ *             load and execute them is very simple). They will also be 
+ *             used for device drivers and possibly some executable files
+ *             in the MOSCOW operating system. See Rdoff.txt for
+ *             details.
+ *
+ * The Netwide Assembler is copyright (C) 1996-1998 Simon Tatham and
+ * Julian Hall. All rights reserved. The software is
+ * redistributable under the licence given in the file "Licence"
+ * distributed in the NASM archive.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <assert.h>
+
+#include "nasm.h"
+#include "nasmlib.h"
+#include "outform.h"
+
+/* VERBOSE_WARNINGS: define this to add some extra warnings... */
+#define VERBOSE_WARNINGS     
+
+#ifdef OF_RDF2
+
+#define RDF_MAXSEGS 64 /* maximum number of segments - user configurable */
+
+typedef unsigned short int16;
+typedef unsigned char byte;
+
+static const char *RDOFF2Id = "RDOFF2";        /* written to start of RDOFF files */
+
+
+/* the records that can be found in the RDOFF header */
+
+/* Note that whenever a segment is referred to in the RDOFF file, its number
+ * is always half of the segment number that NASM uses to refer to it; this
+ * is because NASM only allocates even numbered segments, so as to not
+ * waste any of the 16 bits of segment number written to the file - this
+ * allows up to 65533 external labels to be defined; otherwise it would be
+ * 32764. */
+
+struct RelocRec {
+  byte type;           /* must be 1, or 6 for segment base ref */
+  byte reclen;         /* set to 8 */
+  byte segment;        /* only 0 for code, or 1 for data supported,
+                        * but add 64 for relative refs (ie do not require
+                        * reloc @ loadtime, only linkage) */
+  long offset;         /* from start of segment in which reference is loc'd */
+  byte length;         /* 1 2 or 4 bytes */
+  int16        refseg;         /* segment to which reference refers to */
+};
+
+struct ImportRec {
+  byte         type;           /* must be 2, or 7 for FAR import */
+  byte reclen;         /* equals 3+label length */
+  int16        segment;        /* segment number allocated to the label for reloc
+                        * records - label is assumed to be at offset zero
+                        * in this segment, so linker must fix up with offset
+                        * of segment and of offset within segment */
+  char label[33];      /* zero terminated... should be written to file until
+                        * the zero, but not after it - max len = 32 chars */
+};
+
+struct ExportRec {
+  byte type;           /* must be 3 */
+  byte  reclen;                /* equals 6+label length */
+  byte segment;        /* segment referred to (0/1) */
+  long offset;         /* offset within segment */
+  char label[33];      /* zero terminated as above. max len = 32 chars */
+};
+
+struct DLLRec {
+  byte type;           /* must be 4 */
+  byte  reclen;                /* equals 1+library name */
+  char libname[128];   /* name of library to link with at load time */
+};
+
+struct BSSRec {
+  byte type;           /* must be 5 */
+  byte  reclen;                /* equeals 4 */
+  long amount;         /* number of bytes BSS to reserve */
+};
+
+#define COUNT_SEGTYPES 9
+
+static char * segmenttypes[COUNT_SEGTYPES] = {
+  "null", "text", "code", "data", "comment", "lcomment", "pcomment",
+  "symdebug", "linedebug" 
+};
+
+static int segmenttypenumbers[COUNT_SEGTYPES] = {
+  0, 1, 1, 2, 3, 4, 5, 6, 7
+};
+
+/* code for managing buffers needed to seperate code and data into individual
+ * sections until they are ready to be written to the file.
+ * We'd better hope that it all fits in memory else we're buggered... */
+
+#define BUF_BLOCK_LEN 4088             /* selected to match page size (4096)
+                                         * on 80x86 machines for efficiency */
+
+/***********************************************************************
+ * Actual code to deal with RDOFF2 ouput format begins here...
+ */
+
+/* global variables set during the initialisation phase */
+
+static struct SAA *seg[RDF_MAXSEGS];   /* seg 0 = code, seg 1 = data */
+static struct SAA *header;     /* relocation/import/export records */
+
+static FILE *ofile;
+
+static efunc error;
+
+static struct seginfo {
+  char *segname;
+  int   segnumber;
+  int16 segtype;
+  int16 segreserved;
+  long  seglength;
+} segments[RDF_MAXSEGS];
+
+static int nsegments;
+
+static long bsslength;
+static long headerlength;
+
+static void rdf2_init(FILE *fp, efunc errfunc, ldfunc ldef, evalfunc eval)
+{
+  int segtext, segdata, segbss;
+
+  /* set up the initial segments */
+  segments[0].segname = ".text"; 
+  segments[0].segnumber = 0;
+  segments[0].segtype = 1;
+  segments[0].segreserved = 0;
+  segments[0].seglength = 0;
+
+  segments[1].segname = ".data";
+  segments[1].segnumber = 1;
+  segments[1].segtype = 2;
+  segments[1].segreserved = 0;
+  segments[1].seglength = 0;
+
+  segments[2].segname = ".bss";
+  segments[2].segnumber = 2;
+  segments[2].segtype = 0xFFFF;        /* reserved - should never be produced */
+  segments[2].segreserved = 0;
+  segments[2].seglength = 0;
+
+  nsegments = 3;
+
+  ofile = fp;
+  error = errfunc;
+
+  seg[0] = saa_init(1L);
+  seg[1] = saa_init(1L);
+  seg[2] = NULL;               /* special case! */
+
+  header = saa_init(1L);
+
+  segtext = seg_alloc();
+  segdata = seg_alloc();
+  segbss = seg_alloc();
+  if (segtext != 0 || segdata != 2 || segbss != 4)
+    error(ERR_PANIC,"rdf segment numbers not allocated as expected (%d,%d,%d)",
+         segtext,segdata,segbss);
+  bsslength=0;
+  headerlength = 0;
+}
+
+static long rdf2_section_names(char *name, int pass, int *bits)
+{
+  int  i;
+  char         * p, * q;
+  int  code = -1;
+  int  reserved = 0;
+
+  /*
+   * Default is 32 bits, in the text segment.
+   */
+  if (!name) {
+    *bits = 32;
+    return 0;
+  }
+
+  /* look for segment type code following segment name */
+  p = name;
+  while (*p && !isspace(*p)) p++;
+  if (*p) {    /* we're now in whitespace */
+    *p++ = '\0';
+    while (*p && isspace(80)) *p++ = '\0';
+  }
+  if (*p) {    /* we're now in an attribute value */
+    /*
+     * see if we have an optional ',number' following the type code
+     */
+    if ((q = strchr(p, ','))) {
+      *q++ = '\0';
+
+      reserved = readnum(q, &i);
+      if (i) {
+         error(ERR_NONFATAL, "value following comma must be numeric");
+         reserved = 0;
+      }
+    }
+    /*
+     * check it against the text strings in segmenttypes 
+     */
+
+    for (i = 0; i < COUNT_SEGTYPES; i++)
+      if (!nasm_stricmp(p, segmenttypes[i])) {
+       code = segmenttypenumbers[i];
+       break;
+      }
+    if (code == -1) {  /* didn't find anything */
+      code = readnum(p, &i);
+      if (i) {
+       error(ERR_NONFATAL, "unrecognised RDF segment type (%s)",p);
+       code = 3;
+      }
+    }
+  }    
+  for (i = 0; i < nsegments; i++) {
+    if (!strcmp(name, segments[i].segname)) {
+      if (code != -1 || reserved != 0) 
+       error(ERR_NONFATAL, "segment attributes specified on"
+             " redeclaration of segment");
+      return segments[i].segnumber * 2;
+    }
+  }
+
+  /* declaring a new segment! */
+
+  if (code == -1) {
+    error(ERR_NONFATAL, "new segment declared without type code");
+    code = 3;
+  }
+  if (nsegments == RDF_MAXSEGS) {
+    error(ERR_FATAL, "reached compiled-in maximum segment limit (%d)",
+         RDF_MAXSEGS);
+    return NO_SEG;
+  }
+
+  segments[nsegments].segname = nasm_strdup(name);
+  i = seg_alloc();
+  if (i % 2 != 0)
+    error(ERR_PANIC, "seg_alloc() returned odd number");
+  segments[nsegments].segnumber = i >> 1;
+  segments[nsegments].segtype = code;
+  segments[nsegments].segreserved = reserved;
+  segments[nsegments].seglength = 0;
+
+  seg[nsegments] = saa_init(1L);
+
+  return i;
+}
+
+static void write_reloc_rec(struct RelocRec *r)
+{
+  char buf[4],*b;
+
+  if (r->refseg != (int16)NO_SEG && (r->refseg & 1)) /* segment base ref */
+      r->type = 6;
+
+  r->refseg >>= 1;    /* adjust segment nos to RDF rather than NASM */
+
+  saa_wbytes(header,&r->type,1);
+  saa_wbytes(header,&r->reclen,1);
+  saa_wbytes(header,&r->segment,1);
+  b = buf; WRITELONG(b,r->offset);
+  saa_wbytes(header,buf,4);
+  saa_wbytes(header,&r->length,1);
+  b = buf; WRITESHORT(b,r->refseg);
+  saa_wbytes(header,buf,2);
+  headerlength += r->reclen + 2;
+}
+
+static void write_export_rec(struct ExportRec *r)
+{
+  char buf[4], *b;
+
+  r->segment >>= 1;
+
+  saa_wbytes(header,&r->type,1);
+  saa_wbytes(header,&r->reclen,1);
+  saa_wbytes(header,&r->segment,1);
+  b = buf; WRITELONG(b,r->offset);
+  saa_wbytes(header,buf,4);
+  saa_wbytes(header,r->label,strlen(r->label) + 1);
+  headerlength += r->reclen + 2;
+}
+
+static void write_import_rec(struct ImportRec *r)
+{
+  char buf[4], *b;
+
+  r->segment >>= 1;
+
+  saa_wbytes(header,&r->type,1);
+  saa_wbytes(header,&r->reclen,1);
+  b = buf; WRITESHORT(b,r->segment);
+  saa_wbytes(header,buf,2);
+  saa_wbytes(header,r->label,strlen(r->label) + 1);
+  headerlength += r->reclen + 2;
+}
+
+static void write_bss_rec(struct BSSRec *r)
+{
+    char buf[4], *b;
+
+    saa_wbytes(header,&r->type,1);
+    saa_wbytes(header,&r->reclen,1);
+    b = buf; WRITELONG(b,r->amount);
+    saa_wbytes(header,buf,4);
+    headerlength += r->reclen + 2;
+}
+
+static void write_dll_rec(struct DLLRec *r)
+{
+    saa_wbytes(header,&r->type,1);
+    saa_wbytes(header,&r->reclen,1);
+    saa_wbytes(header,r->libname,strlen(r->libname) + 1);
+    headerlength += r->reclen + 2;
+}
+
+static void rdf2_deflabel(char *name, long segment, long offset,
+                        int is_global, char *special)
+{
+  struct ExportRec r;
+  struct ImportRec ri;
+#ifdef VERBOSE_WARNINGS
+  static int warned_common = 0;
+#endif
+  static int farsym = 0;
+  static int i;
+
+  if (special) {
+    while(*special == ' ' || *special == '\t') special++;
+
+    if (!nasm_stricmp(special, "far")) {
+      farsym = 1;
+    }
+    else if (!nasm_stricmp(special, "near")) {
+      farsym = 0;
+    }
+    else
+      error(ERR_NONFATAL, "unrecognised symbol type `%s'", special);
+  }
+
+  if (name[0] == '.' && name[1] == '.' && name[2] != '@') {
+    error (ERR_NONFATAL, "unrecognised special symbol `%s'", name);
+    return;
+  }
+
+  if (is_global == 2) {
+#ifdef VERBOSE_WARNINGS
+    if (!warned_common) {
+      error(ERR_WARNING,"common declarations not supported: using extern");
+      warned_common = 1;
+    }
+#endif
+    is_global = 1;
+  }
+
+  for (i = 0; i < nsegments; i++) {
+    if (segments[i].segnumber == segment>>1) break;
+  }
+  if (i >= nsegments) {   /* EXTERN declaration */
+    if (farsym)
+      ri.type = 7;
+    else
+      ri.type = 2;
+    ri.segment = segment;
+    strncpy(ri.label,name,32);
+    ri.label[32] = 0;
+    ri.reclen = 3 + strlen(ri.label);
+    write_import_rec(&ri);
+  } else if (is_global) {
+    r.type = 3;
+    r.segment = segment;
+    r.offset = offset;
+    strncpy(r.label,name,32);
+    r.label[32] = 0;
+    r.reclen = 6 + strlen(r.label);
+    write_export_rec(&r);
+  }
+}
+
+static void membufwrite(int segment, void * data, int bytes)
+{
+  int i;
+  char buf[4], * b;
+
+  for (i = 0; i < nsegments; i++) {
+    if (segments[i].segnumber == segment) break;
+  }
+  if (i == nsegments)
+    error(ERR_PANIC, "can't find segment %d", segment);
+  
+  if (bytes < 0) {
+    b = buf;
+    if (bytes == -2)
+      WRITESHORT(b,*(short *)data);
+    else
+      WRITELONG(b,*(long *)data);
+    data = buf;
+    bytes = -bytes;
+  }
+  segments[i].seglength += bytes;
+  saa_wbytes(seg[i],data,bytes);
+}
+
+static int getsegmentlength(int segment)
+{
+  int i;
+  for (i = 0; i < nsegments; i++) {
+    if (segments[i].segnumber == segment) break;
+  }
+  if (i == nsegments)
+    error(ERR_PANIC, "can't find segment %d", segment);
+
+  return segments[i].seglength;
+}
+    
+static void rdf2_out (long segto, void *data, unsigned long type,
+                    long segment, long wrt)
+{
+  long bytes = type & OUT_SIZMASK;
+  struct RelocRec rr;
+  unsigned char databuf[4],*pd;
+  int seg;
+
+  if (segto == NO_SEG) {
+      if ((type & OUT_TYPMASK) != OUT_RESERVE)
+         error (ERR_NONFATAL, "attempt to assemble code in ABSOLUTE space");
+      return;
+  }
+
+  segto >>= 1;    /* convert NASM segment no to RDF number */
+
+  for (seg = 0; seg < nsegments; seg++) {
+    if (segments[seg].segnumber == segto) break;
+  }
+  if (seg >= nsegments) {
+    error(ERR_NONFATAL,"specified segment not supported by rdf output format");
+    return;
+  }
+
+  if (wrt != NO_SEG) {
+    wrt = NO_SEG;                     /* continue to do _something_ */
+    error (ERR_NONFATAL, "WRT not supported by rdf output format");
+  }
+
+  type &= OUT_TYPMASK;
+
+  if (segto == 2 && type != OUT_RESERVE)
+  {
+      error(ERR_NONFATAL, "BSS segments may not be initialised");
+
+      /* just reserve the space for now... */
+
+      if (type == OUT_REL2ADR)
+       bytes = 2;
+      else
+       bytes = 4;
+      type = OUT_RESERVE;
+  }
+
+  if (type == OUT_RESERVE) {
+      if (segto == 2)          /* BSS segment space reserverd */
+         bsslength += bytes;
+      else
+       while (bytes --)
+           membufwrite(segto,databuf,1);
+  }
+  else if (type == OUT_RAWDATA) {
+      if (segment != NO_SEG)
+         error(ERR_PANIC, "OUT_RAWDATA with other than NO_SEG");
+
+      membufwrite(segto,data,bytes);
+  }
+  else if (type == OUT_ADDRESS) {
+
+    /* if segment == NO_SEG then we are writing an address of an
+       object within the same segment - do not produce reloc rec. */
+
+    /* FIXME - is this behaviour sane? at first glance it doesn't
+       appear to be. Must test this thoroughly...! */
+
+    if (segment != NO_SEG)
+    {
+       /* it's an address, so we must write a relocation record */
+
+       rr.type = 1;            /* type signature */
+       rr.reclen = 8;
+       rr.segment = segto;             /* segment we're currently in */
+       rr.offset = getsegmentlength(segto);    /* current offset */
+       rr.length = bytes;              /* length of reference */
+       rr.refseg = segment;    /* segment referred to */
+       write_reloc_rec(&rr);
+    }
+
+    pd = databuf;      /* convert address to little-endian */
+    if (bytes == 2)
+      WRITESHORT (pd, *(long *)data);
+    else
+      WRITELONG (pd, *(long *)data);
+
+    membufwrite(segto,databuf,bytes);
+
+  }
+  else if (type == OUT_REL2ADR)
+  {
+    if (segment == segto)
+      error(ERR_PANIC, "intra-segment OUT_REL2ADR");
+
+    rr.reclen = 8;
+    rr.offset = getsegmentlength(segto);       /* current offset */
+    rr.length = 2;             /* length of reference */
+    rr.refseg = segment;       /* segment referred to (will be >>1'd)*/
+
+    if (segment != NO_SEG && segment % 2) {
+      rr.type = 6;
+      rr.segment = segto;      /* memory base refs *aren't ever* relative! */
+      write_reloc_rec(&rr);
+
+      /* what do we put in the code? Simply the data. This should almost
+       * always be zero, unless someone's doing segment arithmetic...
+       */
+      rr.offset = *(long *) data;
+    }
+    else
+    {
+      rr.type = 1;             /* type signature */
+      rr.segment = segto+64;   /* segment we're currently in + rel flag */
+      write_reloc_rec(&rr);
+
+      /* work out what to put in the code: offset of the end of this operand,
+       * subtracted from any data specified, so that loader can just add
+       * address of imported symbol onto it to get address relative to end of
+       * instruction: import_address + data(offset) - end_of_instrn */
+
+      rr.offset = *(long *)data -(rr.offset + bytes);
+    }
+    
+    membufwrite(segto,&rr.offset,-2);
+  }
+  else if (type == OUT_REL4ADR)
+  {
+    if (segment == segto)
+      error(ERR_PANIC, "intra-segment OUT_REL4ADR");
+    if (segment != NO_SEG && segment % 2) {
+      error(ERR_PANIC, "erm... 4 byte segment base ref?");
+    }
+
+    rr.type = 1;               /* type signature */
+    rr.segment = segto+64;     /* segment we're currently in + rel tag */
+    rr.offset = getsegmentlength(segto);       /* current offset */
+    rr.length = 4;             /* length of reference */
+    rr.refseg = segment;       /* segment referred to */
+    rr.reclen = 8;
+    write_reloc_rec(&rr);
+
+    rr.offset = *(long *)data -(rr.offset + bytes);
+
+    membufwrite(segto,&rr.offset,-4);
+  }
+}
+
+static void rdf2_cleanup (int debuginfo) {
+  long         l;
+  struct BSSRec        bs;
+  int          i;
+
+    (void) debuginfo;
+
+  /* should write imported & exported symbol declarations to header here */
+
+  /* generate the output file... */
+  fwrite(RDOFF2Id,6,1,ofile);  /* file type magic number */
+
+  if (bsslength != 0)          /* reserve BSS */
+  {
+      bs.type = 5;
+      bs.amount = bsslength;
+      bs.reclen = 4;
+      write_bss_rec(&bs);
+  }
+
+  /*
+   * calculate overall length of the output object
+   */
+  l = headerlength + 4;
+  
+  for (i = 0; i < nsegments; i++) {
+    if (i == 2) continue;      /* skip BSS segment */
+    l += 10 + segments[i].seglength;
+  }
+  l += 10;     /* null segment */
+
+  fwritelong(l, ofile);
+
+  fwritelong(headerlength, ofile);
+  saa_fpwrite(header,ofile);   /* dump header */
+  saa_free(header);
+
+  for (i = 0; i < nsegments; i++) {
+    if (i == 2) continue;
+
+    fwriteshort(segments[i].segtype, ofile);
+    fwriteshort(segments[i].segnumber, ofile);
+    fwriteshort(segments[i].segreserved, ofile);
+    fwritelong(segments[i].seglength, ofile);
+
+    saa_fpwrite(seg[i], ofile);
+    saa_free(seg[i]);
+  }
+
+  /* null segment - write 10 bytes of zero */
+  fwritelong(0,ofile);
+  fwritelong(0,ofile);
+  fwriteshort(0,ofile);
+
+  fclose(ofile);
+}
+
+static long rdf2_segbase (long segment) {
+    return segment;
+}
+
+static int rdf2_directive (char *directive, char *value, int pass) {
+    struct DLLRec r;
+    
+    if (! strcmp(directive, "library")) {
+       if (pass == 1) {
+           r.type = 4;
+           strcpy(r.libname, value);
+           write_dll_rec(&r);
+       }
+       return 1;
+    }
+
+    return 0;
+}
+
+static void rdf2_filename (char *inname, char *outname, efunc error) {
+  standard_extension(inname,outname,".rdf",error);
+}
+
+static char *rdf2_stdmac[] = {
+    "%define __SECT__ [section .text]",
+    "%imacro library 1+.nolist",
+    "[library %1]",
+    "%endmacro",
+    "%macro __NASM_CDecl__ 1",
+    "%endmacro",
+    NULL
+};
+
+static int rdf2_set_info(enum geninfo type, char **val)
+{
+    return 0;
+}
+
+
+struct ofmt of_rdf2 = {
+  "Relocatable Dynamic Object File Format v2.0",
+  "rdf",
+  NULL,
+  null_debug_arr,
+  &null_debug_form,
+  rdf2_stdmac,
+  rdf2_init,
+  rdf2_set_info,
+  rdf2_out,
+  rdf2_deflabel,
+  rdf2_section_names,
+  rdf2_segbase,
+  rdf2_directive,
+  rdf2_filename,
+  rdf2_cleanup
+};
+
+#endif /* OF_RDF2 */
index d7bbdb0..704e2eb 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -41,26 +41,34 @@ static int is_comma_next (void);
 static int i;
 static struct tokenval tokval;
 static efunc error;
+static struct ofmt *outfmt;  /* Structure of addresses of output routines */
+static loc_t *location;             /* Pointer to current line's segment,offset */
+
+void parser_global_info (struct ofmt *output, loc_t *locp) 
+{
+    outfmt = output;
+    location = locp;
+}
 
 insn *parse_line (int pass, char *buffer, insn *result,
-                 efunc errfunc, evalfunc evaluate, evalinfofunc einfo) {
+                 efunc errfunc, evalfunc evaluate, ldfunc ldef) 
+{
     int operand;
     int critical;
     struct eval_hints hints;
 
     result->forw_ref = FALSE;
     error = errfunc;
-    einfo ("", 0L, 0L);
 
     stdscan_reset();
     stdscan_bufptr = buffer;
     i = stdscan(NULL, &tokval);
 
+    result->label = NULL;             /* Assume no label */
     result->eops = NULL;              /* must do this, whatever happens */
     result->operands = 0;             /* must initialise this */
 
     if (i==0) {                               /* blank line - ignore */
-       result->label = NULL;          /* so, no label on it */
        result->opcode = -1;           /* and no instruction either */
        return result;
     }
@@ -68,23 +76,32 @@ insn *parse_line (int pass, char *buffer, insn *result,
        (i!=TOKEN_REG || (REG_SREG & ~reg_flags[tokval.t_integer]))) {
        error (ERR_NONFATAL, "label or instruction expected"
               " at start of line");
-       result->label = NULL;
        result->opcode = -1;
        return result;
     }
 
     if (i == TOKEN_ID) {              /* there's a label here */
        result->label = tokval.t_charptr;
-       einfo (result->label, 0L, 0L);
        i = stdscan(NULL, &tokval);
        if (i == ':') {                /* skip over the optional colon */
            i = stdscan(NULL, &tokval);
-       } else if (i == 0 && pass == 1) {
-           error (ERR_WARNING|ERR_WARN_OL,
+       } else if (i == 0) {
+           error (ERR_WARNING|ERR_WARN_OL|ERR_PASS1,
                   "label alone on a line without a colon might be in error");
        }
-    } else                            /* no label; so, moving swiftly on */
-       result->label = NULL;
+       if (i != TOKEN_INSN || tokval.t_integer != I_EQU)
+       {
+           /*
+            * FIXME: location->segment could be NO_SEG, in which case
+            * it is possible we should be passing 'abs_seg'. Look into this.
+            * Work out whether that is *really* what we should be doing.
+            * Generally fix things. I think this is right as it is, but
+            * am still not certain.
+            */
+           ldef (result->label, location->segment,
+                 location->offset, NULL, TRUE, FALSE, outfmt, errfunc);
+       }
+    }
 
     if (i==0) {
        result->opcode = -1;           /* this line contains just a label */
@@ -95,7 +112,8 @@ insn *parse_line (int pass, char *buffer, insn *result,
     result->times = 1L;
 
     while (i == TOKEN_PREFIX ||
-          (i==TOKEN_REG && !(REG_SREG & ~reg_flags[tokval.t_integer]))) {
+          (i==TOKEN_REG && !(REG_SREG & ~reg_flags[tokval.t_integer]))) 
+    {
        /*
         * Handle special case: the TIMES prefix.
         */
@@ -115,9 +133,11 @@ insn *parse_line (int pass, char *buffer, insn *result,
                result->times = 1L;
            } else {
                result->times = value->value;
-               if (value->value < 0)
+               if (value->value < 0) {
                    error(ERR_NONFATAL, "TIMES value %d is negative",
                          value->value);
+                   result->times = 0;
+               }
            }
        } else {
            if (result->nprefix == MAXPREFIX)
@@ -169,7 +189,9 @@ insn *parse_line (int pass, char *buffer, insn *result,
        result->opcode == I_RESQ ||
        result->opcode == I_REST ||
        result->opcode == I_EQU)
+    {
        critical = pass;
+    }
     else
        critical = (pass==2 ? 2 : 0);
 
@@ -178,12 +200,15 @@ insn *parse_line (int pass, char *buffer, insn *result,
        result->opcode == I_DD ||
        result->opcode == I_DQ ||
        result->opcode == I_DT ||
-       result->opcode == I_INCBIN) {
+       result->opcode == I_INCBIN) 
+    {
        extop *eop, **tail = &result->eops, **fixptr;
        int oper_num = 0;
 
+       result->eops_float = FALSE;
+
        /*
-        * Begin to read the DB/DW/DD/DQ/DT operands.
+        * Begin to read the DB/DW/DD/DQ/DT/INCBIN operands.
         */
        while (1) {
            i = stdscan(NULL, &tokval);
@@ -204,14 +229,14 @@ insn *parse_line (int pass, char *buffer, insn *result,
                continue;
            }
 
-           if (i == TOKEN_FLOAT || i == '-') {
+           if ((i == TOKEN_FLOAT && is_comma_next()) || i == '-') {
                long sign = +1L;
 
                if (i == '-') {
                    char *save = stdscan_bufptr;
                    i = stdscan(NULL, &tokval);
                    sign = -1L;
-                   if (i != TOKEN_FLOAT) {
+                   if (i != TOKEN_FLOAT || !is_comma_next()) {
                        stdscan_bufptr = save;
                        i = tokval.t_type = '-';
                    }
@@ -219,23 +244,30 @@ insn *parse_line (int pass, char *buffer, insn *result,
 
                if (i == TOKEN_FLOAT) {
                    eop->type = EOT_DB_STRING;
+                   result->eops_float = TRUE;
                    if (result->opcode == I_DD)
                        eop->stringlen = 4;
                    else if (result->opcode == I_DQ)
                        eop->stringlen = 8;
                    else if (result->opcode == I_DT)
-                   eop->stringlen = 10;
+                       eop->stringlen = 10;
                    else {
                        error(ERR_NONFATAL, "floating-point constant"
                              " encountered in `D%c' instruction",
                              result->opcode == I_DW ? 'W' : 'B');
-                       eop->type = EOT_NOTHING;
+                       /*
+                        * fix suggested by Pedro Gimeno... original line
+                        * was:
+                        * eop->type = EOT_NOTHING;
+                        */
+                       eop->stringlen = 0;
                    }
                    eop = nasm_realloc(eop, sizeof(extop)+eop->stringlen);
                    tail = &eop->next;
                    *fixptr = eop;
                    eop->stringval = (char *)eop + sizeof(extop);
-                   if (!float_const (tokval.t_charptr, sign,
+                   if (eop->stringlen < 4 ||
+                       !float_const (tokval.t_charptr, sign,
                                      (unsigned char *)eop->stringval,
                                      eop->stringlen, error))
                        eop->type = EOT_NOTHING;
@@ -244,7 +276,8 @@ insn *parse_line (int pass, char *buffer, insn *result,
                }
            }
 
-           /* anything else */ {
+           /* anything else */ 
+           {
                expr *value;
                value = evaluate (stdscan, NULL, &tokval, NULL,
                                  critical, error, NULL);
@@ -312,7 +345,12 @@ insn *parse_line (int pass, char *buffer, insn *result,
             */
            result->opcode = -1;
            return result;
-       }
+       } else /* DB ... */
+           if (oper_num == 0)
+               error (ERR_WARNING|ERR_PASS1,
+                      "no operand for data declaration");
+            else
+                result->operands = oper_num;
 
        return result;
     }
@@ -324,29 +362,42 @@ insn *parse_line (int pass, char *buffer, insn *result,
        expr *value;                   /* used most of the time */
        int mref;                      /* is this going to be a memory ref? */
        int bracket;                   /* is it a [] mref, or a & mref? */
+       int setsize = 0;
 
        result->oprs[operand].addr_size = 0;/* have to zero this whatever */
        result->oprs[operand].eaflags = 0;   /* and this */
+       result->oprs[operand].opflags = 0;
+
        i = stdscan(NULL, &tokval);
        if (i == 0) break;             /* end of operands: get out of here */
        result->oprs[operand].type = 0;   /* so far, no override */
        while (i == TOKEN_SPECIAL)      {/* size specifiers */
            switch ((int)tokval.t_integer) {
              case S_BYTE:
-               result->oprs[operand].type |= BITS8;
+               if (!setsize)            /* we want to use only the first */
+                   result->oprs[operand].type |= BITS8;
+               setsize = 1;
                break;
              case S_WORD:
-               result->oprs[operand].type |= BITS16;
+               if (!setsize)
+                   result->oprs[operand].type |= BITS16;
+               setsize = 1;
                break;
              case S_DWORD:
              case S_LONG:
-               result->oprs[operand].type |= BITS32;
+               if (!setsize)
+                   result->oprs[operand].type |= BITS32;
+               setsize = 1;
                break;
              case S_QWORD:
-               result->oprs[operand].type |= BITS64;
+               if (!setsize)
+                   result->oprs[operand].type |= BITS64;
+               setsize = 1;
                break;
              case S_TWORD:
-               result->oprs[operand].type |= BITS80;
+               if (!setsize)
+                   result->oprs[operand].type |= BITS80;
+               setsize = 1;
                break;
              case S_TO:
                result->oprs[operand].type |= TO;
@@ -360,6 +411,8 @@ insn *parse_line (int pass, char *buffer, insn *result,
              case S_SHORT:
                result->oprs[operand].type |= SHORT;
                break;
+             default:
+               error (ERR_NONFATAL, "invalid operand size specification");
            }
            i = stdscan(NULL, &tokval);
        }
@@ -397,8 +450,12 @@ insn *parse_line (int pass, char *buffer, insn *result,
        }
 
        value = evaluate (stdscan, NULL, &tokval,
-                         &result->forw_ref, critical, error, &hints);
+                         &result->oprs[operand].opflags,
+                         critical, error, &hints);
        i = tokval.t_type;
+       if (result->oprs[operand].opflags & OPFLAG_FORWARD) {
+           result->forw_ref = TRUE;
+       }
        if (!value) {                  /* error in evaluator */
            result->opcode = -1;       /* unrecoverable parse error: */
            return result;             /* ignore this instruction */
@@ -434,8 +491,12 @@ insn *parse_line (int pass, char *buffer, insn *result,
                i = stdscan(NULL, &tokval);
            }
            value = evaluate (stdscan, NULL, &tokval,
-                             &result->forw_ref, critical, error, &hints);
+                             &result->oprs[operand].opflags,
+                             critical, error, &hints);
            i = tokval.t_type;
+           if (result->oprs[operand].opflags & OPFLAG_FORWARD) {
+               result->forw_ref = TRUE;
+           }
            /* and get the offset */
            if (!value) {              /* but, error in evaluator */
                result->opcode = -1;   /* unrecoverable parse error: */
@@ -480,34 +541,38 @@ insn *parse_line (int pass, char *buffer, insn *result,
                    i = e->type, s = e->value;
                e++;
            }
-           if (e->type && e->type <= EXPR_REG_END) {/* it's a 2nd register */
-               if (e->value != 1) {   /* it has to be indexreg */
-                   if (i != -1) {     /* but it can't be */
-                       error(ERR_NONFATAL, "invalid effective address");
-                       result->opcode = -1;
-                       return result;
-                   } else
-                       i = e->type, s = e->value;
-               } else {               /* it can be basereg */
-                   if (b != -1)       /* or can it? */
-                       i = e->type, s = 1;
-                   else
-                       b = e->type;
-               }
+           if (e->type && e->type <= EXPR_REG_END)   /* it's a 2nd register */
+           {
+               if (b != -1)               /* If the first was the base, ... */
+                   i = e->type, s = e->value;  /* second has to be indexreg */
+
+               else if (e->value != 1)          /* If both want to be index */
+               {
+                   error(ERR_NONFATAL, "invalid effective address");
+                   result->opcode = -1;
+                   return result;
+               } 
+               else
+                   b = e->type;
                e++;
            }
            if (e->type != 0) {        /* is there an offset? */
-               if (e->type <= EXPR_REG_END) {/* in fact, is there an error? */
+               if (e->type <= EXPR_REG_END)  /* in fact, is there an error? */
+               {
                    error (ERR_NONFATAL, "invalid effective address");
                    result->opcode = -1;
                    return result;
-               } else {
+               } 
+               else 
+               {
                    if (e->type == EXPR_UNKNOWN) {
-                       o = 0;         /* doesn't matter what */
-                       result->oprs[operand].wrt = NO_SEG;   /* nor this */
+                       o = 0;                       /* doesn't matter what */
+                       result->oprs[operand].wrt = NO_SEG;     /* nor this */
                        result->oprs[operand].segment = NO_SEG;  /* or this */
                        while (e->type) e++;   /* go to the end of the line */
-                   } else {
+                   } 
+                   else 
+                   {
                        if (e->type == EXPR_SIMPLE) {
                            o = e->value;
                            e++;
@@ -566,30 +631,63 @@ insn *parse_line (int pass, char *buffer, insn *result,
            result->oprs[operand].indexreg = i;
            result->oprs[operand].scale = s;
            result->oprs[operand].offset = o;
-       } else {                       /* it's not a memory reference */
+       } 
+       else                                  /* it's not a memory reference */
+       {
            if (is_just_unknown(value)) {     /* it's immediate but unknown */
                result->oprs[operand].type |= IMMEDIATE;
                result->oprs[operand].offset = 0;   /* don't care */
                result->oprs[operand].segment = NO_SEG; /* don't care again */
                result->oprs[operand].wrt = NO_SEG;/* still don't care */
-           } else if (is_reloc(value)) {     /* it's immediate */
+           } 
+           else if (is_reloc(value))         /* it's immediate */
+           {
                result->oprs[operand].type |= IMMEDIATE;
                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;
-           } else {           /* it's a register */
+           } 
+           else               /* it's a register */
+           {
+               int i;
+
                if (value->type>=EXPR_SIMPLE || value->value!=1) {
                    error (ERR_NONFATAL, "invalid operand type");
                    result->opcode = -1;
                    return result;
                }
+
+               /*
+                * check that its only 1 register, not an expression...
+                */
+               for (i = 1; value[i].type; i++)
+                   if (value[i].value) {
+                       error (ERR_NONFATAL, "invalid operand type");
+                       result->opcode = -1;
+                       return result;
+                   }
+
                /* clear overrides, except TO which applies to FPU regs */
+               if (result->oprs[operand].type & ~TO) {
+                   /*
+                    * we want to produce a warning iff the specified size
+                    * is different from the register size
+                    */
+                   i = result->oprs[operand].type & SIZE_MASK;
+               }
+               else
+                   i = 0;
+
                result->oprs[operand].type &= TO;
                result->oprs[operand].type |= REGISTER;
                result->oprs[operand].type |= reg_flags[value->type];
                result->oprs[operand].basereg = value->type;
+
+               if (i && (result->oprs[operand].type & SIZE_MASK) != i)
+                   error (ERR_WARNING|ERR_PASS1,
+                          "register size specification ignored");
            }
        }
     }
@@ -612,7 +710,8 @@ insn *parse_line (int pass, char *buffer, insn *result,
     return result;
 }
 
-static int is_comma_next (void) {
+static int is_comma_next (void) 
+{
     char *p;
     int i;
     struct tokenval tv;
@@ -623,7 +722,8 @@ static int is_comma_next (void) {
     return (i == ',' || i == ';' || !i);
 }
 
-void cleanup_insn (insn *i) {
+void cleanup_insn (insn *i) 
+{
     extop *e;
 
     while (i->eops) {
index 0681cd0..bc2135d 100644 (file)
--- a/parser.h
+++ b/parser.h
@@ -10,8 +10,9 @@
 #ifndef NASM_PARSER_H
 #define NASM_PARSER_H
 
+void parser_global_info (struct ofmt *output, loc_t *locp);
 insn *parse_line (int pass, char *buffer, insn *result,
-                 efunc error, evalfunc evaluate, evalinfofunc einfo);
+                 efunc error, evalfunc evaluate, ldfunc ldef);
 void cleanup_insn (insn *instruction);
 
 #endif
index 032854e..291b57e 100644 (file)
--- a/preproc.c
+++ b/preproc.c
@@ -8,6 +8,11 @@
  * initial version 18/iii/97 by Simon Tatham
  */
 
+#define br0 '{'
+#define br1 "{"
+#define br2 '}'
+#define br3 "}"
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <stddef.h>
@@ -64,12 +69,14 @@ struct MMacro {
     int plus;                         /* is the last parameter greedy? */
     int nolist;                               /* is this macro listing-inhibited? */
     int in_progress;
-    Token **defaults, *dlist;
+    Token *dlist;                     /* All defaults as one list */
+    Token **defaults;                 /* Parameter default pointers */
     int ndefs;                        /* number of default parameters */
     Line *expansion;
 
     MMacro *next_active;
-    Token **params, *iline;
+    Token **params;                   /* actual parameters */
+    Token *iline;                     /* invocation line */
     int nparam, rotate, *paramlen;
     unsigned long unique;
 };
@@ -88,11 +95,6 @@ struct Context {
  * This is the internal form which we break input lines up into.
  * Typically stored in linked lists.
  *
- * TOK_PS_OTHER is a token type used internally within
- * expand_smacro(), to denote a token which has already been
- * checked for being a potential macro, but may still be a context-
- * local label.
- *
  * Note that `type' serves a double meaning: TOK_SMAC_PARAM is not
  * necessarily used as-is, but is intended to denote the number of
  * the substituted parameter. So in the definition
@@ -116,7 +118,7 @@ struct Token {
 };
 enum {
     TOK_WHITESPACE = 1, TOK_COMMENT, TOK_ID, TOK_PREPROC_ID, TOK_STRING,
-    TOK_NUMBER, TOK_SMAC_END, TOK_OTHER, TOK_PS_OTHER, TOK_SMAC_PARAM,
+    TOK_NUMBER, TOK_SMAC_END, TOK_OTHER, TOK_SMAC_PARAM,
     TOK_INTERNAL_STRING
 };
 
@@ -271,14 +273,14 @@ static int pass;
 
 static unsigned long unique;          /* unique identifier numbers */
 
-static char *linesync, *outline;
-
 static Line *predef = NULL;
 
 static ListGen *list;
 
 /*
  * The number of hash values we use for the macro lookup tables.
+ * FIXME: We should *really* be able to configure this at run time,
+ * or even have the hash table automatically expanding when necessary.
  */
 #define NHASH 31
 
@@ -321,7 +323,15 @@ int any_extrastdmac;
  * Forward declarations.
  */
 static Token *expand_smacro (Token *tline);
-static void update_fileline (int which);
+static void make_tok_num(Token *tok, long val);
+
+/*
+ * Macros for safe checking of token pointers, avoid *(NULL)
+ */
+#define tok_type_(x,t) ((x) && (x)->type == (t))
+#define skip_white_(x) if (tok_type_((x), TOK_WHITESPACE)) (x)=(x)->next
+#define tok_is_(x,v) (tok_type_((x), TOK_OTHER) && !strcmp((x)->text,(v)))
+#define tok_isnt_(x,v) ((x) && ((x)->type!=TOK_OTHER || strcmp((x)->text,(v))))
 
 /*
  * The pre-preprocessing stage... This function translates line
@@ -329,7 +339,8 @@ static void update_fileline (int which);
  * flags') into NASM preprocessor line number indications (`%line
  * lineno file').
  */
-static char *prepreproc(char *line) {
+static char *prepreproc(char *line) 
+{
     int lineno, fnlen;
     char *fname, *oldline;
 
@@ -354,7 +365,10 @@ static char *prepreproc(char *line) {
  * invariant under case changes. We implement this by applying a
  * perfectly normal hash function to the uppercase of the string.
  */
-static int hash(char *s) {
+static int hash(char *s) 
+{
+    unsigned int h = 0;
+    int i = 0;
     /*
      * Powers of three, mod 31.
      */
@@ -362,8 +376,7 @@ static int hash(char *s) {
        1, 3, 9, 27, 19, 26, 16, 17, 20, 29, 25, 13, 8, 24, 10,
        30, 28, 22, 4, 12, 5, 15, 14, 11, 2, 6, 18, 23, 7, 21
     };
-    int h = 0;
-    int i = 0;
+
 
     while (*s) {
        h += multipliers[i] * (unsigned char) (toupper(*s));
@@ -378,7 +391,8 @@ static int hash(char *s) {
 /*
  * Free a linked list of tokens.
  */
-static void free_tlist (Token *list) {
+static void free_tlist (Token *list) 
+{
     Token *t;
     while (list) {
        t = list;
@@ -391,7 +405,8 @@ static void free_tlist (Token *list) {
 /*
  * Free a linked list of lines.
  */
-static void free_llist (Line *list) {
+static void free_llist (Line *list) 
+{
     Line *l;
     while (list) {
        l = list;
@@ -402,9 +417,22 @@ static void free_llist (Line *list) {
 }
 
 /*
+ * Free an MMacro
+ */
+static void free_mmacro (MMacro *m) 
+{
+    nasm_free (m->name);
+    free_tlist (m->dlist);
+    nasm_free (m->defaults);
+    free_llist (m->expansion);
+    nasm_free (m);
+}
+
+/*
  * Pop the context stack.
  */
-static void ctx_pop (void) {
+static void ctx_pop (void) 
+{
     Context *c = cstk;
     SMacro *smac, *s;
 
@@ -421,19 +449,6 @@ static void ctx_pop (void) {
     nasm_free (c);
 }
 
-/*
- * Generate a line synchronisation comment, to ensure the assembler
- * knows which source file the current output has really come from.
- */
-static void line_sync (void) {
-    char text[30+FILENAME_MAX];
-    sprintf(text, "%%line %d+%d %s",
-           (istk->expansion ? istk->lineno - istk->lineinc : istk->lineno),
-           (istk->expansion ? 0 : istk->lineinc), istk->fname);
-    nasm_free (linesync);
-    linesync = nasm_strdup(text);
-}
-
 #define BUF_DELTA 512
 /*
  * Read a line from the top file in istk, handling multiple CR/LFs
@@ -441,14 +456,16 @@ static void line_sync (void) {
  * return lines from the standard macro set if this has not already
  * been done.
  */
-static char *read_line (void) {
+static char *read_line (void) 
+{
     char *buffer, *p, *q;
     int bufsize;
 
     if (stdmacpos) {
        if (*stdmacpos) {
            char *ret = nasm_strdup(*stdmacpos++);
-           if (!*stdmacpos && any_extrastdmac) {
+           if (!*stdmacpos && any_extrastdmac) 
+           {
                stdmacpos = extrastdmac;
                any_extrastdmac = FALSE;
                return ret;
@@ -459,7 +476,8 @@ static char *read_line (void) {
             * most convenient way to implement the pre-include and
             * pre-define features.
             */
-           if (!*stdmacpos) {
+           if (!*stdmacpos) 
+           {
                Line *pd, *l;
                Token *head, **tail, *t, *tt;
 
@@ -482,10 +500,9 @@ static char *read_line (void) {
                }
            }
            return ret;
-       } else {
+       } 
+       else {
            stdmacpos = NULL;
-           line_sync();
-           update_fileline(3);        /* update __FILE__ and __LINE__ */
        }
     }
 
@@ -498,13 +515,13 @@ static char *read_line (void) {
            break;
        p += strlen(p);
        if (p > buffer && p[-1] == '\n') {
-           istk->lineno += istk->lineinc;
-           update_fileline(1);        /* update __LINE__ only */
            break;
        }
        if (p-buffer > bufsize-10) {
+           long offset = p-buffer;
            bufsize += BUF_DELTA;
            buffer = nasm_realloc(buffer, bufsize);
+           p = buffer+offset;         /* prevent stale-pointer problems */
        }
     }
 
@@ -513,12 +530,14 @@ static char *read_line (void) {
        return NULL;
     }
 
+    src_set_linnum(src_get_linnum() + istk->lineinc);
+
     /*
      * Play safe: remove CRs as well as LFs, if any of either are
      * present at the end of the line.
      */
-    while (p > buffer && (p[-1] == '\n' || p[-1] == '\r'))
-       *--p = '\0';
+    while (--p >= buffer && (*p == '\n' || *p == '\r'))
+       *p = '\0';
 
     /*
      * Handle spurious ^Z, which may be inserted into source files
@@ -536,7 +555,8 @@ static char *read_line (void) {
  * don't need to parse the value out of e.g. numeric tokens: we
  * simply split one string into many.
  */
-static Token *tokenise (char *line) {
+static Token *tokenise (char *line) 
+{
     char *p = line;
     int type;
     Token *list = NULL;
@@ -544,31 +564,42 @@ static Token *tokenise (char *line) {
 
     while (*line) {
        p = line;
-       if (*p == '%' &&
-           (p[1] == '{' || p[1] == '!' || (p[1] == '%' && isidchar(p[2])) ||
-            p[1] == '$' || p[1] == '+' || p[1] == '-' || isidchar(p[1]))) {
-           type = TOK_PREPROC_ID;
+       if (*p == '%' && ( isdigit(p[1]) || 
+             ((p[1] == '-' || p[1] == '+') && isdigit(p[2]))))
+       {
            p++;
-           if (*p == '{') {
+           do {
+               p++;
+           } while (isdigit(*p));
+           type = TOK_PREPROC_ID;
+       }
+       else if (*p == '%' && p[1] == '{') {
+           p += 2;
+           while (*p && *p != '}') {
+               p[-1] = *p;
                p++;
-               while (*p && *p != '}') {
-                   p[-1] = *p;
-                   p++;
-               }
-               p[-1] = '\0';
-               if (*p) p++;
-           } else {
-               if (*p == '!' || *p == '%' || *p == '$' ||
-                   *p == '+' || *p == '-') p++;
-               while (*p && isidchar(*p))
-                   p++;
            }
-       } else if (isidstart(*p) || (*p == '$' && isidstart(p[1]))) {
+           p[-1] = '\0';
+           if (*p) p++;
+           type = TOK_PREPROC_ID;
+       }
+       else if (*p == '%' && (isidchar(p[1]) ||
+                 ((p[1] == '!' || p[1] == '%' || p[1] == '$') &&
+                 isidchar(p[2]))))
+       {
+           p++;
+           do {
+               p++;
+           } while (isidchar(*p));
+           type = TOK_PREPROC_ID;
+       }
+       else if (isidstart(*p) || (*p == '$' && isidstart(p[1]))) {
            type = TOK_ID;
            p++;
            while (*p && isidchar(*p))
                p++;
-       } else if (*p == '\'' || *p == '"') {
+       }
+       else if (*p == '\'' || *p == '"') {
            /*
             * A string token.
             */
@@ -578,7 +609,8 @@ static Token *tokenise (char *line) {
            while (*p && *p != c)
                p++;
            if (*p) p++;
-       } else if (isnumstart(*p)) {
+       } 
+       else if (isnumstart(*p)) {
            /*
             * A number token.
             */
@@ -586,7 +618,8 @@ static Token *tokenise (char *line) {
            p++;
            while (*p && isnumchar(*p))
                p++;
-       } else if (isspace(*p)) {
+       } 
+       else if (isspace(*p)) {
            type = TOK_WHITESPACE;
            p++;
            while (*p && isspace(*p))
@@ -600,10 +633,12 @@ static Token *tokenise (char *line) {
                type = TOK_COMMENT;
                while (*p) p++;
            }
-       } else if (*p == ';') {
+       } 
+       else if (*p == ';') {
            type = TOK_COMMENT;
            while (*p) p++;
-       } else {
+       } 
+       else {
            /*
             * Anything else is an operator of some kind. We check
             * for all the double-character operators (>>, <<, //,
@@ -623,7 +658,9 @@ static Token *tokenise (char *line) {
                (p[0] == '&' && p[1] == '&') ||
                (p[0] == '|' && p[1] == '|') ||
                (p[0] == '^' && p[1] == '^'))
+           {
                p++;
+           }
            p++;
        }
        if (type != TOK_COMMENT) {
@@ -644,7 +681,8 @@ static Token *tokenise (char *line) {
 /*
  * Convert a line of tokens back into text.
  */
-static char *detoken (Token *tlist) {
+char *detoken (Token *tlist) 
+{
     Token *t;
     int len;
     char *line, *p;
@@ -679,7 +717,8 @@ static char *detoken (Token *tlist) {
  * the first token in the line to be passed in as its private_data
  * field.
  */
-static int ppscan(void *private_data, struct tokenval *tokval) {
+static int ppscan(void *private_data, struct tokenval *tokval) 
+{
     Token **tlineptr = private_data;
     Token *tline;
 
@@ -724,6 +763,25 @@ static int ppscan(void *private_data, struct tokenval *tokval) {
        return tokval->t_type = TOKEN_NUM;
     }
 
+    if (tline->type == TOK_STRING) {
+       int rn_warn;
+       char q, *r;
+       int l;
+
+       r = tline->text;
+       q = *r++;
+       l = strlen(r);
+
+       if (l == 0 || r[l-1] != q)
+           return tokval->t_type = TOKEN_ERRNUM;
+       tokval->t_integer = readstrnum(r, l-1, &rn_warn);
+       if (rn_warn)
+           error(ERR_WARNING|ERR_PASS1,
+                 "character constant too long");
+       tokval->t_charptr = NULL;
+       return tokval->t_type = TOKEN_NUM;
+    }
+
     if (tline->type == TOK_OTHER) {
        if (!strcmp(tline->text, "<<")) return tokval->t_type = TOKEN_SHL;
        if (!strcmp(tline->text, ">>")) return tokval->t_type = TOKEN_SHR;
@@ -752,12 +810,13 @@ static int ppscan(void *private_data, struct tokenval *tokval) {
  * context stack isn't deep enough for the supplied number of $
  * signs.
  */
-static Context *get_ctx (char *name) {
+static Context *get_ctx (char *name) 
+{
     Context *ctx;
     int i;
 
     if (!cstk) {
-       error (ERR_NONFATAL|ERR_OFFBY1, "`%s': context stack is empty", name);
+       error (ERR_NONFATAL, "`%s': context stack is empty", name);
        return NULL;
     }
 
@@ -767,7 +826,7 @@ static Context *get_ctx (char *name) {
        i++;
        ctx = ctx->next;
        if (!ctx) {
-           error (ERR_NONFATAL|ERR_OFFBY1, "`%s': context stack is only"
+           error (ERR_NONFATAL, "`%s': context stack is only"
                   " %d level%s deep", name, i-1, (i==2 ? "" : "s"));
            return NULL;
        }
@@ -780,7 +839,8 @@ static Context *get_ctx (char *name) {
  * 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) {
+static int mstrcmp(char *p, char *q, int casesense) 
+{
     return casesense ? strcmp(p,q) : nasm_stricmp(p,q);
 }
 
@@ -791,26 +851,25 @@ static int mstrcmp(char *p, char *q, int casesense) {
  * the include path one by one until it finds the file or reaches
  * the end of the path.
  */
-static FILE *inc_fopen(char *file) {
+static FILE *inc_fopen(char *file) 
+{
     FILE *fp;
     char *prefix = "", *combine;
     IncPath *ip = ipath;
-    int len = strlen(file);
 
-    do {
-       combine = nasm_malloc(strlen(prefix)+len+1);
-       strcpy(combine, prefix);
-       strcat(combine, file);
+    while (1) {
+       combine = nasm_strcat(prefix,file);
        fp = fopen(combine, "r");
        nasm_free (combine);
        if (fp)
            return fp;
-       prefix = ip ? ip->path : NULL;
-       if (ip)
-           ip = ip->next;
-    } while (prefix);
+       if (!ip)
+           break;
+       prefix = ip->path;
+       ip = ip->next;
+    }
 
-    error (ERR_FATAL|ERR_OFFBY1,
+    error (ERR_FATAL,
           "unable to open include file `%s'", file);
     return NULL;                      /* never reached - placate compilers */
 }
@@ -831,7 +890,8 @@ static FILE *inc_fopen(char *file) {
  * Note that this is also called with nparam zero to resolve
  * `ifdef'.
  */
-static int smacro_defined (char *name, int nparam, SMacro **defn) {
+static int smacro_defined (char *name, int nparam, SMacro **defn, int nocase) 
+{
     SMacro *m;
     Context *ctx;
     char *p;
@@ -849,7 +909,7 @@ static int smacro_defined (char *name, int nparam, SMacro **defn) {
     }
 
     while (m) {
-       if (!mstrcmp(m->name, p, m->casesense) &&
+       if (!mstrcmp(m->name, p, m->casesense & nocase) &&
            (nparam == 0 || m->nparam == 0 || nparam == m->nparam)) {
            if (defn) {
                if (nparam == m->nparam)
@@ -865,48 +925,13 @@ static int smacro_defined (char *name, int nparam, SMacro **defn) {
 }
 
 /*
- * Update the __FILE__ and __LINE__ macros. Specifically, update
- * __FILE__ if bit 1 of our argument is set, and update __LINE__ if
- * bit 0 is set.
- *
- * If the macros don't exist, a `%clear' must have happened, in
- * which case we should exit quite happily and carry on going. It's
- * not an error condition.
- */
-static void update_fileline(int which) {
-    SMacro *sm;
-    char num[20];
-
-    if ((which & 3) && smacro_defined ("__FILE__", 0, &sm) && sm) {
-       free_tlist(sm->expansion);
-       sm->expansion = nasm_malloc(sizeof(Token));
-       sm->expansion->next = NULL;
-       sm->expansion->mac = NULL;
-       sm->expansion->type = TOK_STRING;
-       sm->expansion->text = nasm_malloc(3+strlen(istk->fname));
-       /* FIXME: throw an error if both sorts of quote are present */
-       /* Better still, invent a way for us to cope with that case */
-       sprintf(sm->expansion->text, "\"%s\"", istk->fname);
-    }
-
-    if ((which & 1) && smacro_defined ("__LINE__", 0, &sm) && sm) {
-       free_tlist(sm->expansion);
-       sm->expansion = nasm_malloc(sizeof(Token));
-       sm->expansion->next = NULL;
-       sm->expansion->mac = NULL;
-       sm->expansion->type = TOK_NUMBER;
-       sprintf(num, "%d", istk->lineno - istk->lineinc);
-       sm->expansion->text = nasm_strdup(num);
-    }
-}
-
-/*
  * Count and mark off the parameters in a multi-line macro call.
  * This is called both from within the multi-line macro expansion
  * code, and also to mark off the default parameters when provided
  * in a %macro definition line.
  */
-static void count_mmac_params (Token *t, int *nparam, Token ***params) {
+static void count_mmac_params (Token *t, int *nparam, Token ***params) 
+{
     int paramsize, brace;
 
     *nparam = paramsize = 0;
@@ -916,14 +941,12 @@ static void count_mmac_params (Token *t, int *nparam, Token ***params) {
            paramsize += PARAM_DELTA;
            *params = nasm_realloc(*params, sizeof(**params) * paramsize);
        }
-       if (t && t->type == TOK_WHITESPACE)
-           t = t->next;
+       skip_white_(t);
        brace = FALSE;
-       if (t && t->type == TOK_OTHER && !strcmp(t->text, "{"))
+       if (tok_is_(t, "{"))
            brace = TRUE;
        (*params)[(*nparam)++] = t;
-       while (t && (t->type != TOK_OTHER ||
-                    strcmp(t->text, brace ? "}" : ",")))
+       while (tok_isnt_(t, brace ? "}" : ","))
            t = t->next;
        if (t) {                       /* got a comma/brace */
            t = t->next;
@@ -932,21 +955,17 @@ static void count_mmac_params (Token *t, int *nparam, Token ***params) {
                 * Now we've found the closing brace, look further
                 * for the comma.
                 */
-               if (t && t->type == TOK_WHITESPACE)
-                   t = t->next;
-               if (t && (t->type != TOK_OTHER || strcmp(t->text, ","))) {
-                   error (ERR_NONFATAL|ERR_OFFBY1,
+               skip_white_(t);
+               if (tok_isnt_(t, ",")) {
+                   error (ERR_NONFATAL,
                           "braces do not enclose all of macro parameter");
-                   while (t && (t->type != TOK_OTHER ||
-                                strcmp(t->text, ",")))
+                   while (tok_isnt_(t, ","))
                        t = t->next;
                }
                if (t)
                    t = t->next;               /* eat the comma */
            }
        }
-       else                           /* got EOL */
-           break;
     }
 }
 
@@ -956,11 +975,12 @@ static void count_mmac_params (Token *t, int *nparam, Token ***params) {
  *
  * We must free the tline we get passed.
  */
-static int if_condition (Token *tline, int i) {
-    int j, casesense;
-    Token *t, *tt, **tptr, *origline;
+static int if_condition (Token *tline, int i) 
+{
+    int    j, casesense;
+    Token  * t, * tt, ** tptr, * origline;
     struct tokenval tokval;
-    expr *evalresult;
+    expr   * evalresult;
 
     origline = tline;
 
@@ -969,13 +989,12 @@ static int if_condition (Token *tline, int i) {
       case PP_IFNCTX: case PP_ELIFNCTX:
        j = FALSE;                     /* have we matched yet? */
        if (!cstk)
-           error(ERR_FATAL|ERR_OFFBY1,
+           error(ERR_FATAL,
                  "`%s': context stack is empty", directives[i]);
        else while (tline) {
-           if (tline->type == TOK_WHITESPACE)
-               tline = tline->next;
+           skip_white_(tline);
            if (!tline || tline->type != TOK_ID) {
-               error(ERR_NONFATAL|ERR_OFFBY1,
+               error(ERR_NONFATAL,
                      "`%s' expects context identifiers", directives[i]);
                free_tlist (origline);
                return -1;
@@ -993,18 +1012,17 @@ static int if_condition (Token *tline, int i) {
       case PP_IFNDEF: case PP_ELIFNDEF:
        j = FALSE;                     /* have we matched yet? */
        while (tline) {
-           if (tline->type == TOK_WHITESPACE)
-               tline = tline->next;
+           skip_white_(tline);
            if (!tline || (tline->type != TOK_ID &&
                           (tline->type != TOK_PREPROC_ID ||
                            tline->text[1] != '$'))) {
-               error(ERR_NONFATAL|ERR_OFFBY1,
+               error(ERR_NONFATAL,
                      "`%%if%sdef' expects macro identifiers",
                      (i==PP_ELIFNDEF ? "n" : ""));
                free_tlist (origline);
                return -1;
            }
-           if (smacro_defined(tline->text, 0, NULL))
+           if (smacro_defined(tline->text, 0, NULL, 1))
                j = TRUE;
                tline = tline->next;
        }
@@ -1017,7 +1035,7 @@ static int if_condition (Token *tline, int i) {
       case PP_IFIDNI: case PP_ELIFIDNI: case PP_IFNIDNI: case PP_ELIFNIDNI:
        tline = expand_smacro(tline);
        t = tt = tline;
-       while (tt && (tt->type != TOK_OTHER || strcmp(tt->text, ",")))
+       while (tok_isnt_(tt, ","))
            tt = tt->next;
        if (!tt) {
            error(ERR_NONFATAL, "`%s' expects two comma-separated arguments");
@@ -1054,7 +1072,8 @@ static int if_condition (Token *tline, int i) {
        }
        if ((t->type != TOK_OTHER || strcmp(t->text, ",")) || tt)
            j = FALSE;                 /* trailing gunk on one end or other */
-       if (i == PP_IFNIDN || i == PP_ELIFNIDN)
+       if (i == PP_IFNIDN || i == PP_ELIFNIDN ||
+           i == PP_IFNIDNI || i == PP_ELIFNIDNI)
            j = !j;
        free_tlist (tline);
        return j;
@@ -1064,10 +1083,10 @@ static int if_condition (Token *tline, int i) {
       case PP_IFSTR: case PP_ELIFSTR: case PP_IFNSTR: case PP_ELIFNSTR:
        tline = expand_smacro(tline);
        t = tline;
-       while (t && t->type == TOK_WHITESPACE)
+       while (tok_type_(t, TOK_WHITESPACE))
            t = t->next;
        j = FALSE;                     /* placate optimiser */
-       switch (i) {
+       if (t) switch (i) {
          case PP_IFID: case PP_ELIFID: case PP_IFNID: case PP_ELIFNID:
            j = (t->type == TOK_ID);
            break;
@@ -1095,17 +1114,17 @@ static int if_condition (Token *tline, int i) {
        if (!evalresult)
            return -1;
        if (tokval.t_type)
-           error(ERR_WARNING|ERR_OFFBY1,
+           error(ERR_WARNING,
                  "trailing garbage after expression ignored");
        if (!is_simple(evalresult)) {
-           error(ERR_NONFATAL|ERR_OFFBY1,
+           error(ERR_NONFATAL,
                  "non-constant value given to `%s'", directives[i]);
            return -1;
        }
        return reloc_value(evalresult) != 0;
 
       default:
-       error(ERR_FATAL|ERR_OFFBY1,
+       error(ERR_FATAL,
              "preprocessor directive `%s' not yet implemented",
              directives[i]);
        free_tlist (origline);
@@ -1123,14 +1142,9 @@ static int if_condition (Token *tline, int i) {
  * Return values go like this:
  * 
  * bit 0 is set if a directive was found (so the line gets freed)
- * bit 1 is set if a blank line should be emitted
- * bit 2 is set if a re-sync line number comment should be emitted
- *
- * (bits 1 and 2 are mutually exclusive in that the rest of the
- * preprocessor doesn't guarantee to be able to handle the case in
- * which both are set)
  */
-static int do_directive (Token *tline) {
+static int do_directive (Token *tline) 
+{
     int i, j, k, m, nparam, nolist;
     char *p, *mname;
     Include *inc;
@@ -1145,9 +1159,8 @@ static int do_directive (Token *tline) {
 
     origline = tline;
 
-    if (tline && tline->type == TOK_WHITESPACE)
-       tline = tline->next;
-    if (!tline || tline->type != TOK_PREPROC_ID ||
+    skip_white_(tline);
+    if (!tok_type_(tline, TOK_PREPROC_ID) ||
        (tline->text[1]=='%' || tline->text[1]=='$' || tline->text[1]=='!'))
        return 0;
 
@@ -1190,21 +1203,26 @@ static int do_directive (Token *tline) {
        i != PP_IFNUM && i != PP_ELIFNUM &&
        i != PP_IFSTR && i != PP_ELIFSTR &&
        i != PP_ELSE && i != PP_ENDIF)
+    {
        return 0;
+    }
 
     /*
      * If we're defining a macro or reading a %rep block, we should
      * ignore all directives except for %macro/%imacro (which
      * generate an error), %endm/%endmacro, and (only if we're in a
-     * %rep block) %endrep.
+     * %rep block) %endrep. If we're in a %rep block, another %rep
+     * causes an error, so should be let through.
      */
     if (defining && i != PP_MACRO && i != PP_IMACRO &&
        i != PP_ENDMACRO && i != PP_ENDM &&
-       (defining->name || i != PP_ENDREP))
+       (defining->name || (i != PP_ENDREP && i != PP_REP)))
+    {
        return 0;
+    }
 
     if (j != -2) {
-       error(ERR_NONFATAL|ERR_OFFBY1, "unknown preprocessor directive `%s'",
+       error(ERR_NONFATAL, "unknown preprocessor directive `%s'",
              tline->text);
        return 0;                      /* didn't get it */
     }
@@ -1213,16 +1231,13 @@ static int do_directive (Token *tline) {
 
       case PP_CLEAR:
        if (tline->next)
-           error(ERR_WARNING|ERR_OFFBY1,
+           error(ERR_WARNING,
                  "trailing garbage after `%%clear' ignored");
        for (j=0; j<NHASH; j++) {
            while (mmacros[j]) {
                MMacro *m = mmacros[j];
-               mmacros[j] = mmacros[j]->next;
-               nasm_free (m->name);
-               free_tlist (m->dlist);
-               free_llist (m->expansion);
-               nasm_free (m);
+               mmacros[j] = m->next;
+               free_mmacro(m);
            }
            while (smacros[j]) {
                SMacro *s = smacros[j];
@@ -1237,16 +1252,16 @@ static int do_directive (Token *tline) {
 
       case PP_INCLUDE:
        tline = tline->next;
-       if (tline && tline->type == TOK_WHITESPACE)
-           tline = tline->next;
+       skip_white_(tline);
        if (!tline || (tline->type != TOK_STRING &&
-                      tline->type != TOK_INTERNAL_STRING)) {
-           error(ERR_NONFATAL|ERR_OFFBY1, "`%%include' expects a file name");
+                      tline->type != TOK_INTERNAL_STRING)) 
+       {
+           error(ERR_NONFATAL, "`%%include' expects a file name");
            free_tlist (origline);
            return 3;                  /* but we did _something_ */
        }
        if (tline->next)
-           error(ERR_WARNING|ERR_OFFBY1,
+           error(ERR_WARNING,
                  "trailing garbage after `%%include' ignored");
        if (tline->type != TOK_INTERNAL_STRING) {
            p = tline->text+1;         /* point past the quote to the name */
@@ -1257,28 +1272,27 @@ static int do_directive (Token *tline) {
        inc->next = istk;
        inc->conds = NULL;
        inc->fp = inc_fopen(p);
-       inc->fname = nasm_strdup(p);
-       inc->lineno = inc->lineinc = 1;
+       inc->fname = src_set_fname(nasm_strdup(p));
+       inc->lineno = src_set_linnum(0);
+       inc->lineinc = 1;
        inc->expansion = NULL;
        inc->mstk = NULL;
        istk = inc;
        list->uplevel (LIST_INCLUDE);
-       update_fileline(3);            /* update __FILE__ and __LINE__ */
        free_tlist (origline);
        return 5;
 
       case PP_PUSH:
        tline = tline->next;
-       if (tline && tline->type == TOK_WHITESPACE)
-           tline = tline->next;
-       if (!tline || tline->type != TOK_ID) {
-           error(ERR_NONFATAL|ERR_OFFBY1,
+       skip_white_(tline);
+       if (!tok_type_(tline, TOK_ID)) {
+           error(ERR_NONFATAL,
                  "`%%push' expects a context identifier");
            free_tlist (origline);
            return 3;                  /* but we did _something_ */
        }
        if (tline->next)
-           error(ERR_WARNING|ERR_OFFBY1,
+           error(ERR_WARNING,
                  "trailing garbage after `%%push' ignored");
        ctx = nasm_malloc(sizeof(Context));
        ctx->next = cstk;
@@ -1291,19 +1305,18 @@ static int do_directive (Token *tline) {
 
       case PP_REPL:
        tline = tline->next;
-       if (tline && tline->type == TOK_WHITESPACE)
-           tline = tline->next;
-       if (!tline || tline->type != TOK_ID) {
-           error(ERR_NONFATAL|ERR_OFFBY1,
+       skip_white_(tline);
+       if (!tok_type_(tline, TOK_ID)) {
+           error(ERR_NONFATAL,
                  "`%%repl' expects a context identifier");
            free_tlist (origline);
            return 3;                  /* but we did _something_ */
        }
        if (tline->next)
-           error(ERR_WARNING|ERR_OFFBY1,
+           error(ERR_WARNING,
                  "trailing garbage after `%%repl' ignored");
        if (!cstk)
-           error(ERR_NONFATAL|ERR_OFFBY1,
+           error(ERR_NONFATAL,
                  "`%%repl': context stack is empty");
        else {
            nasm_free (cstk->name);
@@ -1314,10 +1327,10 @@ static int do_directive (Token *tline) {
 
       case PP_POP:
        if (tline->next)
-           error(ERR_WARNING|ERR_OFFBY1,
+           error(ERR_WARNING,
                  "trailing garbage after `%%pop' ignored");
        if (!cstk)
-           error(ERR_NONFATAL|ERR_OFFBY1,
+           error(ERR_NONFATAL,
                  "`%%pop': context stack is already empty");
        else
            ctx_pop();
@@ -1325,21 +1338,18 @@ static int do_directive (Token *tline) {
        break;
 
       case PP_ERROR:
+       tline->next = expand_smacro (tline->next);
        tline = tline->next;
-       if (tline && tline->type == TOK_WHITESPACE)
-           tline = tline->next;
-       if (!tline || tline->type != TOK_STRING) {
-           error(ERR_NONFATAL|ERR_OFFBY1,
-                 "`%%error' expects an error string");
-           free_tlist (origline);
-           return 3;                  /* but we did _something_ */
+       skip_white_(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);
+       } else {
+           p = detoken(tline);
+           error(ERR_WARNING, "user error: %s", p);
+           nasm_free(p);
        }
-       if (tline->next)
-           error(ERR_WARNING|ERR_OFFBY1,
-                 "trailing garbage after `%%error' ignored");
-       p = tline->text+1;             /* point past the quote to the name */
-       p[strlen(p)-1] = '\0';         /* remove the trailing quote */
-       error(ERR_NONFATAL|ERR_OFFBY1, "user error: %s", p);
        free_tlist (origline);
        break;
 
@@ -1365,7 +1375,12 @@ static int do_directive (Token *tline) {
            tline->next = NULL;        /* it got freed */
            free_tlist (origline);
            if (j < 0)
-               return 3;
+               /*
+                * 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;
        }
@@ -1391,7 +1406,7 @@ static int do_directive (Token *tline) {
       case PP_ELIFNUM:
       case PP_ELIFSTR:
        if (!istk->conds)
-           error(ERR_FATAL|ERR_OFFBY1, "`%s': no matching `%%if'",
+           error(ERR_FATAL, "`%s': no matching `%%if'",
                  directives[i]);
        if (emitting(istk->conds->state) || istk->conds->state == COND_NEVER)
            istk->conds->state = COND_NEVER;
@@ -1400,7 +1415,11 @@ static int do_directive (Token *tline) {
            tline->next = NULL;        /* it got freed */
            free_tlist (origline);
            if (j < 0)
-               return 3;
+               /*
+                * 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;
        }
@@ -1408,10 +1427,10 @@ static int do_directive (Token *tline) {
 
       case PP_ELSE:
        if (tline->next)
-           error(ERR_WARNING|ERR_OFFBY1,
+           error(ERR_WARNING,
                  "trailing garbage after `%%else' ignored");
        if (!istk->conds)
-           error(ERR_FATAL|ERR_OFFBY1,
+           error(ERR_FATAL,
                  "`%%else': no matching `%%if'");
        if (emitting(istk->conds->state) || istk->conds->state == COND_NEVER)
            istk->conds->state = COND_ELSE_FALSE;
@@ -1422,10 +1441,10 @@ static int do_directive (Token *tline) {
 
       case PP_ENDIF:
        if (tline->next)
-           error(ERR_WARNING|ERR_OFFBY1,
+           error(ERR_WARNING,
                  "trailing garbage after `%%endif' ignored");
        if (!istk->conds)
-           error(ERR_FATAL|ERR_OFFBY1,
+           error(ERR_FATAL,
                  "`%%endif': no matching `%%if'");
        cond = istk->conds;
        istk->conds = cond->next;
@@ -1436,14 +1455,13 @@ static int do_directive (Token *tline) {
       case PP_MACRO:
       case PP_IMACRO:
        if (defining)
-           error (ERR_FATAL|ERR_OFFBY1,
+           error (ERR_FATAL,
                   "`%%%smacro': already defining a macro",
                   (i == PP_IMACRO ? "i" : ""));
        tline = tline->next;
-       if (tline && tline->type == TOK_WHITESPACE)
-           tline = tline->next;
-       if (!tline || tline->type != TOK_ID) {
-           error (ERR_NONFATAL|ERR_OFFBY1,
+       skip_white_(tline);
+       if (!tok_type_(tline, TOK_ID)) {
+           error (ERR_NONFATAL,
                   "`%%%smacro' expects a macro name",
                   (i == PP_IMACRO ? "i" : ""));
            return 3;
@@ -1455,10 +1473,9 @@ static int do_directive (Token *tline) {
        defining->nolist = FALSE;
        defining->in_progress = FALSE;
        tline = tline->next;
-       if (tline && tline->type == TOK_WHITESPACE)
-           tline = tline->next;
-       if (!tline || tline->type != TOK_NUMBER) {
-           error (ERR_NONFATAL|ERR_OFFBY1,
+       skip_white_(tline);
+       if (!tok_type_(tline, TOK_NUMBER)) {
+           error (ERR_NONFATAL,
                   "`%%%smacro' expects a parameter count",
                   (i == PP_IMACRO ? "i" : ""));
            defining->nparam_min = defining->nparam_max = 0;
@@ -1466,37 +1483,35 @@ static int do_directive (Token *tline) {
            defining->nparam_min = defining->nparam_max =
                readnum(tline->text, &j);
            if (j)
-               error (ERR_NONFATAL|ERR_OFFBY1,
+               error (ERR_NONFATAL,
                       "unable to parse parameter count `%s'", tline->text);
        }
-       if (tline && tline->next && tline->next->type == TOK_OTHER &&
-           !strcmp(tline->next->text, "-")) {
+       if (tline && tok_is_(tline->next, "-")) {
            tline = tline->next->next;
-           if (tline && tline->type == TOK_OTHER &&
-               !strcmp(tline->text, "*"))
+           if (tok_is_(tline, "*"))
                defining->nparam_max = INT_MAX;
-           else if (!tline || tline->type != TOK_NUMBER)
-               error (ERR_NONFATAL|ERR_OFFBY1,
+           else if (!tok_type_(tline, TOK_NUMBER))
+               error (ERR_NONFATAL,
                       "`%%%smacro' expects a parameter count after `-'",
                       (i == PP_IMACRO ? "i" : ""));
            else {
                defining->nparam_max = readnum(tline->text, &j);
                if (j)
-                   error (ERR_NONFATAL|ERR_OFFBY1,
+                   error (ERR_NONFATAL,
                           "unable to parse parameter count `%s'",
                           tline->text);
                if (defining->nparam_min > defining->nparam_max)
-                   error (ERR_NONFATAL|ERR_OFFBY1,
+                   error (ERR_NONFATAL,
                           "minimum parameter count exceeds maximum");
            }
        }
-       if (tline && tline->next && tline->next->type == TOK_OTHER &&
-           !strcmp(tline->next->text, "+")) {
+       if (tline && tok_is_(tline->next, "+")) {
            tline = tline->next;
            defining->plus = TRUE;
        }
-       if (tline && tline->next && tline->next->type == TOK_ID &&
-           !nasm_stricmp(tline->next->text, ".nolist")) {
+       if (tline && tok_type_(tline->next, TOK_ID) &&
+           !nasm_stricmp(tline->next->text, ".nolist")) 
+       {
            tline = tline->next;
            defining->nolist = TRUE;
        }
@@ -1504,8 +1519,9 @@ static int do_directive (Token *tline) {
        while (mmac) {
            if (!strcmp(mmac->name, defining->name) &&
                (mmac->nparam_min<=defining->nparam_max || defining->plus) &&
-               (defining->nparam_min<=mmac->nparam_max || mmac->plus)) {
-               error (ERR_WARNING|ERR_OFFBY1,
+               (defining->nparam_min<=mmac->nparam_max || mmac->plus)) 
+           {
+               error (ERR_WARNING,
                       "redefining multi-line macro `%s'", defining->name);
                break;
            }
@@ -1530,7 +1546,7 @@ static int do_directive (Token *tline) {
       case PP_ENDM:
       case PP_ENDMACRO:
        if (!defining) {
-           error (ERR_NONFATAL|ERR_OFFBY1, "`%s': not defining a macro",
+           error (ERR_NONFATAL, "`%s': not defining a macro",
                   tline->text);
            return 3;
        }
@@ -1555,10 +1571,10 @@ static int do_directive (Token *tline) {
        if (!evalresult)
            return 3;
        if (tokval.t_type)
-           error(ERR_WARNING|ERR_OFFBY1,
+           error(ERR_WARNING,
                  "trailing garbage after expression ignored");
        if (!is_simple(evalresult)) {
-           error(ERR_NONFATAL|ERR_OFFBY1,
+           error(ERR_NONFATAL,
                  "non-constant value given to `%%rotate'");
            return 3;
        }
@@ -1566,7 +1582,7 @@ static int do_directive (Token *tline) {
        while (mmac && !mmac->name)    /* avoid mistaking %reps for macros */
            mmac = mmac->next_active;
        if (!mmac)
-           error(ERR_NONFATAL, "`%rotate' invoked outside a macro call");
+           error(ERR_NONFATAL, "`%%rotate' invoked outside a macro call");
        mmac->rotate = mmac->rotate + reloc_value(evalresult);
        if (mmac->rotate < 0)
            mmac->rotate = mmac->nparam - (-mmac->rotate) % mmac->nparam;
@@ -1574,6 +1590,24 @@ static int do_directive (Token *tline) {
        return 1;
 
       case PP_REP:
+         if (defining) {
+             /*
+              * We don't allow nested %reps, because of a strange bug
+              * that was causing a panic. The cause of the bug appears to be
+              * that the nested %rep isn't taken into account when matching
+              * against the %endreps, so some mechanism to count the
+              * %reps in and the %endreps out may well work here.
+              * 
+              * That's for experimentation with later, though.
+              * For informations sake, the panic produced by
+              * nesting %reps was:
+              *
+              * istk->mstk has no name but defining is set at end
+              * of expansion
+              */
+             error(ERR_NONFATAL, "nested `%%rep' invocation not allowed");
+             break;
+         }
        nolist = FALSE;
        tline = tline->next;
        if (tline->next && tline->next->type == TOK_WHITESPACE)
@@ -1594,10 +1628,10 @@ static int do_directive (Token *tline) {
        if (!evalresult)
            return 3;
        if (tokval.t_type)
-           error(ERR_WARNING|ERR_OFFBY1,
+           error(ERR_WARNING,
                  "trailing garbage after expression ignored");
        if (!is_simple(evalresult)) {
-           error(ERR_NONFATAL|ERR_OFFBY1,
+           error(ERR_NONFATAL,
                  "non-constant value given to `%%rep'");
            return 3;
        }
@@ -1608,13 +1642,15 @@ static int do_directive (Token *tline) {
        defining->nolist = nolist;
        defining->in_progress = reloc_value(evalresult) + 1;
        defining->nparam_min = defining->nparam_max = 0;
+       defining->defaults = NULL;
+       defining->dlist = NULL;
        defining->expansion = NULL;
        defining->next_active = istk->mstk;
        return 1;
 
       case PP_ENDREP:
-       if (!defining) {
-           error (ERR_NONFATAL|ERR_OFFBY1,
+       if (!defining || defining->name) {
+           error (ERR_NONFATAL,
                   "`%%endrep': no matching `%%rep'");
            return 3;
        }
@@ -1641,7 +1677,7 @@ static int do_directive (Token *tline) {
        list->uplevel (defining->nolist ? LIST_MACRO_NOLIST : LIST_MACRO);
        defining = NULL;
        free_tlist (origline);
-       return 1;                      /* the expansion will line-sync */
+       return 1;
 
       case PP_EXITREP:
        /*
@@ -1653,22 +1689,21 @@ static int do_directive (Token *tline) {
            if (l->finishes && !l->finishes->name)
                break;
 
-       if (l->finishes && !l->finishes->name)
+       if (l)
            l->finishes->in_progress = 0;
        else
            error (ERR_NONFATAL, "`%%exitrep' not within `%%rep' block");
        free_tlist (origline);
-       return 1;                      /* the end marker will line-sync */
+       return 1;
 
       case PP_DEFINE:
       case PP_IDEFINE:
        tline = tline->next;
-       if (tline && tline->type == TOK_WHITESPACE)
-           tline = tline->next;
+       skip_white_(tline);
        if (!tline || (tline->type != TOK_ID &&
                       (tline->type != TOK_PREPROC_ID ||
                        tline->text[1] != '$'))) {
-           error (ERR_NONFATAL|ERR_OFFBY1,
+           error (ERR_NONFATAL,
                   "`%%%sdefine' expects a macro identifier",
                   (i == PP_IDEFINE ? "i" : ""));
            free_tlist (origline);
@@ -1691,23 +1726,22 @@ static int do_directive (Token *tline) {
        last = tline;
        param_start = tline = tline->next;
        nparam = 0;
-       if (tline && tline->type == TOK_OTHER && !strcmp(tline->text, "(")) {
+       if (tok_is_(tline, "(")) {
            /*
             * This macro has parameters.
             */
 
            tline = tline->next;
            while (1) {
-               if (tline && tline->type == TOK_WHITESPACE)
-                   tline = tline->next;
+               skip_white_(tline);
                if (!tline) {
-                   error (ERR_NONFATAL|ERR_OFFBY1,
+                   error (ERR_NONFATAL,
                           "parameter identifier expected");
                    free_tlist (origline);
                    return 3;
                }
                if (tline->type != TOK_ID) {
-                   error (ERR_NONFATAL|ERR_OFFBY1,
+                   error (ERR_NONFATAL,
                           "`%s': parameter identifier expected",
                           tline->text);
                    free_tlist (origline);
@@ -1715,16 +1749,13 @@ static int do_directive (Token *tline) {
                }
                tline->type = TOK_SMAC_PARAM + nparam++;
                tline = tline->next;
-               if (tline && tline->type == TOK_WHITESPACE)
-                   tline = tline->next;
-               if (tline && tline->type == TOK_OTHER &&
-                   !strcmp(tline->text, ",")) {
+               skip_white_(tline);
+               if (tok_is_(tline, ",")) {
                    tline = tline->next;
                    continue;
                }
-               if (!tline || tline->type != TOK_OTHER ||
-                   strcmp(tline->text, ")")) {
-                   error (ERR_NONFATAL|ERR_OFFBY1,
+               if (!tok_is_(tline, ")")) {
+                   error (ERR_NONFATAL,
                           "`)' expected to terminate macro template");
                    free_tlist (origline);
                    return 3;
@@ -1734,7 +1765,7 @@ static int do_directive (Token *tline) {
            last = tline;
            tline = tline->next;
        }
-       if (tline && tline->type == TOK_WHITESPACE)
+       if (tok_type_(tline, TOK_WHITESPACE))
            last = tline, tline = tline->next;
        macro_start = NULL;
        last->next = NULL;
@@ -1759,12 +1790,15 @@ static int do_directive (Token *tline) {
         * carefully re-terminated after chopping off the expansion
         * from the end).
         */
-       if (smacro_defined (mname, nparam, &smac)) {
-           if (!smac)
-               error (ERR_WARNING|ERR_OFFBY1,
+       if (smacro_defined (mname, nparam, &smac, i==PP_DEFINE)) {
+           if (!smac) {
+               error (ERR_WARNING,
                       "single-line macro `%s' defined both with and"
                       " without parameters", mname);
-           else {
+               free_tlist (origline);
+               free_tlist (macro_start);
+               return 3;
+           } else {
                /*
                 * We're redefining, so we have to take over an
                 * existing SMacro structure. This means freeing
@@ -1789,12 +1823,11 @@ static int do_directive (Token *tline) {
       case PP_ASSIGN:
       case PP_IASSIGN:
        tline = tline->next;
-       if (tline && tline->type == TOK_WHITESPACE)
-           tline = tline->next;
+       skip_white_(tline);
        if (!tline || (tline->type != TOK_ID &&
                       (tline->type != TOK_PREPROC_ID ||
                        tline->text[1] != '$'))) {
-           error (ERR_NONFATAL|ERR_OFFBY1,
+           error (ERR_NONFATAL,
                   "`%%%sassign' expects a macro identifier",
                   (i == PP_IASSIGN ? "i" : ""));
            free_tlist (origline);
@@ -1831,11 +1864,11 @@ static int do_directive (Token *tline) {
        }
 
        if (tokval.t_type)
-           error(ERR_WARNING|ERR_OFFBY1,
+           error(ERR_WARNING,
                  "trailing garbage after expression ignored");
 
        if (!is_simple(evalresult)) {
-           error(ERR_NONFATAL|ERR_OFFBY1,
+           error(ERR_NONFATAL,
                  "non-constant value given to `%%%sassign'",
                  (i == PP_IASSIGN ? "i" : ""));
            free_tlist (origline);
@@ -1844,22 +1877,17 @@ static int do_directive (Token *tline) {
 
        macro_start = nasm_malloc(sizeof(*macro_start));
        macro_start->next = NULL;
-       {
-           char numbuf[20];
-           sprintf(numbuf, "%ld", reloc_value(evalresult));
-           macro_start->text = nasm_strdup(numbuf);
-       }
+       make_tok_num(macro_start, reloc_value(evalresult));
        macro_start->mac = NULL;
-       macro_start->type = TOK_NUMBER;
 
        /*
         * We now have a macro name, an implicit parameter count of
         * zero, and a numeric token to use as an expansion. Create
         * and store an SMacro.
         */
-       if (smacro_defined (mname, 0, &smac)) {
+       if (smacro_defined (mname, 0, &smac, i==PP_ASSIGN)) {
            if (!smac)
-               error (ERR_WARNING|ERR_OFFBY1,
+               error (ERR_WARNING,
                       "single-line macro `%s' defined both with and"
                       " without parameters", mname);
            else {
@@ -1871,7 +1899,8 @@ static int do_directive (Token *tline) {
                nasm_free (smac->name);
                free_tlist (smac->expansion);
            }
-       } else {
+       } 
+       else {
            smac = nasm_malloc(sizeof(SMacro));
            smac->next = *smhead;
            *smhead = smac;
@@ -1889,20 +1918,19 @@ static int do_directive (Token *tline) {
         * Syntax is `%line nnn[+mmm] [filename]'
         */
        tline = tline->next;
-       if (tline && tline->type == TOK_WHITESPACE)
-           tline = tline->next;
-       if (!tline || tline->type != TOK_NUMBER) {
-           error (ERR_NONFATAL|ERR_OFFBY1, "`%%line' expects line number");
+       skip_white_(tline);
+       if (!tok_type_(tline, TOK_NUMBER)) {
+           error (ERR_NONFATAL, "`%%line' expects line number");
            free_tlist (origline);
            return 3;
        }
        k = readnum(tline->text, &j);
        m = 1;
        tline = tline->next;
-       if (tline && tline->type == TOK_OTHER && !strcmp(tline->text, "+")) {
+       if (tok_is_(tline, "+")) {
            tline = tline->next;
-           if (!tline || tline->type != TOK_NUMBER) {
-               error (ERR_NONFATAL|ERR_OFFBY1,
+           if (!tok_type_(tline, TOK_NUMBER)) {
+               error (ERR_NONFATAL,
                       "`%%line' expects line increment");
                free_tlist (origline);
                return 3;
@@ -1910,21 +1938,17 @@ static int do_directive (Token *tline) {
            m = readnum(tline->text, &j);
            tline = tline->next;
        }
-       if (tline && tline->type == TOK_WHITESPACE)
-           tline = tline->next;
-       istk->lineno = k;
+       skip_white_(tline);
+       src_set_linnum(k);
        istk->lineinc = m;
-       update_fileline(3);            /* update __FILE__ and __LINE__ */
        if (tline) {
-           char *s = detoken(tline);
-           nasm_free (istk->fname);
-           istk->fname = s;
+           nasm_free ( src_set_fname ( detoken(tline) ) );
        }
        free_tlist (origline);
        return 5;
 
       default:
-       error(ERR_FATAL|ERR_OFFBY1,
+       error(ERR_FATAL,
              "preprocessor directive `%s' not yet implemented",
              directives[i]);
        break;
@@ -1937,17 +1961,16 @@ static int do_directive (Token *tline) {
  * nothing else. Return the condition code index if so, or -1
  * otherwise.
  */
-static int find_cc (Token *t) {
+static int find_cc (Token *t) 
+{
     Token *tt;
     int i, j, k, m;
 
-    if (t && t->type == TOK_WHITESPACE)
-       t = t->next;
+    skip_white_(t);
     if (t->type != TOK_ID)
        return -1;
     tt = t->next;
-    if (tt && tt->type == TOK_WHITESPACE)
-       tt = tt->next;
+    skip_white_(tt);
     if (tt && (tt->type != TOK_OTHER || strcmp(tt->text, ",")))
        return -1;
 
@@ -1974,7 +1997,8 @@ static int find_cc (Token *t) {
  * Expand MMacro-local things: parameter references (%0, %n, %+n,
  * %-n) and MMacro-local identifiers (%%foo).
  */
-static Token *expand_mmac_params (Token *tline) {
+static Token *expand_mmac_params (Token *tline) 
+{
     Token *t, *tt, *ttt, **tail, *thead;
 
     tail = &thead;
@@ -2012,9 +2036,7 @@ static Token *expand_mmac_params (Token *tline) {
              case '%':
                type = TOK_ID;
                sprintf(tmpbuf, "..@%lu.", mac->unique);
-               text = nasm_malloc(strlen(tmpbuf)+strlen(t->text+2)+1);
-               strcpy(text, tmpbuf);
-               strcat(text, t->text+2);
+               text = nasm_strcat(tmpbuf, t->text+2);
                break;
              case '-':
                n = atoi(t->text+2)-1;
@@ -2027,14 +2049,14 @@ static Token *expand_mmac_params (Token *tline) {
                }
                cc = find_cc (tt);
                if (cc == -1) {
-                   error (ERR_NONFATAL|ERR_OFFBY1,
+                   error (ERR_NONFATAL,
                           "macro parameter %d is not a condition code",
                           n+1);
                    text = NULL;
                } else {
                    type = TOK_ID;
                    if (inverse_ccs[cc] == -1) {
-                       error (ERR_NONFATAL|ERR_OFFBY1,
+                       error (ERR_NONFATAL,
                               "condition code `%s' is not invertible",
                               conditions[cc]);
                        text = NULL;
@@ -2053,7 +2075,7 @@ static Token *expand_mmac_params (Token *tline) {
                }
                cc = find_cc (tt);
                if (cc == -1) {
-                   error (ERR_NONFATAL|ERR_OFFBY1,
+                   error (ERR_NONFATAL,
                           "macro parameter %d is not a condition code",
                           n+1);
                    text = NULL;
@@ -2074,7 +2096,6 @@ static Token *expand_mmac_params (Token *tline) {
                if (tt) {
                    for (i=0; i<mac->paramlen[n]; i++) {
                        ttt = *tail = nasm_malloc(sizeof(Token));
-                       ttt->next = NULL;
                        tail = &ttt->next;
                        ttt->type = tt->type;
                        ttt->text = nasm_strdup(tt->text);
@@ -2086,10 +2107,10 @@ static Token *expand_mmac_params (Token *tline) {
                break;
            }
            nasm_free (t->text);
-           nasm_free (t);
-           if (text) {
-               t = *tail = nasm_malloc(sizeof(Token));
-               t->next = NULL;
+           if (!text) {
+               nasm_free (t);
+           } else {
+               *tail = t;
                tail = &t->next;
                t->type = type;
                t->text = text;
@@ -2100,10 +2121,42 @@ static Token *expand_mmac_params (Token *tline) {
            t = *tail = tline;
            tline = tline->next;
            t->mac = NULL;
-           t->next = NULL;
            tail = &t->next;
        }
     }
+    *tail = NULL;
+    t = thead;
+    for (; t && (tt=t->next)!=NULL ; t = t->next)
+       switch (t->type) {
+       case TOK_WHITESPACE:
+           if (tt->type == TOK_WHITESPACE) {
+               t->next = tt->next;
+               nasm_free(tt->text);
+               nasm_free(tt); 
+           }
+           break;
+       case TOK_ID:
+           if (tt->type == TOK_ID || tt->type == TOK_NUMBER) {
+               char *tmp = nasm_strcat(t->text, tt->text);
+               nasm_free(t->text);
+               t->text = tmp;
+               t->next = tt->next;
+               nasm_free(tt->text);
+               nasm_free(tt); 
+           }
+           break;
+       case TOK_NUMBER:
+           if (tt->type == TOK_NUMBER) {
+               char *tmp = nasm_strcat(t->text, tt->text);
+               nasm_free(t->text);
+               t->text = tmp;
+               t->next = tt->next;
+               nasm_free(tt->text);
+               nasm_free(tt); 
+           }
+           break;
+       }
+               
     return thead;
 }
 
@@ -2114,9 +2167,10 @@ static Token *expand_mmac_params (Token *tline) {
  * Tokens from input to output a lot of the time, rather than
  * actually bothering to destroy and replicate.)
  */
-static Token *expand_smacro (Token *tline) {
+static Token *expand_smacro (Token *tline) 
+{
     Token *t, *tt, *mstart, **tail, *thead;
-    SMacro *head, *m;
+    SMacro *head = NULL, *m;
     Token **params;
     int *paramsize;
     int nparam, sparam, brackets;
@@ -2125,239 +2179,256 @@ static Token *expand_smacro (Token *tline) {
     tail = &thead;
     thead = NULL;
 
-    while (tline) {
-       while (tline && tline->type != TOK_ID &&
-              (tline->type != TOK_PREPROC_ID || tline->text[1] != '$')) {
-           if (tline->type == TOK_SMAC_END) {
-               tline->mac->in_progress = FALSE;
-               t = tline;
-               tline = tline->next;
-               nasm_free (t);
-           } else {
-               t = *tail = tline;
-               tline = tline->next;
-               t->mac = NULL;
-               t->next = NULL;
-               tail = &t->next;
-               if (t->type == TOK_PS_OTHER) {
-                   /*
-                    * If we see a PS_OTHER, we must at the very
-                    * least restore its correct token type. We
-                    * should also check for a %$ token, since this
-                    * is the point at which we expand context-
-                    * local labels.
-                    */
-                   t->type = TOK_ID;
-                   if (t->text[0] == '%' && t->text[1] == '$') {
-                       Context *c = get_ctx (t->text);
-                       char *p, *q, buffer[40];
-
-                       if (c) {
-                           q = t->text+1;
-                           q += strspn(q, "$");
-                           sprintf(buffer, "..@%lu.", c->number);
-                           p = nasm_malloc (strlen(buffer)+strlen(q)+1);
-                           strcpy (p, buffer);
-                           strcat (p, q);
-                           nasm_free (t->text);
-                           t->text = p;
-                       }
-                   }
-               }
-           }
-       }
-
-       if (!tline)
-           break;
-       /*
-        * We've hit an identifier. As in is_mmacro below, we first
-        * check whether the identifier is a single-line macro at
-        * all, then think about checking for parameters if
-        * necessary.
-        */
+    while (tline) {  /* main token loop */
+       p = NULL;
        if (tline->type == TOK_ID) {
            head = smacros[hash(tline->text)];
            p = tline->text;
-       } else {
+       } else if (tline->type == TOK_PREPROC_ID && tline->text[1] == '$') {
            Context *ctx = get_ctx (tline->text);
            if (ctx) {
-               p = tline->text+1;
-               p += strspn(p, "$");
                head = ctx->localmac;
-           } else {
-               tline->type = TOK_OTHER; /* so it will get copied above */
-               continue;               
+               p = tline->text+2;
+               p += strspn(p, "$");
            }
        }
-       for (m = head; m; m = m->next)
-           if (!mstrcmp(m->name, p, m->casesense))
-               break;
-       if (!m || m->in_progress) {
-           /*
-            * Either we didn't find a macro, so this can't be a
-            * macro call, or we found a macro which was already in
-            * progress, in which case we don't _treat_ this as a
-            * macro call. Copy it through and ignore it.
-            */
-           tline->type = TOK_PS_OTHER;   /* so it will get copied above */
-           continue;
-       }
-       mstart = tline;
-       if (m->nparam == 0) {
-           /*
-            * Simple case: the macro is parameterless. Discard the
-            * one token that the macro call took, and push the
-            * expansion back on the to-do stack.
-            */
-           params = NULL;
-           paramsize = NULL;
-       } else {
-           /*
-            * Complicated case: at least one macro with this name
-            * exists and takes parameters. We must find the
-            * parameters in the call, count them, find the SMacro
-            * that corresponds to that form of the macro call, and
-            * substitute for the parameters when we expand. What a
-            * pain.
-            */
-           nparam = sparam = 0;
-           params = NULL;
-           paramsize = NULL;
-           tline = tline->next;
-           if (tline && tline->type == TOK_WHITESPACE)
-               tline = tline->next;
-           if (!tline || tline->type != TOK_OTHER ||
-               strcmp(tline->text, "(")) {
+       if (p) {
+       /*
+        * We've hit an identifier. As in is_mmacro below, we first
+        * check whether the identifier is a single-line macro at
+        * all, then think about checking for parameters if
+        * necessary.
+        */
+           for (m = head; m; m = m->next)
+               if (!mstrcmp(m->name, p, m->casesense))
+                   break;
+           if (m) {
+             mstart = tline;
+             params = NULL;
+             paramsize = NULL;
+             if (m->nparam == 0) {
                /*
-                * This macro wasn't called with parameters: ignore
-                * the call. (Behaviour borrowed from gnu cpp.)
+                * Simple case: the macro is parameterless. Discard the
+                * one token that the macro call took, and push the
+                * expansion back on the to-do stack.
                 */
-               tline = mstart;
-               tline->type = TOK_PS_OTHER;
-               continue;
-           }
-           tline = tline->next;
-           while (1) {
-               if (tline && tline->type == TOK_WHITESPACE)
+               if (!m->expansion) 
+               {
+                   if (!strcmp("__FILE__", m->name)) {
+                       long num=0;
+                       src_get(&num, &(tline->text));
+                       nasm_quote(&(tline->text));
+                       tline->type = TOK_STRING;
+                       continue;
+                   }
+                   if (!strcmp("__LINE__", m->name)) {
+                       nasm_free(tline->text);
+                       make_tok_num(tline, src_get_linnum());
+                       continue;
+                   }
+                   t = tline;
                    tline = tline->next;
-               if (!tline) {
-                   error(ERR_NONFATAL|ERR_OFFBY1,
-                         "macro call expects terminating `)'");
-                   break;
+                   nasm_free (t->text);
+                   nasm_free (t);
+                   continue;
                }
-               if (nparam >= sparam) {
-                   sparam += PARAM_DELTA;
-                   params = nasm_realloc (params, sparam*sizeof(Token *));
-                   paramsize = nasm_realloc (paramsize, sparam*sizeof(int));
+             } 
+             else {
+                 /*
+                  * Complicated case: at least one macro with this name
+                  * exists and takes parameters. We must find the
+                  * parameters in the call, count them, find the SMacro
+                  * that corresponds to that form of the macro call, and
+                  * substitute for the parameters when we expand. What a
+                  * pain.
+                  */
+                 tline = tline->next;
+                 skip_white_(tline);
+                 if (!tok_is_(tline, "(")) {
+                     /*
+                      * This macro wasn't called with parameters: ignore
+                      * the call. (Behaviour borrowed from gnu cpp.)
+                      */
+                     tline = mstart;
+                     m = NULL;
+                 } 
+                 else {
+                     int paren = 0;
+                     int white = 0;
+                     brackets = 0;
+                     nparam = 0;
+                     tline = tline->next;
+                     sparam = PARAM_DELTA;
+                     params = nasm_malloc (sparam*sizeof(Token *));
+                     params[0] = tline;
+                     paramsize = nasm_malloc (sparam*sizeof(int));
+                     paramsize[0] = 0;
+                     for (;;tline = tline->next) {    /* parameter loop */
+                         if (!tline) {
+                             error(ERR_NONFATAL,
+                                   "macro call expects terminating `)'");
+                             break;
+                         }
+                         if (tline->type == TOK_WHITESPACE && brackets<=0) {
+                             if (paramsize[nparam])
+                                 white++;
+                             else
+                                 params[nparam] = tline->next;
+                             continue;    /* parameter loop */
+                         }
+                         if (tline->type == TOK_OTHER && tline->text[1]==0) {
+                             char ch = tline->text[0];
+                             if (ch == ',' && !paren && brackets<=0) {
+                                 if (++nparam >= sparam) {
+                                     sparam += PARAM_DELTA;
+                                     params = nasm_realloc (params, 
+                                                    sparam*sizeof(Token *));
+                                     paramsize = nasm_realloc (paramsize,
+                                                    sparam*sizeof(int));
+                                 }
+                                 params[nparam] = tline->next;
+                                 paramsize[nparam] = 0;
+                                 white = 0;
+                                 continue; /* parameter loop */
+                             }
+                             if (ch == br0 && 
+                                 (brackets>0 || (brackets==0 &&
+                                                 !paramsize[nparam])))
+                             {
+                                 if (!(brackets++))
+                                 {
+                                     params[nparam] = tline->next;
+                                     continue; /* parameter loop */
+                                 }
+                             }
+                             if (ch == br2 && brackets>0)
+                                 if (--brackets == 0) {
+                                     brackets = -1;
+                                     continue; /* parameter loop */
+                                 }
+                             if (ch == '(' && !brackets)
+                                 paren++;
+                             if (ch == ')' && brackets<=0)
+                                 if (--paren < 0)
+                                     break;
+                         }
+                         if (brackets<0) {
+                             brackets = 0;
+                             error (ERR_NONFATAL, "braces do not "
+                                    "enclose all of macro parameter");
+                         }
+                         paramsize[nparam] += white+1;
+                         white = 0;
+                     } /* parameter loop */
+                     nparam++;
+                     while (m && (m->nparam != nparam ||
+                                  mstrcmp(m->name, p, m->casesense)))
+                         m = m->next;
+                     if (!m)
+                         error (ERR_WARNING|ERR_WARN_MNP, 
+                                "macro `%s' exists, "
+                                "but not taking %d parameters",
+                                mstart->text, nparam);
+                 }
+             }
+             if (m && m->in_progress)
+                 m = NULL;
+             if (!m)    /* in progess or didn't find '(' or wrong nparam */
+             {
+                  /* 
+                  * Design question: should we handle !tline, which
+                  * indicates missing ')' here, or expand those
+                  * macros anyway, which requires the (t) test a few
+                  * lines down?  
+                  */
+                 nasm_free (params);
+                 nasm_free (paramsize);
+                 tline = mstart;
+             } 
+             else {
+               /*
+                * Expand the macro: we are placed on the last token of the
+                * call, so that we can easily split the call from the
+                * following tokens. We also start by pushing an SMAC_END
+                * token for the cycle removal.
+                */
+               t = tline;
+               if (t) {
+                   tline = t->next;
+                   t->next = NULL;
                }
-               params[nparam] = tline;
-               paramsize[nparam] = 0;
-               brackets = 0;
-               if (tline && tline->type == TOK_OTHER &&
-                   !strcmp(tline->text, "{")) {
-                   params[nparam] = tline = tline->next;
-                   while (tline && (brackets > 0 ||
-                                    tline->type != TOK_OTHER ||
-                                    strcmp(tline->text, "}"))) {
-                       tline = tline->next;
-                       paramsize[nparam]++;
-                   }
-                   tline = tline->next;
-                   if (tline && tline->type == TOK_WHITESPACE)
-                       tline = tline->next;
-                   if (tline && (tline->type != TOK_OTHER ||
-                                 (strcmp(tline->text, ")") &&
-                                  strcmp(tline->text, ",")))) {
-                       error (ERR_NONFATAL|ERR_OFFBY1, "braces do not "
-                              "enclose all of macro parameter");
-                   }
-                   if (tline && tline->type == TOK_OTHER &&
-                       !strcmp(tline->text, ","))
-                       tline = tline->next;
-               } else {
-                   while (tline && (brackets > 0 ||
-                                    tline->type != TOK_OTHER ||
-                                    (strcmp(tline->text, ",") &&
-                                     strcmp(tline->text, ")")))) {
-                       if (tline->type == TOK_OTHER && !tline->text[1])
-                           brackets += (tline->text[0] == '(' ? 1 :
-                                        tline->text[0] == ')' ? -1 : 0);
-                       tline = tline->next;
-                       paramsize[nparam]++;
+               tt = nasm_malloc(sizeof(Token));
+               tt->type = TOK_SMAC_END;
+               tt->text = NULL;
+               tt->mac = m;
+               m->in_progress = TRUE;
+               tt->next = tline;
+               tline = tt;
+               for (t = m->expansion; t; t = t->next) {
+                   if (t->type >= TOK_SMAC_PARAM) {
+                       Token *pcopy = tline, **ptail = &pcopy;
+                       Token *ttt, *pt;
+                       int i;
+                       
+                       ttt = params[t->type - TOK_SMAC_PARAM];
+                       for (i=paramsize[t->type-TOK_SMAC_PARAM]; --i>=0;) {
+                           pt = *ptail = nasm_malloc(sizeof(Token));
+                           pt->next = tline;
+                           ptail = &pt->next;
+                           pt->text = nasm_strdup(ttt->text);
+                           pt->type = ttt->type;
+                           pt->mac = NULL;
+                           ttt = ttt->next;
+                       }
+                       tline = pcopy;
+                   } else {
+                       tt = nasm_malloc(sizeof(Token));
+                       tt->type = t->type;
+                       tt->text = nasm_strdup(t->text);
+                       tt->mac = NULL;
+                       tt->next = tline;
+                       tline = tt;
                    }
                }
-               nparam++;
-               if (tline && !strcmp(tline->text, ")"))
-                   break;
-               if (tline && !strcmp(tline->text, ","))
-                   tline = tline->next;
-           }
-           while (m && m->nparam != nparam) {
-               while ( (m = m->next) )
-                   if (!strcmp(m->name, mstart->text))
-                       break;
-           }
-           if (!m) {
-               error (ERR_WARNING|ERR_OFFBY1|ERR_WARN_MNP,
-                      "macro `%s' exists, but not taking %d parameters",
-                      mstart->text, nparam);
+       
+               /*
+                * Having done that, get rid of the macro call, and clean
+                * up the parameters.
+                */
                nasm_free (params);
                nasm_free (paramsize);
-               tline = mstart;
-               tline->type = TOK_PS_OTHER;
-               continue;
+               free_tlist (mstart);
+               continue;  /* main token loop */
+             }
            }
        }
-       /*
-        * Expand the macro: we are placed on the last token of the
-        * call, so that we can easily split the call from the
-        * following tokens. We also start by pushing an SMAC_END
-        * token for the cycle removal.
-        */
-       t = tline;
-       tline = tline->next;
-       t->next = NULL;
-       tt = nasm_malloc(sizeof(Token));
-       tt->type = TOK_SMAC_END;
-       tt->text = NULL;
-       tt->mac = m;
-       m->in_progress = TRUE;
-       tt->next = tline;
-       tline = tt;
-       for (t = m->expansion; t; t = t->next) {
-           if (t->type >= TOK_SMAC_PARAM) {
-               Token *pcopy = tline, **ptail = &pcopy;
-               Token *ttt, *pt;
-               int i;
-               
-               ttt = params[t->type - TOK_SMAC_PARAM];
-               for (i=0; i<paramsize[t->type-TOK_SMAC_PARAM]; i++) {
-                   pt = *ptail = nasm_malloc(sizeof(Token));
-                   pt->next = tline;
-                   ptail = &pt->next;
-                   pt->text = nasm_strdup(ttt->text);
-                   pt->type = ttt->type;
-                   pt->mac = NULL;
-                   ttt = ttt->next;
+
+       if (tline->type == TOK_SMAC_END) {
+           tline->mac->in_progress = FALSE;
+           t = tline;
+           tline = tline->next;
+           nasm_free (t);
+       } else {
+           t = *tail = tline;
+           tline = tline->next;
+           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);
+                   nasm_free (t->text);
+                   t->text = p;
                }
-               tline = pcopy;
-           } else {
-               tt = nasm_malloc(sizeof(Token));
-               tt->type = t->type;
-               tt->text = nasm_strdup(t->text);
-               tt->mac = NULL;
-               tt->next = tline;
-               tline = tt;
            }
        }
-
-       /*
-        * Having done that, get rid of the macro call, and clean
-        * up the parameters.
-        */
-       nasm_free (params);
-       nasm_free (paramsize);
-       free_tlist (mstart);
     }
 
     return thead;
@@ -2371,7 +2442,8 @@ static Token *expand_smacro (Token *tline) {
  * to be called with tline->type == TOK_ID, so the putative macro
  * name is easy to find.
  */
-static MMacro *is_mmacro (Token *tline, Token ***params_array) {
+static MMacro *is_mmacro (Token *tline, Token ***params_array) 
+{
     MMacro *head, *m;
     Token **params;
     int nparam;
@@ -2407,9 +2479,11 @@ static MMacro *is_mmacro (Token *tline, Token ***params_array) {
             * prohibits us using it before we actually celebrate...
             */
            if (m->in_progress) {
-               error (ERR_NONFATAL|ERR_OFFBY1,
+#if 0
+               error (ERR_NONFATAL,
                       "self-reference in multi-line macro `%s'",
                       m->name);
+#endif
                nasm_free (params);
                return NULL;
            }
@@ -2456,7 +2530,7 @@ static MMacro *is_mmacro (Token *tline, Token ***params_array) {
      * After all that, we didn't find one with the right number of
      * parameters. Issue a warning, and fail to expand the macro.
      */
-    error (ERR_WARNING|ERR_OFFBY1|ERR_WARN_MNP,
+    error (ERR_WARNING|ERR_WARN_MNP,
           "macro `%s' exists, but not taking %d parameters",
           tline->text, nparam);
     nasm_free (params);
@@ -2466,62 +2540,54 @@ static MMacro *is_mmacro (Token *tline, Token ***params_array) {
 /*
  * Expand the multi-line macro call made by the given line, if
  * there is one to be expanded. If there is, push the expansion on
- * istk->expansion and return 1 or 2, as according to whether a
- * line sync is needed (2 if it is). Otherwise return 0.
+ * istk->expansion and return 1. Otherwise return 0.
  */
-static int expand_mmacro (Token *tline) {
-    Token *label = NULL, **params, *t, *tt, *last = NULL;
-    MMacro *m = NULL;
+static int expand_mmacro (Token *tline) 
+{
+    Token *startline = tline;
+    Token *label = NULL;
+    int dont_prepend = 0;
+    Token **params, *t, *tt;
+    MMacro *m;
     Line *l, *ll;
     int i, nparam, *paramlen;
-    int need_sync = FALSE;
 
     t = tline;
-    if (t && t->type == TOK_WHITESPACE)
+    skip_white_(t);
+    if (!tok_type_(t, TOK_ID))
+       return 0;
+    m = is_mmacro (t, &params);
+    if (!m) {
+       Token *last;
+       /*
+        * We have an id which isn't a macro call. We'll assume
+        * it might be a label; we'll also check to see if a
+        * colon follows it. Then, if there's another id after
+        * that lot, we'll check it again for macro-hood.
+        */
+       label = last = t;
        t = t->next;
-    if (t && t->type == TOK_ID) {
-       m = is_mmacro (t, &params);
-       if (!m) {
-           /*
-            * We have an id which isn't a macro call. We'll assume
-            * it might be a label; we'll also check to see if a
-            * colon follows it. Then, if there's another id after
-            * that lot, we'll check it again for macro-hood.
-            */
+       if (tok_type_(t, TOK_WHITESPACE))
            last = t, t = t->next;
-           if (t && t->type == TOK_WHITESPACE)
-               last = t, t = t->next;
-           if (t && t->type == TOK_OTHER && !strcmp(t->text, ":"))
-               last = t, t = t->next;
-           if (t && t->type == TOK_WHITESPACE)
+       if (tok_is_(t, ":")) {
+           dont_prepend = 1;
+           last = t, t = t->next;
+           if (tok_type_(t, TOK_WHITESPACE))
                last = t, t = t->next;
-           if (t && t->type == TOK_ID) {
-               m = is_mmacro(t, &params);
-               if (m) {
-                   last->next = NULL;
-                   label = tline;
-                   tline = t;
-               }
-           }
-       }       
+       }
+       if (!tok_type_(t, TOK_ID) || (m = is_mmacro(t, &params)) == NULL)
+           return 0;
+       last->next = NULL;
+       tline = t;
     }
-    if (!m)
-       return 0;
-
-    /*
-     * If we're not already inside another macro expansion, we'd
-     * better push a line synchronisation to ensure we stay put on
-     * line numbering.
-     */
-    if (!istk->expansion)
-       need_sync = TRUE;
 
     /*
      * Fix up the parameters: this involves stripping leading and
      * trailing whitespace, then stripping braces if they are
      * present.
      */
-    for (nparam = 0; params[nparam]; nparam++);
+    for (nparam = 0; params[nparam]; nparam++)
+       ;
     paramlen = nparam ? nasm_malloc(nparam*sizeof(*paramlen)) : NULL;
 
     for (i = 0; params[i]; i++) {
@@ -2529,19 +2595,15 @@ static int expand_mmacro (Token *tline) {
        int comma = (!m->plus || i < nparam-1);
 
        t = params[i];
-       if (t && t->type == TOK_WHITESPACE)
-           t = t->next;
-       if (t && t->type == TOK_OTHER && !strcmp(t->text, "{"))
+       skip_white_(t);
+       if (tok_is_(t, "{"))
            t = t->next, brace = TRUE, comma = FALSE;
        params[i] = t;
        paramlen[i] = 0;
        while (t) {
-           if (!t)                    /* end of param because EOL */
-               break;
            if (comma && t->type == TOK_OTHER && !strcmp(t->text, ","))
                break;                 /* ... because we have hit a comma */
-           if (comma && t->type == TOK_WHITESPACE &&
-               t->next->type == TOK_OTHER && !strcmp(t->next->text, ","))
+           if (comma && t->type == TOK_WHITESPACE && tok_is_(t->next, ","))
                break;                 /* ... or a space then a comma */
            if (brace && t->type == TOK_OTHER && !strcmp(t->text, "}"))
                break;                 /* ... or a brace */
@@ -2584,61 +2646,76 @@ static int expand_mmacro (Token *tline) {
        Token **tail;
 
        ll = nasm_malloc(sizeof(Line));
-       ll->next = istk->expansion;
        ll->finishes = NULL;
-       ll->first = NULL;
+       ll->next = istk->expansion;
+       istk->expansion = ll;
        tail = &ll->first;
 
        for (t = l->first; t; t = t->next) {
+           Token *x = t;
+           if (t->type == TOK_PREPROC_ID && 
+               t->text[1]=='0' && t->text[2]=='0') 
+           {
+               dont_prepend = -1;
+               x = label;
+               if (!x)
+                   continue;
+           }
            tt = *tail = nasm_malloc(sizeof(Token));
-           tt->next = NULL;
            tail = &tt->next;
-           tt->type = t->type;
-           tt->text = nasm_strdup(t->text);
+           tt->type = x->type;
+           tt->text = nasm_strdup(x->text);
            tt->mac = NULL;
        }
-
-       istk->expansion = ll;
-
+       *tail = NULL;
     }
 
     /*
-     * If we had a label, push it on the front of the first line of
-     * the macro expansion. We must check that this doesn't give
-     * two consecutive TOK_WHITESPACE.
+     * If we had a label, push it on as the first line of
+     * the macro expansion.
      */
-    if (label) {
-       if (last->type == TOK_WHITESPACE &&
-           istk->expansion->first->type == TOK_WHITESPACE) {
-           Token *victim = istk->expansion->first; /* kill this whitespace */
-           istk->expansion->first = victim->next;
-           nasm_free (victim->text);
-           nasm_free (victim);
-       }
-       last->next = istk->expansion->first;
-       istk->expansion->first = label;
-    }
+    if (label)
+       if (dont_prepend<0)
+           free_tlist(startline);
+       else {
+           ll = nasm_malloc(sizeof(Line));
+           ll->finishes = NULL;
+           ll->next = istk->expansion;
+           istk->expansion = ll;
+           ll->first = startline;
+           if (!dont_prepend) {
+               while (label->next)
+                   label = label->next;
+               label->next = tt = nasm_malloc(sizeof(Token));
+               tt->next = NULL;
+               tt->mac = NULL;
+               tt->type = TOK_OTHER;
+               tt->text = nasm_strdup(":");
+           }
+       }
 
     list->uplevel (m->nolist ? LIST_MACRO_NOLIST : LIST_MACRO);
 
-    return need_sync ? 2 : 1;
+    return 1;
 }
 
 static void pp_reset (char *file, int apass, efunc errfunc, evalfunc eval,
-                     ListGen *listgen) {
+                     ListGen *listgen) 
+{
     int h;
 
     error = errfunc;
     cstk = NULL;
-    linesync = outline = NULL;
     istk = nasm_malloc(sizeof(Include));
     istk->next = NULL;
     istk->conds = NULL;
     istk->expansion = NULL;
     istk->mstk = NULL;
     istk->fp = fopen(file, "r");
-    istk->fname = nasm_strdup(file);
-    istk->lineno = istk->lineinc = 1;
+    istk->fname = NULL;
+    src_set_fname(nasm_strdup(file));
+    src_set_linnum(0);
+    istk->lineinc = 1;
     if (!istk->fp)
        error (ERR_FATAL|ERR_NOFILE, "unable to open input file `%s'", file);
     defining = NULL;
@@ -2654,17 +2731,12 @@ static void pp_reset (char *file, int apass, efunc errfunc, evalfunc eval,
     pass = apass;
 }
 
-static char *pp_getline (void) {
+static char *pp_getline (void) 
+{
     char *line;
     Token *tline;
     int ret;
 
-    if (outline) {
-       line = outline;
-       outline = NULL;
-       return line;
-    }
-
     while (1) {
        /*
         * Fetch a tokenised line, either from the macro-expansion
@@ -2712,7 +2784,6 @@ static char *pp_getline (void) {
 
                    istk->expansion = ll;
                }
-               line_sync();
            } else {
                /*
                 * Check whether a `%rep' was started and not ended
@@ -2733,62 +2804,68 @@ static char *pp_getline (void) {
                               " expansion of macro `%s'", istk->mstk->name);
                }
 
-               if (istk->mstk->name) {
-                   /*
-                    * This was a real macro call, not a %rep, and
-                    * therefore the parameter information needs to
-                    * be freed.
-                    */
-                   nasm_free(istk->mstk->params);
-                   free_tlist(istk->mstk->iline);
-                   nasm_free(istk->mstk->paramlen);
+                /*
+                * FIXME:  investigate the relationship at this point between
+                * istk->mstk and l->finishes
+                */
+               {
+                   MMacro *m = istk->mstk;
+                   istk->mstk = m->next_active;
+                   if (m->name) {
+                       /*
+                        * This was a real macro call, not a %rep, and
+                        * therefore the parameter information needs to
+                        * be freed.
+                        */
+                       nasm_free(m->params);
+                       free_tlist(m->iline);
+                       nasm_free(m->paramlen);
+                       l->finishes->in_progress = FALSE;
+                   } 
+                   else
+                       free_mmacro(m);
                }
-               istk->mstk = istk->mstk->next_active;
-               l->finishes->in_progress = FALSE;
                istk->expansion = l->next;
                nasm_free (l);
                list->downlevel (LIST_MACRO);
-               if (!istk->expansion)
-                   line_sync();
            }
        }
-       if (istk->expansion) {
-           char *p;
-           Line *l = istk->expansion;
-           tline = l->first;
-           istk->expansion = l->next;
-           nasm_free (l);
-           p = detoken(tline);
-           list->line (LIST_MACRO, p);
-           nasm_free(p);
-           if (!istk->expansion)
-               line_sync();
-       } else {
+       while (1) {  /* until we get a line we can use */
+
+           if (istk->expansion) {   /* from a macro expansion */
+               char *p;
+               Line *l = istk->expansion;
+               tline = l->first;
+               istk->expansion = l->next;
+               nasm_free (l);
+               p = detoken(tline);
+               list->line (LIST_MACRO, p);
+               nasm_free(p);
+               break;
+           }
            line = read_line();
-           while (!line) {
-               /*
-                * The current file has ended; work down the istk
-                * until we find a file we can read from.
-                */
-               Include *i;
-               fclose(istk->fp);
-               if (istk->conds)
+           if (line) {    /* from the current input file */
+               line = prepreproc(line);
+               tline = tokenise(line);
+               nasm_free (line);
+               break;
+           }
+           /*
+            * The current file has ended; work down the istk
+            */
+           {
+               Include *i = istk;
+               fclose(i->fp);
+               if (i->conds)
                    error(ERR_FATAL, "expected `%%endif' before end of file");
-               i = istk;
-               istk = istk->next;
+               istk = i->next;
                list->downlevel (LIST_INCLUDE);
-               nasm_free (i->fname);
+               src_set_linnum(i->lineno);
+               nasm_free ( src_set_fname(i->fname) );
                nasm_free (i);
                if (!istk)
                    return NULL;
-               else
-                   line_sync();
-               update_fileline(3);    /* update __FILE__ and __LINE__ */
-               line = read_line();
            }
-           line = prepreproc(line);
-           tline = tokenise(line);
-           nasm_free (line);
        }
 
        /*
@@ -2797,9 +2874,11 @@ static char *pp_getline (void) {
         * with things like `%define something %1' such as STRUC
         * uses. Unless we're _defining_ a MMacro, in which case
         * those tokens should be left alone to go into the
-        * definition.
+        * definition; and unless we're in a non-emitting
+        * condition, in which case we don't want to meddle with
+        * anything.
         */
-       if (!defining)
+       if (!defining && !(istk->conds && !emitting(istk->conds->state)))
            tline = expand_mmac_params(tline);
 
        /*
@@ -2807,20 +2886,11 @@ static char *pp_getline (void) {
         */
        ret = do_directive(tline);
        if (ret & 1) {
-           if (ret & 4)
-               line_sync();
-           if ((ret & 2) && !stdmacpos) {/* give a blank line to the output */
-               outline = nasm_strdup("");
-               break;
-           }
-           else
                continue;
        } else if (defining) {
            /*
             * We're defining a multi-line macro. We emit nothing
-            * at all, not even a blank line (when we finish
-            * defining the macro, we'll emit a line-number
-            * directive so that we keep sync properly), and just
+            * at all, and just
             * shove the tokenised line on to the macro definition.
             */
            Line *l = nasm_malloc(sizeof(Line));
@@ -2858,54 +2928,32 @@ static char *pp_getline (void) {
                 */
                line = detoken(tline);
                free_tlist (tline);
-               outline = line;
                break;
            } else {
-               if (ret == 2)
-                   line_sync();
                continue;              /* expand_mmacro calls free_tlist */
            }
        }
     }
 
-    /*
-     * Once we're out of this loop, outline _must_ be non-NULL. The
-     * only question is whether linesync is NULL or not.
-     */
-    if (linesync) {
-       line = linesync;
-       linesync = NULL;
-    } else {
-       line = outline;
-       outline = NULL;
-    }
     return line;
 }
 
-static void pp_cleanup (void) {
+static void pp_cleanup (void) 
+{
     int h;
 
     if (defining) {
        error (ERR_NONFATAL, "end of file while still defining macro `%s'",
               defining->name);
-       nasm_free (defining->name);
-       free_tlist (defining->dlist);
-       free_llist (defining->expansion);
-       nasm_free (defining);
+       free_mmacro (defining);
     }
-    nasm_free (linesync);             /* might just be necessary */
-    nasm_free (outline);              /* really shouldn't be necessary */
     while (cstk)
        ctx_pop();
     for (h=0; h<NHASH; h++) {
        while (mmacros[h]) {
            MMacro *m = mmacros[h];
            mmacros[h] = mmacros[h]->next;
-           nasm_free (m->name);
-           free_tlist (m->dlist);
-           nasm_free (m->defaults);
-           free_llist (m->expansion);
-           nasm_free (m);
+           free_mmacro(m);
        }
        while (smacros[h]) {
            SMacro *s = smacros[h];
@@ -2926,7 +2974,8 @@ static void pp_cleanup (void) {
        ctx_pop();
 }
 
-void pp_include_path (char *path) {
+void pp_include_path (char *path) 
+{
     IncPath *i;
 
     i = nasm_malloc(sizeof(IncPath));
@@ -2936,7 +2985,8 @@ void pp_include_path (char *path) {
     ipath = i;
 }
 
-void pp_pre_include (char *fname) {
+void pp_pre_include (char *fname) 
+{
     Token *inc, *space, *name;
     Line *l;
 
@@ -2961,8 +3011,9 @@ void pp_pre_include (char *fname) {
     predef = l;
 }
 
-void pp_pre_define (char *definition) {
-    Token *def, *space, *name;
+void pp_pre_define (char *definition) 
+{
+    Token *def, *space;
     Line *l;
     char *equals;
 
@@ -2972,7 +3023,7 @@ void pp_pre_define (char *definition) {
     def->next = space = nasm_malloc(sizeof(Token));
     if (equals)
        *equals = ' ';
-    space->next = name = tokenise(definition);
+    space->next = tokenise(definition);
     if (equals)
        *equals = '=';
 
@@ -2990,10 +3041,19 @@ void pp_pre_define (char *definition) {
     predef = l;
 }
 
-void pp_extra_stdmac (char **macros) {
+void pp_extra_stdmac (char **macros) 
+{
     extrastdmac = macros;
 }
 
+static void make_tok_num(Token *tok, long val) 
+{
+    char numbuf[20];
+    sprintf(numbuf, "%ld", val);
+    tok->text = nasm_strdup(numbuf);
+    tok->type = TOK_NUMBER;
+}
+
 Preproc nasmpp = {
     pp_reset,
     pp_getline,
diff --git a/sync.c b/sync.c
index 7acba0e..261afbc 100644 (file)
--- a/sync.c
+++ b/sync.c
@@ -25,7 +25,8 @@ static struct Sync {
 } *synx;
 static int nsynx;
 
-void init_sync(void) {
+void init_sync(void) 
+{
     /*
      * I'd like to allocate an array of size SYNC_MAX, then write
      * `synx--' which would allow numbering the array from one
@@ -48,7 +49,8 @@ void init_sync(void) {
     nsynx = 0;
 }
 
-void add_sync(unsigned long pos, unsigned long length) {
+void add_sync(unsigned long pos, unsigned long length) 
+{
     int i;
 
     if (nsynx == SYNC_MAX)
@@ -68,7 +70,8 @@ void add_sync(unsigned long pos, unsigned long length) {
     }
 }
 
-unsigned long next_sync(unsigned long position, unsigned long *length) {
+unsigned long next_sync(unsigned long position, unsigned long *length) 
+{
     while (nsynx > 0 && synx[1].pos + synx[1].length <= position) {
        int i, j;
        struct Sync t;
diff --git a/zoutieee.c b/zoutieee.c
new file mode 100644 (file)
index 0000000..b36098a
--- /dev/null
@@ -0,0 +1,1457 @@
+/* outieee.c   output routines for the Netwide Assembler to produce
+ *             IEEE-std object files
+ *
+ * The Netwide Assembler is copyright (C) 1996 Simon Tatham and
+ * Julian Hall. All rights reserved. The software is
+ * redistributable under the licence given in the file "Licence"
+ * distributed in the NASM archive.
+ */
+
+/* notes: I have tried to make this correspond to the IEEE version
+ * of the standard, specifically the primary ASCII version.  It should
+ * be trivial to create the binary version given this source (which is
+ * one of MANY things that have to be done to make this correspond to
+ * the hp-microtek version of the standard).
+ *
+ * 16-bit support is assumed to use 24-bit addresses
+ * The linker can sort out segmentation-specific stuff
+ * if it keeps track of externals
+ * in terms of being relative to section bases
+ *
+ * A non-standard variable type, the 'Yn' variable, has been introduced.
+ * Basically it is a reference to extern 'n'- denoting the low limit
+ * (L-variable) of the section that extern 'n' is defined in.  Like the
+ * x variable, there may be no explicit assignment to it, it is derived
+ * from the public definition corresponding to the extern name.  This
+ * is required because the one thing the mufom guys forgot to do well was
+ * take into account segmented architectures.
+ *
+ * I use comment classes for various things and these are undefined by
+ * the standard.
+ *
+ * Debug info should be considered totally non-standard (local labels are
+ * standard but linenum records are not covered by the standard.
+ * Type defs have the standard format but absolute meanings for ordinal
+ * types are not covered by the standard.)
+ *
+ * David Lindauer, LADsoft
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <stdarg.h>  /* Note: we need the ANSI version of stdarg.h */
+#include <ctype.h>
+
+#include "nasm.h"
+#include "nasmlib.h"
+#include "outform.h"
+
+#ifdef OF_IEEE
+
+#define ARRAY_BOT 0x1
+
+static char ieee_infile[FILENAME_MAX];
+static int ieee_uppercase;
+
+static efunc error;
+static ldfunc deflabel;
+static FILE *ofp;
+static int any_segs;
+static int arrindex;
+
+#define HUNKSIZE 1024                 /* Size of the data hunk */
+#define EXT_BLKSIZ 512
+#define LDPERLINE 32                   /* bytes per line in output */
+
+struct ieeeSection;
+
+struct LineNumber {
+    struct LineNumber *next;
+    struct ieeeSection *segment;
+    long offset;
+    long lineno;
+};
+
+static struct FileName {
+    struct FileName *next;
+    char *name;
+    long index;
+} *fnhead, **fntail;
+
+static struct Array {
+    struct Array *next;
+    unsigned size;
+    int basetype;
+} *arrhead, **arrtail;
+
+static struct ieeePublic {
+    struct ieeePublic *next;
+    char *name;
+    long offset;
+    long segment;                     /* only if it's far-absolute */
+    long index;
+    int type;                          /* for debug purposes */        
+} *fpubhead, **fpubtail, *last_defined;
+
+static struct ieeeExternal {
+    struct ieeeExternal *next;
+    char *name;
+    long commonsize;
+} *exthead, **exttail;
+
+static int externals;
+
+static struct ExtBack {
+    struct ExtBack *next;
+    int index[EXT_BLKSIZ];
+} *ebhead, **ebtail;
+
+/* NOTE: the first segment MUST be the lineno segment */
+static struct ieeeSection {
+    struct ieeeObjData *data,*datacurr;
+    struct ieeeSection *next;
+    struct ieeeFixupp *fptr, * flptr;
+    long index;                               /* the NASM segment id */
+    long ieee_index;                  /* the OBJ-file segment index */
+    long currentpos;
+    long align;                               /* can be SEG_ABS + absolute addr */
+    long startpos;
+    enum {
+       CMB_PRIVATE = 0,
+       CMB_PUBLIC = 2,
+       CMB_COMMON = 6
+    } combine;
+    long use32;                               /* is this segment 32-bit? */
+    struct ieeePublic *pubhead, **pubtail, *lochead, **loctail;
+    char *name;
+} *seghead, **segtail, *ieee_seg_needs_update;
+
+static struct ieeeObjData {
+    struct ieeeObjData *next;
+    unsigned char data[HUNKSIZE];
+};
+
+struct ieeeFixupp {
+    struct ieeeFixupp *next;
+    enum { 
+       FT_SEG = 0,
+       FT_REL = 1,
+       FT_OFS = 2,
+       FT_EXT = 3,
+       FT_WRT = 4,
+       FT_EXTREL = 5,
+       FT_EXTWRT = 6,
+       FT_EXTSEG = 7
+    } ftype;
+    short size;
+    long id1;
+    long id2;
+    long offset;
+    long addend;
+};
+               
+static long ieee_entry_seg, ieee_entry_ofs;
+static int checksum;
+
+extern struct ofmt of_ieee;
+
+static void ieee_data_new(struct ieeeSection *);
+static void ieee_write_fixup (long, long, struct ieeeSection *,
+                               int, long, long);
+static void ieee_install_fixup(struct ieeeSection *, struct ieeeFixupp *);
+static long ieee_segment (char *, int, int *);
+static void ieee_write_file(int debuginfo);
+static void ieee_write_byte(struct ieeeSection *, int);
+static void ieee_write_word(struct ieeeSection *, int);
+static void ieee_write_dword(struct ieeeSection *, long);
+static void ieee_putascii(char *, ...);
+static void ieee_putcs(int);
+static long ieee_putld(long, long, unsigned char *);
+static long ieee_putlr(struct ieeeFixupp *);
+static void ieee_unqualified_name(char *, char *);
+
+
+/* 
+ * pup init 
+ */
+static void ieee_init (FILE *fp, efunc errfunc, ldfunc ldef, evalfunc eval) 
+{
+    (void) eval;
+    ofp = fp;
+    error = errfunc;
+    deflabel = ldef;
+    any_segs = FALSE;
+    fpubhead = NULL;
+    fpubtail = &fpubhead;
+    exthead = NULL;
+    exttail = &exthead;
+    externals = 1;
+    ebhead = NULL;
+    ebtail = &ebhead;
+    seghead = ieee_seg_needs_update = NULL;
+    segtail = &seghead;
+    ieee_entry_seg = NO_SEG;
+    ieee_uppercase = FALSE;
+    checksum = 0;
+    of_ieee.current_dfmt->init (&of_ieee,NULL,fp,errfunc);
+}
+static int ieee_set_info(enum geninfo type, char **val)
+{
+    (void) type;
+    (void) val;
+
+    return 0;
+}
+/*
+ * Rundown
+ */
+static void ieee_cleanup (int debuginfo) 
+{
+    ieee_write_file(debuginfo);
+    of_ieee.current_dfmt->cleanup ();
+    fclose (ofp);
+    while (seghead) {
+       struct ieeeSection *segtmp = seghead;
+       seghead = seghead->next;
+       while (segtmp->pubhead) {
+           struct ieeePublic *pubtmp = segtmp->pubhead;
+           segtmp->pubhead = pubtmp->next;
+           nasm_free (pubtmp);
+       }
+       while (segtmp->fptr) {
+           struct ieeeFixupp *fixtmp = segtmp->fptr;
+           segtmp->fptr = fixtmp->next;
+           nasm_free(fixtmp);
+       }
+       while (segtmp->data) {
+           struct ieeeObjData *dattmp = segtmp->data;
+           segtmp->data = dattmp->next;
+           nasm_free(dattmp);
+       }
+       nasm_free (segtmp);
+    }
+    while (fpubhead) {
+       struct ieeePublic *pubtmp = fpubhead;
+       fpubhead = fpubhead->next;
+       nasm_free (pubtmp);
+    }
+    while (exthead) {
+       struct ieeeExternal *exttmp = exthead;
+       exthead = exthead->next;
+       nasm_free (exttmp);
+    }
+    while (ebhead) {
+       struct ExtBack *ebtmp = ebhead;
+       ebhead = ebhead->next;
+       nasm_free (ebtmp);
+    }
+}
+/*
+ * callback for labels
+ */
+static void ieee_deflabel (char *name, long segment,
+                         long offset, int is_global, char *special) {
+    /*
+     * We have three cases:
+     *
+     * (i) `segment' is a segment-base. If so, set the name field
+     * for the segment structure it refers to, and then
+     * return.
+     *
+     * (ii) `segment' is one of our segments, or a SEG_ABS segment.
+     * Save the label position for later output of a PUBDEF record.
+     * 
+     *
+     * (iii) `segment' is not one of our segments. Save the label
+     * position for later output of an EXTDEF.
+     */
+    struct ieeeExternal *ext;
+    struct ExtBack *eb;
+    struct ieeeSection *seg;
+    int i;
+
+    if (special) {
+        error(ERR_NONFATAL, "unrecognised symbol type `%s'", special);
+    }
+    /*
+     * First check for the double-period, signifying something
+     * unusual.
+     */
+    if (name[0] == '.' && name[1] == '.') {
+       if (!strcmp(name, "..start")) {
+           ieee_entry_seg = segment;
+           ieee_entry_ofs = offset;
+       }
+       return;
+    }
+
+    /*
+     * Case (i):
+     */
+    if (ieee_seg_needs_update) {
+       ieee_seg_needs_update->name = name;
+       return;
+    } 
+    if (segment < SEG_ABS && segment != NO_SEG && segment % 2)
+       return;
+
+    /*
+     * case (ii)
+     */
+    if (segment >= SEG_ABS) {
+       /*
+        * SEG_ABS subcase of (ii).
+        */
+       if (is_global) {
+           struct ieeePublic *pub;
+
+           pub = *fpubtail = nasm_malloc(sizeof(*pub));
+           fpubtail = &pub->next;
+           pub->next = NULL;
+           pub->name = name;
+           pub->offset = offset;
+           pub->segment = segment & ~SEG_ABS;
+       }
+       return;
+    }
+
+    for (seg = seghead; seg && is_global; seg = seg->next)
+       if (seg->index == segment) {
+               struct ieeePublic *pub;
+
+           last_defined = pub = *seg->pubtail = nasm_malloc(sizeof(*pub));
+           seg->pubtail = &pub->next;
+           pub->next = NULL;
+           pub->name = name;
+           pub->offset = offset;
+           pub->index = seg->ieee_index;
+           pub->segment = -1;
+           return;
+       }
+
+    /*
+     * Case (iii).
+     */
+    if (is_global) {
+        ext = *exttail = nasm_malloc(sizeof(*ext));
+        ext->next = NULL;
+        exttail = &ext->next;
+        ext->name = name;
+        if (is_global == 2)
+           ext->commonsize = offset;
+       else
+           ext->commonsize = 0;
+       i = segment/2;
+       eb = ebhead;
+       if (!eb) {
+           eb = *ebtail = nasm_malloc(sizeof(*eb));
+           eb->next = NULL;
+           ebtail = &eb->next;
+        }
+       while (i > EXT_BLKSIZ) {
+           if (eb && eb->next)
+               eb = eb->next;
+           else {
+               eb = *ebtail = nasm_malloc(sizeof(*eb));
+               eb->next = NULL;
+               ebtail = &eb->next;
+           }
+           i -= EXT_BLKSIZ;
+       }
+        eb->index[i] = externals++;
+    }
+       
+}
+
+/*
+ * Put data out
+ */
+static void ieee_out (long segto, void *data, unsigned long type,
+                    long segment, long wrt) {
+    long size, realtype;
+    unsigned char *ucdata;
+    long ldata;
+    struct ieeeSection *seg;
+
+    /*
+     * handle absolute-assembly (structure definitions)
+     */
+    if (segto == NO_SEG) {
+       if ((type & OUT_TYPMASK) != OUT_RESERVE)
+           error (ERR_NONFATAL, "attempt to assemble code in [ABSOLUTE]"
+                  " space");
+       return;
+    }
+
+    /*
+     * If `any_segs' is still FALSE, we must define a default
+     * segment.
+     */
+    if (!any_segs) {
+       int tempint;                   /* ignored */
+       if (segto != ieee_segment("__NASMDEFSEG", 2, &tempint))
+           error (ERR_PANIC, "strange segment conditions in IEEE driver");
+    }
+
+    /*
+     * Find the segment we are targetting.
+     */
+    for (seg = seghead; seg; seg = seg->next)
+       if (seg->index == segto)
+           break;
+    if (!seg)
+       error (ERR_PANIC, "code directed to nonexistent segment?");
+
+    size = type & OUT_SIZMASK;
+    realtype = type & OUT_TYPMASK;
+    if (realtype == OUT_RAWDATA) {
+       ucdata = data;
+       while (size--)
+           ieee_write_byte(seg,*ucdata++);
+    } else if (realtype == OUT_ADDRESS || realtype == OUT_REL2ADR ||
+              realtype == OUT_REL4ADR) {
+       if (segment == NO_SEG && realtype != OUT_ADDRESS)
+           error(ERR_NONFATAL, "relative call to absolute address not"
+                 " supported by IEEE format");
+       ldata = *(long *)data;
+       if (realtype == OUT_REL2ADR)
+           ldata += (size-2);
+       if (realtype == OUT_REL4ADR)
+           ldata += (size-4);
+       ieee_write_fixup (segment, wrt, seg, size, realtype,ldata);
+       if (size == 2)
+           ieee_write_word (seg, ldata);
+       else
+           ieee_write_dword (seg, ldata);
+    } 
+    else if (realtype == OUT_RESERVE) {
+       while (size--)
+           ieee_write_byte(seg,0);
+    }
+}
+
+static void ieee_data_new(struct ieeeSection *segto) {
+    
+    if (!segto->data)
+       segto->data = segto->datacurr = nasm_malloc(sizeof(*(segto->datacurr)));
+    else
+       segto->datacurr = segto->datacurr->next = nasm_malloc(sizeof(*(segto->datacurr)));
+    segto->datacurr->next = NULL;
+}
+
+
+/*
+ * this routine is unalduterated bloatware.  I usually don't do this
+ * but I might as well see what it is like on a harmless program.
+ * If anyone wants to optimize this is a good canditate!
+ */
+static void ieee_write_fixup (long segment, long wrt, struct ieeeSection * segto,
+                               int size, long realtype, long offset) {
+    struct ieeeSection *target;
+    struct ieeeFixupp s;
+
+    /* Don't put a fixup for things NASM can calculate */
+    if (wrt == NO_SEG && segment == NO_SEG)
+       return;
+
+    s.ftype = -1;
+    /* if it is a WRT offset */
+    if (wrt != NO_SEG) {
+       s.ftype = FT_WRT;
+       s.addend = offset;
+       if (wrt >= SEG_ABS)
+           s.id1 = -(wrt-SEG_ABS);
+       else {
+           if (wrt %2 && realtype != OUT_REL2ADR && realtype != OUT_REL4ADR) {
+               wrt--;
+
+               for (target = seghead; target; target = target->next)
+                   if (target->index == wrt)
+                       break;
+               if (target) {
+                   s.id1 = target->ieee_index;
+                   for (target = seghead; target; target = target->next)
+                       if (target->index == segment)
+                           break;
+               
+                   if (target) 
+                       s.id2 = target->ieee_index;
+                   else {
+                       /*
+                        * Now we assume the segment field is being used
+                        * to hold an extern index
+                        */
+                       long i = segment/2;
+                       struct ExtBack *eb = ebhead;
+                       while (i > EXT_BLKSIZ) {
+                           if (eb)
+                               eb = eb->next;
+                           else
+                               break;
+                           i -= EXT_BLKSIZ;
+                       }
+                               /* if we have an extern decide the type and make a record
+                        */
+                       if (eb) {
+                               s.ftype = FT_EXTWRT;
+                               s.addend = 0;
+                               s.id2 = eb->index[i];
+                       }
+                       else
+                           error(ERR_NONFATAL,
+                               "Source of WRT must be an offset");
+                   }
+                       
+               }
+               else 
+                   error(ERR_PANIC,
+                         "unrecognised WRT value in ieee_write_fixup");
+           }
+           else 
+               error(ERR_NONFATAL,"target of WRT must be a section ");
+       }
+       s.size = size;
+       ieee_install_fixup(segto,&s);
+       return;
+    }
+    /* Pure segment fixup ? */
+    if (segment != NO_SEG) {
+       s.ftype = FT_SEG;
+       s.id1 = 0;
+       if (segment >= SEG_ABS) {
+           /* absolute far segment fixup */
+           s.id1 = -(segment -~SEG_ABS);
+       }
+       else if (segment % 2) {
+           /* fixup to named segment */
+           /* look it up */
+           for (target = seghead; target; target = target->next)
+               if (target->index == segment-1)
+                   break;
+           if (target)
+               s.id1 = target->ieee_index;
+           else {
+               /*
+                * Now we assume the segment field is being used
+                * to hold an extern index
+                */
+               long i = segment/2;
+               struct ExtBack *eb = ebhead;
+               while (i > EXT_BLKSIZ) {
+                   if (eb)
+                       eb = eb->next;
+                   else
+                       break;
+                   i -= EXT_BLKSIZ;
+               }
+               /* if we have an extern decide the type and make a record
+                */
+               if (eb) {
+                   if (realtype == OUT_REL2ADR || realtype == OUT_REL4ADR) {
+                       error(ERR_PANIC,"Segment of a rel not supported in ieee_write_fixup");
+                   }
+                   else {
+                               /* If we want the segment */
+                           s.ftype = FT_EXTSEG;
+                           s.addend = 0;
+                           s.id1 = eb->index[i];
+                   }
+                   
+               }
+               else 
+                   /* If we get here the seg value doesn't make sense */
+                   error(ERR_PANIC,
+                         "unrecognised segment value in ieee_write_fixup");
+           }
+
+        } else {
+           /* Assume we are offsetting directly from a section
+            * So look up the target segment
+            */
+           for (target = seghead; target; target = target->next)
+               if (target->index == segment)
+                   break;
+           if (target) {
+               if (realtype == OUT_REL2ADR || realtype == OUT_REL4ADR) {
+                   /* PC rel to a known offset */
+                   s.id1 = target->ieee_index;
+                   s.ftype = FT_REL;
+                   s.size = size;
+                   s.addend = offset;
+               }
+               else {
+                   /* We were offsetting from a seg */
+                   s.id1 = target->ieee_index;
+                   s.ftype = FT_OFS;
+                   s.size = size;
+                   s.addend = offset;
+               }
+           }
+           else {
+               /*
+                * Now we assume the segment field is being used
+                * to hold an extern index
+                */
+               long i = segment/2;
+               struct ExtBack *eb = ebhead;
+               while (i > EXT_BLKSIZ) {
+                   if (eb)
+                       eb = eb->next;
+                   else
+                       break;
+                   i -= EXT_BLKSIZ;
+               }
+               /* if we have an extern decide the type and make a record
+                */
+               if (eb) {
+                   if (realtype == OUT_REL2ADR || realtype == OUT_REL4ADR) {
+                       s.ftype = FT_EXTREL;
+                       s.addend = 0;
+                       s.id1 = eb->index[i];
+                   }
+                   else {
+                           /* else we want the external offset */
+                           s.ftype = FT_EXT;
+                           s.addend = 0;
+                           s.id1 = eb->index[i];
+                   }
+                   
+               }
+               else 
+                   /* If we get here the seg value doesn't make sense */
+                   error(ERR_PANIC,
+                         "unrecognised segment value in ieee_write_fixup");
+           }
+       }
+       if (size != 2 && s.ftype == FT_SEG)
+           error(ERR_NONFATAL, "IEEE format can only handle 2-byte"
+                    " segment base references");
+       s.size = size;
+       ieee_install_fixup(segto,&s);
+       return;
+    }
+    /* should never get here */
+}
+static void ieee_install_fixup(struct ieeeSection *seg, struct ieeeFixupp *fix)
+{
+    struct ieeeFixupp *f;
+    f = nasm_malloc(sizeof(struct ieeeFixupp));
+    memcpy(f,fix,sizeof(struct ieeeFixupp));
+    f->offset = seg->currentpos;
+    seg->currentpos += fix->size;
+    f->next = NULL;
+    if (seg->fptr)
+       seg->flptr = seg->flptr->next = f;
+    else
+       seg->fptr = seg->flptr = f;
+
+}
+
+/*
+ * segment registry
+ */
+static long ieee_segment (char *name, int pass, int *bits) {
+    /*
+     * We call the label manager here to define a name for the new
+     * segment, and when our _own_ label-definition stub gets
+     * called in return, it should register the new segment name
+     * using the pointer it gets passed. That way we save memory,
+     * by sponging off the label manager.
+     */
+    if (!name) {
+       *bits = 16;
+       if (!any_segs)
+               return 0;
+       return seghead->index;
+    } else {
+       struct ieeeSection *seg;
+       int ieee_idx, attrs, rn_error;
+       char *p;
+
+       /*
+        * Look for segment attributes.
+        */
+       attrs = 0;
+       while (*name == '.')
+           name++;                    /* hack, but a documented one */
+       p = name;
+       while (*p && !isspace(*p))
+           p++;
+       if (*p) {
+           *p++ = '\0';
+           while (*p && isspace(*p))
+               *p++ = '\0';
+       }
+       while (*p) {
+           while (*p && !isspace(*p))
+               p++;
+           if (*p) {
+               *p++ = '\0';
+               while (*p && isspace(*p))
+                   *p++ = '\0';
+           }
+
+           attrs++;
+       }
+
+       ieee_idx = 1;
+       for (seg = seghead; seg; seg = seg->next) {
+           ieee_idx++;
+           if (!strcmp(seg->name, name)) {
+               if (attrs > 0 && pass == 1)
+                   error(ERR_WARNING, "segment attributes specified on"
+                         " redeclaration of segment: ignoring");
+               if (seg->use32)
+                   *bits = 32;
+               else
+                   *bits = 16;
+               return seg->index;
+           }
+       }
+
+       *segtail = seg = nasm_malloc(sizeof(*seg));
+       seg->next = NULL;
+       segtail = &seg->next;
+       seg->index = seg_alloc();
+       seg->ieee_index = ieee_idx;
+       any_segs = TRUE;
+       seg->name = NULL;
+       seg->currentpos = 0;
+       seg->align = 1;                /* default */
+       seg->use32 = *bits == 32;      /* default to user spec */
+       seg->combine = CMB_PUBLIC;     /* default */
+       seg->pubhead = NULL;
+       seg->pubtail = &seg->pubhead;
+       seg->data = NULL;
+       seg->fptr = NULL;
+       seg->lochead = NULL;
+       seg->loctail = &seg->lochead;
+
+       /*
+        * Process the segment attributes.
+        */
+       p = name;
+       while (attrs--) {
+           p += strlen(p);
+           while (!*p) p++;
+
+           /*
+            * `p' contains a segment attribute.
+            */
+           if (!nasm_stricmp(p, "private"))
+               seg->combine = CMB_PRIVATE;
+           else if (!nasm_stricmp(p, "public"))
+               seg->combine = CMB_PUBLIC;
+           else if (!nasm_stricmp(p, "common"))
+               seg->combine = CMB_COMMON;
+           else if (!nasm_stricmp(p, "use16"))
+               seg->use32 = FALSE;
+           else if (!nasm_stricmp(p, "use32"))
+               seg->use32 = TRUE;
+           else if (!nasm_strnicmp(p, "align=", 6)) {
+               seg->align = readnum(p+6, &rn_error);
+               if (seg->align == 0)
+                   seg->align = 1;
+               if (rn_error) {
+                   seg->align = 1;
+                   error (ERR_NONFATAL, "segment alignment should be"
+                          " numeric");
+               }
+               switch ((int) seg->align) {
+                 case 1:              /* BYTE */
+                 case 2:              /* WORD */
+                 case 4:              /* DWORD */
+                 case 16:             /* PARA */
+                 case 256:            /* PAGE */
+                 case 8:
+                 case 32:
+                 case 64:
+                 case 128:
+                   break;
+                 default:
+                   error(ERR_NONFATAL, "invalid alignment value %d",
+                         seg->align);
+                   seg->align = 1;
+                   break;
+               }
+           } else if (!nasm_strnicmp(p, "absolute=", 9)) {
+               seg->align = SEG_ABS + readnum(p+9, &rn_error);
+               if (rn_error)
+                   error (ERR_NONFATAL, "argument to `absolute' segment"
+                          " attribute should be numeric");
+           }
+       }
+
+       ieee_seg_needs_update = seg;
+       if (seg->align >= SEG_ABS)
+           deflabel (name, NO_SEG, seg->align - SEG_ABS, 
+                       NULL, FALSE, FALSE, &of_ieee, error);
+       else
+           deflabel (name, seg->index+1, 0L, 
+                       NULL, FALSE, FALSE, &of_ieee, error);
+       ieee_seg_needs_update = NULL;
+
+       if (seg->use32)
+           *bits = 32;
+       else
+           *bits = 16;
+       return seg->index;
+    }
+}
+/*
+ * directives supported
+ */
+static int ieee_directive (char *directive, char *value, int pass) 
+{
+    
+    (void) value;
+    (void) pass;
+    if (!strcmp(directive, "uppercase")) {
+       ieee_uppercase = TRUE;
+       return 1;
+    }
+    return 0;
+}
+/*
+ * Return segment data
+ */
+static long ieee_segbase (long segment) 
+{
+    struct ieeeSection *seg;
+
+    /*
+     * Find the segment in our list.
+     */
+    for (seg = seghead; seg; seg = seg->next)
+       if (seg->index == segment-1)
+           break;
+
+    if (!seg)
+       return segment;                /* not one of ours - leave it alone */
+
+    if (seg->align >= SEG_ABS)
+       return seg->align;             /* absolute segment */
+
+    return segment;                   /* no special treatment */
+}
+/*
+ * filename
+ */
+static void ieee_filename (char *inname, char *outname, efunc error) {
+    strcpy(ieee_infile, inname);
+    standard_extension (inname, outname, ".o", error);
+}
+
+static void ieee_write_file (int debuginfo) {
+    struct tm *thetime;
+    time_t reltime;
+    struct FileName *fn;
+    struct ieeeSection *seg;
+    struct ieeePublic *pub, *loc;
+    struct ieeeExternal *ext;
+    struct ieeeObjData *data;
+    struct ieeeFixupp *fix;
+    struct Array *arr;
+    static char boast[] = "The Netwide Assembler " NASM_VER;
+    int i;
+
+    /*
+     * Write the module header
+     */
+    ieee_putascii("MBFNASM,%02X%s.\r\n",strlen(ieee_infile),ieee_infile);
+
+    /*
+     * Write the NASM boast comment.
+     */
+    ieee_putascii("CO0,%02X%s.\r\n",strlen(boast),boast);
+
+    /* 
+     * write processor-specific information
+     */
+    ieee_putascii("AD8,4,L.\r\n");
+
+    /*
+     * date and time
+     */
+    time(&reltime);
+    thetime = localtime(&reltime);
+    ieee_putascii("DT%04d%02d%02d%02d%02d%02d.\r\n", 
+                       1900+thetime->tm_year,thetime->tm_mon+1,thetime->tm_mday,
+                       thetime->tm_hour, thetime->tm_min, thetime->tm_sec);
+    /* 
+     * if debugging, dump file names
+     */
+    for (fn = fnhead; fn && debuginfo; fn = fn->next) {
+       ieee_putascii("C0105,%02X%s.\r\n",strlen(fn->name),fn->name);
+    }
+     
+    ieee_putascii("CO101,07ENDHEAD.\r\n");
+    /*
+     * the standard doesn't specify when to put checksums,
+     * we'll just do it periodically.
+     */
+    ieee_putcs(FALSE);
+
+    /* 
+     * Write the section headers
+     */
+    seg = seghead;
+    if (!debuginfo && !strcmp(seg->name,"??LINE"))
+       seg = seg->next;
+    while (seg) {
+       char buf[256];
+       char attrib;
+       switch(seg->combine) {
+           case CMB_PUBLIC:
+           default:
+               attrib = 'C';
+               break;
+           case CMB_PRIVATE:
+               attrib = 'S';
+               break;
+           case CMB_COMMON:
+               attrib = 'M';
+               break;
+       }
+       ieee_unqualified_name(buf,seg->name);
+       if (seg->align >= SEG_ABS) {
+           ieee_putascii("ST%X,A,%02X%s.\r\n",seg->ieee_index,strlen(buf), buf);
+           ieee_putascii("ASL%X,%lX.\r\n",seg->ieee_index, (seg->align - SEG_ABS)*16);
+       }
+       else {
+           ieee_putascii("ST%X,%c,%02X%s.\r\n",seg->ieee_index,attrib,strlen(buf), buf);
+           ieee_putascii("SA%X,%lX.\r\n",seg->ieee_index,seg->align);
+           ieee_putascii("ASS%X,%X.\r\n",seg->ieee_index, seg->currentpos);
+       }
+       seg = seg->next;
+    }
+    /*
+     * write the start address if there is one
+     */
+    if (ieee_entry_seg) {
+        for (seg = seghead; seg; seg = seg->next)
+           if (seg->index == ieee_entry_seg)
+               break;
+       if (!seg)
+           error(ERR_PANIC,"Start address records are incorrect");
+       else 
+           ieee_putascii("ASG,R%X,%lX,+.\r\n",seg->ieee_index, ieee_entry_ofs);
+    }  
+
+
+    ieee_putcs(FALSE);
+    /*
+     * Write the publics
+     */
+    i = 1;
+    for (seg = seghead; seg; seg = seg->next) {
+        for (pub = seg->pubhead; pub; pub = pub->next) {
+           char buf[256];
+           ieee_unqualified_name(buf,pub->name);
+                   ieee_putascii("NI%X,%02X%s.\r\n",i, strlen(buf), buf);
+           if (pub->segment == -1)  
+                       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 (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 = fpubhead;
+    i = 1;
+    while (pub) {
+       char buf[256];
+       ieee_unqualified_name(buf,pub->name);
+               ieee_putascii("NI%X,%02X%s.\r\n",i, strlen(buf), buf);
+       if (pub->segment == -1)  
+                   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 (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;
+    }
+    /*
+     * Write the externals
+     */
+    ext = exthead;
+    i = 1;
+    while (ext) {
+       char buf[256];
+       ieee_unqualified_name(buf,ext->name);
+               ieee_putascii("NX%X,%02X%s.\r\n",i++, strlen(buf), buf);
+        ext = ext->next;
+    }
+    ieee_putcs(FALSE);
+
+    /*
+     * IEEE doesn't have a standard pass break record
+     * so use the ladsoft variant
+     */
+    ieee_putascii("CO100,06ENDSYM.\r\n");
+
+    /*
+     * now put types
+     */
+    i = ARRAY_BOT;
+    for (arr = arrhead; arr && debuginfo; arr = arr->next) {
+       ieee_putascii("TY%X,20,%X,%lX.\r\n",i++,arr->basetype,arr->size);
+    }
+    /*
+     * now put locals
+     */
+    i = 1;
+    for (seg = seghead; seg && debuginfo; seg = seg->next) {
+        for (loc = seg->lochead; loc; loc = loc->next) {
+           char buf[256];
+           ieee_unqualified_name(buf,loc->name);
+                   ieee_putascii("NN%X,%02X%s.\r\n",i, strlen(buf), buf);
+           if (loc->segment == -1)  
+                       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 (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++;
+        }
+    }
+
+    /*
+     *  put out section data;
+     */ 
+    seg = seghead;
+    if (!debuginfo && !strcmp(seg->name,"??LINE"))
+       seg = seg->next;
+    while (seg) {
+       if (seg->currentpos) {
+           long size,org = 0;
+           data = seg->data;
+           ieee_putascii("SB%X.\r\n",seg->ieee_index);
+           fix = seg->fptr;
+           while (fix) {
+               size = HUNKSIZE - (org %HUNKSIZE);
+               size = size +org > seg->currentpos ? seg->currentpos-org : size;
+               size = fix->offset - org > size ? size : fix->offset-org;
+               org = ieee_putld(org,org+size,data->data);
+               if (org % HUNKSIZE == 0)
+                   data = data->next;
+               if (org == fix->offset) {
+                   org += ieee_putlr(fix);
+                   fix = fix->next;
+               }
+           }
+           while (org < seg->currentpos && data) {
+               size = seg->currentpos-org > HUNKSIZE ? HUNKSIZE : seg->currentpos - org;
+               org = ieee_putld(org,org+size,data->data);
+               data = data->next;
+           }
+           ieee_putcs(FALSE);
+               
+       }
+       seg = seg->next;
+    }
+    /*
+     * module end record
+     */
+    ieee_putascii("ME.\r\n");
+}
+
+static void ieee_write_byte(struct ieeeSection *seg, int data) {
+    int temp;
+    if (!(temp = seg->currentpos++ % HUNKSIZE))
+       ieee_data_new(seg);
+    seg->datacurr->data[temp] = data;
+}
+
+static void ieee_write_word(struct ieeeSection *seg, int data) {
+    ieee_write_byte(seg, data & 0xFF);
+    ieee_write_byte(seg,(data >> 8) & 0xFF);
+}
+
+static void ieee_write_dword(struct ieeeSection *seg, long data) {
+    ieee_write_byte(seg, data & 0xFF);
+    ieee_write_byte(seg,(data >> 8) & 0xFF);
+    ieee_write_byte(seg,(data >> 16) & 0xFF);
+    ieee_write_byte(seg,(data >> 24) & 0xFF);
+}
+static void ieee_putascii(char *format, ...)
+{
+       char buffer[256];
+       int i,l;
+       va_list ap;
+
+       va_start(ap, format);
+       vsprintf(buffer, format, ap);
+       l = strlen(buffer);
+       for (i=0; i < l; i++)
+               if ((buffer[i] & 0xff) > 31)
+                       checksum+=buffer[i];
+       va_end(ap);
+       fprintf(ofp,buffer);
+}
+
+/*
+ * put out a checksum record */
+static void ieee_putcs(int toclear)
+{
+       if (toclear) {
+               ieee_putascii("CS.\r\n");
+       }
+       else {
+               checksum += 'C';
+               checksum += 'S';
+               ieee_putascii("CS%02X.\r\n",checksum & 127);
+       }
+       checksum = 0;
+}
+
+static long ieee_putld(long start, long end, unsigned char *buf)
+{
+       long val;
+       if (start == end)
+               return(start);
+       val = start % HUNKSIZE;
+       /* fill up multiple lines */
+       while (end - start >= LDPERLINE) {
+               int i;
+               ieee_putascii("LD");
+               for (i=0; i < LDPERLINE; i++) {
+                       ieee_putascii("%02X",buf[val++]);
+                       start++;
+               }
+               ieee_putascii(".\r\n");
+       }
+       /* if no partial lines */
+       if (start == end)
+               return(start);
+       /* make a partial line */
+       ieee_putascii("LD");
+       while (start < end) {
+               ieee_putascii("%02X",buf[val++]);
+               start++;
+       }
+       ieee_putascii(".\r\n");
+       return(start);
+}
+static long ieee_putlr(struct ieeeFixupp *p)
+{
+/*
+ * To deal with the vagaries of segmentation the LADsoft linker
+ * defines two types of segments: absolute and virtual.  Note that
+ * 'absolute' in this context is a different thing from the IEEE
+ * definition of an absolute segment type, which is also supported. If a
+ * sement is linked in virtual mode the low limit (L-var) is
+ * subtracted from each R,X, and P variable which appears in an
+ * expression, so that we can have relative offsets.  Meanwhile
+ * in the ABSOLUTE mode this subtraction is not done and
+ * so we can use absolute offsets from 0.  In the LADsoft linker
+ * this configuration is not done in the assemblker source but in
+ * a source the linker reads.  Generally this type of thing only
+ * becomes an issue if real mode code is used.  A pure 32-bit linker could
+ * get away without defining the virtual mode...
+ */
+       char buf[40];
+       long size=p->size;
+       switch(p->ftype) {
+           case FT_SEG:
+               if (p->id1 < 0)
+                   sprintf(buf,"%lX",-p->id1);
+               else
+                   sprintf(buf,"L%X,10,/",p->id1);
+               break;
+           case FT_OFS:
+               sprintf(buf,"R%X,%lX,+",p->id1,p->addend);
+               break;
+           case FT_REL:
+               sprintf(buf,"R%X,%lX,+,P,-,%X,-",p->id1,p->addend,p->size);
+               break;
+               
+           case FT_WRT:
+               if (p->id2 < 0)
+                   sprintf(buf,"R%X,%lX,+,L%X,+,%lX,-",p->id2,p->addend,p->id2,-p->id1*16);
+               else
+                   sprintf(buf,"R%X,%lX,+,L%X,+,L%X,-",p->id2,p->addend,p->id2,p->id1);
+               break;
+           case FT_EXT:
+               sprintf(buf,"X%X",p->id1,p->id1);
+               break;
+           case FT_EXTREL:
+               sprintf(buf,"X%X,P,-,%X,-",p->id1,size);
+               break;
+           case FT_EXTSEG:
+               /* We needed a non-ieee hack here.
+                * We introduce the Y variable, which is the low
+                * limit of the native segment the extern resides in
+                */
+               sprintf(buf,"Y%X,10,/",p->id1);
+               break;
+           case FT_EXTWRT:
+               if (p->id2 < 0)
+                   sprintf(buf,"X%X,Y%X,+,%lX,-",p->id2,p->id2,-p->id1*16);
+               else
+                   sprintf(buf,"X%X,Y%X,+,L%X,-",p->id2,p->id2,p->id1);
+               break;
+       }
+       ieee_putascii("LR(%s,%lX).\r\n", buf, size);
+
+       return(size);
+}
+/* Dump all segment data (text and fixups )*/
+
+static void ieee_unqualified_name(char *dest, char *source)
+{
+    if (ieee_uppercase) {
+       while (*source)
+           *dest++ = toupper(*source++);
+        *dest = 0;
+    }
+    else strcpy(dest,source);
+}
+void dbgls_init(struct ofmt * of, void * id, FILE * fp, efunc error)
+{
+    int tempint;
+    (void) of;
+    (void) id;
+    (void) fp;
+    (void) error;
+
+    fnhead = NULL;
+    fntail = &fnhead;
+    arrindex = ARRAY_BOT ;
+    arrhead = NULL;
+    arrtail = &arrhead;
+    ieee_segment("??LINE", 2, &tempint);
+    any_segs = FALSE;
+}
+static void dbgls_cleanup(void)
+{
+    struct ieeeSection *segtmp;
+    while (fnhead) {
+       struct FileName *fntemp = fnhead;
+       fnhead = fnhead->next;
+       nasm_free (fntemp->name);
+       nasm_free (fntemp);
+    }
+    for (segtmp = seghead; segtmp; segtmp = segtmp->next) {
+       while (segtmp->lochead) {
+           struct ieeePublic *loctmp = segtmp->lochead;
+           segtmp->lochead = loctmp->next;
+           nasm_free (loctmp->name);
+           nasm_free (loctmp);
+       }
+    }
+    while (arrhead) {
+       struct Array *arrtmp = arrhead;
+        arrhead = arrhead->next;
+        nasm_free (arrtmp);
+    }
+}
+
+/*
+ * because this routine is not bracketed in
+ * the main program, this routine will be called even if there
+ * is no request for debug info
+ * so, we have to make sure the ??LINE segment is avaialbe
+ * as the first segment when this debug format is selected
+ */
+static void dbgls_linnum (const char *lnfname, long lineno, long segto)
+{
+    struct FileName *fn;
+    struct ieeeSection *seg;
+    int i = 0;
+    if (segto == NO_SEG)
+       return;
+
+    /*
+     * If `any_segs' is still FALSE, we must define a default
+     * segment.
+     */
+    if (!any_segs) {
+       int tempint;                   /* ignored */
+       if (segto != ieee_segment("__NASMDEFSEG", 2, &tempint))
+           error (ERR_PANIC, "strange segment conditions in OBJ driver");
+    }
+
+    /*
+     * Find the segment we are targetting.
+     */
+    for (seg = seghead; seg; seg = seg->next)
+       if (seg->index == segto)
+           break;
+    if (!seg)
+       error (ERR_PANIC, "lineno directed to nonexistent segment?");
+
+    for (fn = fnhead; fn; fn = fnhead->next) {
+       if (!nasm_stricmp(lnfname,fn->name))
+           break;
+        i++;
+    }
+    if (!fn) {
+       fn = nasm_malloc ( sizeof( *fn));
+       fn->name = nasm_malloc ( strlen(lnfname) + 1) ;
+       fn->index = i;
+        strcpy (fn->name,lnfname);
+       fn->next = NULL;
+       *fntail = fn;
+       fntail = &fn->next;
+    }
+    ieee_write_byte(seghead, fn->index);
+    ieee_write_word(seghead, lineno);
+    ieee_write_fixup (segto, NO_SEG, seghead, 4,OUT_ADDRESS,seg->currentpos);
+
+}
+static void dbgls_deflabel (char *name, long segment,
+                         long offset, int is_global, char *special) 
+{
+    struct ieeeSection *seg;
+    int used_special = FALSE;         /* have we used the special text? */
+
+    (void) special;
+
+    /*
+     * If it's a special-retry from pass two, discard it.
+     */
+    if (is_global == 3)
+       return;
+
+    /*
+     * First check for the double-period, signifying something
+     * unusual.
+     */
+    if (name[0] == '.' && name[1] == '.' && name[2] != '@') {
+       return;
+    }
+
+    /*
+     * Case (i):
+     */
+    if (ieee_seg_needs_update)
+       return;
+    if (segment < SEG_ABS && segment != NO_SEG && segment % 2)
+       return;
+
+    if (segment >= SEG_ABS || segment == NO_SEG) {
+       return;
+    }
+
+    /*
+     * If `any_segs' is still FALSE, we might need to define a
+     * default segment, if they're trying to declare a label in
+     * `first_seg'.  But the label should exist due to a prior
+     * call to ieee_deflabel so we can skip that.
+     */
+
+    for (seg = seghead; seg; seg = seg->next)
+       if (seg->index == segment) {
+           struct ieeePublic *loc;
+           /*
+            * Case (ii). Maybe MODPUB someday?
+            */
+           if (!is_global) {
+               last_defined = loc  = nasm_malloc (sizeof(*loc));
+               *seg->loctail = loc;
+               seg->loctail = &loc->next;
+               loc->next = NULL;
+               loc->name = nasm_strdup(name);
+               loc->offset = offset;
+               loc->segment = -1;
+               loc->index = seg->ieee_index;
+           }
+       }
+}
+static void dbgls_typevalue (long type)
+{
+    int elem = TYM_ELEMENTS(type);
+    type = TYM_TYPE(type);
+
+    if (! last_defined)
+       return;
+
+    switch (type) {
+       case TY_BYTE:
+           last_defined->type = 1; /* unsigned char */
+           break;
+       case TY_WORD:
+           last_defined->type = 3; /* unsigned word */
+           break;
+       case TY_DWORD:
+           last_defined->type = 5; /* unsigned dword */
+           break;
+       case TY_FLOAT:
+           last_defined->type = 9; /* float */
+           break;
+       case TY_QWORD:
+           last_defined->type = 10; /* qword */
+           break;
+       case TY_TBYTE:
+           last_defined->type = 11; /* TBYTE */
+           break;
+       default:
+           last_defined->type = 0x10; /* near label */
+           break;
+    }
+               
+    if (elem > 1) {
+        struct Array *arrtmp = nasm_malloc (sizeof(*arrtmp));
+        int vtype = last_defined->type;
+        arrtmp->size = elem;
+        arrtmp->basetype = vtype;
+        arrtmp->next = NULL;
+        last_defined->type = arrindex++ + 0x100;
+        *arrtail = arrtmp;
+        arrtail = & (arrtmp->next);
+    }
+    last_defined = NULL;
+}
+static void dbgls_output (int output_type, void *param)
+{
+    (void) output_type;
+    (void) param;
+}
+static struct dfmt ladsoft_debug_form = {
+    "LADsoft Debug Records",
+    "ladsoft",
+    dbgls_init,
+    dbgls_linnum,
+    dbgls_deflabel,
+    null_debug_routine,
+    dbgls_typevalue,
+    dbgls_output,
+    dbgls_cleanup,
+};
+static struct dfmt *ladsoft_debug_arr[3] = {
+       &ladsoft_debug_form,
+       &null_debug_form,
+       NULL
+};
+struct ofmt of_ieee = {
+    "IEEE-695 (LADsoft variant) object file format",
+    "ieee",
+    NULL,
+    ladsoft_debug_arr,
+    &null_debug_form,
+    NULL,
+    ieee_init,
+    ieee_set_info,
+    ieee_out,
+    ieee_deflabel,
+    ieee_segment,
+    ieee_segbase,
+    ieee_directive,
+    ieee_filename,
+    ieee_cleanup
+};
+
+#endif /* OF_IEEE */