[Nasm-commits] [nasm:branch-0_98-j] NASM 0.98-j4

nasm-bot for H. Peter Anvin hpa at zytor.com
Thu Jun 4 19:56:10 PDT 2020


Commit-ID:  da74f9ee394b8903a625c6602972025a8125d28f
Gitweb:     http://repo.or.cz/w/nasm.git?a=commitdiff;h=da74f9ee394b8903a625c6602972025a8125d28f
Author:     H. Peter Anvin <hpa at zytor.com>
AuthorDate: Tue, 30 Apr 2002 20:53:37 +0000
Committer:  H. Peter Anvin <hpa at zytor.com>
CommitDate: Tue, 30 Apr 2002 20:53:37 +0000

NASM 0.98-j4



---
 Changes                       |   94 +++
 Wishlist                      |  225 +++++-
 assemble.c                    |  858 ++++++++++++----------
 misc/c16.mac => c16.mac       |    8 +-
 misc/c32.mac => c32.mac       |    2 +-
 changes.asm                   |  292 ++++++++
 disasm.c                      |   41 +-
 eval.c                        |  284 +++++---
 eval.h                        |   12 +-
 misc/exebin.mac => exebin.mac |    0
 float.c                       |   38 +-
 insns.dat                     |  122 +++-
 labels.c                      |  117 ++-
 labels.h                      |    3 +-
 listing.c                     |   84 ++-
 macros.c                      |    2 +-
 names.c                       |   20 +-
 nasm.c                        |  901 ++++++++++++++---------
 nasm.h                        |  186 ++++-
 nasmlib.c                     |  360 ++++++---
 nasmlib.h                     |   79 +-
 ndisasm.c                     |   41 +-
 outaout.c                     |   73 +-
 outas86.c                     |   60 +-
 outbin.c                      |   57 +-
 outcoff.c                     |   84 ++-
 outdbg.c                      |   95 ++-
 outelf.c                      |   95 ++-
 outform.c                     |   37 +-
 outform.h                     |   84 ++-
 outform.h => outforms.h       |   65 +-
 outobj.c                      | 1608 +++++++++++++++++++++++++++++------------
 outrdf.c                      |   25 +-
 outrdf2.c                     |  690 ++++++++++++++++++
 parser.c                      |  202 ++++--
 parser.h                      |    3 +-
 preproc.c                     | 1460 +++++++++++++++++++------------------
 standard.mac                  |    4 +-
 sync.c                        |    9 +-
 zoutieee.c                    | 1457 +++++++++++++++++++++++++++++++++++++
 40 files changed, 7403 insertions(+), 2474 deletions(-)

diff --git a/Changes b/Changes
index 24f4bfef..57584bdb 100644
--- 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.
+
diff --git a/Wishlist b/Wishlist
index 197b113b..b1529bfe 100644
--- a/Wishlist
+++ b/Wishlist
@@ -1,23 +1,168 @@
 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 at 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 at 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 at starbase.spd.louisville.edu>
+    wants to have some say in how this goes through.
+  * Andrew Crabtree <andrewc at 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 at 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 at 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.
+
+
diff --git a/assemble.c b/assemble.c
index 8d144121..65bcea39 100644
--- a/assemble.c
+++ b/assemble.c
@@ -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;
 }
diff --git a/misc/c16.mac b/c16.mac
similarity index 79%
copy from misc/c16.mac
copy to c16.mac
index 86e6bf92..81a9c5e2 100644
--- a/misc/c16.mac
+++ b/c16.mac
@@ -7,14 +7,18 @@
 	  mov bp,sp
 %ifdef FARCODE PASCAL		; arguments may start at bp+4 or bp+6
 %assign %$arg 6
+%define %$firstarg 6
 %else
 %assign %$arg 4
+%define %$firstarg 4
 %endif
 %define %$procname %1
 %endmacro
 
 %imacro arg 0-1 2		; used with the argument name as a label
-	  equ %$arg
+%00	  equ %$arg
+				; we could possibly be adding some
+				; debug information at this point...?
 %assign %$arg %1+%$arg
 %endmacro
 
@@ -25,7 +29,7 @@
           mov sp,bp
           pop bp
 %ifdef PASCAL
-          retf %$arg
+          retf %$arg - %$firstarg
 %elifdef FARCODE
 	  retf
 %else
diff --git a/misc/c32.mac b/c32.mac
similarity index 96%
copy from misc/c32.mac
copy to c32.mac
index a59acfde..b187b470 100644
--- a/misc/c32.mac
+++ b/c32.mac
@@ -10,7 +10,7 @@
 %endmacro
 
 %imacro arg 0-1 4		; used with the argument name as a label
-	  equ %$arg
+%00	  equ %$arg
 %assign %$arg %1+%$arg
 %endmacro
 
diff --git a/changes.asm b/changes.asm
new file mode 100644
index 00000000..7b9dd491
--- /dev/null
+++ b/changes.asm
@@ -0,0 +1,292 @@
+;This file demonstrates many of the differences between NASM version X and NASM
+;version 0.97
+;
+; changes.asm is copyright (C) 1998 John S. Fine
+;
+;  It may be redistributed under the same conditions as NASM as described in
+;  Licence file in the NASM archive
+;_________________________________
+;
+;  nasm changes.asm -l changes.lst
+;
+; When assembled without any -d switches, it includes examples which:
+;       Work correctly in version X
+;  and  Work incorrectly and/or display warnings in version 0.97
+;  and  Do not prevent the generation of output in version 0.97
+;
+; Not all the differences can be seen in the .lst file.  I suggest that you use
+; "ndisasm changes"  to examine the code actually generated.
+;_________________________________
+;
+;  nasm changes.asm -l changes.lst -doldmsg
+;
+; When assembled with -doldmsg, it adds examples which:
+;       Work correctly in version X
+;  and  Generate error messages in version 0.97 and do not generate output
+;_________________________________
+;
+;  nasm changes.asm -l changes.lst -doldcrash
+;
+; When assembled with -doldcrash, it adds examples which:
+;       Work correctly in version X
+;  and  Cause NASM to crash in version 0.97
+;_________________________________
+;
+;  nasm changes.asm -l changes.lst -dnewmsg
+;
+; When assembled with -dnewmsg, it adds examples which:
+;       Generate error messages in version X
+;  and  Generate wrong output without warning or error message in version 0.97
+;-----------------------------------------------------------------------------
+
+; Please note that I have reported the name of the person who made the
+; correction based on very limited information.  In several cases, I am sure I
+; will identify the wrong author.  Please send me any corrections;  I don't
+; intend to insult or exclude anyone.
+
+;-----------------------------------------------------------------------------
+; Bug fixed by Simon in assemble()
+;
+; The following generated "call next" / "call next-1" instead of
+; two copies of "call next"
+;
+	times 2 a16 call next
+next:
+
+;-----------------------------------------------------------------------------
+; Bug fixed by John in parse_line()  (and other routines)
+;
+; This used to jmp to prior.1, when it should be here.1
+;
+prior:
+.1:
+here:	jmp	.1
+.1:
+
+;-----------------------------------------------------------------------------
+; Bug fixed by John in assemble()
+;
+; Strings used in dq and dt were not zero filled correctly
+;
+	dq	'b'
+
+
+;-----------------------------------------------------------------------------
+; Bug fixed by Simon in isn_names[]
+;
+; Was not recognised as an instruction
+;
+	int01
+
+;-----------------------------------------------------------------------------
+; Bug fixed by Jim Hague in ???
+;
+; Forward references were instruction level rather than per operand
+;
+	shr word [forwardref],1
+forwardref:
+
+;-----------------------------------------------------------------------------
+; Bug fixed by John in preproc.c
+;
+; It used to silently discard id characters appended to a multi-line
+; macro parameter (such as the x in %1x below).
+;
+%macro xxx 1
+%1: nop
+%{1}x: jmp %1x
+%endmacro
+xxx yyy
+
+%ifdef oldmsg
+;***************************************************************
+;
+; The following examples will generate error messages in 0.97 and will generate
+; correct output in the new version.
+
+;-----------------------------------------------------------------------------
+; Bug fixed by Simon in isns.dat
+;
+; The optional "near" was not permitted on JMP and CALL
+;
+	jmp near here
+
+;-----------------------------------------------------------------------------
+; Feature added by Simon in stdscan()
+;
+; You can now use the numeric value of strings in %assign
+;
+%assign xxx 'ABCD'
+	dd xxx
+
+;-----------------------------------------------------------------------------
+; Feature added by John in add_vectors()
+;
+; Stranger address expressions are now supported as long as they resolve to
+; something valid.
+;
+	mov ax, [eax + ebx + ecx - eax]
+
+;-----------------------------------------------------------------------------
+; Bug fixed by Simon in ???
+;
+; The EQU directive affected local labels in a way that was inconsistent
+; between passes
+;
+.local:
+neither equ $
+	jmp .local
+
+;-----------------------------------------------------------------------------
+; Feature added by Jules in parse_line
+;
+; You can override a size specifier
+;
+%define arg1 dword [bp+4]
+	cmp word arg1, 2
+
+;-----------------------------------------------------------------------------
+; Bug fixed by John in preproc.c
+;
+; You could not use a label on the same line with a macro invocation, if the
+; macro definition began with a preprocessor directive.
+;
+	struc mytype
+.long	resd	1
+	endstruc
+
+lbl	istruc mytype
+	at mytype.long, dd 'ABCD'
+	iend
+
+;-----------------------------------------------------------------------------
+; Warning removed by John in preproc.c
+;
+; In order to allow macros that extend the definition of instructions, I
+; disabled the warning on a multi-line macro referencing itself.
+;
+%endif			;NASM 0.97 doesn't handle %0 etc. inside false %if
+%macro push 1-*		;
+%rep %0			;
+push %1			;
+%rotate 1		;
+%endrep			;
+%endmacro		;
+%ifdef oldmsg		;
+
+	push ax,bx
+
+;-----------------------------------------------------------------------------
+; Warning removed by John in preproc.c
+;
+; To support other types of macros that extend the definition of instructions,
+; I disabled the warning on a multi-line macro called with the wrong number of
+; parameters.  PUSH and POP can be extended equally well by either method, but
+; other intruction extensions may need one method or the other, so I made both
+; work.
+;
+; Note that neither of these warnings was really needed, because a later stage
+; of NASM would almost always give an adequate error message if the macro use
+; really was wrong.
+;
+%endif
+%macro pop 2-*
+%rep %0
+pop %1
+%rotate 1
+%endrep
+%endmacro
+%ifdef oldmsg
+
+	pop ax,bx
+%endif
+
+
+%ifdef newmsg  ;***************************************************************
+
+;-----------------------------------------------------------------------------
+; Bug fixed by John in parse_line()  (and other routines)
+;
+; This invalid code used to assemble without errors
+;
+myself equ myself+1
+	jmp myself
+
+;-----------------------------------------------------------------------------
+; Change made by John in preproc.c
+;
+; In 0.97, an id that appears as a label on a macro invocation was always
+; prepended to the first line of the macro expansion.  That caused several
+; bugs, but also could be used in tricks like the arg macro in c16.mac and
+; c32.mac.
+;
+; In version X, an id that appears as a label on a macro invocation will
+; normally be defined as a label for the address at which the macro is
+; invoked, regardless of whether the first line of the macro expansion is
+; something that can take a label.  The new token %00 may be used for any
+; of the situations in which the old prepend behavior was doing something
+; tricky but useful.  %00 can also be used more than once and in places
+; other than the start of the expansion.
+;
+%endif
+%assign arg_off 0
+
+%imacro arg 0-1 2		;arg defined the old way
+	  equ arg_off
+%assign arg_off %1+arg_off
+%endmacro
+
+%ifdef newmsg
+arg_example arg
+%endif
+
+%imacro arg2 0-1 2		;arg defined the new way
+%00	  equ arg_off
+%assign arg_off %1+arg_off
+%endmacro
+
+%ifdef oldmsg
+arg_example2 arg2
+
+;-----------------------------------------------------------------------------
+; Change made by Jules and John in INSNS.DAT
+;
+; Various instruction in which the size of an immediate is built-in to the
+; instruction set, now allow you to redundantly specify that size as long
+; as you specify it correctly
+;
+	AAD	byte 5
+	AAM	byte 5
+	BT	bx, byte 3
+	BTC	cx, byte 4
+	BTR	dx, byte 5
+	BTS	si, byte 6
+	IN	eax, byte 0x40
+	INT	byte 21h
+	OUT	byte 70h, ax
+	RET	word 2
+	RETN	word 2
+	RETF	word 4
+
+; note "ENTER" has not been changed yet.
+	
+%endif
+
+%ifdef oldcrash  ;*************************************************************
+
+This_label_is_256_characters_long__There_used_to_be_a_bug_in_stdscan_which_made_it_crash_when_it_did_a_keyword_search_on_any_label_longer_than_255_characters__Now_anything_longer_than_MAX_KEYWORD_is_always_a_symbol__It_will_not_even_try_a_keyword_search___
+
+;-----------------------------------------------------------------------------
+; Bug fixed by John in preproc.c
+;
+; Builds of NASM that prohibit dereferencing a NULL pointer used to crash if a
+; macro that started with a blank line was invoked with a label
+;
+%macro empty_macro 0
+
+%endm
+
+emlabel empty_macro
+	jmp	emlabel
+
+%endif
diff --git a/disasm.c b/disasm.c
index 3dded0d9..4764bc16 100644
--- 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 0e81c928..edb51b12 100644
--- a/eval.c
+++ b/eval.c
@@ -17,37 +17,56 @@
 #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" :
@@ -626,42 +698,36 @@ static expr *expr6(int critical) {
 		break;
 	    }
 
-	    /*
-	     * Since the whole line is parsed before the label it
-	     * defines is given to the label manager, we have
-	     * problems with lines such as
-	     *
-	     *   end: TIMES 512-(end-start) DB 0
-	     *
-	     * where `end' is not known on pass one, despite not
-	     * really being a forward reference, and due to
-	     * criticality it is _needed_. Hence we check our label
-	     * against the currently defined one, and do our own
-	     * resolution of it if we have to.
-	     */
 	    type = EXPR_SIMPLE;	       /* might get overridden by UNKNOWN */
-	    if (i == TOKEN_BASE) {
-		label_seg = seg;
+	    if (i == TOKEN_BASE)
+	    {
+		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 (!labelfunc(tokval->t_charptr,&label_seg,&label_ofs)) {
-		if (critical == 2) {
-		    error (ERR_NONFATAL, "symbol `%s' undefined",
-			   tokval->t_charptr);
-		    return NULL;
-		} else if (critical == 1) {
-		    error (ERR_NONFATAL, "symbol `%s' not defined before use",
-			   tokval->t_charptr);
-		    return NULL;
-		} else {
-		    if (forward)
-			*forward = TRUE;
-		    type = EXPR_UNKNOWN;
-		    label_seg = NO_SEG;
-		    label_ofs = 1;
+	    } 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",
+				tokval->t_charptr);
+			return NULL;
+		    } else if (critical == 1) {
+			error (ERR_NONFATAL,
+				"symbol `%s' not defined before use",
+				tokval->t_charptr);
+			return NULL;
+		    } else {
+			if (opflags)
+			    *opflags |= 1;
+			type = EXPR_UNKNOWN;
+			label_seg = NO_SEG;
+			label_ofs = 1;
+		    }
 		}
+		if (opflags && is_extern (tokval->t_charptr))
+		    *opflags |= OPFLAG_EXTERN;
 	    }
 	    addtotemp(type, label_ofs);
 	    if (label_seg!=NO_SEG)
@@ -676,26 +742,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 +770,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 +805,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 26bde15a..a933cbfd 100644
--- a/eval.h
+++ b/eval.h
@@ -14,15 +14,7 @@
  * 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/misc/exebin.mac b/exebin.mac
similarity index 100%
copy from misc/exebin.mac
copy to exebin.mac
diff --git a/float.c b/float.c
index 1f66ca61..545ae773 100644
--- a/float.c
+++ b/float.c
@@ -25,9 +25,10 @@
  * => 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)
diff --git a/insns.dat b/insns.dat
index 27436f1b..441f4654 100644
--- a/insns.dat
+++ b/insns.dat
@@ -14,9 +14,9 @@
 
 AAA       void                \1\x37                        8086
 AAD       void                \2\xD5\x0A                    8086
-AAD       imm                 \1\xD5\24                     8086
+AAD       imm                 \1\xD5\24                     8086,SB
 AAM       void                \2\xD4\x0A                    8086
-AAM       imm                 \1\xD4\24                     8086
+AAM       imm                 \1\xD4\24                     8086,SB
 AAS       void                \1\x3F                        8086
 ADC       mem,reg8            \300\1\x10\101                8086,SM
 ADC       reg8,reg8           \300\1\x10\101                8086
@@ -104,27 +104,28 @@ BT        mem,reg16           \320\300\2\x0F\xA3\101        386,SM
 BT        reg16,reg16         \320\300\2\x0F\xA3\101        386
 BT        mem,reg32           \321\300\2\x0F\xA3\101        386,SM
 BT        reg32,reg32         \321\300\2\x0F\xA3\101        386
-BT        rm16,imm            \320\300\2\x0F\xBA\204\25     386
-BT        rm32,imm            \321\300\2\x0F\xBA\204\25     386
+BT        rm16,imm            \320\300\2\x0F\xBA\204\25     386,SB
+BT        rm32,imm            \321\300\2\x0F\xBA\204\25     386,SB
 BTC       mem,reg16           \320\300\2\x0F\xBB\101        386,SM
 BTC       reg16,reg16         \320\300\2\x0F\xBB\101        386
 BTC       mem,reg32           \321\300\2\x0F\xBB\101        386,SM
 BTC       reg32,reg32         \321\300\2\x0F\xBB\101        386
-BTC       rm16,imm            \320\300\2\x0F\xBA\207\25     386
-BTC       rm32,imm            \321\300\2\x0F\xBA\207\25     386
+BTC       rm16,imm            \320\300\2\x0F\xBA\207\25     386,SB
+BTC       rm32,imm            \321\300\2\x0F\xBA\207\25     386,SB
 BTR       mem,reg16           \320\300\2\x0F\xB3\101        386,SM
 BTR       reg16,reg16         \320\300\2\x0F\xB3\101        386
 BTR       mem,reg32           \321\300\2\x0F\xB3\101        386,SM
 BTR       reg32,reg32         \321\300\2\x0F\xB3\101        386
-BTR       rm16,imm            \320\300\2\x0F\xBA\206\25     386
-BTR       rm32,imm            \321\300\2\x0F\xBA\206\25     386
+BTR       rm16,imm            \320\300\2\x0F\xBA\206\25     386,SB
+BTR       rm32,imm            \321\300\2\x0F\xBA\206\25     386,SB
 BTS       mem,reg16           \320\300\2\x0F\xAB\101        386,SM
 BTS       reg16,reg16         \320\300\2\x0F\xAB\101        386
 BTS       mem,reg32           \321\300\2\x0F\xAB\101        386,SM
 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
+BTS       rm16,imm            \320\300\2\x0F\xBA\205\25     386,SB
+BTS       rm32,imm            \321\300\2\x0F\xBA\205\25     386,SB
 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
@@ -418,9 +420,9 @@ IMUL      reg16,imm8          \320\1\x6B\100\15             286
 IMUL      reg16,imm           \320\1\x69\100\31             286,SM
 IMUL      reg32,imm8          \321\1\x6B\100\15             386
 IMUL      reg32,imm           \321\1\x69\100\41             386,SM
-IN        reg_al,imm          \1\xE4\25                     8086
-IN        reg_ax,imm          \320\1\xE5\25                 8086
-IN        reg_eax,imm         \321\1\xE5\25                 386
+IN        reg_al,imm          \1\xE4\25                     8086,SB
+IN        reg_ax,imm          \320\1\xE5\25                 8086,SB
+IN        reg_eax,imm         \321\1\xE5\25                 386,SB
 IN        reg_al,reg_dx       \1\xEC                        8086
 IN        reg_ax,reg_dx       \320\1\xED                    8086
 IN        reg_eax,reg_dx      \321\1\xED                    386
@@ -433,7 +435,7 @@ INCBIN    ignore              ignore                        ignore
 INSB      void                \1\x6C                        186
 INSD      void                \321\1\x6D                    386
 INSW      void                \320\1\x6D                    186
-INT       imm                 \1\xCD\24                     8086
+INT       imm                 \1\xCD\24                     8086,SB
 INT01     void                \1\xF1                        P6,ND
 INT1      void                \1\xF1                        P6
 INT3      void                \1\xCC                        8086
@@ -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
@@ -797,26 +840,26 @@ RESQ      ignore              ignore                        ignore
 REST      ignore              ignore                        ignore
 RESW      ignore              ignore                        ignore
 RET       void                \1\xC3                        8086
-RET       imm                 \1\xC2\30                     8086
+RET       imm                 \1\xC2\30                     8086,SW
 RETF      void                \1\xCB                        8086
-RETF      imm                 \1\xCA\30                     8086
+RETF      imm                 \1\xCA\30                     8086,SW
 RETN      void                \1\xC3                        8086
-RETN      imm                 \1\xC2\30                     8086
+RETN      imm                 \1\xC2\30                     8086,SW
 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
diff --git a/labels.c b/labels.c
index 2c17c7c8..dc7e0759 100644
--- 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.
+ */
diff --git a/labels.h b/labels.h
index 111104bf..b78c8564 100644
--- 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);
diff --git a/listing.c b/listing.c
index 89b722a6..af8a9bf8 100644
--- 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/macros.c b/macros.c
index ea02959a..ed70a75e 100644
--- a/macros.c
+++ b/macros.c
@@ -2,7 +2,7 @@
 
 static char *stdmac[] = {
     "%define __NASM_MAJOR__ 0",
-    "%define __NASM_MINOR__ 97",
+    "%define __NASM_MINOR__ 98",
     "%define __FILE__",
     "%define __LINE__",
     "%define __SECT__",
diff --git a/names.c b/names.c
index 218ce5aa..cc168452 100644
--- 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 a1e4dd8a..1404db15 100644
--- a/nasm.c
+++ b/nasm.c
@@ -22,6 +22,11 @@
 #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 8dafac5d..93c41a77 100644
--- 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 J4"
 
 #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
@@ -260,13 +263,6 @@ typedef expr *(*evalfunc) (scanner sc, void *scprivate, struct tokenval *tv,
 			   int *fwref, int critical, efunc error,
 			   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
@@ -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
@@ -568,6 +583,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
@@ -586,6 +622,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
@@ -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);
 };
 
 /*
@@ -734,6 +779,103 @@ struct ofmt {
 #define OUT_TYPMASK 0xF0000000UL
 #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
diff --git a/nasmlib.c b/nasmlib.c
index 4508fec4..86ed6c47 100644
--- 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 };
diff --git a/nasmlib.h b/nasmlib.h
index 9168f183..d2997b18 100644
--- 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
@@ -60,6 +60,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
diff --git a/ndisasm.c b/ndisasm.c
index 90639e90..a07a2781 100644
--- 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 :-) */
 
     /*
diff --git a/outaout.c b/outaout.c
index e4c7610c..b82109a9 100644
--- 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,
diff --git a/outas86.c b/outas86.c
index f214d866..eb02186b 100644
--- 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,
diff --git a/outbin.c b/outbin.c
index 3540739f..a3289cfc 100644
--- 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,
diff --git a/outcoff.c b/outcoff.c
index 09e886ce..f546a8e0 100644
--- 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,
diff --git a/outdbg.c b/outdbg.c
index b3d23a04..723e372d 100644
--- 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,
diff --git a/outelf.c b/outelf.c
index 6f6c1be6..0b77c017 100644
--- 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,
diff --git a/outform.c b/outform.c
index 09202de3..c8b95323 100644
--- a/outform.c
+++ b/outform.c
@@ -11,9 +11,10 @@
 
 #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);
 }
diff --git a/outform.h b/outform.h
index e23f3c79..2e7a32d0 100644
--- 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.
  *
@@ -35,12 +38,6 @@
 
 #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/outform.h b/outforms.h
similarity index 78%
copy from outform.h
copy to outforms.h
index e23f3c79..2afbbe27 100644
--- a/outform.h
+++ b/outforms.h
@@ -30,17 +30,11 @@
  *
  * You probably only want to set these options while compiling 'nasm.c'. */
 
-#ifndef NASM_OUTFORM_H
-#define NASM_OUTFORM_H
+#ifndef NASM_OUTFORMS_H
+#define NASM_OUTFORMS_H
 
 #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 ---------------- */
 
 /*
@@ -173,4 +167,57 @@ void ofmt_register (struct ofmt *);
 #define OF_DEFAULT of_bin
 #endif
 
-#endif  /* NASM_OUTFORM_H */
+#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 */
diff --git a/outobj.c b/outobj.c
index f54d2976..0a7544d6 100644
--- 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
@@ -18,8 +18,446 @@
 
 #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 at 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,
diff --git a/outrdf.c b/outrdf.c
index cde13277..d9989e52 100644
--- 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
index 00000000..4ae6799b
--- /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 */
diff --git a/parser.c b/parser.c
index d7bbdb0c..704e2eb4 100644
--- 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) {
diff --git a/parser.h b/parser.h
index 0681cd03..bc2135de 100644
--- 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
diff --git a/preproc.c b/preproc.c
index 032854e1..291b57ec 100644
--- 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;
@@ -401,10 +416,23 @@ 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)
@@ -864,49 +924,14 @@ static int smacro_defined (char *name, int nparam, SMacro **defn) {
     return FALSE;
 }
 
-/*
- * 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/standard.mac b/standard.mac
index 0be81088..5f862980 100644
--- a/standard.mac
+++ b/standard.mac
@@ -1,10 +1,10 @@
-; Standard macro set for NASM 0.97 -*- nasm -*-
+; Standard macro set for NASM 0.98 -*- nasm -*-
 ; Note that although some user-level forms of directives are defined
 ; here, not all of them are: the user-level form of a format-specific
 ; directive should be defined in the module for that directive.
 
 %define __NASM_MAJOR__ 0
-%define __NASM_MINOR__ 97
+%define __NASM_MINOR__ 98
 
 ; These two need to be defined, though the actual definitions will
 ; be constantly updated during preprocessing.
diff --git a/sync.c b/sync.c
index 7acba0ee..261afbca 100644
--- 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
index 00000000..b36098a6
--- /dev/null
+++ b/zoutieee.c
@@ -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 */


More information about the Nasm-commits mailing list