summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@zytor.com>2002-04-30 20:53:55 +0000
committerH. Peter Anvin <hpa@zytor.com>2002-04-30 20:53:55 +0000
commiteba20a73f2b3396f617747e789e35a679eb09606 (patch)
tree2a1b5e2652e39022a1d6ff7a36a630041edad1b6
parent87bc61964cf5d2cc2e322883d6f927a43fb53af3 (diff)
downloadnasm-eba20a73f2b3396f617747e789e35a679eb09606.tar.gz
nasm-eba20a73f2b3396f617747e789e35a679eb09606.tar.bz2
nasm-eba20a73f2b3396f617747e789e35a679eb09606.zip
NASM 0.98p3
-rw-r--r--Changes94
-rw-r--r--Wishlist225
-rw-r--r--assemble.c858
-rw-r--r--disasm.c41
-rw-r--r--eval.c241
-rw-r--r--eval.h12
-rw-r--r--float.c38
-rw-r--r--insns.dat88
-rw-r--r--labels.c117
-rw-r--r--labels.h3
-rw-r--r--listing.c84
-rw-r--r--names.c20
-rw-r--r--nasm.c901
-rw-r--r--nasm.h186
-rw-r--r--nasmlib.c360
-rw-r--r--nasmlib.h79
-rw-r--r--ndisasm.c41
-rw-r--r--outaout.c73
-rw-r--r--outas86.c60
-rw-r--r--outbin.c57
-rw-r--r--outcoff.c84
-rw-r--r--outdbg.c95
-rw-r--r--outelf.c95
-rw-r--r--outform.c37
-rw-r--r--outform.h84
-rw-r--r--outforms.h223
-rw-r--r--outobj.c1608
-rw-r--r--outrdf.c25
-rw-r--r--outrdf2.c690
-rw-r--r--parser.c202
-rw-r--r--parser.h3
-rw-r--r--preproc.c1460
-rw-r--r--sync.c9
-rw-r--r--zoutieee.c1457
34 files changed, 7234 insertions, 2416 deletions
diff --git a/Changes b/Changes
index 24f4bfe..57584bd 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 197b113..b1529bf 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@dlc.fi)
+
+- Package the Linux Assembler HOWTO. 0.98
+
+- AMD 3dNow extensions need documenting. 0.98
+
+- prototypes of lrotate don't match in test/*. Fix. 0.98
+
+- Build djgpp binaries for 0.98 onwards. Look into PMODE/W as a stub 0.98
+ - it might be a lot better than CWSDPMI. It's in PMW133.ZIP.
+
+- Fix `%error' giving error messages twice. 0.99
+ Not especially important, as changes planned for 1.1x below will make
+ the preprocessor be only called once.
+
+- Sort out problems with OBJ: 0.99
+ * TLINK32 doesn't seem to like SEGDEF32 et al. So for that, we
+ should avoid xxx32 records wherever we can.
+ * However, didn't we change _to_ using xxx32 at some stage? Try
+ to remember why and when.
+ * Apparently Delphi's linker has trouble with two or more
+ globals being defined inside a PUBDEF32. Don't even know if it
+ _can_ cope with a PUBDEF16.
+ * Might need extra flags. *sigh*
+
+- Symbol table output may possibly be useful. 0.99
+ Ken Martwick (kenm@efn.org) wants the following format:
+ labelname type offset(hex) repetition count
+ Possibly include xref addresses after repetition count?
+
+- There are various other bugs in outelf.c that make certain kinds 0.99
+ of relocation not work. See zbrown.asm. Looks like we may have to do
+ a major rewrite of parts of it. Compare some NASM code output with
+ equivalent GAS code output. Look at the ELF spec. Generally fix things.
+
+- NASM is currently using a kludge in ELF that involves defining 0.99
+ a symbol at a zero absolute offset. This isn't needed, as the
+ documented solution to the problem that this solves is to use
+ SHN_UNDEF.
+
+- Debug information, in all formats it can be usefully done in. 0.99
+ * including line-number record support.
+ * "George C. Lindauer" <gclind01@starbase.spd.louisville.edu>
+ wants to have some say in how this goes through.
+ * Andrew Crabtree <andrewc@rosemail.rose.hp.com> wants to help out.
+
+- Think about a line-continuation character. 0.99
+
+- Consider allowing declaration of two labels on the same line,
+ syntax 'label1[:] label2[:] ... instruction'. Need to investigate
+ feasibility. 0.99
+
+- Quoting of quotes by doubling them, in string and char constants. 0.99
+
+- Two-operand syntax for SEGMENT/SECTION macro to avoid warnings 0.99
+ of ignored section parameters on reissue of __SECT__.
+ Or maybe skip the warning if the given parameters are identical to
+ what was actually stored. Investigate.
+
+- Apparently we are not missing a PSRAQ instruction, because it
+ doesn't exist. Check that it doesn't exist as an undocumented
+ instruction, or something stupid like that. 0.99
+
+- Any assembled form starting 0x80 can also start 0x82. ndisasm 1.00
+ should know this. New special code in instruction encodings,
+ probably.
+
+- Pointing an EQU at an external symbol now generates an error. There 1.05
+ may be a better way of handling this; we should look into it.
+ Ideally, the label mechanism should be changed to cope with one
+ label being declared relative to another - that may work, but could be
+ a pain to implement (or is it? it may be easy enough that you just
+ need to declare a new offset in the same segment...) This should be done
+ before v1.0 is released. There is a comment regarding this in labels.c,
+ towards the end of the file, which discusses ways of fixing this.
+
+- nested %rep used to cause a panic. Now a more informative error 1.10
+ message is produced. This problem whould be fixed before v1.0.
+ See comment in switch() statement block for PP_REP in do_directive()
+ in preproc.c (line 1585, or thereabouts)
+
+- Contribution: zgraeme.tar contains improved hash table routines ?
+ contributed by Graeme Defty <graeme@HK.Super.NET> for use in the
+ label manager.
+
+- Contribution: zsyntax.zip contains a syntax-highlighting mode for ?
+ NASM, for use with the Aurora text editor (??).
+
+- Contribution: zvim.zip contains a syntax-highlighting mode for ?
+ NASM, for use with vim.
+
+- Contribution: zkendal1.zip and zkendal2.zip contain Kendall ?
+ Bennett's (<KendallB@scitechsoft.com>) alternative syntax stuff,
+ providing an alternative syntax mode for NASM which allows a macro
+ set to be written that allows the same source files to be
+ assembled with NASM and TASM.
+
+- Add the UD2 instruction. ?
+
+- Add the four instructions documented in 24368901.pdf (Intel's own ?
+ document).
+
+- Some means of avoiding MOV memoffs,EAX which apparently the 1.10?
+ Pentium pairing detector thinks modifies EAX. Similar means of
+ choosing instruction encodings where necessary.
+
+- The example of ..@ makes it clear that a ..@ label isn't just ?
+ local, but doesn't make it clear that it isn't just global either.
+
+- hpa wants an evaluator operator for ceil(log2(x)). ?
+
+- Extra reloc types in ELF: R_386_16 type 20, PC16 is 21, 8 is 22, PC8 is 23.
+ Add support for the 16s at least. ?
+
+
+- Lazy section creation or selective section output, in COFF/win32 ?
+ at least and probably other formats: don't bother to emit a section
+ if it contains no data. Particularly the default auto-created
+ section. We believe zero-length sections crash at least WLINK (in
+ win32).
+
+- Make the flags field in `struct itemplate' in insns.h a long ?
+ instead of an int.
+
+- Implement %ifref to check whether a single-line macro has ever been ?
+ expanded since (last re) definition. Or maybe not. We'll see.
+
+- add pointer to \k{insLEAVE} and \k{insENTER} in chapters about ?
+ mixed-language programming.
+
+- Some equivalent to TASM's GLOBAL directive, ie something which ?
+ defines a symbol as external if it doesn't end up being defined
+ but defines it as public if it does end up being defined.
+
+- Documentation doesn't explain about C++ name mangling. ?
+
+- see if BITS can be made to do anything sensible in obj (eg set the ?
default new-segment property to Use32).
-- __DATE__, __TIME__, and text variants of __NASM_MAJOR__ and
+- OBJ: coalesce consecutive offset and segment fixups for the same ?
+ location into full-32bit-pointer fixups. This is apparently
+ necessary because some twazzock in the PowerBASIC development
+ team didn't deign to support the OMF spec the way the rest of the
+ world sees it.
+
+- Allow % to be separated from the rest of a preproc directive, for ?
+ alternative directive indentation styles.
+
+- __DATE__, __TIME__, and text variants of __NASM_MAJOR__ and ?
__NASM_MINOR__.
-- Warn on TIMES combined with multi-line macros. TIMES gets applied
+- Warn on TIMES combined with multi-line macros. TIMES gets applied 1.00
to first line only - should bring to users' attention.
-- Add support for lcc 4.0.
- * If-when this happens, remember to bump the `supported lcc
- version' number in Readme.
-
-- Re-work the evaluator, again, with a per-object-format fixup
+- Re-work the evaluator, again, with a per-object-format fixup 1.10
routine, so as to be able to cope with section offsets "really"
being pure numbers; should be able to allow at _least_ the two
common idioms
@@ -28,17 +173,33 @@ NASM Wishlist
had to. (_Always_ returning UNKNOWN on pass one, though a lovely
clean design, breaks the first of the above examples.)
-- Preprocessor identifier concatenation?
+- Preprocessor identifier concatenation? 1.10
-- Arbitrary section names in `bin'.
+- Arbitrary section names in `bin'. ?
+ Is this necessary? Is it even desirable?
-- Ability to read from a pipe. Obviously not useful under dos, so
+- Ability to read from a pipe. Obviously not useful under dos, so 1.10
memory problems with storing entire input file aren't a problem
either.
-- Subsection support?
+ Related topic: file caching under DOS/32 bit... 1.10?
+ maybe even implement discardable buffers that get thrown away
+ when we get a NULL returned from malloc(). Only really useful under
+ DOS. Think about it.
+
+ Another related topic: possibly spool out the pre-processed 1.10?
+ stuff to a file, to avoid having to re-process it. Possible problems
+ with preprocessor values not known on pass 1? Have a look...
+
+ Or maybe we can spool out a pre-parsed version...? 1.10
+ Need to investigate feasibility. Does the results from the parser
+ change from pass 1 to pass 2? Would it be feasible to alter it so that
+ the parser returns an invariant result, and this is then processed
+ afterwards to resolve label references, etc?
-- A good ALIGN mechanism, similar to GAS's. GAS pads out space by
+- Subsection support? ?
+
+- A good ALIGN mechanism, similar to GAS's. GAS pads out space by 1.10?
means of the following (32-bit) instructions:
8DB42600000000 lea esi,[esi+0x0]
8DB600000000 lea esi,[esi+0x0]
@@ -55,7 +216,7 @@ NASM Wishlist
Also re-work the macro form so that when given one argument in a
code section it calls this feature.
-- Possibly a means whereby FP constants can be specified as
+- Possibly a means whereby FP constants can be specified as ?
immediate operands to non-FP instructions.
* Possible syntax: MOV EAX,FLOAT 1.2 to get a single-precision FP
constant. Then maybe MOV EAX,HI_FLOAT 1.2 and MOV EAX,LO_FLOAT
@@ -67,37 +228,41 @@ NASM Wishlist
chunks, one-byte chunks, even stranger chunks, and pieces of
ten-byte reals to be bandied around as well.
-- A UNION macro might be quite cool, now that ABSOLUTE is sane
+- A UNION macro might be quite cool, now that ABSOLUTE is sane ?
enough to be able to handle it.
-- An equivalent to gcc's ## stringify operator, plus string
+- An equivalent to gcc's ## stringify operator, plus string ?
concatenation, somehow implemented without undue ugliness, so as
to be able to do `%include "/my/path/%1"' in a macro, or something
similar...
-- Actually _do_ something with the processor, privileged and
- undocumented flags in the instruction table.
+- Actually _do_ something with the processor, privileged and 1.10
+ undocumented flags in the instruction table. When this happens,
+ consider allowing PMULHRW to map to either of the Cyrix or AMD
+ versions?
-- Maybe NEC V20/V30 instructions?
+- Maybe NEC V20/V30 instructions? ?
- Yet more object formats.
- * Possibly direct support for .EXE files?
-
-- Debug information, in all formats it can be usefully done in.
- * including line-number record support.
+ * Possibly direct support for .EXE files? 1.10
-- Symbol map in binary format. Format-specific options...
+- Symbol map in binary format. Format-specific options... 1.10?
-- REDESIGN: Think about EQU dependency, and about start-point
+- REDESIGN: Think about EQU dependency, and about start-point 1.20?
specification in OBJ. Possibly re-think directive support.
-- Think about a wrapper program like gcc? Possibly invent a _patch_
+- Think about a wrapper program like gcc? Possibly invent a _patch_ 2.00?
for gcc so that it can take .asm files on the command line?
-- If a wrapper happens, think about adding an option to cause the
+- If a wrapper happens, think about adding an option to cause the ?
resulting executable file to be executed immediately, thus
allowing NASM source files to have #!... (probably silly)
-- Multi-platform support? If so: definitely Alpha; possibly Java
+- Multi-platform support? If so: definitely Alpha; possibly Java ?
byte code; probably ARM/StrongARM; maybe Sparc; maybe Mips; maybe
Vax. Perhaps Z80 and 6502, just for a laugh?
+
+- Consider a 'verbose' option that prints information about the resulting ?
+ object file onto stdout.
+
+
diff --git a/assemble.c b/assemble.c
index 8d14412..65bcea3 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/disasm.c b/disasm.c
index 3dded0d..4764bc1 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 0e81c92..6dd3f4d 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" :
@@ -641,11 +713,11 @@ static expr *expr6(int critical) {
*/
type = EXPR_SIMPLE; /* might get overridden by UNKNOWN */
if (i == TOKEN_BASE) {
- label_seg = seg;
+ label_seg = location->segment;
label_ofs = 0;
- } else if (i == TOKEN_HERE || !strcmp(tokval->t_charptr, label)) {
- label_seg = seg;
- label_ofs = ofs;
+ } else if (i == TOKEN_HERE) {
+ label_seg = location->segment;
+ label_ofs = location->offset;
} else if (!labelfunc(tokval->t_charptr,&label_seg,&label_ofs)) {
if (critical == 2) {
error (ERR_NONFATAL, "symbol `%s' undefined",
@@ -656,16 +728,19 @@ static expr *expr6(int critical) {
tokval->t_charptr);
return NULL;
} else {
- if (forward)
- *forward = TRUE;
+ if (opflags)
+ *opflags |= 1;
type = EXPR_UNKNOWN;
label_seg = NO_SEG;
label_ofs = 1;
}
}
addtotemp(type, label_ofs);
- if (label_seg!=NO_SEG)
+ if (label_seg!=NO_SEG) {
addtotemp(EXPR_SEGBASE + label_seg, 1L);
+ if (opflags && is_extern (tokval->t_charptr))
+ *opflags |= OPFLAG_EXTERN;
+ }
break;
}
i = scan(scpriv, tokval);
@@ -676,26 +751,17 @@ static expr *expr6(int critical) {
}
}
-void eval_global_info (struct ofmt *output, lfunc lookup_label) {
+void eval_global_info (struct ofmt *output, lfunc lookup_label, loc_t *locp)
+{
outfmt = output;
labelfunc = lookup_label;
-}
-
-void eval_info (char *labelname, long segment, long offset) {
- if (label != special_empty_string)
- nasm_free (label);
- if (labelname)
- label = nasm_strdup(labelname);
- else {
- label = special_empty_string;
- seg = segment;
- ofs = offset;
- }
+ location = locp;
}
expr *evaluate (scanner sc, void *scprivate, struct tokenval *tv,
int *fwref, int critical, efunc report_error,
- struct eval_hints *hints) {
+ struct eval_hints *hints)
+{
expr *e;
expr *f = NULL;
@@ -713,7 +779,7 @@ expr *evaluate (scanner sc, void *scprivate, struct tokenval *tv,
scpriv = scprivate;
tokval = tv;
error = report_error;
- forward = fwref;
+ opflags = fwref;
if (tokval->t_type == TOKEN_INVALID)
i = scan(scpriv, tokval);
@@ -748,7 +814,8 @@ expr *evaluate (scanner sc, void *scprivate, struct tokenval *tv,
value = reloc_seg(f);
if (value == NO_SEG)
value = reloc_value(f) | SEG_ABS;
- else if (!(value & SEG_ABS) && !(value % 2) && critical) {
+ else if (!(value & SEG_ABS) && !(value % 2) && critical)
+ {
error(ERR_NONFATAL, "invalid right-hand operand to WRT");
return NULL;
}
diff --git a/eval.h b/eval.h
index 26bde15..a933cbf 100644
--- 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/float.c b/float.c
index 1f66ca6..545ae77 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 27436f1..4113a07 100644
--- a/insns.dat
+++ b/insns.dat
@@ -125,6 +125,7 @@ BTS reg32,reg32 \321\300\2\x0F\xAB\101 386
BTS rm16,imm \320\300\2\x0F\xBA\205\25 386
BTS rm32,imm \321\300\2\x0F\xBA\205\25 386
CALL imm \322\1\xE8\64 8086
+CALL imm|near \322\1\xE8\64 8086
CALL imm|far \322\1\x9A\34\37 8086,ND
CALL imm:imm \322\1\x9A\35\30 8086
CALL imm16:imm \320\1\x9A\31\30 8086
@@ -274,6 +275,7 @@ FDIVR fpureg \1\xD8\10\xF8 8086,FPU
FDIVR fpu0,fpureg \1\xD8\11\xF8 8086,FPU
FDIVRP fpureg \1\xDE\10\xF0 8086,FPU
FDIVRP fpureg,fpu0 \1\xDE\10\xF0 8086,FPU
+FEMMS void \2\x0F\x0E PENT,MMX,FPU
FENI void \3\x9B\xDB\xE0 8086,FPU
FFREE fpureg \1\xDD\10\xC0 8086,FPU
FIADD mem32 \300\1\xDA\200 8086,FPU
@@ -447,6 +449,7 @@ JCXZ imm \320\1\xE3\50 8086
JECXZ imm \321\1\xE3\50 386
JMP imm|short \1\xEB\50 8086
JMP imm \322\1\xE9\64 8086
+JMP imm|near \322\1\xE9\64 8086
JMP imm|far \322\1\xEA\34\37 8086,ND
JMP imm:imm \322\1\xEA\35\30 8086
JMP imm16:imm \320\1\xEA\31\30 8086
@@ -619,9 +622,9 @@ OR rm32,imm \321\300\1\x81\201\41 386,SM
OR mem,imm8 \300\1\x80\201\21 8086,SM
OR mem,imm16 \320\300\1\x81\201\31 8086,SM
OR mem,imm32 \321\300\1\x81\201\41 386,SM
-OUT imm,reg_al \1\xE6\24 8086
-OUT imm,reg_ax \320\1\xE7\24 8086
-OUT imm,reg_eax \321\1\xE7\24 386
+OUT imm,reg_al \1\xE6\24 8086,SB
+OUT imm,reg_ax \320\1\xE7\24 8086,SB
+OUT imm,reg_eax \321\1\xE7\24 386,SB
OUT reg_dx,reg_al \1\xEE 8086
OUT reg_dx,reg_ax \320\1\xEF 8086
OUT reg_dx,reg_eax \321\1\xEF 386
@@ -656,6 +659,8 @@ PANDN mmxreg,mem \301\2\x0F\xDF\110 PENT,MMX,SM
PANDN mmxreg,mmxreg \2\x0F\xDF\110 PENT,MMX
PAVEB mmxreg,mem \301\2\x0F\x50\110 PENT,MMX,SM,CYRIX
PAVEB mmxreg,mmxreg \2\x0F\x50\110 PENT,MMX,CYRIX
+PAVGUSB mmxreg,mem \301\2\x0F\x0F\110\01\xBF PENT,MMX,SM,FPU
+PAVGUSB mmxreg,mmxreg \2\x0F\x0F\110\01\xBF PENT,MMX,FPU
PCMPEQB mmxreg,mem \301\2\x0F\x74\110 PENT,MMX,SM
PCMPEQB mmxreg,mmxreg \2\x0F\x74\110 PENT,MMX
PCMPEQD mmxreg,mem \301\2\x0F\x76\110 PENT,MMX,SM
@@ -669,15 +674,51 @@ PCMPGTD mmxreg,mmxreg \2\x0F\x66\110 PENT,MMX
PCMPGTW mmxreg,mem \301\2\x0F\x65\110 PENT,MMX,SM
PCMPGTW mmxreg,mmxreg \2\x0F\x65\110 PENT,MMX
PDISTIB mmxreg,mem \301\2\x0F\x54\110 PENT,MMX,SM,CYRIX
+PF2ID mmxreg,mem \301\2\x0F\x0F\110\01\x1D PENT,MMX,SM,FPU
+PF2ID mmxreg,mmxreg \2\x0F\x0F\110\01\x1D PENT,MMX,FPU
+PFACC mmxreg,mem \301\2\x0F\x0F\110\01\xAE PENT,MMX,SM,FPU
+PFACC mmxreg,mmxreg \2\x0F\x0F\110\01\xAE PENT,MMX,FPU
+PFADD mmxreg,mem \301\2\x0F\x0F\110\01\x9E PENT,MMX,SM,FPU
+PFADD mmxreg,mmxreg \2\x0F\x0F\110\01\x9E PENT,MMX,FPU
+PFCMPEQ mmxreg,mem \301\2\x0F\x0F\110\01\xB0 PENT,MMX,SM,FPU
+PFCMPEQ mmxreg,mmxreg \2\x0F\x0F\110\01\xB0 PENT,MMX,FPU
+PFCMPGE mmxreg,mem \301\2\x0F\x0F\110\01\x90 PENT,MMX,SM,FPU
+PFCMPGE mmxreg,mmxreg \2\x0F\x0F\110\01\x90 PENT,MMX,FPU
+PFCMPGT mmxreg,mem \301\2\x0F\x0F\110\01\xA0 PENT,MMX,SM,FPU
+PFCMPGT mmxreg,mmxreg \2\x0F\x0F\110\01\xA0 PENT,MMX,FPU
+PFMAX mmxreg,mem \301\2\x0F\x0F\110\01\xA4 PENT,MMX,SM,FPU
+PFMAX mmxreg,mmxreg \2\x0F\x0F\110\01\xA4 PENT,MMX,FPU
+PFMIN mmxreg,mem \301\2\x0F\x0F\110\01\x94 PENT,MMX,SM,FPU
+PFMIN mmxreg,mmxreg \2\x0F\x0F\110\01\x94 PENT,MMX,FPU
+PFMUL mmxreg,mem \301\2\x0F\x0F\110\01\xB4 PENT,MMX,SM,FPU
+PFMUL mmxreg,mmxreg \2\x0F\x0F\110\01\xB4 PENT,MMX,FPU
+PFRCP mmxreg,mem \301\2\x0F\x0F\110\01\x96 PENT,MMX,SM,FPU
+PFRCP mmxreg,mmxreg \2\x0F\x0F\110\01\x96 PENT,MMX,FPU
+PFRCPIT1 mmxreg,mem \301\2\x0F\x0F\110\01\xA6 PENT,MMX,SM,FPU
+PFRCPIT1 mmxreg,mmxreg \2\x0F\x0F\110\01\xA6 PENT,MMX,FPU
+PFRCPIT2 mmxreg,mem \301\2\x0F\x0F\110\01\xB6 PENT,MMX,SM,FPU
+PFRCPIT2 mmxreg,mmxreg \2\x0F\x0F\110\01\xB6 PENT,MMX,FPU
+PFRSQIT1 mmxreg,mem \301\2\x0F\x0F\110\01\xA7 PENT,MMX,SM,FPU
+PFRSQIT1 mmxreg,mmxreg \2\x0F\x0F\110\01\xA7 PENT,MMX,FPU
+PFRSQRT mmxreg,mem \301\2\x0F\x0F\110\01\x97 PENT,MMX,SM,FPU
+PFRSQRT mmxreg,mmxreg \2\x0F\x0F\110\01\x97 PENT,MMX,FPU
+PFSUB mmxreg,mem \301\2\x0F\x0F\110\01\x9A PENT,MMX,SM,FPU
+PFSUB mmxreg,mmxreg \2\x0F\x0F\110\01\x9A PENT,MMX,FPU
+PFSUBR mmxreg,mem \301\2\x0F\x0F\110\01\xAA PENT,MMX,SM,FPU
+PFSUBR mmxreg,mmxreg \2\x0F\x0F\110\01\xAA PENT,MMX,FPU
+PI2FD mmxreg,mem \301\2\x0F\x0F\110\01\x0D PENT,MMX,SM,FPU
+PI2FD mmxreg,mmxreg \2\x0F\x0F\110\01\x0D PENT,MMX,FPU
PMACHRIW mmxreg,mem \301\2\x0F\x5E\110 PENT,MMX,SM,CYRIX
PMADDWD mmxreg,mem \301\2\x0F\xF5\110 PENT,MMX,SM
PMADDWD mmxreg,mmxreg \2\x0F\xF5\110 PENT,MMX
PMAGW mmxreg,mem \301\2\x0F\x52\110 PENT,MMX,SM,CYRIX
PMAGW mmxreg,mmxreg \2\x0F\x52\110 PENT,MMX,CYRIX
-PMULHRW mmxreg,mem \301\2\x0F\x59\110 PENT,MMX,SM,CYRIX
-PMULHRW mmxreg,mmxreg \2\x0F\x59\110 PENT,MMX,CYRIX
PMULHRIW mmxreg,mem \301\2\x0F\x5D\110 PENT,MMX,SM,CYRIX
PMULHRIW mmxreg,mmxreg \2\x0F\x5D\110 PENT,MMX,CYRIX
+PMULHRWA mmxreg,mem \301\2\x0F\x0F\110\1\xB7 PENT,MMX,SM,FPU
+PMULHRWA mmxreg,mmxreg \2\x0F\x0F\110\1\xB7 PENT,MMX,FPU
+PMULHRWC mmxreg,mem \301\2\x0F\x59\110 PENT,MMX,SM,CYRIX
+PMULHRWC mmxreg,mmxreg \2\x0F\x59\110 PENT,MMX,CYRIX
PMULHW mmxreg,mem \301\2\x0F\xE5\110 PENT,MMX,SM
PMULHW mmxreg,mmxreg \2\x0F\xE5\110 PENT,MMX
PMULLW mmxreg,mem \301\2\x0F\xD5\110 PENT,MMX,SM
@@ -701,6 +742,8 @@ POPFD void \321\1\x9D 386
POPFW void \320\1\x9D 186
POR mmxreg,mem \301\2\x0F\xEB\110 PENT,MMX,SM
POR mmxreg,mmxreg \2\x0F\xEB\110 PENT,MMX
+PREFETCH mem \2\x0F\x0D\200 PENT,MMX,SM,FPU
+PREFETCHW mem \2\x0F\x0D\201 PENT,MMX,SM,FPU
PSLLD mmxreg,mem \301\2\x0F\xF2\110 PENT,MMX,SM
PSLLD mmxreg,mmxreg \2\x0F\xF2\110 PENT,MMX
PSLLD mmxreg,imm \2\x0F\x72\206\25 PENT,MMX
@@ -772,19 +815,19 @@ PXOR mmxreg,mem \301\2\x0F\xEF\110 PENT,MMX,SM
PXOR mmxreg,mmxreg \2\x0F\xEF\110 PENT,MMX
RCL rm8,unity \300\1\xD0\202 8086
RCL rm8,reg_cl \300\1\xD2\202 8086
-RCL rm8,imm \300\1\xC0\202\25 286,SB
+RCL rm8,imm \300\1\xC0\202\25 186,SB
RCL rm16,unity \320\300\1\xD1\202 8086
RCL rm16,reg_cl \320\300\1\xD3\202 8086
-RCL rm16,imm \320\300\1\xC1\202\25 286,SB
+RCL rm16,imm \320\300\1\xC1\202\25 186,SB
RCL rm32,unity \321\300\1\xD1\202 386
RCL rm32,reg_cl \321\300\1\xD3\202 386
RCL rm32,imm \321\300\1\xC1\202\25 386,SB
RCR rm8,unity \300\1\xD0\203 8086
RCR rm8,reg_cl \300\1\xD2\203 8086
-RCR rm8,imm \300\1\xC0\203\25 286,SB
+RCR rm8,imm \300\1\xC0\203\25 186,SB
RCR rm16,unity \320\300\1\xD1\203 8086
RCR rm16,reg_cl \320\300\1\xD3\203 8086
-RCR rm16,imm \320\300\1\xC1\203\25 286,SB
+RCR rm16,imm \320\300\1\xC1\203\25 186,SB
RCR rm32,unity \321\300\1\xD1\203 386
RCR rm32,reg_cl \321\300\1\xD3\203 386
RCR rm32,imm \321\300\1\xC1\203\25 386,SB
@@ -804,19 +847,19 @@ RETN void \1\xC3 8086
RETN imm \1\xC2\30 8086
ROL rm8,unity \300\1\xD0\200 8086
ROL rm8,reg_cl \300\1\xD2\200 8086
-ROL rm8,imm \300\1\xC0\200\25 286,SB
+ROL rm8,imm \300\1\xC0\200\25 186,SB
ROL rm16,unity \320\300\1\xD1\200 8086
ROL rm16,reg_cl \320\300\1\xD3\200 8086
-ROL rm16,imm \320\300\1\xC1\200\25 286,SB
+ROL rm16,imm \320\300\1\xC1\200\25 186,SB
ROL rm32,unity \321\300\1\xD1\200 386
ROL rm32,reg_cl \321\300\1\xD3\200 386
ROL rm32,imm \321\300\1\xC1\200\25 386,SB
ROR rm8,unity \300\1\xD0\201 8086
ROR rm8,reg_cl \300\1\xD2\201 8086
-ROR rm8,imm \300\1\xC0\201\25 286,SB
+ROR rm8,imm \300\1\xC0\201\25 186,SB
ROR rm16,unity \320\300\1\xD1\201 8086
ROR rm16,reg_cl \320\300\1\xD3\201 8086
-ROR rm16,imm \320\300\1\xC1\201\25 286,SB
+ROR rm16,imm \320\300\1\xC1\201\25 186,SB
ROR rm32,unity \321\300\1\xD1\201 386
ROR rm32,reg_cl \321\300\1\xD3\201 386
ROR rm32,imm \321\300\1\xC1\201\25 386,SB
@@ -824,20 +867,20 @@ RSM void \2\x0F\xAA PENT
SAHF void \1\x9E 8086
SAL rm8,unity \300\1\xD0\204 8086,ND
SAL rm8,reg_cl \300\1\xD2\204 8086,ND
-SAL rm8,imm \300\1\xC0\204\25 286,ND,SB
+SAL rm8,imm \300\1\xC0\204\25 186,ND,SB
SAL rm16,unity \320\300\1\xD1\204 8086,ND
SAL rm16,reg_cl \320\300\1\xD3\204 8086,ND
-SAL rm16,imm \320\300\1\xC1\204\25 286,ND,SB
+SAL rm16,imm \320\300\1\xC1\204\25 186,ND,SB
SAL rm32,unity \321\300\1\xD1\204 386,ND
SAL rm32,reg_cl \321\300\1\xD3\204 386,ND
SAL rm32,imm \321\300\1\xC1\204\25 386,ND,SB
SALC void \1\xD6 8086,UNDOC
SAR rm8,unity \300\1\xD0\207 8086
SAR rm8,reg_cl \300\1\xD2\207 8086
-SAR rm8,imm \300\1\xC0\207\25 286,SB
+SAR rm8,imm \300\1\xC0\207\25 186,SB
SAR rm16,unity \320\300\1\xD1\207 8086
SAR rm16,reg_cl \320\300\1\xD3\207 8086
-SAR rm16,imm \320\300\1\xC1\207\25 286,SB
+SAR rm16,imm \320\300\1\xC1\207\25 186,SB
SAR rm32,unity \321\300\1\xD1\207 386
SAR rm32,reg_cl \321\300\1\xD3\207 386
SAR rm32,imm \321\300\1\xC1\207\25 386,SB
@@ -870,10 +913,10 @@ SCASW void \320\1\xAF 8086
SGDT mem \300\2\x0F\x01\200 286,PRIV
SHL rm8,unity \300\1\xD0\204 8086
SHL rm8,reg_cl \300\1\xD2\204 8086
-SHL rm8,imm \300\1\xC0\204\25 286,SB
+SHL rm8,imm \300\1\xC0\204\25 186,SB
SHL rm16,unity \320\300\1\xD1\204 8086
SHL rm16,reg_cl \320\300\1\xD3\204 8086
-SHL rm16,imm \320\300\1\xC1\204\25 286,SB
+SHL rm16,imm \320\300\1\xC1\204\25 186,SB
SHL rm32,unity \321\300\1\xD1\204 386
SHL rm32,reg_cl \321\300\1\xD3\204 386
SHL rm32,imm \321\300\1\xC1\204\25 386,SB
@@ -887,10 +930,10 @@ SHLD mem,reg32,reg_cl \300\321\2\x0F\xA5\101 386,SM
SHLD reg32,reg32,reg_cl \300\321\2\x0F\xA5\101 386
SHR rm8,unity \300\1\xD0\205 8086
SHR rm8,reg_cl \300\1\xD2\205 8086
-SHR rm8,imm \300\1\xC0\205\25 286,SB
+SHR rm8,imm \300\1\xC0\205\25 186,SB
SHR rm16,unity \320\300\1\xD1\205 8086
SHR rm16,reg_cl \320\300\1\xD3\205 8086
-SHR rm16,imm \320\300\1\xC1\205\25 286,SB
+SHR rm16,imm \320\300\1\xC1\205\25 186,SB
SHR rm32,unity \321\300\1\xD1\205 386
SHR rm32,reg_cl \321\300\1\xD3\205 386
SHR rm32,imm \321\300\1\xC1\205\25 386,SB
@@ -948,6 +991,9 @@ TEST mem,reg16 \320\300\1\x85\101 8086,SM
TEST reg16,reg16 \320\300\1\x85\101 8086
TEST mem,reg32 \321\300\1\x85\101 386,SM
TEST reg32,reg32 \321\300\1\x85\101 386
+TEST reg8,mem \301\1\x84\110 8086,SM
+TEST reg16,mem \320\301\1\x85\110 8086,SM
+TEST reg32,mem \321\301\1\x85\110 386,SM
TEST reg_al,imm \1\xA8\21 8086,SM
TEST reg_ax,imm \320\1\xA9\31 8086,SM
TEST reg_eax,imm \321\1\xA9\41 386,SM
diff --git a/labels.c b/labels.c
index 2c17c7c..dc7e075 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 111104b..b78c856 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 89b722a..af8a9bf 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/names.c b/names.c
index 218ce5a..cc16845 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 a1e4dd8..1404db1 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 8dafac5..aabe568 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 3"
#ifndef NULL
#define NULL 0
@@ -72,9 +72,6 @@ typedef void (*efunc) (int severity, char *fmt, ...);
#define ERR_MASK 0x0F /* mask off the above codes */
#define ERR_NOFILE 0x10 /* don't give source file name/line */
#define ERR_USAGE 0x20 /* print a usage message */
-#define ERR_OFFBY1 0x40 /* report error as being on the line
- * we're just _about_ to read, not
- * the one we've just read */
#define ERR_PASS1 0x80 /* only print this error on pass one */
/*
@@ -205,6 +202,12 @@ enum { /* token types, other than chars */
TOKEN_FLOAT /* floating-point constant */
};
+typedef struct {
+ long segment;
+ long offset;
+ int known;
+} loc_t;
+
/*
* Expression-evaluator datatype. Expressions, within the
* evaluator, are stored as an array of these beasts, terminated by
@@ -261,13 +264,6 @@ typedef expr *(*evalfunc) (scanner sc, void *scprivate, struct tokenval *tv,
struct eval_hints *hints);
/*
- * There's also an auxiliary routine through which the evaluator
- * needs to hear about the value of $ and the label (if any)
- * defined on the current line.
- */
-typedef void (*evalinfofunc) (char *labelname, long segment, long offset);
-
-/*
* Special values for expr->type. ASSUMPTION MADE HERE: the number
* of distinct register names (i.e. possible "type" fields for an
* expr structure) does not exceed 124 (EXPR_REG_START through
@@ -311,11 +307,13 @@ typedef struct {
* ----------------------------------------------------------------
*/
-/* isidstart matches any character that may start an identifier, and isidchar
+/*
+ * isidstart matches any character that may start an identifier, and isidchar
* matches any character that may appear at places other than the start of an
* identifier. E.g. a period may only appear at the start of an identifier
* (for local labels), whereas a number may appear anywhere *but* at the
- * start. */
+ * start.
+ */
#define isidstart(c) ( isalpha(c) || (c)=='_' || (c)=='.' || (c)=='?' \
|| (c)=='@' )
@@ -439,7 +437,9 @@ enum { /* instruction names */
I_FCMOVBE, I_FCMOVE, I_FCMOVNB, I_FCMOVNBE, I_FCMOVNE,
I_FCMOVNU, I_FCMOVU, I_FCOM, I_FCOMI, I_FCOMIP, I_FCOMP,
I_FCOMPP, I_FCOS, I_FDECSTP, I_FDISI, I_FDIV, I_FDIVP, I_FDIVR,
- I_FDIVRP, I_FENI, I_FFREE, I_FIADD, I_FICOM, I_FICOMP, I_FIDIV,
+ I_FDIVRP,
+ I_FEMMS,
+ I_FENI, I_FFREE, I_FIADD, I_FICOM, I_FICOMP, I_FIDIV,
I_FIDIVR, I_FILD, I_FIMUL, I_FINCSTP, I_FINIT, I_FIST, I_FISTP,
I_FISUB, I_FISUBR, I_FLD, I_FLD1, I_FLDCW, I_FLDENV, I_FLDL2E,
I_FLDL2T, I_FLDLG2, I_FLDLN2, I_FLDPI, I_FLDZ, I_FMUL, I_FMULP,
@@ -451,7 +451,7 @@ enum { /* instruction names */
I_FUCOMI, I_FUCOMIP, I_FUCOMP, I_FUCOMPP, I_FXAM, I_FXCH,
I_FXTRACT, I_FYL2X, I_FYL2XP1, I_HLT, I_IBTS, I_ICEBP, I_IDIV,
I_IMUL, I_IN, I_INC, I_INCBIN, I_INSB, I_INSD, I_INSW, I_INT,
- I_INT1, I_INT01, I_INT3, I_INTO, I_INVD, I_INVLPG, I_IRET,
+ I_INT01, I_INT1, I_INT3, I_INTO, I_INVD, I_INVLPG, I_IRET,
I_IRETD, I_IRETW, I_JCXZ, I_JECXZ, I_JMP, I_LAHF, I_LAR, I_LDS,
I_LEA, I_LEAVE, I_LES, I_LFS, I_LGDT, I_LGS, I_LIDT, I_LLDT,
I_LMSW, I_LOADALL, I_LOADALL286, I_LODSB, I_LODSD, I_LODSW,
@@ -460,12 +460,18 @@ enum { /* instruction names */
I_MOVSX, I_MOVZX, I_MUL, I_NEG, I_NOP, I_NOT, I_OR, I_OUT,
I_OUTSB, I_OUTSD, I_OUTSW, I_PACKSSDW, I_PACKSSWB, I_PACKUSWB,
I_PADDB, I_PADDD, I_PADDSB, I_PADDSIW, I_PADDSW, I_PADDUSB,
- I_PADDUSW, I_PADDW, I_PAND, I_PANDN, I_PAVEB, I_PCMPEQB,
+ I_PADDUSW, I_PADDW, I_PAND, I_PANDN, I_PAVEB,
+ I_PAVGUSB, I_PCMPEQB,
I_PCMPEQD, I_PCMPEQW, I_PCMPGTB, I_PCMPGTD, I_PCMPGTW,
- I_PDISTIB, I_PMACHRIW, I_PMADDWD, I_PMAGW, I_PMULHRW,
- I_PMULHRIW, I_PMULHW, I_PMULLW, I_PMVGEZB, I_PMVLZB, I_PMVNZB,
+ I_PDISTIB,
+ I_PF2ID, I_PFACC, I_PFADD, I_PFCMPEQ, I_PFCMPGE, I_PFCMPGT,
+ I_PFMAX, I_PFMIN, I_PFMUL, I_PFRCP, I_PFRCPIT1, I_PFRCPIT2,
+ I_PFRSQIT1, I_PFRSQRT, I_PFSUB, I_PFSUBR, I_PI2FD,
+ I_PMACHRIW, I_PMADDWD, I_PMAGW, I_PMULHRIW, I_PMULHRWA,
+ I_PMULHRWC, I_PMULHW, I_PMULLW, I_PMVGEZB, I_PMVLZB, I_PMVNZB,
I_PMVZB, I_POP, I_POPA, I_POPAD, I_POPAW, I_POPF, I_POPFD,
- I_POPFW, I_POR, I_PSLLD, I_PSLLQ, I_PSLLW, I_PSRAD, I_PSRAW,
+ I_POPFW, I_POR, I_PREFETCH, I_PREFETCHW,
+ I_PSLLD, I_PSLLQ, I_PSLLW, I_PSRAD, I_PSRAW,
I_PSRLD, I_PSRLQ, I_PSRLW, I_PSUBB, I_PSUBD, I_PSUBSB,
I_PSUBSIW, I_PSUBSW, I_PSUBUSB, I_PSUBUSW, I_PSUBW, I_PUNPCKHBW,
I_PUNPCKHDQ, I_PUNPCKHWD, I_PUNPCKLBW, I_PUNPCKLDQ, I_PUNPCKLWD,
@@ -480,6 +486,8 @@ enum { /* instruction names */
I_XOR, I_CMOVcc, I_Jcc, I_SETcc
};
+#define MAX_KEYWORD 9 /* max length of any instruction, register name etc. */
+
enum { /* condition code names */
C_A, C_AE, C_B, C_BE, C_C, C_E, C_G, C_GE, C_L, C_LE, C_NA, C_NAE,
C_NB, C_NBE, C_NC, C_NE, C_NG, C_NGE, C_NL, C_NLE, C_NO, C_NP,
@@ -522,8 +530,12 @@ typedef struct { /* operand to an instruction */
long offset; /* any immediate number */
long wrt; /* segment base it's relative to */
int eaflags; /* special EA flags */
+ int opflags; /* see OPFLAG_* defines below */
} operand;
+#define OPFLAG_FORWARD 1 /* operand is a forward reference */
+#define OPFLAG_EXTERN 2 /* operand is an external reference */
+
typedef struct extop { /* extended operand */
struct extop *next; /* linked list */
long type; /* defined above */
@@ -542,13 +554,16 @@ typedef struct { /* an instruction itself */
int nprefix; /* number of entries in above */
int opcode; /* the opcode - not just the string */
int condition; /* the condition code, if Jcc/SETcc */
- int operands; /* how many operands? 0-3 */
+ int operands; /* how many operands? 0-3
+ * (more if db et al) */
operand oprs[3]; /* the operands, defined as above */
extop *eops; /* extended operands */
+ int eops_float; /* true if DD and floating */
long times; /* repeat count (TIMES prefix) */
int forw_ref; /* is there a forward reference? */
} insn;
+enum geninfo { GI_SWITCH };
/*
* ------------------------------------------------------------
* The data structure defining an output format driver, and the
@@ -569,6 +584,27 @@ struct ofmt {
char *shortname;
/*
+ * this is reserved for out module specific help.
+ * It is set to NULL in all the out modules but is not implemented
+ * in the main program
+ */
+ char *helpstring;
+
+ /*
+ * this is a pointer to the first element of the debug information
+ */
+ struct dfmt **debug_formats;
+
+ /*
+ * and a pointer to the element that is being used
+ * note: this is set to the default at compile time and changed if the
+ * -F option is selected. If developing a set of new debug formats for
+ * an output format, be sure to set this to whatever default you want
+ *
+ */
+ struct dfmt *current_dfmt;
+
+ /*
* This, if non-NULL, is a NULL-terminated list of `char *'s
* pointing to extra standard macros supplied by the object
* format (e.g. a sensible initial default value of __SECT__,
@@ -587,6 +623,15 @@ struct ofmt {
void (*init) (FILE *fp, efunc error, ldfunc ldef, evalfunc eval);
/*
+ * This procedure is called to pass generic information to the
+ * object file. The first parameter gives the information type
+ * (currently only command line switches)
+ * and the second parameter gives the value. This function returns
+ * 1 if recognized, 0 if unrecognized
+ */
+ int (*setinfo)(enum geninfo type, char **string);
+
+ /*
* This procedure is called by assemble() to write actual
* generated code or data to the object file. Typically it
* doesn't have to actually _write_ it, just store it for
@@ -705,7 +750,7 @@ struct ofmt {
* One thing the cleanup routine should always do is to close
* the output file pointer.
*/
- void (*cleanup) (void);
+ void (*cleanup) (int debuginfo);
};
/*
@@ -735,6 +780,103 @@ struct ofmt {
#define OUT_SIZMASK 0x0FFFFFFFUL
/*
+ * ------------------------------------------------------------
+ * The data structure defining a debug format driver, and the
+ * interfaces to the functions therein.
+ * ------------------------------------------------------------
+ */
+
+struct dfmt {
+
+ /*
+ * This is a short (one-liner) description of the type of
+ * output generated by the driver.
+ */
+ char *fullname;
+
+ /*
+ * This is a single keyword used to select the driver.
+ */
+ char *shortname;
+
+
+ /*
+ * init - called initially to set up local pointer to object format,
+ * void pointer to implementation defined data, file pointer (which
+ * probably won't be used, but who knows?), and error function.
+ */
+ void (*init) (struct ofmt * of, void * id, FILE * fp, efunc error);
+
+ /*
+ * linenum - called any time there is output with a change of
+ * line number or file.
+ */
+ void (*linenum) (const char * filename, long linenumber, long segto);
+
+ /*
+ * debug_deflabel - called whenever a label is defined. Parameters
+ * are the same as to 'symdef()' in the output format. This function
+ * would be called before the output format version.
+ */
+
+ void (*debug_deflabel) (char * name, long segment, long offset,
+ int is_global, char * special);
+ /*
+ * debug_directive - called whenever a DEBUG directive other than 'LINE'
+ * is encountered. 'directive' contains the first parameter to the
+ * DEBUG directive, and params contains the rest. For example,
+ * 'DEBUG VAR _somevar:int' would translate to a call to this
+ * function with 'directive' equal to "VAR" and 'params' equal to
+ * "_somevar:int".
+ */
+ void (*debug_directive) (const char * directive, const char * params);
+
+ /*
+ * typevalue - called whenever the assembler wishes to register a type
+ * for the last defined label. This routine MUST detect if a type was
+ * already registered and not re-register it.
+ */
+ void (*debug_typevalue) (long type);
+
+ /*
+ * debug_output - called whenever output is required
+ * 'type' is the type of info required, and this is format-specific
+ */
+ void (*debug_output) (int type, void *param);
+
+ /*
+ * cleanup - called after processing of file is complete
+ */
+ void (*cleanup) (void);
+
+};
+/*
+ * The type definition macros
+ * for debugging
+ *
+ * low 3 bits: reserved
+ * next 5 bits: type
+ * next 24 bits: number of elements for arrays (0 for labels)
+ */
+
+#define TY_UNKNOWN 0x00
+#define TY_LABEL 0x08
+#define TY_BYTE 0x10
+#define TY_WORD 0x18
+#define TY_DWORD 0x20
+#define TY_FLOAT 0x28
+#define TY_QWORD 0x30
+#define TY_TBYTE 0x38
+#define TY_COMMON 0xE0
+#define TY_SEG 0xE8
+#define TY_EXTERN 0xF0
+#define TY_EQU 0xF8
+
+#define TYM_TYPE(x) ((x) & 0xF8)
+#define TYM_ELEMENTS(x) (((x) & 0xFFFFFF00) >> 8)
+
+#define TYS_ELEMENTS(x) ((x) << 8)
+/*
* -----
* Other
* -----
diff --git a/nasmlib.c b/nasmlib.c
index 4508fec..86ed6c4 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 9168f18..d2997b1 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
@@ -61,6 +61,14 @@ int nasm_strnicmp (char *, char *, int);
long readnum(char *str, int *error);
/*
+ * Convert a character constant into a number. Sets
+ * `*warn' to TRUE if an overflow occurs, and FALSE otherwise.
+ * str points to and length covers the middle of the string,
+ * without the quotes.
+ */
+long readstrnum(char *str, int length, int *warn);
+
+/*
* seg_init: Initialise the segment-number allocator.
* seg_alloc: allocate a hitherto unused segment number.
*/
@@ -108,7 +116,41 @@ void fwritelong (long data, FILE *fp);
* chunk.
*/
-struct RAA;
+#define RAA_BLKSIZE 4096 /* this many longs allocated at once */
+#define RAA_LAYERSIZE 1024 /* this many _pointers_ allocated */
+
+typedef struct RAA RAA;
+typedef union RAA_UNION RAA_UNION;
+typedef struct RAA_LEAF RAA_LEAF;
+typedef struct RAA_BRANCH RAA_BRANCH;
+
+struct RAA {
+ /*
+ * Number of layers below this one to get to the real data. 0
+ * means this structure is a leaf, holding RAA_BLKSIZE real
+ * data items; 1 and above mean it's a branch, holding
+ * RAA_LAYERSIZE pointers to the next level branch or leaf
+ * structures.
+ */
+ int layers;
+ /*
+ * Number of real data items spanned by one position in the
+ * `data' array at this level. This number is 1, trivially, for
+ * a leaf (level 0): for a level 1 branch it should be
+ * RAA_BLKSIZE, and for a level 2 branch it's
+ * RAA_LAYERSIZE*RAA_BLKSIZE.
+ */
+ long stepsize;
+ union RAA_UNION {
+ struct RAA_LEAF {
+ long data[RAA_BLKSIZE];
+ } l;
+ struct RAA_BRANCH {
+ struct RAA *data[RAA_LAYERSIZE];
+ } b;
+ } u;
+};
+
struct RAA *raa_init (void);
void raa_free (struct RAA *);
@@ -125,7 +167,15 @@ struct RAA *raa_write (struct RAA *r, long posn, long value);
* of a given size.
*/
-struct SAA;
+struct SAA {
+ /*
+ * members `end' and `elem_len' are only valid in first link in
+ * list; `rptr' and `rpos' are used for reading
+ */
+ struct SAA *next, *end, *rptr;
+ long elem_len, length, posn, start, rpos;
+ char *data;
+};
struct SAA *saa_init (long elem_len); /* 1 == byte */
void saa_free (struct SAA *);
@@ -169,4 +219,23 @@ long reloc_wrt(expr *);
*/
int bsi (char *string, char **array, int size);
+
+char *src_set_fname(char *newname);
+long src_set_linnum(long newline);
+long src_get_linnum(void);
+/*
+ * src_get may be used if you simply want to know the source file and line.
+ * It is also used if you maintain private status about the source location
+ * It return 0 if the information was the same as the last time you
+ * checked, -1 if the name changed and (new-old) if just the line changed.
+ */
+int src_get(long *xline, char **xname);
+
+void nasm_quote(char **str);
+char *nasm_strcat(char *one, char *two);
+void nasmlib_cleanup(void);
+
+void null_debug_routine();
+extern struct dfmt null_debug_form;
+extern struct dfmt *null_debug_arr[2];
#endif
diff --git a/ndisasm.c b/ndisasm.c
index 90639e9..a07a278 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 e4c7610..b82109a 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 f214d86..eb02186 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 3540739..a3289cf 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 09e886c..f546a8e 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 b3d23a0..723e372 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 6f6c1be..0b77c01 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 09202de..c8b9532 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 e23f3c7..2e7a32d 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/outforms.h b/outforms.h
new file mode 100644
index 0000000..2afbbe2
--- /dev/null
+++ b/outforms.h
@@ -0,0 +1,223 @@
+/* outform.h header file for binding output format drivers to the
+ * remainder of the code in the Netwide Assembler
+ *
+ * The Netwide Assembler is copyright (C) 1996 Simon Tatham and
+ * Julian Hall. All rights reserved. The software is
+ * redistributable under the licence given in the file "Licence"
+ * distributed in the NASM archive.
+ */
+
+/*
+ * This header file allows configuration of which output formats
+ * get compiled into the NASM binary. You can configure by defining
+ * various preprocessor symbols beginning with "OF_", either on the
+ * compiler command line or at the top of this file.
+ *
+ * OF_ONLY -- only include specified object formats
+ * OF_name -- ensure that output format 'name' is included
+ * OF_NO_name -- remove output format 'name'
+ * OF_DOS -- ensure that 'obj', 'bin' & 'win32' are included.
+ * OF_UNIX -- ensure that 'aout', 'aoutb', 'coff', 'elf' are in.
+ * OF_OTHERS -- ensure that 'bin', 'as86' & 'rdf' are in.
+ * OF_ALL -- ensure that all formats are included.
+ *
+ * OF_DEFAULT=of_name -- ensure that 'name' is the default format.
+ *
+ * eg: -DOF_UNIX -DOF_ELF -DOF_DEFAULT=of_elf would be a suitable config
+ * for an average linux system.
+ *
+ * Default config = -DOF_ALL -DOF_DEFAULT=of_bin
+ *
+ * You probably only want to set these options while compiling 'nasm.c'. */
+
+#ifndef NASM_OUTFORMS_H
+#define NASM_OUTFORMS_H
+
+#include "nasm.h"
+
+/* -------------- USER MODIFIABLE PART ---------------- */
+
+/*
+ * Insert #defines here in accordance with the configuration
+ * instructions above.
+ *
+ * E.g.
+ *
+ * #define OF_ONLY
+ * #define OF_OBJ
+ * #define OF_BIN
+ *
+ * for a 16-bit DOS assembler with no extraneous formats.
+ */
+
+/* ------------ END USER MODIFIABLE PART -------------- */
+
+/* ====configurable info begins here==== */
+/* formats configurable:
+ * bin,obj,elf,aout,aoutb,coff,win32,as86,rdf */
+
+/* process options... */
+
+#ifndef OF_ONLY
+#ifndef OF_ALL
+#define OF_ALL /* default is to have all formats */
+#endif
+#endif
+
+#ifdef OF_ALL /* set all formats on... */
+#ifndef OF_BIN
+#define OF_BIN
+#endif
+#ifndef OF_OBJ
+#define OF_OBJ
+#endif
+#ifndef OF_ELF
+#define OF_ELF
+#endif
+#ifndef OF_COFF
+#define OF_COFF
+#endif
+#ifndef OF_AOUT
+#define OF_AOUT
+#endif
+#ifndef OF_AOUTB
+#define OF_AOUTB
+#endif
+#ifndef OF_WIN32
+#define OF_WIN32
+#endif
+#ifndef OF_AS86
+#define OF_AS86
+#endif
+#ifndef OF_RDF
+#define OF_RDF
+#endif
+#endif /* OF_ALL */
+
+/* turn on groups of formats specified.... */
+#ifdef OF_DOS
+#ifndef OF_OBJ
+#define OF_OBJ
+#endif
+#ifndef OF_BIN
+#define OF_BIN
+#endif
+#ifndef OF_WIN32
+#define OF_WIN32
+#endif
+#endif
+
+#ifdef OF_UNIX
+#ifndef OF_AOUT
+#define OF_AOUT
+#endif
+#ifndef OF_AOUTB
+#define OF_AOUTB
+#endif
+#ifndef OF_COFF
+#define OF_COFF
+#endif
+#ifndef OF_ELF
+#define OF_ELF
+#endif
+#endif
+
+#ifdef OF_OTHERS
+#ifndef OF_BIN
+#define OF_BIN
+#endif
+#ifndef OF_AS86
+#define OF_AS86
+#endif
+#ifndef OF_RDF
+#define OF_RDF
+#endif
+#endif
+
+/* finally... override any format specifically specifed to be off */
+#ifdef OF_NO_BIN
+#undef OF_BIN
+#endif
+#ifdef OF_NO_OBJ
+#undef OF_OBJ
+#endif
+#ifdef OF_NO_ELF
+#undef OF_ELF
+#endif
+#ifdef OF_NO_AOUT
+#undef OF_AOUT
+#endif
+#ifdef OF_NO_AOUTB
+#undef OF_AOUTB
+#endif
+#ifdef OF_NO_COFF
+#undef OF_COFF
+#endif
+#ifdef OF_NO_WIN32
+#undef OF_WIN32
+#endif
+#ifdef OF_NO_AS86
+#undef OF_AS86
+#endif
+#ifdef OF_NO_RDF
+#undef OF_RDF
+#endif
+
+#ifndef OF_DEFAULT
+#define OF_DEFAULT of_bin
+#endif
+
+#ifdef BUILD_DRIVERS_ARRAY /* only if included from outform.c */
+
+/* pull in the externs for the different formats, then make the *drivers
+ * array based on the above defines */
+
+extern struct ofmt of_bin;
+extern struct ofmt of_aout;
+extern struct ofmt of_aoutb;
+extern struct ofmt of_coff;
+extern struct ofmt of_elf;
+extern struct ofmt of_as86;
+extern struct ofmt of_obj;
+extern struct ofmt of_win32;
+extern struct ofmt of_rdf;
+extern struct ofmt of_dbg;
+
+struct ofmt *drivers[]={
+#ifdef OF_BIN
+ &of_bin,
+#endif
+#ifdef OF_AOUT
+ &of_aout,
+#endif
+#ifdef OF_AOUTB
+ &of_aoutb,
+#endif
+#ifdef OF_COFF
+ &of_coff,
+#endif
+#ifdef OF_ELF
+ &of_elf,
+#endif
+#ifdef OF_AS86
+ &of_as86,
+#endif
+#ifdef OF_OBJ
+ &of_obj,
+#endif
+#ifdef OF_WIN32
+ &of_win32,
+#endif
+#ifdef OF_RDF
+ &of_rdf,
+#endif
+#ifdef OF_DBG
+ &of_dbg,
+#endif
+
+ NULL
+};
+
+#endif /* BUILD_DRIVERS_ARRAY */
+
+#endif /* NASM_OUTFORMS_H */
diff --git a/outobj.c b/outobj.c
index f54d297..0a7544d 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@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 cde1327..d9989e5 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 0000000..4ae6799
--- /dev/null
+++ b/outrdf2.c
@@ -0,0 +1,690 @@
+/* outrdf2.c output routines for the Netwide Assembler to produce
+ * RDOFF version 2 format object files (which are intended
+ * mainly for use in proprietary projects, as the code to
+ * load and execute them is very simple). They will also be
+ * used for device drivers and possibly some executable files
+ * in the MOSCOW operating system. See Rdoff.txt for
+ * details.
+ *
+ * The Netwide Assembler is copyright (C) 1996-1998 Simon Tatham and
+ * Julian Hall. All rights reserved. The software is
+ * redistributable under the licence given in the file "Licence"
+ * distributed in the NASM archive.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <assert.h>
+
+#include "nasm.h"
+#include "nasmlib.h"
+#include "outform.h"
+
+/* VERBOSE_WARNINGS: define this to add some extra warnings... */
+#define VERBOSE_WARNINGS
+
+#ifdef OF_RDF2
+
+#define RDF_MAXSEGS 64 /* maximum number of segments - user configurable */
+
+typedef unsigned short int16;
+typedef unsigned char byte;
+
+static const char *RDOFF2Id = "RDOFF2"; /* written to start of RDOFF files */
+
+
+/* the records that can be found in the RDOFF header */
+
+/* Note that whenever a segment is referred to in the RDOFF file, its number
+ * is always half of the segment number that NASM uses to refer to it; this
+ * is because NASM only allocates even numbered segments, so as to not
+ * waste any of the 16 bits of segment number written to the file - this
+ * allows up to 65533 external labels to be defined; otherwise it would be
+ * 32764. */
+
+struct RelocRec {
+ byte type; /* must be 1, or 6 for segment base ref */
+ byte reclen; /* set to 8 */
+ byte segment; /* only 0 for code, or 1 for data supported,
+ * but add 64 for relative refs (ie do not require
+ * reloc @ loadtime, only linkage) */
+ long offset; /* from start of segment in which reference is loc'd */
+ byte length; /* 1 2 or 4 bytes */
+ int16 refseg; /* segment to which reference refers to */
+};
+
+struct ImportRec {
+ byte type; /* must be 2, or 7 for FAR import */
+ byte reclen; /* equals 3+label length */
+ int16 segment; /* segment number allocated to the label for reloc
+ * records - label is assumed to be at offset zero
+ * in this segment, so linker must fix up with offset
+ * of segment and of offset within segment */
+ char label[33]; /* zero terminated... should be written to file until
+ * the zero, but not after it - max len = 32 chars */
+};
+
+struct ExportRec {
+ byte type; /* must be 3 */
+ byte reclen; /* equals 6+label length */
+ byte segment; /* segment referred to (0/1) */
+ long offset; /* offset within segment */
+ char label[33]; /* zero terminated as above. max len = 32 chars */
+};
+
+struct DLLRec {
+ byte type; /* must be 4 */
+ byte reclen; /* equals 1+library name */
+ char libname[128]; /* name of library to link with at load time */
+};
+
+struct BSSRec {
+ byte type; /* must be 5 */
+ byte reclen; /* equeals 4 */
+ long amount; /* number of bytes BSS to reserve */
+};
+
+#define COUNT_SEGTYPES 9
+
+static char * segmenttypes[COUNT_SEGTYPES] = {
+ "null", "text", "code", "data", "comment", "lcomment", "pcomment",
+ "symdebug", "linedebug"
+};
+
+static int segmenttypenumbers[COUNT_SEGTYPES] = {
+ 0, 1, 1, 2, 3, 4, 5, 6, 7
+};
+
+/* code for managing buffers needed to seperate code and data into individual
+ * sections until they are ready to be written to the file.
+ * We'd better hope that it all fits in memory else we're buggered... */
+
+#define BUF_BLOCK_LEN 4088 /* selected to match page size (4096)
+ * on 80x86 machines for efficiency */
+
+/***********************************************************************
+ * Actual code to deal with RDOFF2 ouput format begins here...
+ */
+
+/* global variables set during the initialisation phase */
+
+static struct SAA *seg[RDF_MAXSEGS]; /* seg 0 = code, seg 1 = data */
+static struct SAA *header; /* relocation/import/export records */
+
+static FILE *ofile;
+
+static efunc error;
+
+static struct seginfo {
+ char *segname;
+ int segnumber;
+ int16 segtype;
+ int16 segreserved;
+ long seglength;
+} segments[RDF_MAXSEGS];
+
+static int nsegments;
+
+static long bsslength;
+static long headerlength;
+
+static void rdf2_init(FILE *fp, efunc errfunc, ldfunc ldef, evalfunc eval)
+{
+ int segtext, segdata, segbss;
+
+ /* set up the initial segments */
+ segments[0].segname = ".text";
+ segments[0].segnumber = 0;
+ segments[0].segtype = 1;
+ segments[0].segreserved = 0;
+ segments[0].seglength = 0;
+
+ segments[1].segname = ".data";
+ segments[1].segnumber = 1;
+ segments[1].segtype = 2;
+ segments[1].segreserved = 0;
+ segments[1].seglength = 0;
+
+ segments[2].segname = ".bss";
+ segments[2].segnumber = 2;
+ segments[2].segtype = 0xFFFF; /* reserved - should never be produced */
+ segments[2].segreserved = 0;
+ segments[2].seglength = 0;
+
+ nsegments = 3;
+
+ ofile = fp;
+ error = errfunc;
+
+ seg[0] = saa_init(1L);
+ seg[1] = saa_init(1L);
+ seg[2] = NULL; /* special case! */
+
+ header = saa_init(1L);
+
+ segtext = seg_alloc();
+ segdata = seg_alloc();
+ segbss = seg_alloc();
+ if (segtext != 0 || segdata != 2 || segbss != 4)
+ error(ERR_PANIC,"rdf segment numbers not allocated as expected (%d,%d,%d)",
+ segtext,segdata,segbss);
+ bsslength=0;
+ headerlength = 0;
+}
+
+static long rdf2_section_names(char *name, int pass, int *bits)
+{
+ int i;
+ char * p, * q;
+ int code = -1;
+ int reserved = 0;
+
+ /*
+ * Default is 32 bits, in the text segment.
+ */
+ if (!name) {
+ *bits = 32;
+ return 0;
+ }
+
+ /* look for segment type code following segment name */
+ p = name;
+ while (*p && !isspace(*p)) p++;
+ if (*p) { /* we're now in whitespace */
+ *p++ = '\0';
+ while (*p && isspace(80)) *p++ = '\0';
+ }
+ if (*p) { /* we're now in an attribute value */
+ /*
+ * see if we have an optional ',number' following the type code
+ */
+ if ((q = strchr(p, ','))) {
+ *q++ = '\0';
+
+ reserved = readnum(q, &i);
+ if (i) {
+ error(ERR_NONFATAL, "value following comma must be numeric");
+ reserved = 0;
+ }
+ }
+ /*
+ * check it against the text strings in segmenttypes
+ */
+
+ for (i = 0; i < COUNT_SEGTYPES; i++)
+ if (!nasm_stricmp(p, segmenttypes[i])) {
+ code = segmenttypenumbers[i];
+ break;
+ }
+ if (code == -1) { /* didn't find anything */
+ code = readnum(p, &i);
+ if (i) {
+ error(ERR_NONFATAL, "unrecognised RDF segment type (%s)",p);
+ code = 3;
+ }
+ }
+ }
+ for (i = 0; i < nsegments; i++) {
+ if (!strcmp(name, segments[i].segname)) {
+ if (code != -1 || reserved != 0)
+ error(ERR_NONFATAL, "segment attributes specified on"
+ " redeclaration of segment");
+ return segments[i].segnumber * 2;
+ }
+ }
+
+ /* declaring a new segment! */
+
+ if (code == -1) {
+ error(ERR_NONFATAL, "new segment declared without type code");
+ code = 3;
+ }
+ if (nsegments == RDF_MAXSEGS) {
+ error(ERR_FATAL, "reached compiled-in maximum segment limit (%d)",
+ RDF_MAXSEGS);
+ return NO_SEG;
+ }
+
+ segments[nsegments].segname = nasm_strdup(name);
+ i = seg_alloc();
+ if (i % 2 != 0)
+ error(ERR_PANIC, "seg_alloc() returned odd number");
+ segments[nsegments].segnumber = i >> 1;
+ segments[nsegments].segtype = code;
+ segments[nsegments].segreserved = reserved;
+ segments[nsegments].seglength = 0;
+
+ seg[nsegments] = saa_init(1L);
+
+ return i;
+}
+
+static void write_reloc_rec(struct RelocRec *r)
+{
+ char buf[4],*b;
+
+ if (r->refseg != (int16)NO_SEG && (r->refseg & 1)) /* segment base ref */
+ r->type = 6;
+
+ r->refseg >>= 1; /* adjust segment nos to RDF rather than NASM */
+
+ saa_wbytes(header,&r->type,1);
+ saa_wbytes(header,&r->reclen,1);
+ saa_wbytes(header,&r->segment,1);
+ b = buf; WRITELONG(b,r->offset);
+ saa_wbytes(header,buf,4);
+ saa_wbytes(header,&r->length,1);
+ b = buf; WRITESHORT(b,r->refseg);
+ saa_wbytes(header,buf,2);
+ headerlength += r->reclen + 2;
+}
+
+static void write_export_rec(struct ExportRec *r)
+{
+ char buf[4], *b;
+
+ r->segment >>= 1;
+
+ saa_wbytes(header,&r->type,1);
+ saa_wbytes(header,&r->reclen,1);
+ saa_wbytes(header,&r->segment,1);
+ b = buf; WRITELONG(b,r->offset);
+ saa_wbytes(header,buf,4);
+ saa_wbytes(header,r->label,strlen(r->label) + 1);
+ headerlength += r->reclen + 2;
+}
+
+static void write_import_rec(struct ImportRec *r)
+{
+ char buf[4], *b;
+
+ r->segment >>= 1;
+
+ saa_wbytes(header,&r->type,1);
+ saa_wbytes(header,&r->reclen,1);
+ b = buf; WRITESHORT(b,r->segment);
+ saa_wbytes(header,buf,2);
+ saa_wbytes(header,r->label,strlen(r->label) + 1);
+ headerlength += r->reclen + 2;
+}
+
+static void write_bss_rec(struct BSSRec *r)
+{
+ char buf[4], *b;
+
+ saa_wbytes(header,&r->type,1);
+ saa_wbytes(header,&r->reclen,1);
+ b = buf; WRITELONG(b,r->amount);
+ saa_wbytes(header,buf,4);
+ headerlength += r->reclen + 2;
+}
+
+static void write_dll_rec(struct DLLRec *r)
+{
+ saa_wbytes(header,&r->type,1);
+ saa_wbytes(header,&r->reclen,1);
+ saa_wbytes(header,r->libname,strlen(r->libname) + 1);
+ headerlength += r->reclen + 2;
+}
+
+static void rdf2_deflabel(char *name, long segment, long offset,
+ int is_global, char *special)
+{
+ struct ExportRec r;
+ struct ImportRec ri;
+#ifdef VERBOSE_WARNINGS
+ static int warned_common = 0;
+#endif
+ static int farsym = 0;
+ static int i;
+
+ if (special) {
+ while(*special == ' ' || *special == '\t') special++;
+
+ if (!nasm_stricmp(special, "far")) {
+ farsym = 1;
+ }
+ else if (!nasm_stricmp(special, "near")) {
+ farsym = 0;
+ }
+ else
+ error(ERR_NONFATAL, "unrecognised symbol type `%s'", special);
+ }
+
+ if (name[0] == '.' && name[1] == '.' && name[2] != '@') {
+ error (ERR_NONFATAL, "unrecognised special symbol `%s'", name);
+ return;
+ }
+
+ if (is_global == 2) {
+#ifdef VERBOSE_WARNINGS
+ if (!warned_common) {
+ error(ERR_WARNING,"common declarations not supported: using extern");
+ warned_common = 1;
+ }
+#endif
+ is_global = 1;
+ }
+
+ for (i = 0; i < nsegments; i++) {
+ if (segments[i].segnumber == segment>>1) break;
+ }
+ if (i >= nsegments) { /* EXTERN declaration */
+ if (farsym)
+ ri.type = 7;
+ else
+ ri.type = 2;
+ ri.segment = segment;
+ strncpy(ri.label,name,32);
+ ri.label[32] = 0;
+ ri.reclen = 3 + strlen(ri.label);
+ write_import_rec(&ri);
+ } else if (is_global) {
+ r.type = 3;
+ r.segment = segment;
+ r.offset = offset;
+ strncpy(r.label,name,32);
+ r.label[32] = 0;
+ r.reclen = 6 + strlen(r.label);
+ write_export_rec(&r);
+ }
+}
+
+static void membufwrite(int segment, void * data, int bytes)
+{
+ int i;
+ char buf[4], * b;
+
+ for (i = 0; i < nsegments; i++) {
+ if (segments[i].segnumber == segment) break;
+ }
+ if (i == nsegments)
+ error(ERR_PANIC, "can't find segment %d", segment);
+
+ if (bytes < 0) {
+ b = buf;
+ if (bytes == -2)
+ WRITESHORT(b,*(short *)data);
+ else
+ WRITELONG(b,*(long *)data);
+ data = buf;
+ bytes = -bytes;
+ }
+ segments[i].seglength += bytes;
+ saa_wbytes(seg[i],data,bytes);
+}
+
+static int getsegmentlength(int segment)
+{
+ int i;
+ for (i = 0; i < nsegments; i++) {
+ if (segments[i].segnumber == segment) break;
+ }
+ if (i == nsegments)
+ error(ERR_PANIC, "can't find segment %d", segment);
+
+ return segments[i].seglength;
+}
+
+static void rdf2_out (long segto, void *data, unsigned long type,
+ long segment, long wrt)
+{
+ long bytes = type & OUT_SIZMASK;
+ struct RelocRec rr;
+ unsigned char databuf[4],*pd;
+ int seg;
+
+ if (segto == NO_SEG) {
+ if ((type & OUT_TYPMASK) != OUT_RESERVE)
+ error (ERR_NONFATAL, "attempt to assemble code in ABSOLUTE space");
+ return;
+ }
+
+ segto >>= 1; /* convert NASM segment no to RDF number */
+
+ for (seg = 0; seg < nsegments; seg++) {
+ if (segments[seg].segnumber == segto) break;
+ }
+ if (seg >= nsegments) {
+ error(ERR_NONFATAL,"specified segment not supported by rdf output format");
+ return;
+ }
+
+ if (wrt != NO_SEG) {
+ wrt = NO_SEG; /* continue to do _something_ */
+ error (ERR_NONFATAL, "WRT not supported by rdf output format");
+ }
+
+ type &= OUT_TYPMASK;
+
+ if (segto == 2 && type != OUT_RESERVE)
+ {
+ error(ERR_NONFATAL, "BSS segments may not be initialised");
+
+ /* just reserve the space for now... */
+
+ if (type == OUT_REL2ADR)
+ bytes = 2;
+ else
+ bytes = 4;
+ type = OUT_RESERVE;
+ }
+
+ if (type == OUT_RESERVE) {
+ if (segto == 2) /* BSS segment space reserverd */
+ bsslength += bytes;
+ else
+ while (bytes --)
+ membufwrite(segto,databuf,1);
+ }
+ else if (type == OUT_RAWDATA) {
+ if (segment != NO_SEG)
+ error(ERR_PANIC, "OUT_RAWDATA with other than NO_SEG");
+
+ membufwrite(segto,data,bytes);
+ }
+ else if (type == OUT_ADDRESS) {
+
+ /* if segment == NO_SEG then we are writing an address of an
+ object within the same segment - do not produce reloc rec. */
+
+ /* FIXME - is this behaviour sane? at first glance it doesn't
+ appear to be. Must test this thoroughly...! */
+
+ if (segment != NO_SEG)
+ {
+ /* it's an address, so we must write a relocation record */
+
+ rr.type = 1; /* type signature */
+ rr.reclen = 8;
+ rr.segment = segto; /* segment we're currently in */
+ rr.offset = getsegmentlength(segto); /* current offset */
+ rr.length = bytes; /* length of reference */
+ rr.refseg = segment; /* segment referred to */
+ write_reloc_rec(&rr);
+ }
+
+ pd = databuf; /* convert address to little-endian */
+ if (bytes == 2)
+ WRITESHORT (pd, *(long *)data);
+ else
+ WRITELONG (pd, *(long *)data);
+
+ membufwrite(segto,databuf,bytes);
+
+ }
+ else if (type == OUT_REL2ADR)
+ {
+ if (segment == segto)
+ error(ERR_PANIC, "intra-segment OUT_REL2ADR");
+
+ rr.reclen = 8;
+ rr.offset = getsegmentlength(segto); /* current offset */
+ rr.length = 2; /* length of reference */
+ rr.refseg = segment; /* segment referred to (will be >>1'd)*/
+
+ if (segment != NO_SEG && segment % 2) {
+ rr.type = 6;
+ rr.segment = segto; /* memory base refs *aren't ever* relative! */
+ write_reloc_rec(&rr);
+
+ /* what do we put in the code? Simply the data. This should almost
+ * always be zero, unless someone's doing segment arithmetic...
+ */
+ rr.offset = *(long *) data;
+ }
+ else
+ {
+ rr.type = 1; /* type signature */
+ rr.segment = segto+64; /* segment we're currently in + rel flag */
+ write_reloc_rec(&rr);
+
+ /* work out what to put in the code: offset of the end of this operand,
+ * subtracted from any data specified, so that loader can just add
+ * address of imported symbol onto it to get address relative to end of
+ * instruction: import_address + data(offset) - end_of_instrn */
+
+ rr.offset = *(long *)data -(rr.offset + bytes);
+ }
+
+ membufwrite(segto,&rr.offset,-2);
+ }
+ else if (type == OUT_REL4ADR)
+ {
+ if (segment == segto)
+ error(ERR_PANIC, "intra-segment OUT_REL4ADR");
+ if (segment != NO_SEG && segment % 2) {
+ error(ERR_PANIC, "erm... 4 byte segment base ref?");
+ }
+
+ rr.type = 1; /* type signature */
+ rr.segment = segto+64; /* segment we're currently in + rel tag */
+ rr.offset = getsegmentlength(segto); /* current offset */
+ rr.length = 4; /* length of reference */
+ rr.refseg = segment; /* segment referred to */
+ rr.reclen = 8;
+ write_reloc_rec(&rr);
+
+ rr.offset = *(long *)data -(rr.offset + bytes);
+
+ membufwrite(segto,&rr.offset,-4);
+ }
+}
+
+static void rdf2_cleanup (int debuginfo) {
+ long l;
+ struct BSSRec bs;
+ int i;
+
+ (void) debuginfo;
+
+ /* should write imported & exported symbol declarations to header here */
+
+ /* generate the output file... */
+ fwrite(RDOFF2Id,6,1,ofile); /* file type magic number */
+
+ if (bsslength != 0) /* reserve BSS */
+ {
+ bs.type = 5;
+ bs.amount = bsslength;
+ bs.reclen = 4;
+ write_bss_rec(&bs);
+ }
+
+ /*
+ * calculate overall length of the output object
+ */
+ l = headerlength + 4;
+
+ for (i = 0; i < nsegments; i++) {
+ if (i == 2) continue; /* skip BSS segment */
+ l += 10 + segments[i].seglength;
+ }
+ l += 10; /* null segment */
+
+ fwritelong(l, ofile);
+
+ fwritelong(headerlength, ofile);
+ saa_fpwrite(header,ofile); /* dump header */
+ saa_free(header);
+
+ for (i = 0; i < nsegments; i++) {
+ if (i == 2) continue;
+
+ fwriteshort(segments[i].segtype, ofile);
+ fwriteshort(segments[i].segnumber, ofile);
+ fwriteshort(segments[i].segreserved, ofile);
+ fwritelong(segments[i].seglength, ofile);
+
+ saa_fpwrite(seg[i], ofile);
+ saa_free(seg[i]);
+ }
+
+ /* null segment - write 10 bytes of zero */
+ fwritelong(0,ofile);
+ fwritelong(0,ofile);
+ fwriteshort(0,ofile);
+
+ fclose(ofile);
+}
+
+static long rdf2_segbase (long segment) {
+ return segment;
+}
+
+static int rdf2_directive (char *directive, char *value, int pass) {
+ struct DLLRec r;
+
+ if (! strcmp(directive, "library")) {
+ if (pass == 1) {
+ r.type = 4;
+ strcpy(r.libname, value);
+ write_dll_rec(&r);
+ }
+ return 1;
+ }
+
+ return 0;
+}
+
+static void rdf2_filename (char *inname, char *outname, efunc error) {
+ standard_extension(inname,outname,".rdf",error);
+}
+
+static char *rdf2_stdmac[] = {
+ "%define __SECT__ [section .text]",
+ "%imacro library 1+.nolist",
+ "[library %1]",
+ "%endmacro",
+ "%macro __NASM_CDecl__ 1",
+ "%endmacro",
+ NULL
+};
+
+static int rdf2_set_info(enum geninfo type, char **val)
+{
+ return 0;
+}
+
+
+struct ofmt of_rdf2 = {
+ "Relocatable Dynamic Object File Format v2.0",
+ "rdf",
+ NULL,
+ null_debug_arr,
+ &null_debug_form,
+ rdf2_stdmac,
+ rdf2_init,
+ rdf2_set_info,
+ rdf2_out,
+ rdf2_deflabel,
+ rdf2_section_names,
+ rdf2_segbase,
+ rdf2_directive,
+ rdf2_filename,
+ rdf2_cleanup
+};
+
+#endif /* OF_RDF2 */
diff --git a/parser.c b/parser.c
index d7bbdb0..704e2eb 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 0681cd0..bc2135d 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 032854e..291b57e 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;
@@ -402,9 +417,22 @@ static void free_llist (Line *list) {
}
/*
+ * Free an MMacro
+ */
+static void free_mmacro (MMacro *m)
+{
+ nasm_free (m->name);
+ free_tlist (m->dlist);
+ nasm_free (m->defaults);
+ free_llist (m->expansion);
+ nasm_free (m);
+}
+
+/*
* Pop the context stack.
*/
-static void ctx_pop (void) {
+static void ctx_pop (void)
+{
Context *c = cstk;
SMacro *smac, *s;
@@ -421,19 +449,6 @@ static void ctx_pop (void) {
nasm_free (c);
}
-/*
- * Generate a line synchronisation comment, to ensure the assembler
- * knows which source file the current output has really come from.
- */
-static void line_sync (void) {
- char text[30+FILENAME_MAX];
- sprintf(text, "%%line %d+%d %s",
- (istk->expansion ? istk->lineno - istk->lineinc : istk->lineno),
- (istk->expansion ? 0 : istk->lineinc), istk->fname);
- nasm_free (linesync);
- linesync = nasm_strdup(text);
-}
-
#define BUF_DELTA 512
/*
* Read a line from the top file in istk, handling multiple CR/LFs
@@ -441,14 +456,16 @@ static void line_sync (void) {
* return lines from the standard macro set if this has not already
* been done.
*/
-static char *read_line (void) {
+static char *read_line (void)
+{
char *buffer, *p, *q;
int bufsize;
if (stdmacpos) {
if (*stdmacpos) {
char *ret = nasm_strdup(*stdmacpos++);
- if (!*stdmacpos && any_extrastdmac) {
+ if (!*stdmacpos && any_extrastdmac)
+ {
stdmacpos = extrastdmac;
any_extrastdmac = FALSE;
return ret;
@@ -459,7 +476,8 @@ static char *read_line (void) {
* most convenient way to implement the pre-include and
* pre-define features.
*/
- if (!*stdmacpos) {
+ if (!*stdmacpos)
+ {
Line *pd, *l;
Token *head, **tail, *t, *tt;
@@ -482,10 +500,9 @@ static char *read_line (void) {
}
}
return ret;
- } else {
+ }
+ else {
stdmacpos = NULL;
- line_sync();
- update_fileline(3); /* update __FILE__ and __LINE__ */
}
}
@@ -498,13 +515,13 @@ static char *read_line (void) {
break;
p += strlen(p);
if (p > buffer && p[-1] == '\n') {
- istk->lineno += istk->lineinc;
- update_fileline(1); /* update __LINE__ only */
break;
}
if (p-buffer > bufsize-10) {
+ long offset = p-buffer;
bufsize += BUF_DELTA;
buffer = nasm_realloc(buffer, bufsize);
+ p = buffer+offset; /* prevent stale-pointer problems */
}
}
@@ -513,12 +530,14 @@ static char *read_line (void) {
return NULL;
}
+ src_set_linnum(src_get_linnum() + istk->lineinc);
+
/*
* Play safe: remove CRs as well as LFs, if any of either are
* present at the end of the line.
*/
- while (p > buffer && (p[-1] == '\n' || p[-1] == '\r'))
- *--p = '\0';
+ while (--p >= buffer && (*p == '\n' || *p == '\r'))
+ *p = '\0';
/*
* Handle spurious ^Z, which may be inserted into source files
@@ -536,7 +555,8 @@ static char *read_line (void) {
* don't need to parse the value out of e.g. numeric tokens: we
* simply split one string into many.
*/
-static Token *tokenise (char *line) {
+static Token *tokenise (char *line)
+{
char *p = line;
int type;
Token *list = NULL;
@@ -544,31 +564,42 @@ static Token *tokenise (char *line) {
while (*line) {
p = line;
- if (*p == '%' &&
- (p[1] == '{' || p[1] == '!' || (p[1] == '%' && isidchar(p[2])) ||
- p[1] == '$' || p[1] == '+' || p[1] == '-' || isidchar(p[1]))) {
- type = TOK_PREPROC_ID;
+ if (*p == '%' && ( isdigit(p[1]) ||
+ ((p[1] == '-' || p[1] == '+') && isdigit(p[2]))))
+ {
p++;
- if (*p == '{') {
+ do {
+ p++;
+ } while (isdigit(*p));
+ type = TOK_PREPROC_ID;
+ }
+ else if (*p == '%' && p[1] == '{') {
+ p += 2;
+ while (*p && *p != '}') {
+ p[-1] = *p;
p++;
- while (*p && *p != '}') {
- p[-1] = *p;
- p++;
- }
- p[-1] = '\0';
- if (*p) p++;
- } else {
- if (*p == '!' || *p == '%' || *p == '$' ||
- *p == '+' || *p == '-') p++;
- while (*p && isidchar(*p))
- p++;
}
- } else if (isidstart(*p) || (*p == '$' && isidstart(p[1]))) {
+ p[-1] = '\0';
+ if (*p) p++;
+ type = TOK_PREPROC_ID;
+ }
+ else if (*p == '%' && (isidchar(p[1]) ||
+ ((p[1] == '!' || p[1] == '%' || p[1] == '$') &&
+ isidchar(p[2]))))
+ {
+ p++;
+ do {
+ p++;
+ } while (isidchar(*p));
+ type = TOK_PREPROC_ID;
+ }
+ else if (isidstart(*p) || (*p == '$' && isidstart(p[1]))) {
type = TOK_ID;
p++;
while (*p && isidchar(*p))
p++;
- } else if (*p == '\'' || *p == '"') {
+ }
+ else if (*p == '\'' || *p == '"') {
/*
* A string token.
*/
@@ -578,7 +609,8 @@ static Token *tokenise (char *line) {
while (*p && *p != c)
p++;
if (*p) p++;
- } else if (isnumstart(*p)) {
+ }
+ else if (isnumstart(*p)) {
/*
* A number token.
*/
@@ -586,7 +618,8 @@ static Token *tokenise (char *line) {
p++;
while (*p && isnumchar(*p))
p++;
- } else if (isspace(*p)) {
+ }
+ else if (isspace(*p)) {
type = TOK_WHITESPACE;
p++;
while (*p && isspace(*p))
@@ -600,10 +633,12 @@ static Token *tokenise (char *line) {
type = TOK_COMMENT;
while (*p) p++;
}
- } else if (*p == ';') {
+ }
+ else if (*p == ';') {
type = TOK_COMMENT;
while (*p) p++;
- } else {
+ }
+ else {
/*
* Anything else is an operator of some kind. We check
* for all the double-character operators (>>, <<, //,
@@ -623,7 +658,9 @@ static Token *tokenise (char *line) {
(p[0] == '&' && p[1] == '&') ||
(p[0] == '|' && p[1] == '|') ||
(p[0] == '^' && p[1] == '^'))
+ {
p++;
+ }
p++;
}
if (type != TOK_COMMENT) {
@@ -644,7 +681,8 @@ static Token *tokenise (char *line) {
/*
* Convert a line of tokens back into text.
*/
-static char *detoken (Token *tlist) {
+char *detoken (Token *tlist)
+{
Token *t;
int len;
char *line, *p;
@@ -679,7 +717,8 @@ static char *detoken (Token *tlist) {
* the first token in the line to be passed in as its private_data
* field.
*/
-static int ppscan(void *private_data, struct tokenval *tokval) {
+static int ppscan(void *private_data, struct tokenval *tokval)
+{
Token **tlineptr = private_data;
Token *tline;
@@ -724,6 +763,25 @@ static int ppscan(void *private_data, struct tokenval *tokval) {
return tokval->t_type = TOKEN_NUM;
}
+ if (tline->type == TOK_STRING) {
+ int rn_warn;
+ char q, *r;
+ int l;
+
+ r = tline->text;
+ q = *r++;
+ l = strlen(r);
+
+ if (l == 0 || r[l-1] != q)
+ return tokval->t_type = TOKEN_ERRNUM;
+ tokval->t_integer = readstrnum(r, l-1, &rn_warn);
+ if (rn_warn)
+ error(ERR_WARNING|ERR_PASS1,
+ "character constant too long");
+ tokval->t_charptr = NULL;
+ return tokval->t_type = TOKEN_NUM;
+ }
+
if (tline->type == TOK_OTHER) {
if (!strcmp(tline->text, "<<")) return tokval->t_type = TOKEN_SHL;
if (!strcmp(tline->text, ">>")) return tokval->t_type = TOKEN_SHR;
@@ -752,12 +810,13 @@ static int ppscan(void *private_data, struct tokenval *tokval) {
* context stack isn't deep enough for the supplied number of $
* signs.
*/
-static Context *get_ctx (char *name) {
+static Context *get_ctx (char *name)
+{
Context *ctx;
int i;
if (!cstk) {
- error (ERR_NONFATAL|ERR_OFFBY1, "`%s': context stack is empty", name);
+ error (ERR_NONFATAL, "`%s': context stack is empty", name);
return NULL;
}
@@ -767,7 +826,7 @@ static Context *get_ctx (char *name) {
i++;
ctx = ctx->next;
if (!ctx) {
- error (ERR_NONFATAL|ERR_OFFBY1, "`%s': context stack is only"
+ error (ERR_NONFATAL, "`%s': context stack is only"
" %d level%s deep", name, i-1, (i==2 ? "" : "s"));
return NULL;
}
@@ -780,7 +839,8 @@ static Context *get_ctx (char *name) {
* simple wrapper which calls either strcmp or nasm_stricmp
* depending on the value of the `casesense' parameter.
*/
-static int mstrcmp(char *p, char *q, int casesense) {
+static int mstrcmp(char *p, char *q, int casesense)
+{
return casesense ? strcmp(p,q) : nasm_stricmp(p,q);
}
@@ -791,26 +851,25 @@ static int mstrcmp(char *p, char *q, int casesense) {
* the include path one by one until it finds the file or reaches
* the end of the path.
*/
-static FILE *inc_fopen(char *file) {
+static FILE *inc_fopen(char *file)
+{
FILE *fp;
char *prefix = "", *combine;
IncPath *ip = ipath;
- int len = strlen(file);
- do {
- combine = nasm_malloc(strlen(prefix)+len+1);
- strcpy(combine, prefix);
- strcat(combine, file);
+ while (1) {
+ combine = nasm_strcat(prefix,file);
fp = fopen(combine, "r");
nasm_free (combine);
if (fp)
return fp;
- prefix = ip ? ip->path : NULL;
- if (ip)
- ip = ip->next;
- } while (prefix);
+ if (!ip)
+ break;
+ prefix = ip->path;
+ ip = ip->next;
+ }
- error (ERR_FATAL|ERR_OFFBY1,
+ error (ERR_FATAL,
"unable to open include file `%s'", file);
return NULL; /* never reached - placate compilers */
}
@@ -831,7 +890,8 @@ static FILE *inc_fopen(char *file) {
* Note that this is also called with nparam zero to resolve
* `ifdef'.
*/
-static int smacro_defined (char *name, int nparam, SMacro **defn) {
+static int smacro_defined (char *name, int nparam, SMacro **defn, int nocase)
+{
SMacro *m;
Context *ctx;
char *p;
@@ -849,7 +909,7 @@ static int smacro_defined (char *name, int nparam, SMacro **defn) {
}
while (m) {
- if (!mstrcmp(m->name, p, m->casesense) &&
+ if (!mstrcmp(m->name, p, m->casesense & nocase) &&
(nparam == 0 || m->nparam == 0 || nparam == m->nparam)) {
if (defn) {
if (nparam == m->nparam)
@@ -865,48 +925,13 @@ static int smacro_defined (char *name, int nparam, SMacro **defn) {
}
/*
- * Update the __FILE__ and __LINE__ macros. Specifically, update
- * __FILE__ if bit 1 of our argument is set, and update __LINE__ if
- * bit 0 is set.
- *
- * If the macros don't exist, a `%clear' must have happened, in
- * which case we should exit quite happily and carry on going. It's
- * not an error condition.
- */
-static void update_fileline(int which) {
- SMacro *sm;
- char num[20];
-
- if ((which & 3) && smacro_defined ("__FILE__", 0, &sm) && sm) {
- free_tlist(sm->expansion);
- sm->expansion = nasm_malloc(sizeof(Token));
- sm->expansion->next = NULL;
- sm->expansion->mac = NULL;
- sm->expansion->type = TOK_STRING;
- sm->expansion->text = nasm_malloc(3+strlen(istk->fname));
- /* FIXME: throw an error if both sorts of quote are present */
- /* Better still, invent a way for us to cope with that case */
- sprintf(sm->expansion->text, "\"%s\"", istk->fname);
- }
-
- if ((which & 1) && smacro_defined ("__LINE__", 0, &sm) && sm) {
- free_tlist(sm->expansion);
- sm->expansion = nasm_malloc(sizeof(Token));
- sm->expansion->next = NULL;
- sm->expansion->mac = NULL;
- sm->expansion->type = TOK_NUMBER;
- sprintf(num, "%d", istk->lineno - istk->lineinc);
- sm->expansion->text = nasm_strdup(num);
- }
-}
-
-/*
* Count and mark off the parameters in a multi-line macro call.
* This is called both from within the multi-line macro expansion
* code, and also to mark off the default parameters when provided
* in a %macro definition line.
*/
-static void count_mmac_params (Token *t, int *nparam, Token ***params) {
+static void count_mmac_params (Token *t, int *nparam, Token ***params)
+{
int paramsize, brace;
*nparam = paramsize = 0;
@@ -916,14 +941,12 @@ static void count_mmac_params (Token *t, int *nparam, Token ***params) {
paramsize += PARAM_DELTA;
*params = nasm_realloc(*params, sizeof(**params) * paramsize);
}
- if (t && t->type == TOK_WHITESPACE)
- t = t->next;
+ skip_white_(t);
brace = FALSE;
- if (t && t->type == TOK_OTHER && !strcmp(t->text, "{"))
+ if (tok_is_(t, "{"))
brace = TRUE;
(*params)[(*nparam)++] = t;
- while (t && (t->type != TOK_OTHER ||
- strcmp(t->text, brace ? "}" : ",")))
+ while (tok_isnt_(t, brace ? "}" : ","))
t = t->next;
if (t) { /* got a comma/brace */
t = t->next;
@@ -932,21 +955,17 @@ static void count_mmac_params (Token *t, int *nparam, Token ***params) {
* Now we've found the closing brace, look further
* for the comma.
*/
- if (t && t->type == TOK_WHITESPACE)
- t = t->next;
- if (t && (t->type != TOK_OTHER || strcmp(t->text, ","))) {
- error (ERR_NONFATAL|ERR_OFFBY1,
+ skip_white_(t);
+ if (tok_isnt_(t, ",")) {
+ error (ERR_NONFATAL,
"braces do not enclose all of macro parameter");
- while (t && (t->type != TOK_OTHER ||
- strcmp(t->text, ",")))
+ while (tok_isnt_(t, ","))
t = t->next;
}
if (t)
t = t->next; /* eat the comma */
}
}
- else /* got EOL */
- break;
}
}
@@ -956,11 +975,12 @@ static void count_mmac_params (Token *t, int *nparam, Token ***params) {
*
* We must free the tline we get passed.
*/
-static int if_condition (Token *tline, int i) {
- int j, casesense;
- Token *t, *tt, **tptr, *origline;
+static int if_condition (Token *tline, int i)
+{
+ int j, casesense;
+ Token * t, * tt, ** tptr, * origline;
struct tokenval tokval;
- expr *evalresult;
+ expr * evalresult;
origline = tline;
@@ -969,13 +989,12 @@ static int if_condition (Token *tline, int i) {
case PP_IFNCTX: case PP_ELIFNCTX:
j = FALSE; /* have we matched yet? */
if (!cstk)
- error(ERR_FATAL|ERR_OFFBY1,
+ error(ERR_FATAL,
"`%s': context stack is empty", directives[i]);
else while (tline) {
- if (tline->type == TOK_WHITESPACE)
- tline = tline->next;
+ skip_white_(tline);
if (!tline || tline->type != TOK_ID) {
- error(ERR_NONFATAL|ERR_OFFBY1,
+ error(ERR_NONFATAL,
"`%s' expects context identifiers", directives[i]);
free_tlist (origline);
return -1;
@@ -993,18 +1012,17 @@ static int if_condition (Token *tline, int i) {
case PP_IFNDEF: case PP_ELIFNDEF:
j = FALSE; /* have we matched yet? */
while (tline) {
- if (tline->type == TOK_WHITESPACE)
- tline = tline->next;
+ skip_white_(tline);
if (!tline || (tline->type != TOK_ID &&
(tline->type != TOK_PREPROC_ID ||
tline->text[1] != '$'))) {
- error(ERR_NONFATAL|ERR_OFFBY1,
+ error(ERR_NONFATAL,
"`%%if%sdef' expects macro identifiers",
(i==PP_ELIFNDEF ? "n" : ""));
free_tlist (origline);
return -1;
}
- if (smacro_defined(tline->text, 0, NULL))
+ if (smacro_defined(tline->text, 0, NULL, 1))
j = TRUE;
tline = tline->next;
}
@@ -1017,7 +1035,7 @@ static int if_condition (Token *tline, int i) {
case PP_IFIDNI: case PP_ELIFIDNI: case PP_IFNIDNI: case PP_ELIFNIDNI:
tline = expand_smacro(tline);
t = tt = tline;
- while (tt && (tt->type != TOK_OTHER || strcmp(tt->text, ",")))
+ while (tok_isnt_(tt, ","))
tt = tt->next;
if (!tt) {
error(ERR_NONFATAL, "`%s' expects two comma-separated arguments");
@@ -1054,7 +1072,8 @@ static int if_condition (Token *tline, int i) {
}
if ((t->type != TOK_OTHER || strcmp(t->text, ",")) || tt)
j = FALSE; /* trailing gunk on one end or other */
- if (i == PP_IFNIDN || i == PP_ELIFNIDN)
+ if (i == PP_IFNIDN || i == PP_ELIFNIDN ||
+ i == PP_IFNIDNI || i == PP_ELIFNIDNI)
j = !j;
free_tlist (tline);
return j;
@@ -1064,10 +1083,10 @@ static int if_condition (Token *tline, int i) {
case PP_IFSTR: case PP_ELIFSTR: case PP_IFNSTR: case PP_ELIFNSTR:
tline = expand_smacro(tline);
t = tline;
- while (t && t->type == TOK_WHITESPACE)
+ while (tok_type_(t, TOK_WHITESPACE))
t = t->next;
j = FALSE; /* placate optimiser */
- switch (i) {
+ if (t) switch (i) {
case PP_IFID: case PP_ELIFID: case PP_IFNID: case PP_ELIFNID:
j = (t->type == TOK_ID);
break;
@@ -1095,17 +1114,17 @@ static int if_condition (Token *tline, int i) {
if (!evalresult)
return -1;
if (tokval.t_type)
- error(ERR_WARNING|ERR_OFFBY1,
+ error(ERR_WARNING,
"trailing garbage after expression ignored");
if (!is_simple(evalresult)) {
- error(ERR_NONFATAL|ERR_OFFBY1,
+ error(ERR_NONFATAL,
"non-constant value given to `%s'", directives[i]);
return -1;
}
return reloc_value(evalresult) != 0;
default:
- error(ERR_FATAL|ERR_OFFBY1,
+ error(ERR_FATAL,
"preprocessor directive `%s' not yet implemented",
directives[i]);
free_tlist (origline);
@@ -1123,14 +1142,9 @@ static int if_condition (Token *tline, int i) {
* Return values go like this:
*
* bit 0 is set if a directive was found (so the line gets freed)
- * bit 1 is set if a blank line should be emitted
- * bit 2 is set if a re-sync line number comment should be emitted
- *
- * (bits 1 and 2 are mutually exclusive in that the rest of the
- * preprocessor doesn't guarantee to be able to handle the case in
- * which both are set)
*/
-static int do_directive (Token *tline) {
+static int do_directive (Token *tline)
+{
int i, j, k, m, nparam, nolist;
char *p, *mname;
Include *inc;
@@ -1145,9 +1159,8 @@ static int do_directive (Token *tline) {
origline = tline;
- if (tline && tline->type == TOK_WHITESPACE)
- tline = tline->next;
- if (!tline || tline->type != TOK_PREPROC_ID ||
+ skip_white_(tline);
+ if (!tok_type_(tline, TOK_PREPROC_ID) ||
(tline->text[1]=='%' || tline->text[1]=='$' || tline->text[1]=='!'))
return 0;
@@ -1190,21 +1203,26 @@ static int do_directive (Token *tline) {
i != PP_IFNUM && i != PP_ELIFNUM &&
i != PP_IFSTR && i != PP_ELIFSTR &&
i != PP_ELSE && i != PP_ENDIF)
+ {
return 0;
+ }
/*
* If we're defining a macro or reading a %rep block, we should
* ignore all directives except for %macro/%imacro (which
* generate an error), %endm/%endmacro, and (only if we're in a
- * %rep block) %endrep.
+ * %rep block) %endrep. If we're in a %rep block, another %rep
+ * causes an error, so should be let through.
*/
if (defining && i != PP_MACRO && i != PP_IMACRO &&
i != PP_ENDMACRO && i != PP_ENDM &&
- (defining->name || i != PP_ENDREP))
+ (defining->name || (i != PP_ENDREP && i != PP_REP)))
+ {
return 0;
+ }
if (j != -2) {
- error(ERR_NONFATAL|ERR_OFFBY1, "unknown preprocessor directive `%s'",
+ error(ERR_NONFATAL, "unknown preprocessor directive `%s'",
tline->text);
return 0; /* didn't get it */
}
@@ -1213,16 +1231,13 @@ static int do_directive (Token *tline) {
case PP_CLEAR:
if (tline->next)
- error(ERR_WARNING|ERR_OFFBY1,
+ error(ERR_WARNING,
"trailing garbage after `%%clear' ignored");
for (j=0; j<NHASH; j++) {
while (mmacros[j]) {
MMacro *m = mmacros[j];
- mmacros[j] = mmacros[j]->next;
- nasm_free (m->name);
- free_tlist (m->dlist);
- free_llist (m->expansion);
- nasm_free (m);
+ mmacros[j] = m->next;
+ free_mmacro(m);
}
while (smacros[j]) {
SMacro *s = smacros[j];
@@ -1237,16 +1252,16 @@ static int do_directive (Token *tline) {
case PP_INCLUDE:
tline = tline->next;
- if (tline && tline->type == TOK_WHITESPACE)
- tline = tline->next;
+ skip_white_(tline);
if (!tline || (tline->type != TOK_STRING &&
- tline->type != TOK_INTERNAL_STRING)) {
- error(ERR_NONFATAL|ERR_OFFBY1, "`%%include' expects a file name");
+ tline->type != TOK_INTERNAL_STRING))
+ {
+ error(ERR_NONFATAL, "`%%include' expects a file name");
free_tlist (origline);
return 3; /* but we did _something_ */
}
if (tline->next)
- error(ERR_WARNING|ERR_OFFBY1,
+ error(ERR_WARNING,
"trailing garbage after `%%include' ignored");
if (tline->type != TOK_INTERNAL_STRING) {
p = tline->text+1; /* point past the quote to the name */
@@ -1257,28 +1272,27 @@ static int do_directive (Token *tline) {
inc->next = istk;
inc->conds = NULL;
inc->fp = inc_fopen(p);
- inc->fname = nasm_strdup(p);
- inc->lineno = inc->lineinc = 1;
+ inc->fname = src_set_fname(nasm_strdup(p));
+ inc->lineno = src_set_linnum(0);
+ inc->lineinc = 1;
inc->expansion = NULL;
inc->mstk = NULL;
istk = inc;
list->uplevel (LIST_INCLUDE);
- update_fileline(3); /* update __FILE__ and __LINE__ */
free_tlist (origline);
return 5;
case PP_PUSH:
tline = tline->next;
- if (tline && tline->type == TOK_WHITESPACE)
- tline = tline->next;
- if (!tline || tline->type != TOK_ID) {
- error(ERR_NONFATAL|ERR_OFFBY1,
+ skip_white_(tline);
+ if (!tok_type_(tline, TOK_ID)) {
+ error(ERR_NONFATAL,
"`%%push' expects a context identifier");
free_tlist (origline);
return 3; /* but we did _something_ */
}
if (tline->next)
- error(ERR_WARNING|ERR_OFFBY1,
+ error(ERR_WARNING,
"trailing garbage after `%%push' ignored");
ctx = nasm_malloc(sizeof(Context));
ctx->next = cstk;
@@ -1291,19 +1305,18 @@ static int do_directive (Token *tline) {
case PP_REPL:
tline = tline->next;
- if (tline && tline->type == TOK_WHITESPACE)
- tline = tline->next;
- if (!tline || tline->type != TOK_ID) {
- error(ERR_NONFATAL|ERR_OFFBY1,
+ skip_white_(tline);
+ if (!tok_type_(tline, TOK_ID)) {
+ error(ERR_NONFATAL,
"`%%repl' expects a context identifier");
free_tlist (origline);
return 3; /* but we did _something_ */
}
if (tline->next)
- error(ERR_WARNING|ERR_OFFBY1,
+ error(ERR_WARNING,
"trailing garbage after `%%repl' ignored");
if (!cstk)
- error(ERR_NONFATAL|ERR_OFFBY1,
+ error(ERR_NONFATAL,
"`%%repl': context stack is empty");
else {
nasm_free (cstk->name);
@@ -1314,10 +1327,10 @@ static int do_directive (Token *tline) {
case PP_POP:
if (tline->next)
- error(ERR_WARNING|ERR_OFFBY1,
+ error(ERR_WARNING,
"trailing garbage after `%%pop' ignored");
if (!cstk)
- error(ERR_NONFATAL|ERR_OFFBY1,
+ error(ERR_NONFATAL,
"`%%pop': context stack is already empty");
else
ctx_pop();
@@ -1325,21 +1338,18 @@ static int do_directive (Token *tline) {
break;
case PP_ERROR:
+ tline->next = expand_smacro (tline->next);
tline = tline->next;
- if (tline && tline->type == TOK_WHITESPACE)
- tline = tline->next;
- if (!tline || tline->type != TOK_STRING) {
- error(ERR_NONFATAL|ERR_OFFBY1,
- "`%%error' expects an error string");
- free_tlist (origline);
- return 3; /* but we did _something_ */
+ skip_white_(tline);
+ if (tok_type_(tline, TOK_STRING)) {
+ p = tline->text+1; /* point past the quote to the name */
+ p[strlen(p)-1] = '\0'; /* remove the trailing quote */
+ error(ERR_NONFATAL, "user error: %s", p);
+ } else {
+ p = detoken(tline);
+ error(ERR_WARNING, "user error: %s", p);
+ nasm_free(p);
}
- if (tline->next)
- error(ERR_WARNING|ERR_OFFBY1,
- "trailing garbage after `%%error' ignored");
- p = tline->text+1; /* point past the quote to the name */
- p[strlen(p)-1] = '\0'; /* remove the trailing quote */
- error(ERR_NONFATAL|ERR_OFFBY1, "user error: %s", p);
free_tlist (origline);
break;
@@ -1365,7 +1375,12 @@ static int do_directive (Token *tline) {
tline->next = NULL; /* it got freed */
free_tlist (origline);
if (j < 0)
- return 3;
+ /*
+ * Bogus expression in %if, but we should pretend
+ * it was OK anyway, so that we don't get an error
+ * cascade on the subsequent %else / %endif.
+ */
+ j = COND_NEVER;
else
j = j ? COND_IF_TRUE : COND_IF_FALSE;
}
@@ -1391,7 +1406,7 @@ static int do_directive (Token *tline) {
case PP_ELIFNUM:
case PP_ELIFSTR:
if (!istk->conds)
- error(ERR_FATAL|ERR_OFFBY1, "`%s': no matching `%%if'",
+ error(ERR_FATAL, "`%s': no matching `%%if'",
directives[i]);
if (emitting(istk->conds->state) || istk->conds->state == COND_NEVER)
istk->conds->state = COND_NEVER;
@@ -1400,7 +1415,11 @@ static int do_directive (Token *tline) {
tline->next = NULL; /* it got freed */
free_tlist (origline);
if (j < 0)
- return 3;
+ /*
+ * The expression was bogus, but let's make
+ * %endif not complain about missing %if
+ */
+ j = COND_NEVER;
else
istk->conds->state = j ? COND_IF_TRUE : COND_IF_FALSE;
}
@@ -1408,10 +1427,10 @@ static int do_directive (Token *tline) {
case PP_ELSE:
if (tline->next)
- error(ERR_WARNING|ERR_OFFBY1,
+ error(ERR_WARNING,
"trailing garbage after `%%else' ignored");
if (!istk->conds)
- error(ERR_FATAL|ERR_OFFBY1,
+ error(ERR_FATAL,
"`%%else': no matching `%%if'");
if (emitting(istk->conds->state) || istk->conds->state == COND_NEVER)
istk->conds->state = COND_ELSE_FALSE;
@@ -1422,10 +1441,10 @@ static int do_directive (Token *tline) {
case PP_ENDIF:
if (tline->next)
- error(ERR_WARNING|ERR_OFFBY1,
+ error(ERR_WARNING,
"trailing garbage after `%%endif' ignored");
if (!istk->conds)
- error(ERR_FATAL|ERR_OFFBY1,
+ error(ERR_FATAL,
"`%%endif': no matching `%%if'");
cond = istk->conds;
istk->conds = cond->next;
@@ -1436,14 +1455,13 @@ static int do_directive (Token *tline) {
case PP_MACRO:
case PP_IMACRO:
if (defining)
- error (ERR_FATAL|ERR_OFFBY1,
+ error (ERR_FATAL,
"`%%%smacro': already defining a macro",
(i == PP_IMACRO ? "i" : ""));
tline = tline->next;
- if (tline && tline->type == TOK_WHITESPACE)
- tline = tline->next;
- if (!tline || tline->type != TOK_ID) {
- error (ERR_NONFATAL|ERR_OFFBY1,
+ skip_white_(tline);
+ if (!tok_type_(tline, TOK_ID)) {
+ error (ERR_NONFATAL,
"`%%%smacro' expects a macro name",
(i == PP_IMACRO ? "i" : ""));
return 3;
@@ -1455,10 +1473,9 @@ static int do_directive (Token *tline) {
defining->nolist = FALSE;
defining->in_progress = FALSE;
tline = tline->next;
- if (tline && tline->type == TOK_WHITESPACE)
- tline = tline->next;
- if (!tline || tline->type != TOK_NUMBER) {
- error (ERR_NONFATAL|ERR_OFFBY1,
+ skip_white_(tline);
+ if (!tok_type_(tline, TOK_NUMBER)) {
+ error (ERR_NONFATAL,
"`%%%smacro' expects a parameter count",
(i == PP_IMACRO ? "i" : ""));
defining->nparam_min = defining->nparam_max = 0;
@@ -1466,37 +1483,35 @@ static int do_directive (Token *tline) {
defining->nparam_min = defining->nparam_max =
readnum(tline->text, &j);
if (j)
- error (ERR_NONFATAL|ERR_OFFBY1,
+ error (ERR_NONFATAL,
"unable to parse parameter count `%s'", tline->text);
}
- if (tline && tline->next && tline->next->type == TOK_OTHER &&
- !strcmp(tline->next->text, "-")) {
+ if (tline && tok_is_(tline->next, "-")) {
tline = tline->next->next;
- if (tline && tline->type == TOK_OTHER &&
- !strcmp(tline->text, "*"))
+ if (tok_is_(tline, "*"))
defining->nparam_max = INT_MAX;
- else if (!tline || tline->type != TOK_NUMBER)
- error (ERR_NONFATAL|ERR_OFFBY1,
+ else if (!tok_type_(tline, TOK_NUMBER))
+ error (ERR_NONFATAL,
"`%%%smacro' expects a parameter count after `-'",
(i == PP_IMACRO ? "i" : ""));
else {
defining->nparam_max = readnum(tline->text, &j);
if (j)
- error (ERR_NONFATAL|ERR_OFFBY1,
+ error (ERR_NONFATAL,
"unable to parse parameter count `%s'",
tline->text);
if (defining->nparam_min > defining->nparam_max)
- error (ERR_NONFATAL|ERR_OFFBY1,
+ error (ERR_NONFATAL,
"minimum parameter count exceeds maximum");
}
}
- if (tline && tline->next && tline->next->type == TOK_OTHER &&
- !strcmp(tline->next->text, "+")) {
+ if (tline && tok_is_(tline->next, "+")) {
tline = tline->next;
defining->plus = TRUE;
}
- if (tline && tline->next && tline->next->type == TOK_ID &&
- !nasm_stricmp(tline->next->text, ".nolist")) {
+ if (tline && tok_type_(tline->next, TOK_ID) &&
+ !nasm_stricmp(tline->next->text, ".nolist"))
+ {
tline = tline->next;
defining->nolist = TRUE;
}
@@ -1504,8 +1519,9 @@ static int do_directive (Token *tline) {
while (mmac) {
if (!strcmp(mmac->name, defining->name) &&
(mmac->nparam_min<=defining->nparam_max || defining->plus) &&
- (defining->nparam_min<=mmac->nparam_max || mmac->plus)) {
- error (ERR_WARNING|ERR_OFFBY1,
+ (defining->nparam_min<=mmac->nparam_max || mmac->plus))
+ {
+ error (ERR_WARNING,
"redefining multi-line macro `%s'", defining->name);
break;
}
@@ -1530,7 +1546,7 @@ static int do_directive (Token *tline) {
case PP_ENDM:
case PP_ENDMACRO:
if (!defining) {
- error (ERR_NONFATAL|ERR_OFFBY1, "`%s': not defining a macro",
+ error (ERR_NONFATAL, "`%s': not defining a macro",
tline->text);
return 3;
}
@@ -1555,10 +1571,10 @@ static int do_directive (Token *tline) {
if (!evalresult)
return 3;
if (tokval.t_type)
- error(ERR_WARNING|ERR_OFFBY1,
+ error(ERR_WARNING,
"trailing garbage after expression ignored");
if (!is_simple(evalresult)) {
- error(ERR_NONFATAL|ERR_OFFBY1,
+ error(ERR_NONFATAL,
"non-constant value given to `%%rotate'");
return 3;
}
@@ -1566,7 +1582,7 @@ static int do_directive (Token *tline) {
while (mmac && !mmac->name) /* avoid mistaking %reps for macros */
mmac = mmac->next_active;
if (!mmac)
- error(ERR_NONFATAL, "`%rotate' invoked outside a macro call");
+ error(ERR_NONFATAL, "`%%rotate' invoked outside a macro call");
mmac->rotate = mmac->rotate + reloc_value(evalresult);
if (mmac->rotate < 0)
mmac->rotate = mmac->nparam - (-mmac->rotate) % mmac->nparam;
@@ -1574,6 +1590,24 @@ static int do_directive (Token *tline) {
return 1;
case PP_REP:
+ if (defining) {
+ /*
+ * We don't allow nested %reps, because of a strange bug
+ * that was causing a panic. The cause of the bug appears to be
+ * that the nested %rep isn't taken into account when matching
+ * against the %endreps, so some mechanism to count the
+ * %reps in and the %endreps out may well work here.
+ *
+ * That's for experimentation with later, though.
+ * For informations sake, the panic produced by
+ * nesting %reps was:
+ *
+ * istk->mstk has no name but defining is set at end
+ * of expansion
+ */
+ error(ERR_NONFATAL, "nested `%%rep' invocation not allowed");
+ break;
+ }
nolist = FALSE;
tline = tline->next;
if (tline->next && tline->next->type == TOK_WHITESPACE)
@@ -1594,10 +1628,10 @@ static int do_directive (Token *tline) {
if (!evalresult)
return 3;
if (tokval.t_type)
- error(ERR_WARNING|ERR_OFFBY1,
+ error(ERR_WARNING,
"trailing garbage after expression ignored");
if (!is_simple(evalresult)) {
- error(ERR_NONFATAL|ERR_OFFBY1,
+ error(ERR_NONFATAL,
"non-constant value given to `%%rep'");
return 3;
}
@@ -1608,13 +1642,15 @@ static int do_directive (Token *tline) {
defining->nolist = nolist;
defining->in_progress = reloc_value(evalresult) + 1;
defining->nparam_min = defining->nparam_max = 0;
+ defining->defaults = NULL;
+ defining->dlist = NULL;
defining->expansion = NULL;
defining->next_active = istk->mstk;
return 1;
case PP_ENDREP:
- if (!defining) {
- error (ERR_NONFATAL|ERR_OFFBY1,
+ if (!defining || defining->name) {
+ error (ERR_NONFATAL,
"`%%endrep': no matching `%%rep'");
return 3;
}
@@ -1641,7 +1677,7 @@ static int do_directive (Token *tline) {
list->uplevel (defining->nolist ? LIST_MACRO_NOLIST : LIST_MACRO);
defining = NULL;
free_tlist (origline);
- return 1; /* the expansion will line-sync */
+ return 1;
case PP_EXITREP:
/*
@@ -1653,22 +1689,21 @@ static int do_directive (Token *tline) {
if (l->finishes && !l->finishes->name)
break;
- if (l->finishes && !l->finishes->name)
+ if (l)
l->finishes->in_progress = 0;
else
error (ERR_NONFATAL, "`%%exitrep' not within `%%rep' block");
free_tlist (origline);
- return 1; /* the end marker will line-sync */
+ return 1;
case PP_DEFINE:
case PP_IDEFINE:
tline = tline->next;
- if (tline && tline->type == TOK_WHITESPACE)
- tline = tline->next;
+ skip_white_(tline);
if (!tline || (tline->type != TOK_ID &&
(tline->type != TOK_PREPROC_ID ||
tline->text[1] != '$'))) {
- error (ERR_NONFATAL|ERR_OFFBY1,
+ error (ERR_NONFATAL,
"`%%%sdefine' expects a macro identifier",
(i == PP_IDEFINE ? "i" : ""));
free_tlist (origline);
@@ -1691,23 +1726,22 @@ static int do_directive (Token *tline) {
last = tline;
param_start = tline = tline->next;
nparam = 0;
- if (tline && tline->type == TOK_OTHER && !strcmp(tline->text, "(")) {
+ if (tok_is_(tline, "(")) {
/*
* This macro has parameters.
*/
tline = tline->next;
while (1) {
- if (tline && tline->type == TOK_WHITESPACE)
- tline = tline->next;
+ skip_white_(tline);
if (!tline) {
- error (ERR_NONFATAL|ERR_OFFBY1,
+ error (ERR_NONFATAL,
"parameter identifier expected");
free_tlist (origline);
return 3;
}
if (tline->type != TOK_ID) {
- error (ERR_NONFATAL|ERR_OFFBY1,
+ error (ERR_NONFATAL,
"`%s': parameter identifier expected",
tline->text);
free_tlist (origline);
@@ -1715,16 +1749,13 @@ static int do_directive (Token *tline) {
}
tline->type = TOK_SMAC_PARAM + nparam++;
tline = tline->next;
- if (tline && tline->type == TOK_WHITESPACE)
- tline = tline->next;
- if (tline && tline->type == TOK_OTHER &&
- !strcmp(tline->text, ",")) {
+ skip_white_(tline);
+ if (tok_is_(tline, ",")) {
tline = tline->next;
continue;
}
- if (!tline || tline->type != TOK_OTHER ||
- strcmp(tline->text, ")")) {
- error (ERR_NONFATAL|ERR_OFFBY1,
+ if (!tok_is_(tline, ")")) {
+ error (ERR_NONFATAL,
"`)' expected to terminate macro template");
free_tlist (origline);
return 3;
@@ -1734,7 +1765,7 @@ static int do_directive (Token *tline) {
last = tline;
tline = tline->next;
}
- if (tline && tline->type == TOK_WHITESPACE)
+ if (tok_type_(tline, TOK_WHITESPACE))
last = tline, tline = tline->next;
macro_start = NULL;
last->next = NULL;
@@ -1759,12 +1790,15 @@ static int do_directive (Token *tline) {
* carefully re-terminated after chopping off the expansion
* from the end).
*/
- if (smacro_defined (mname, nparam, &smac)) {
- if (!smac)
- error (ERR_WARNING|ERR_OFFBY1,
+ if (smacro_defined (mname, nparam, &smac, i==PP_DEFINE)) {
+ if (!smac) {
+ error (ERR_WARNING,
"single-line macro `%s' defined both with and"
" without parameters", mname);
- else {
+ free_tlist (origline);
+ free_tlist (macro_start);
+ return 3;
+ } else {
/*
* We're redefining, so we have to take over an
* existing SMacro structure. This means freeing
@@ -1789,12 +1823,11 @@ static int do_directive (Token *tline) {
case PP_ASSIGN:
case PP_IASSIGN:
tline = tline->next;
- if (tline && tline->type == TOK_WHITESPACE)
- tline = tline->next;
+ skip_white_(tline);
if (!tline || (tline->type != TOK_ID &&
(tline->type != TOK_PREPROC_ID ||
tline->text[1] != '$'))) {
- error (ERR_NONFATAL|ERR_OFFBY1,
+ error (ERR_NONFATAL,
"`%%%sassign' expects a macro identifier",
(i == PP_IASSIGN ? "i" : ""));
free_tlist (origline);
@@ -1831,11 +1864,11 @@ static int do_directive (Token *tline) {
}
if (tokval.t_type)
- error(ERR_WARNING|ERR_OFFBY1,
+ error(ERR_WARNING,
"trailing garbage after expression ignored");
if (!is_simple(evalresult)) {
- error(ERR_NONFATAL|ERR_OFFBY1,
+ error(ERR_NONFATAL,
"non-constant value given to `%%%sassign'",
(i == PP_IASSIGN ? "i" : ""));
free_tlist (origline);
@@ -1844,22 +1877,17 @@ static int do_directive (Token *tline) {
macro_start = nasm_malloc(sizeof(*macro_start));
macro_start->next = NULL;
- {
- char numbuf[20];
- sprintf(numbuf, "%ld", reloc_value(evalresult));
- macro_start->text = nasm_strdup(numbuf);
- }
+ make_tok_num(macro_start, reloc_value(evalresult));
macro_start->mac = NULL;
- macro_start->type = TOK_NUMBER;
/*
* We now have a macro name, an implicit parameter count of
* zero, and a numeric token to use as an expansion. Create
* and store an SMacro.
*/
- if (smacro_defined (mname, 0, &smac)) {
+ if (smacro_defined (mname, 0, &smac, i==PP_ASSIGN)) {
if (!smac)
- error (ERR_WARNING|ERR_OFFBY1,
+ error (ERR_WARNING,
"single-line macro `%s' defined both with and"
" without parameters", mname);
else {
@@ -1871,7 +1899,8 @@ static int do_directive (Token *tline) {
nasm_free (smac->name);
free_tlist (smac->expansion);
}
- } else {
+ }
+ else {
smac = nasm_malloc(sizeof(SMacro));
smac->next = *smhead;
*smhead = smac;
@@ -1889,20 +1918,19 @@ static int do_directive (Token *tline) {
* Syntax is `%line nnn[+mmm] [filename]'
*/
tline = tline->next;
- if (tline && tline->type == TOK_WHITESPACE)
- tline = tline->next;
- if (!tline || tline->type != TOK_NUMBER) {
- error (ERR_NONFATAL|ERR_OFFBY1, "`%%line' expects line number");
+ skip_white_(tline);
+ if (!tok_type_(tline, TOK_NUMBER)) {
+ error (ERR_NONFATAL, "`%%line' expects line number");
free_tlist (origline);
return 3;
}
k = readnum(tline->text, &j);
m = 1;
tline = tline->next;
- if (tline && tline->type == TOK_OTHER && !strcmp(tline->text, "+")) {
+ if (tok_is_(tline, "+")) {
tline = tline->next;
- if (!tline || tline->type != TOK_NUMBER) {
- error (ERR_NONFATAL|ERR_OFFBY1,
+ if (!tok_type_(tline, TOK_NUMBER)) {
+ error (ERR_NONFATAL,
"`%%line' expects line increment");
free_tlist (origline);
return 3;
@@ -1910,21 +1938,17 @@ static int do_directive (Token *tline) {
m = readnum(tline->text, &j);
tline = tline->next;
}
- if (tline && tline->type == TOK_WHITESPACE)
- tline = tline->next;
- istk->lineno = k;
+ skip_white_(tline);
+ src_set_linnum(k);
istk->lineinc = m;
- update_fileline(3); /* update __FILE__ and __LINE__ */
if (tline) {
- char *s = detoken(tline);
- nasm_free (istk->fname);
- istk->fname = s;
+ nasm_free ( src_set_fname ( detoken(tline) ) );
}
free_tlist (origline);
return 5;
default:
- error(ERR_FATAL|ERR_OFFBY1,
+ error(ERR_FATAL,
"preprocessor directive `%s' not yet implemented",
directives[i]);
break;
@@ -1937,17 +1961,16 @@ static int do_directive (Token *tline) {
* nothing else. Return the condition code index if so, or -1
* otherwise.
*/
-static int find_cc (Token *t) {
+static int find_cc (Token *t)
+{
Token *tt;
int i, j, k, m;
- if (t && t->type == TOK_WHITESPACE)
- t = t->next;
+ skip_white_(t);
if (t->type != TOK_ID)
return -1;
tt = t->next;
- if (tt && tt->type == TOK_WHITESPACE)
- tt = tt->next;
+ skip_white_(tt);
if (tt && (tt->type != TOK_OTHER || strcmp(tt->text, ",")))
return -1;
@@ -1974,7 +1997,8 @@ static int find_cc (Token *t) {
* Expand MMacro-local things: parameter references (%0, %n, %+n,
* %-n) and MMacro-local identifiers (%%foo).
*/
-static Token *expand_mmac_params (Token *tline) {
+static Token *expand_mmac_params (Token *tline)
+{
Token *t, *tt, *ttt, **tail, *thead;
tail = &thead;
@@ -2012,9 +2036,7 @@ static Token *expand_mmac_params (Token *tline) {
case '%':
type = TOK_ID;
sprintf(tmpbuf, "..@%lu.", mac->unique);
- text = nasm_malloc(strlen(tmpbuf)+strlen(t->text+2)+1);
- strcpy(text, tmpbuf);
- strcat(text, t->text+2);
+ text = nasm_strcat(tmpbuf, t->text+2);
break;
case '-':
n = atoi(t->text+2)-1;
@@ -2027,14 +2049,14 @@ static Token *expand_mmac_params (Token *tline) {
}
cc = find_cc (tt);
if (cc == -1) {
- error (ERR_NONFATAL|ERR_OFFBY1,
+ error (ERR_NONFATAL,
"macro parameter %d is not a condition code",
n+1);
text = NULL;
} else {
type = TOK_ID;
if (inverse_ccs[cc] == -1) {
- error (ERR_NONFATAL|ERR_OFFBY1,
+ error (ERR_NONFATAL,
"condition code `%s' is not invertible",
conditions[cc]);
text = NULL;
@@ -2053,7 +2075,7 @@ static Token *expand_mmac_params (Token *tline) {
}
cc = find_cc (tt);
if (cc == -1) {
- error (ERR_NONFATAL|ERR_OFFBY1,
+ error (ERR_NONFATAL,
"macro parameter %d is not a condition code",
n+1);
text = NULL;
@@ -2074,7 +2096,6 @@ static Token *expand_mmac_params (Token *tline) {
if (tt) {
for (i=0; i<mac->paramlen[n]; i++) {
ttt = *tail = nasm_malloc(sizeof(Token));
- ttt->next = NULL;
tail = &ttt->next;
ttt->type = tt->type;
ttt->text = nasm_strdup(tt->text);
@@ -2086,10 +2107,10 @@ static Token *expand_mmac_params (Token *tline) {
break;
}
nasm_free (t->text);
- nasm_free (t);
- if (text) {
- t = *tail = nasm_malloc(sizeof(Token));
- t->next = NULL;
+ if (!text) {
+ nasm_free (t);
+ } else {
+ *tail = t;
tail = &t->next;
t->type = type;
t->text = text;
@@ -2100,10 +2121,42 @@ static Token *expand_mmac_params (Token *tline) {
t = *tail = tline;
tline = tline->next;
t->mac = NULL;
- t->next = NULL;
tail = &t->next;
}
}
+ *tail = NULL;
+ t = thead;
+ for (; t && (tt=t->next)!=NULL ; t = t->next)
+ switch (t->type) {
+ case TOK_WHITESPACE:
+ if (tt->type == TOK_WHITESPACE) {
+ t->next = tt->next;
+ nasm_free(tt->text);
+ nasm_free(tt);
+ }
+ break;
+ case TOK_ID:
+ if (tt->type == TOK_ID || tt->type == TOK_NUMBER) {
+ char *tmp = nasm_strcat(t->text, tt->text);
+ nasm_free(t->text);
+ t->text = tmp;
+ t->next = tt->next;
+ nasm_free(tt->text);
+ nasm_free(tt);
+ }
+ break;
+ case TOK_NUMBER:
+ if (tt->type == TOK_NUMBER) {
+ char *tmp = nasm_strcat(t->text, tt->text);
+ nasm_free(t->text);
+ t->text = tmp;
+ t->next = tt->next;
+ nasm_free(tt->text);
+ nasm_free(tt);
+ }
+ break;
+ }
+
return thead;
}
@@ -2114,9 +2167,10 @@ static Token *expand_mmac_params (Token *tline) {
* Tokens from input to output a lot of the time, rather than
* actually bothering to destroy and replicate.)
*/
-static Token *expand_smacro (Token *tline) {
+static Token *expand_smacro (Token *tline)
+{
Token *t, *tt, *mstart, **tail, *thead;
- SMacro *head, *m;
+ SMacro *head = NULL, *m;
Token **params;
int *paramsize;
int nparam, sparam, brackets;
@@ -2125,239 +2179,256 @@ static Token *expand_smacro (Token *tline) {
tail = &thead;
thead = NULL;
- while (tline) {
- while (tline && tline->type != TOK_ID &&
- (tline->type != TOK_PREPROC_ID || tline->text[1] != '$')) {
- if (tline->type == TOK_SMAC_END) {
- tline->mac->in_progress = FALSE;
- t = tline;
- tline = tline->next;
- nasm_free (t);
- } else {
- t = *tail = tline;
- tline = tline->next;
- t->mac = NULL;
- t->next = NULL;
- tail = &t->next;
- if (t->type == TOK_PS_OTHER) {
- /*
- * If we see a PS_OTHER, we must at the very
- * least restore its correct token type. We
- * should also check for a %$ token, since this
- * is the point at which we expand context-
- * local labels.
- */
- t->type = TOK_ID;
- if (t->text[0] == '%' && t->text[1] == '$') {
- Context *c = get_ctx (t->text);
- char *p, *q, buffer[40];
-
- if (c) {
- q = t->text+1;
- q += strspn(q, "$");
- sprintf(buffer, "..@%lu.", c->number);
- p = nasm_malloc (strlen(buffer)+strlen(q)+1);
- strcpy (p, buffer);
- strcat (p, q);
- nasm_free (t->text);
- t->text = p;
- }
- }
- }
- }
- }
-
- if (!tline)
- break;
- /*
- * We've hit an identifier. As in is_mmacro below, we first
- * check whether the identifier is a single-line macro at
- * all, then think about checking for parameters if
- * necessary.
- */
+ while (tline) { /* main token loop */
+ p = NULL;
if (tline->type == TOK_ID) {
head = smacros[hash(tline->text)];
p = tline->text;
- } else {
+ } else if (tline->type == TOK_PREPROC_ID && tline->text[1] == '$') {
Context *ctx = get_ctx (tline->text);
if (ctx) {
- p = tline->text+1;
- p += strspn(p, "$");
head = ctx->localmac;
- } else {
- tline->type = TOK_OTHER; /* so it will get copied above */
- continue;
+ p = tline->text+2;
+ p += strspn(p, "$");
}
}
- for (m = head; m; m = m->next)
- if (!mstrcmp(m->name, p, m->casesense))
- break;
- if (!m || m->in_progress) {
- /*
- * Either we didn't find a macro, so this can't be a
- * macro call, or we found a macro which was already in
- * progress, in which case we don't _treat_ this as a
- * macro call. Copy it through and ignore it.
- */
- tline->type = TOK_PS_OTHER; /* so it will get copied above */
- continue;
- }
- mstart = tline;
- if (m->nparam == 0) {
- /*
- * Simple case: the macro is parameterless. Discard the
- * one token that the macro call took, and push the
- * expansion back on the to-do stack.
- */
- params = NULL;
- paramsize = NULL;
- } else {
- /*
- * Complicated case: at least one macro with this name
- * exists and takes parameters. We must find the
- * parameters in the call, count them, find the SMacro
- * that corresponds to that form of the macro call, and
- * substitute for the parameters when we expand. What a
- * pain.
- */
- nparam = sparam = 0;
- params = NULL;
- paramsize = NULL;
- tline = tline->next;
- if (tline && tline->type == TOK_WHITESPACE)
- tline = tline->next;
- if (!tline || tline->type != TOK_OTHER ||
- strcmp(tline->text, "(")) {
+ if (p) {
+ /*
+ * We've hit an identifier. As in is_mmacro below, we first
+ * check whether the identifier is a single-line macro at
+ * all, then think about checking for parameters if
+ * necessary.
+ */
+ for (m = head; m; m = m->next)
+ if (!mstrcmp(m->name, p, m->casesense))
+ break;
+ if (m) {
+ mstart = tline;
+ params = NULL;
+ paramsize = NULL;
+ if (m->nparam == 0) {
/*
- * This macro wasn't called with parameters: ignore
- * the call. (Behaviour borrowed from gnu cpp.)
+ * Simple case: the macro is parameterless. Discard the
+ * one token that the macro call took, and push the
+ * expansion back on the to-do stack.
*/
- tline = mstart;
- tline->type = TOK_PS_OTHER;
- continue;
- }
- tline = tline->next;
- while (1) {
- if (tline && tline->type == TOK_WHITESPACE)
+ if (!m->expansion)
+ {
+ if (!strcmp("__FILE__", m->name)) {
+ long num=0;
+ src_get(&num, &(tline->text));
+ nasm_quote(&(tline->text));
+ tline->type = TOK_STRING;
+ continue;
+ }
+ if (!strcmp("__LINE__", m->name)) {
+ nasm_free(tline->text);
+ make_tok_num(tline, src_get_linnum());
+ continue;
+ }
+ t = tline;
tline = tline->next;
- if (!tline) {
- error(ERR_NONFATAL|ERR_OFFBY1,
- "macro call expects terminating `)'");
- break;
+ nasm_free (t->text);
+ nasm_free (t);
+ continue;
}
- if (nparam >= sparam) {
- sparam += PARAM_DELTA;
- params = nasm_realloc (params, sparam*sizeof(Token *));
- paramsize = nasm_realloc (paramsize, sparam*sizeof(int));
+ }
+ else {
+ /*
+ * Complicated case: at least one macro with this name
+ * exists and takes parameters. We must find the
+ * parameters in the call, count them, find the SMacro
+ * that corresponds to that form of the macro call, and
+ * substitute for the parameters when we expand. What a
+ * pain.
+ */
+ tline = tline->next;
+ skip_white_(tline);
+ if (!tok_is_(tline, "(")) {
+ /*
+ * This macro wasn't called with parameters: ignore
+ * the call. (Behaviour borrowed from gnu cpp.)
+ */
+ tline = mstart;
+ m = NULL;
+ }
+ else {
+ int paren = 0;
+ int white = 0;
+ brackets = 0;
+ nparam = 0;
+ tline = tline->next;
+ sparam = PARAM_DELTA;
+ params = nasm_malloc (sparam*sizeof(Token *));
+ params[0] = tline;
+ paramsize = nasm_malloc (sparam*sizeof(int));
+ paramsize[0] = 0;
+ for (;;tline = tline->next) { /* parameter loop */
+ if (!tline) {
+ error(ERR_NONFATAL,
+ "macro call expects terminating `)'");
+ break;
+ }
+ if (tline->type == TOK_WHITESPACE && brackets<=0) {
+ if (paramsize[nparam])
+ white++;
+ else
+ params[nparam] = tline->next;
+ continue; /* parameter loop */
+ }
+ if (tline->type == TOK_OTHER && tline->text[1]==0) {
+ char ch = tline->text[0];
+ if (ch == ',' && !paren && brackets<=0) {
+ if (++nparam >= sparam) {
+ sparam += PARAM_DELTA;
+ params = nasm_realloc (params,
+ sparam*sizeof(Token *));
+ paramsize = nasm_realloc (paramsize,
+ sparam*sizeof(int));
+ }
+ params[nparam] = tline->next;
+ paramsize[nparam] = 0;
+ white = 0;
+ continue; /* parameter loop */
+ }
+ if (ch == br0 &&
+ (brackets>0 || (brackets==0 &&
+ !paramsize[nparam])))
+ {
+ if (!(brackets++))
+ {
+ params[nparam] = tline->next;
+ continue; /* parameter loop */
+ }
+ }
+ if (ch == br2 && brackets>0)
+ if (--brackets == 0) {
+ brackets = -1;
+ continue; /* parameter loop */
+ }
+ if (ch == '(' && !brackets)
+ paren++;
+ if (ch == ')' && brackets<=0)
+ if (--paren < 0)
+ break;
+ }
+ if (brackets<0) {
+ brackets = 0;
+ error (ERR_NONFATAL, "braces do not "
+ "enclose all of macro parameter");
+ }
+ paramsize[nparam] += white+1;
+ white = 0;
+ } /* parameter loop */
+ nparam++;
+ while (m && (m->nparam != nparam ||
+ mstrcmp(m->name, p, m->casesense)))
+ m = m->next;
+ if (!m)
+ error (ERR_WARNING|ERR_WARN_MNP,
+ "macro `%s' exists, "
+ "but not taking %d parameters",
+ mstart->text, nparam);
+ }
+ }
+ if (m && m->in_progress)
+ m = NULL;
+ if (!m) /* in progess or didn't find '(' or wrong nparam */
+ {
+ /*
+ * Design question: should we handle !tline, which
+ * indicates missing ')' here, or expand those
+ * macros anyway, which requires the (t) test a few
+ * lines down?
+ */
+ nasm_free (params);
+ nasm_free (paramsize);
+ tline = mstart;
+ }
+ else {
+ /*
+ * Expand the macro: we are placed on the last token of the
+ * call, so that we can easily split the call from the
+ * following tokens. We also start by pushing an SMAC_END
+ * token for the cycle removal.
+ */
+ t = tline;
+ if (t) {
+ tline = t->next;
+ t->next = NULL;
}
- params[nparam] = tline;
- paramsize[nparam] = 0;
- brackets = 0;
- if (tline && tline->type == TOK_OTHER &&
- !strcmp(tline->text, "{")) {
- params[nparam] = tline = tline->next;
- while (tline && (brackets > 0 ||
- tline->type != TOK_OTHER ||
- strcmp(tline->text, "}"))) {
- tline = tline->next;
- paramsize[nparam]++;
- }
- tline = tline->next;
- if (tline && tline->type == TOK_WHITESPACE)
- tline = tline->next;
- if (tline && (tline->type != TOK_OTHER ||
- (strcmp(tline->text, ")") &&
- strcmp(tline->text, ",")))) {
- error (ERR_NONFATAL|ERR_OFFBY1, "braces do not "
- "enclose all of macro parameter");
- }
- if (tline && tline->type == TOK_OTHER &&
- !strcmp(tline->text, ","))
- tline = tline->next;
- } else {
- while (tline && (brackets > 0 ||
- tline->type != TOK_OTHER ||
- (strcmp(tline->text, ",") &&
- strcmp(tline->text, ")")))) {
- if (tline->type == TOK_OTHER && !tline->text[1])
- brackets += (tline->text[0] == '(' ? 1 :
- tline->text[0] == ')' ? -1 : 0);
- tline = tline->next;
- paramsize[nparam]++;
+ tt = nasm_malloc(sizeof(Token));
+ tt->type = TOK_SMAC_END;
+ tt->text = NULL;
+ tt->mac = m;
+ m->in_progress = TRUE;
+ tt->next = tline;
+ tline = tt;
+ for (t = m->expansion; t; t = t->next) {
+ if (t->type >= TOK_SMAC_PARAM) {
+ Token *pcopy = tline, **ptail = &pcopy;
+ Token *ttt, *pt;
+ int i;
+
+ ttt = params[t->type - TOK_SMAC_PARAM];
+ for (i=paramsize[t->type-TOK_SMAC_PARAM]; --i>=0;) {
+ pt = *ptail = nasm_malloc(sizeof(Token));
+ pt->next = tline;
+ ptail = &pt->next;
+ pt->text = nasm_strdup(ttt->text);
+ pt->type = ttt->type;
+ pt->mac = NULL;
+ ttt = ttt->next;
+ }
+ tline = pcopy;
+ } else {
+ tt = nasm_malloc(sizeof(Token));
+ tt->type = t->type;
+ tt->text = nasm_strdup(t->text);
+ tt->mac = NULL;
+ tt->next = tline;
+ tline = tt;
}
}
- nparam++;
- if (tline && !strcmp(tline->text, ")"))
- break;
- if (tline && !strcmp(tline->text, ","))
- tline = tline->next;
- }
- while (m && m->nparam != nparam) {
- while ( (m = m->next) )
- if (!strcmp(m->name, mstart->text))
- break;
- }
- if (!m) {
- error (ERR_WARNING|ERR_OFFBY1|ERR_WARN_MNP,
- "macro `%s' exists, but not taking %d parameters",
- mstart->text, nparam);
+
+ /*
+ * Having done that, get rid of the macro call, and clean
+ * up the parameters.
+ */
nasm_free (params);
nasm_free (paramsize);
- tline = mstart;
- tline->type = TOK_PS_OTHER;
- continue;
+ free_tlist (mstart);
+ continue; /* main token loop */
+ }
}
}
- /*
- * Expand the macro: we are placed on the last token of the
- * call, so that we can easily split the call from the
- * following tokens. We also start by pushing an SMAC_END
- * token for the cycle removal.
- */
- t = tline;
- tline = tline->next;
- t->next = NULL;
- tt = nasm_malloc(sizeof(Token));
- tt->type = TOK_SMAC_END;
- tt->text = NULL;
- tt->mac = m;
- m->in_progress = TRUE;
- tt->next = tline;
- tline = tt;
- for (t = m->expansion; t; t = t->next) {
- if (t->type >= TOK_SMAC_PARAM) {
- Token *pcopy = tline, **ptail = &pcopy;
- Token *ttt, *pt;
- int i;
-
- ttt = params[t->type - TOK_SMAC_PARAM];
- for (i=0; i<paramsize[t->type-TOK_SMAC_PARAM]; i++) {
- pt = *ptail = nasm_malloc(sizeof(Token));
- pt->next = tline;
- ptail = &pt->next;
- pt->text = nasm_strdup(ttt->text);
- pt->type = ttt->type;
- pt->mac = NULL;
- ttt = ttt->next;
+
+ if (tline->type == TOK_SMAC_END) {
+ tline->mac->in_progress = FALSE;
+ t = tline;
+ tline = tline->next;
+ nasm_free (t);
+ } else {
+ t = *tail = tline;
+ tline = tline->next;
+ t->mac = NULL;
+ t->next = NULL;
+ tail = &t->next;
+ if (t->type == TOK_PREPROC_ID && t->text[1] == '$') {
+ Context *c = get_ctx (t->text);
+ char *p, *q, buffer[40];
+
+ t->type = TOK_ID;
+ if (c) {
+ q = t->text+1;
+ q += strspn(q, "$");
+ sprintf(buffer, "..@%lu.", c->number);
+ p = nasm_strcat (buffer,q);
+ nasm_free (t->text);
+ t->text = p;
}
- tline = pcopy;
- } else {
- tt = nasm_malloc(sizeof(Token));
- tt->type = t->type;
- tt->text = nasm_strdup(t->text);
- tt->mac = NULL;
- tt->next = tline;
- tline = tt;
}
}
-
- /*
- * Having done that, get rid of the macro call, and clean
- * up the parameters.
- */
- nasm_free (params);
- nasm_free (paramsize);
- free_tlist (mstart);
}
return thead;
@@ -2371,7 +2442,8 @@ static Token *expand_smacro (Token *tline) {
* to be called with tline->type == TOK_ID, so the putative macro
* name is easy to find.
*/
-static MMacro *is_mmacro (Token *tline, Token ***params_array) {
+static MMacro *is_mmacro (Token *tline, Token ***params_array)
+{
MMacro *head, *m;
Token **params;
int nparam;
@@ -2407,9 +2479,11 @@ static MMacro *is_mmacro (Token *tline, Token ***params_array) {
* prohibits us using it before we actually celebrate...
*/
if (m->in_progress) {
- error (ERR_NONFATAL|ERR_OFFBY1,
+#if 0
+ error (ERR_NONFATAL,
"self-reference in multi-line macro `%s'",
m->name);
+#endif
nasm_free (params);
return NULL;
}
@@ -2456,7 +2530,7 @@ static MMacro *is_mmacro (Token *tline, Token ***params_array) {
* After all that, we didn't find one with the right number of
* parameters. Issue a warning, and fail to expand the macro.
*/
- error (ERR_WARNING|ERR_OFFBY1|ERR_WARN_MNP,
+ error (ERR_WARNING|ERR_WARN_MNP,
"macro `%s' exists, but not taking %d parameters",
tline->text, nparam);
nasm_free (params);
@@ -2466,62 +2540,54 @@ static MMacro *is_mmacro (Token *tline, Token ***params_array) {
/*
* Expand the multi-line macro call made by the given line, if
* there is one to be expanded. If there is, push the expansion on
- * istk->expansion and return 1 or 2, as according to whether a
- * line sync is needed (2 if it is). Otherwise return 0.
+ * istk->expansion and return 1. Otherwise return 0.
*/
-static int expand_mmacro (Token *tline) {
- Token *label = NULL, **params, *t, *tt, *last = NULL;
- MMacro *m = NULL;
+static int expand_mmacro (Token *tline)
+{
+ Token *startline = tline;
+ Token *label = NULL;
+ int dont_prepend = 0;
+ Token **params, *t, *tt;
+ MMacro *m;
Line *l, *ll;
int i, nparam, *paramlen;
- int need_sync = FALSE;
t = tline;
- if (t && t->type == TOK_WHITESPACE)
+ skip_white_(t);
+ if (!tok_type_(t, TOK_ID))
+ return 0;
+ m = is_mmacro (t, &params);
+ if (!m) {
+ Token *last;
+ /*
+ * We have an id which isn't a macro call. We'll assume
+ * it might be a label; we'll also check to see if a
+ * colon follows it. Then, if there's another id after
+ * that lot, we'll check it again for macro-hood.
+ */
+ label = last = t;
t = t->next;
- if (t && t->type == TOK_ID) {
- m = is_mmacro (t, &params);
- if (!m) {
- /*
- * We have an id which isn't a macro call. We'll assume
- * it might be a label; we'll also check to see if a
- * colon follows it. Then, if there's another id after
- * that lot, we'll check it again for macro-hood.
- */
+ if (tok_type_(t, TOK_WHITESPACE))
last = t, t = t->next;
- if (t && t->type == TOK_WHITESPACE)
- last = t, t = t->next;
- if (t && t->type == TOK_OTHER && !strcmp(t->text, ":"))
- last = t, t = t->next;
- if (t && t->type == TOK_WHITESPACE)
+ if (tok_is_(t, ":")) {
+ dont_prepend = 1;
+ last = t, t = t->next;
+ if (tok_type_(t, TOK_WHITESPACE))
last = t, t = t->next;
- if (t && t->type == TOK_ID) {
- m = is_mmacro(t, &params);
- if (m) {
- last->next = NULL;
- label = tline;
- tline = t;
- }
- }
- }
+ }
+ if (!tok_type_(t, TOK_ID) || (m = is_mmacro(t, &params)) == NULL)
+ return 0;
+ last->next = NULL;
+ tline = t;
}
- if (!m)
- return 0;
-
- /*
- * If we're not already inside another macro expansion, we'd
- * better push a line synchronisation to ensure we stay put on
- * line numbering.
- */
- if (!istk->expansion)
- need_sync = TRUE;
/*
* Fix up the parameters: this involves stripping leading and
* trailing whitespace, then stripping braces if they are
* present.
*/
- for (nparam = 0; params[nparam]; nparam++);
+ for (nparam = 0; params[nparam]; nparam++)
+ ;
paramlen = nparam ? nasm_malloc(nparam*sizeof(*paramlen)) : NULL;
for (i = 0; params[i]; i++) {
@@ -2529,19 +2595,15 @@ static int expand_mmacro (Token *tline) {
int comma = (!m->plus || i < nparam-1);
t = params[i];
- if (t && t->type == TOK_WHITESPACE)
- t = t->next;
- if (t && t->type == TOK_OTHER && !strcmp(t->text, "{"))
+ skip_white_(t);
+ if (tok_is_(t, "{"))
t = t->next, brace = TRUE, comma = FALSE;
params[i] = t;
paramlen[i] = 0;
while (t) {
- if (!t) /* end of param because EOL */
- break;
if (comma && t->type == TOK_OTHER && !strcmp(t->text, ","))
break; /* ... because we have hit a comma */
- if (comma && t->type == TOK_WHITESPACE &&
- t->next->type == TOK_OTHER && !strcmp(t->next->text, ","))
+ if (comma && t->type == TOK_WHITESPACE && tok_is_(t->next, ","))
break; /* ... or a space then a comma */
if (brace && t->type == TOK_OTHER && !strcmp(t->text, "}"))
break; /* ... or a brace */
@@ -2584,61 +2646,76 @@ static int expand_mmacro (Token *tline) {
Token **tail;
ll = nasm_malloc(sizeof(Line));
- ll->next = istk->expansion;
ll->finishes = NULL;
- ll->first = NULL;
+ ll->next = istk->expansion;
+ istk->expansion = ll;
tail = &ll->first;
for (t = l->first; t; t = t->next) {
+ Token *x = t;
+ if (t->type == TOK_PREPROC_ID &&
+ t->text[1]=='0' && t->text[2]=='0')
+ {
+ dont_prepend = -1;
+ x = label;
+ if (!x)
+ continue;
+ }
tt = *tail = nasm_malloc(sizeof(Token));
- tt->next = NULL;
tail = &tt->next;
- tt->type = t->type;
- tt->text = nasm_strdup(t->text);
+ tt->type = x->type;
+ tt->text = nasm_strdup(x->text);
tt->mac = NULL;
}
-
- istk->expansion = ll;
-
+ *tail = NULL;
}
/*
- * If we had a label, push it on the front of the first line of
- * the macro expansion. We must check that this doesn't give
- * two consecutive TOK_WHITESPACE.
+ * If we had a label, push it on as the first line of
+ * the macro expansion.
*/
- if (label) {
- if (last->type == TOK_WHITESPACE &&
- istk->expansion->first->type == TOK_WHITESPACE) {
- Token *victim = istk->expansion->first; /* kill this whitespace */
- istk->expansion->first = victim->next;
- nasm_free (victim->text);
- nasm_free (victim);
- }
- last->next = istk->expansion->first;
- istk->expansion->first = label;
- }
+ if (label)
+ if (dont_prepend<0)
+ free_tlist(startline);
+ else {
+ ll = nasm_malloc(sizeof(Line));
+ ll->finishes = NULL;
+ ll->next = istk->expansion;
+ istk->expansion = ll;
+ ll->first = startline;
+ if (!dont_prepend) {
+ while (label->next)
+ label = label->next;
+ label->next = tt = nasm_malloc(sizeof(Token));
+ tt->next = NULL;
+ tt->mac = NULL;
+ tt->type = TOK_OTHER;
+ tt->text = nasm_strdup(":");
+ }
+ }
list->uplevel (m->nolist ? LIST_MACRO_NOLIST : LIST_MACRO);
- return need_sync ? 2 : 1;
+ return 1;
}
static void pp_reset (char *file, int apass, efunc errfunc, evalfunc eval,
- ListGen *listgen) {
+ ListGen *listgen)
+{
int h;
error = errfunc;
cstk = NULL;
- linesync = outline = NULL;
istk = nasm_malloc(sizeof(Include));
istk->next = NULL;
istk->conds = NULL;
istk->expansion = NULL;
istk->mstk = NULL;
istk->fp = fopen(file, "r");
- istk->fname = nasm_strdup(file);
- istk->lineno = istk->lineinc = 1;
+ istk->fname = NULL;
+ src_set_fname(nasm_strdup(file));
+ src_set_linnum(0);
+ istk->lineinc = 1;
if (!istk->fp)
error (ERR_FATAL|ERR_NOFILE, "unable to open input file `%s'", file);
defining = NULL;
@@ -2654,17 +2731,12 @@ static void pp_reset (char *file, int apass, efunc errfunc, evalfunc eval,
pass = apass;
}
-static char *pp_getline (void) {
+static char *pp_getline (void)
+{
char *line;
Token *tline;
int ret;
- if (outline) {
- line = outline;
- outline = NULL;
- return line;
- }
-
while (1) {
/*
* Fetch a tokenised line, either from the macro-expansion
@@ -2712,7 +2784,6 @@ static char *pp_getline (void) {
istk->expansion = ll;
}
- line_sync();
} else {
/*
* Check whether a `%rep' was started and not ended
@@ -2733,62 +2804,68 @@ static char *pp_getline (void) {
" expansion of macro `%s'", istk->mstk->name);
}
- if (istk->mstk->name) {
- /*
- * This was a real macro call, not a %rep, and
- * therefore the parameter information needs to
- * be freed.
- */
- nasm_free(istk->mstk->params);
- free_tlist(istk->mstk->iline);
- nasm_free(istk->mstk->paramlen);
+ /*
+ * FIXME: investigate the relationship at this point between
+ * istk->mstk and l->finishes
+ */
+ {
+ MMacro *m = istk->mstk;
+ istk->mstk = m->next_active;
+ if (m->name) {
+ /*
+ * This was a real macro call, not a %rep, and
+ * therefore the parameter information needs to
+ * be freed.
+ */
+ nasm_free(m->params);
+ free_tlist(m->iline);
+ nasm_free(m->paramlen);
+ l->finishes->in_progress = FALSE;
+ }
+ else
+ free_mmacro(m);
}
- istk->mstk = istk->mstk->next_active;
- l->finishes->in_progress = FALSE;
istk->expansion = l->next;
nasm_free (l);
list->downlevel (LIST_MACRO);
- if (!istk->expansion)
- line_sync();
}
}
- if (istk->expansion) {
- char *p;
- Line *l = istk->expansion;
- tline = l->first;
- istk->expansion = l->next;
- nasm_free (l);
- p = detoken(tline);
- list->line (LIST_MACRO, p);
- nasm_free(p);
- if (!istk->expansion)
- line_sync();
- } else {
+ while (1) { /* until we get a line we can use */
+
+ if (istk->expansion) { /* from a macro expansion */
+ char *p;
+ Line *l = istk->expansion;
+ tline = l->first;
+ istk->expansion = l->next;
+ nasm_free (l);
+ p = detoken(tline);
+ list->line (LIST_MACRO, p);
+ nasm_free(p);
+ break;
+ }
line = read_line();
- while (!line) {
- /*
- * The current file has ended; work down the istk
- * until we find a file we can read from.
- */
- Include *i;
- fclose(istk->fp);
- if (istk->conds)
+ if (line) { /* from the current input file */
+ line = prepreproc(line);
+ tline = tokenise(line);
+ nasm_free (line);
+ break;
+ }
+ /*
+ * The current file has ended; work down the istk
+ */
+ {
+ Include *i = istk;
+ fclose(i->fp);
+ if (i->conds)
error(ERR_FATAL, "expected `%%endif' before end of file");
- i = istk;
- istk = istk->next;
+ istk = i->next;
list->downlevel (LIST_INCLUDE);
- nasm_free (i->fname);
+ src_set_linnum(i->lineno);
+ nasm_free ( src_set_fname(i->fname) );
nasm_free (i);
if (!istk)
return NULL;
- else
- line_sync();
- update_fileline(3); /* update __FILE__ and __LINE__ */
- line = read_line();
}
- line = prepreproc(line);
- tline = tokenise(line);
- nasm_free (line);
}
/*
@@ -2797,9 +2874,11 @@ static char *pp_getline (void) {
* with things like `%define something %1' such as STRUC
* uses. Unless we're _defining_ a MMacro, in which case
* those tokens should be left alone to go into the
- * definition.
+ * definition; and unless we're in a non-emitting
+ * condition, in which case we don't want to meddle with
+ * anything.
*/
- if (!defining)
+ if (!defining && !(istk->conds && !emitting(istk->conds->state)))
tline = expand_mmac_params(tline);
/*
@@ -2807,20 +2886,11 @@ static char *pp_getline (void) {
*/
ret = do_directive(tline);
if (ret & 1) {
- if (ret & 4)
- line_sync();
- if ((ret & 2) && !stdmacpos) {/* give a blank line to the output */
- outline = nasm_strdup("");
- break;
- }
- else
continue;
} else if (defining) {
/*
* We're defining a multi-line macro. We emit nothing
- * at all, not even a blank line (when we finish
- * defining the macro, we'll emit a line-number
- * directive so that we keep sync properly), and just
+ * at all, and just
* shove the tokenised line on to the macro definition.
*/
Line *l = nasm_malloc(sizeof(Line));
@@ -2858,54 +2928,32 @@ static char *pp_getline (void) {
*/
line = detoken(tline);
free_tlist (tline);
- outline = line;
break;
} else {
- if (ret == 2)
- line_sync();
continue; /* expand_mmacro calls free_tlist */
}
}
}
- /*
- * Once we're out of this loop, outline _must_ be non-NULL. The
- * only question is whether linesync is NULL or not.
- */
- if (linesync) {
- line = linesync;
- linesync = NULL;
- } else {
- line = outline;
- outline = NULL;
- }
return line;
}
-static void pp_cleanup (void) {
+static void pp_cleanup (void)
+{
int h;
if (defining) {
error (ERR_NONFATAL, "end of file while still defining macro `%s'",
defining->name);
- nasm_free (defining->name);
- free_tlist (defining->dlist);
- free_llist (defining->expansion);
- nasm_free (defining);
+ free_mmacro (defining);
}
- nasm_free (linesync); /* might just be necessary */
- nasm_free (outline); /* really shouldn't be necessary */
while (cstk)
ctx_pop();
for (h=0; h<NHASH; h++) {
while (mmacros[h]) {
MMacro *m = mmacros[h];
mmacros[h] = mmacros[h]->next;
- nasm_free (m->name);
- free_tlist (m->dlist);
- nasm_free (m->defaults);
- free_llist (m->expansion);
- nasm_free (m);
+ free_mmacro(m);
}
while (smacros[h]) {
SMacro *s = smacros[h];
@@ -2926,7 +2974,8 @@ static void pp_cleanup (void) {
ctx_pop();
}
-void pp_include_path (char *path) {
+void pp_include_path (char *path)
+{
IncPath *i;
i = nasm_malloc(sizeof(IncPath));
@@ -2936,7 +2985,8 @@ void pp_include_path (char *path) {
ipath = i;
}
-void pp_pre_include (char *fname) {
+void pp_pre_include (char *fname)
+{
Token *inc, *space, *name;
Line *l;
@@ -2961,8 +3011,9 @@ void pp_pre_include (char *fname) {
predef = l;
}
-void pp_pre_define (char *definition) {
- Token *def, *space, *name;
+void pp_pre_define (char *definition)
+{
+ Token *def, *space;
Line *l;
char *equals;
@@ -2972,7 +3023,7 @@ void pp_pre_define (char *definition) {
def->next = space = nasm_malloc(sizeof(Token));
if (equals)
*equals = ' ';
- space->next = name = tokenise(definition);
+ space->next = tokenise(definition);
if (equals)
*equals = '=';
@@ -2990,10 +3041,19 @@ void pp_pre_define (char *definition) {
predef = l;
}
-void pp_extra_stdmac (char **macros) {
+void pp_extra_stdmac (char **macros)
+{
extrastdmac = macros;
}
+static void make_tok_num(Token *tok, long val)
+{
+ char numbuf[20];
+ sprintf(numbuf, "%ld", val);
+ tok->text = nasm_strdup(numbuf);
+ tok->type = TOK_NUMBER;
+}
+
Preproc nasmpp = {
pp_reset,
pp_getline,
diff --git a/sync.c b/sync.c
index 7acba0e..261afbc 100644
--- 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 0000000..b36098a
--- /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 */