From da74f9ee394b8903a625c6602972025a8125d28f Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Tue, 30 Apr 2002 20:53:37 +0000 Subject: NASM 0.98-j4 --- Changes | 94 ++++ Wishlist | 225 ++++++-- assemble.c | 858 +++++++++++++++++-------------- c16.mac | 41 ++ c32.mac | 26 + changes.asm | 292 +++++++++++ disasm.c | 41 +- eval.c | 284 ++++++----- eval.h | 12 +- exebin.mac | 57 +++ float.c | 38 +- insns.dat | 122 +++-- labels.c | 117 ++++- labels.h | 3 +- listing.c | 84 ++- macros.c | 2 +- names.c | 20 +- nasm.c | 901 +++++++++++++++++++------------- nasm.h | 186 ++++++- nasmlib.c | 360 +++++++++---- nasmlib.h | 79 ++- ndisasm.c | 41 +- outaout.c | 73 ++- outas86.c | 60 ++- outbin.c | 57 ++- outcoff.c | 84 ++- outdbg.c | 95 +++- outelf.c | 95 +++- outform.c | 37 +- outform.h | 84 ++- outforms.h | 223 ++++++++ outobj.c | 1608 ++++++++++++++++++++++++++++++++++++++++++---------------- outrdf.c | 25 +- outrdf2.c | 690 +++++++++++++++++++++++++ parser.c | 202 ++++++-- parser.h | 3 +- preproc.c | 1460 +++++++++++++++++++++++++++------------------------- standard.mac | 4 +- sync.c | 9 +- zoutieee.c | 1457 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 40 files changed, 7687 insertions(+), 2462 deletions(-) create mode 100644 c16.mac create mode 100644 c32.mac create mode 100644 changes.asm create mode 100644 exebin.mac create mode 100644 outforms.h create mode 100644 outrdf2.c create mode 100644 zoutieee.c diff --git a/Changes b/Changes index 24f4bfef..57584bdb 100644 --- a/Changes +++ b/Changes @@ -442,3 +442,97 @@ corruption at ends of long PUBDEF records. Separated DOS archives into main-program and documentation to reduce download size. + +0.98 not released yet +--------------------- + +Fixed a bug whereby STRUC didn't work at all in RDF. + +Fixed a problem with group specification in PUBDEFs in OBJ. + +Improved ease of adding new output formats. Contribution due to +Fox Cutter. + +Fixed a bug in relocations in the `bin' format: was showing up when +a relocatable reference crossed an 8192-byte boundary in any output +section. + +Fixed a bug in local labels: local-label lookups were inconsistent +between passes one and two if an EQU occurred between the definition +of a global label and the subsequent use of a local label local to +that global. + +Fixed a seg-fault in the preprocessor (again) which happened when +you use a blank line as the first line of a multi-line macro +definition and then defined a label on the same line as a call to +that macro. + +Fixed a stale-pointer bug in the handling of the NASM environment +variable. Thanks to Thomas McWilliams. + +ELF had a hard limit on the number of sections which caused +segfaults when transgressed. Fixed. + +Added ability for ndisasm to read from stdin by using `-' as the +filename. + +ndisasm wasn't outputting the TO keyword. Fixed. + +Fixed error cascade on bogus expression in %if - an error in +evaluation was causing the entire %if to be discarded, thus creating +trouble later when the %else or %endif was encountered. + +Forward reference tracking was instruction-granular not operand- +granular, which was causing 286-specific code to be generated +needlessly on code of the form `shr word [forwardref],1'. Thanks to +Jim Hague for sending a patch. + +All messages now appear on stdout, as sending them to stderr serves +no useful purpose other than to make redirection difficult. + +Fixed the problem with EQUs pointing to an external symbol - this +now generates an error message. + +Allowed multiple size prefixes to an operand, of which only the first +is taken into account. + +Incorporated John Fine's changes, including fixes of a large number +of preprocessor bugs, some small problems in OBJ, and a reworking of +label handling to define labels before their line is assembled, rather +than after. + +Reformatted a lot of the source code to be more readable. Included +'coding.txt' as a guideline for how to format code for contributors. + +Stopped nested %reps causing a panic - they now cause a slightly more +friendly error message instead. + +Fixed floating point constant problems (patch by Pedro Gimeno) + +Fixed the return value of insn_size() not being checked for -1, indicating +an error. + +Incorporated 3D now instructions. + +Fixed the 'mov eax, eax + ebx' bug. + +Fixed the GLOBAL EQU bug in ELF. Released developers release 3. + +Incorporated John Fine's command line parsing changes + +Incorporated David Lindauer's OMF debug support + +Made changes for LCC 4.0 support (__NASM_CDecl__, removed register size +specification warning when sizes agree). + +Released NASM 0.98 Pre-release 1 + +fixed bug in outcoff.c to do with truncating section names longer +than 8 characters, referencing beyond end of string; 0.98 pre-release 2 + +added response file support, improved command line handling, new layout +help screen + +fixed limit checking bug, 'OUT byte nn, reg' bug, and a couple of rdoff +related bugs, updated Wishlist; 0.98 Prerelease 3. + diff --git a/Wishlist b/Wishlist index 197b113b..b1529bfe 100644 --- a/Wishlist +++ b/Wishlist @@ -1,23 +1,168 @@ NASM Wishlist ============= -- forward-reference tracking is instruction-granular not operand- - granular. Bummer. +Numbers on right hand side are version numbers that it would be nice to +have this done by. ? means I haven't looked at it yet. -- see if BITS can be made to do anything sensible in obj (eg set the +- Create a binary RDF tools distribution. Should probably be distributed 0.98 + seperately. + +- Check misc/ide.cfg into RCS as Watcom IDE enhancement thingy. 0.98 + (nop@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" + wants to have some say in how this goes through. + * Andrew Crabtree 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 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 () alternative syntax stuff, + providing an alternative syntax mode for NASM which allows a macro + set to be written that allows the same source files to be + assembled with NASM and TASM. + +- Add the UD2 instruction. ? + +- Add the four instructions documented in 24368901.pdf (Intel's own ? + document). + +- Some means of avoiding MOV memoffs,EAX which apparently the 1.10? + Pentium pairing detector thinks modifies EAX. Similar means of + choosing instruction encodings where necessary. + +- The example of ..@ makes it clear that a ..@ label isn't just ? + local, but doesn't make it clear that it isn't just global either. + +- hpa wants an evaluator operator for ceil(log2(x)). ? + +- Extra reloc types in ELF: R_386_16 type 20, PC16 is 21, 8 is 22, PC8 is 23. + Add support for the 16s at least. ? + + +- Lazy section creation or selective section output, in COFF/win32 ? + at least and probably other formats: don't bother to emit a section + if it contains no data. Particularly the default auto-created + section. We believe zero-length sections crash at least WLINK (in + win32). + +- Make the flags field in `struct itemplate' in insns.h a long ? + instead of an int. + +- Implement %ifref to check whether a single-line macro has ever been ? + expanded since (last re) definition. Or maybe not. We'll see. + +- add pointer to \k{insLEAVE} and \k{insENTER} in chapters about ? + mixed-language programming. + +- Some equivalent to TASM's GLOBAL directive, ie something which ? + defines a symbol as external if it doesn't end up being defined + but defines it as public if it does end up being defined. + +- Documentation doesn't explain about C++ name mangling. ? + +- see if BITS can be made to do anything sensible in obj (eg set the ? default new-segment property to Use32). -- __DATE__, __TIME__, and text variants of __NASM_MAJOR__ and +- OBJ: coalesce consecutive offset and segment fixups for the same ? + location into full-32bit-pointer fixups. This is apparently + necessary because some twazzock in the PowerBASIC development + team didn't deign to support the OMF spec the way the rest of the + world sees it. + +- Allow % to be separated from the rest of a preproc directive, for ? + alternative directive indentation styles. + +- __DATE__, __TIME__, and text variants of __NASM_MAJOR__ and ? __NASM_MINOR__. -- Warn on TIMES combined with multi-line macros. TIMES gets applied +- Warn on TIMES combined with multi-line macros. TIMES gets applied 1.00 to first line only - should bring to users' attention. -- Add support for lcc 4.0. - * If-when this happens, remember to bump the `supported lcc - version' number in Readme. - -- Re-work the evaluator, again, with a per-object-format fixup +- Re-work the evaluator, again, with a per-object-format fixup 1.10 routine, so as to be able to cope with section offsets "really" being pure numbers; should be able to allow at _least_ the two common idioms @@ -28,17 +173,33 @@ NASM Wishlist had to. (_Always_ returning UNKNOWN on pass one, though a lovely clean design, breaks the first of the above examples.) -- Preprocessor identifier concatenation? +- Preprocessor identifier concatenation? 1.10 -- Arbitrary section names in `bin'. +- Arbitrary section names in `bin'. ? + Is this necessary? Is it even desirable? -- Ability to read from a pipe. Obviously not useful under dos, so +- Ability to read from a pipe. Obviously not useful under dos, so 1.10 memory problems with storing entire input file aren't a problem either. -- Subsection support? + Related topic: file caching under DOS/32 bit... 1.10? + maybe even implement discardable buffers that get thrown away + when we get a NULL returned from malloc(). Only really useful under + DOS. Think about it. + + Another related topic: possibly spool out the pre-processed 1.10? + stuff to a file, to avoid having to re-process it. Possible problems + with preprocessor values not known on pass 1? Have a look... + + Or maybe we can spool out a pre-parsed version...? 1.10 + Need to investigate feasibility. Does the results from the parser + change from pass 1 to pass 2? Would it be feasible to alter it so that + the parser returns an invariant result, and this is then processed + afterwards to resolve label references, etc? -- A good ALIGN mechanism, similar to GAS's. GAS pads out space by +- Subsection support? ? + +- A good ALIGN mechanism, similar to GAS's. GAS pads out space by 1.10? means of the following (32-bit) instructions: 8DB42600000000 lea esi,[esi+0x0] 8DB600000000 lea esi,[esi+0x0] @@ -55,7 +216,7 @@ NASM Wishlist Also re-work the macro form so that when given one argument in a code section it calls this feature. -- Possibly a means whereby FP constants can be specified as +- Possibly a means whereby FP constants can be specified as ? immediate operands to non-FP instructions. * Possible syntax: MOV EAX,FLOAT 1.2 to get a single-precision FP constant. Then maybe MOV EAX,HI_FLOAT 1.2 and MOV EAX,LO_FLOAT @@ -67,37 +228,41 @@ NASM Wishlist chunks, one-byte chunks, even stranger chunks, and pieces of ten-byte reals to be bandied around as well. -- A UNION macro might be quite cool, now that ABSOLUTE is sane +- A UNION macro might be quite cool, now that ABSOLUTE is sane ? enough to be able to handle it. -- An equivalent to gcc's ## stringify operator, plus string +- An equivalent to gcc's ## stringify operator, plus string ? concatenation, somehow implemented without undue ugliness, so as to be able to do `%include "/my/path/%1"' in a macro, or something similar... -- Actually _do_ something with the processor, privileged and - undocumented flags in the instruction table. +- Actually _do_ something with the processor, privileged and 1.10 + undocumented flags in the instruction table. When this happens, + consider allowing PMULHRW to map to either of the Cyrix or AMD + versions? -- Maybe NEC V20/V30 instructions? +- Maybe NEC V20/V30 instructions? ? - Yet more object formats. - * Possibly direct support for .EXE files? - -- Debug information, in all formats it can be usefully done in. - * including line-number record support. + * Possibly direct support for .EXE files? 1.10 -- Symbol map in binary format. Format-specific options... +- Symbol map in binary format. Format-specific options... 1.10? -- REDESIGN: Think about EQU dependency, and about start-point +- REDESIGN: Think about EQU dependency, and about start-point 1.20? specification in OBJ. Possibly re-think directive support. -- Think about a wrapper program like gcc? Possibly invent a _patch_ +- Think about a wrapper program like gcc? Possibly invent a _patch_ 2.00? for gcc so that it can take .asm files on the command line? -- If a wrapper happens, think about adding an option to cause the +- If a wrapper happens, think about adding an option to cause the ? resulting executable file to be executed immediately, thus allowing NASM source files to have #!... (probably silly) -- Multi-platform support? If so: definitely Alpha; possibly Java +- Multi-platform support? If so: definitely Alpha; possibly Java ? byte code; probably ARM/StrongARM; maybe Sparc; maybe Mips; maybe Vax. Perhaps Z80 and 6502, just for a laugh? + +- Consider a 'verbose' option that prints information about the resulting ? + object file onto stdout. + + diff --git a/assemble.c b/assemble.c index 8d144121..65bcea39 100644 --- a/assemble.c +++ b/assemble.c @@ -72,10 +72,10 @@ static ListGen *list; static long calcsize (long, long, int, insn *, char *); static void gencode (long, long, int, insn *, char *, long); -static int regval (operand *o); -static int matches (struct itemplate *, insn *); -static ea *process_ea (operand *, ea *, int, int, int); -static int chsize (operand *, int); +static int regval (operand *o); +static int matches (struct itemplate *, insn *); +static ea * process_ea (operand *, ea *, int, int, int); +static int chsize (operand *, int); /* * This routine wrappers the real output format's output routine, @@ -83,7 +83,11 @@ static int chsize (operand *, int); * generator at the same time. */ static void out (long offset, long segto, void *data, unsigned long type, - long segment, long wrt) { + long segment, long wrt) +{ + static long lineno; + static char *lnfname; + if ((type & OUT_TYPMASK) == OUT_ADDRESS) { if (segment != NO_SEG || wrt != NO_SEG) { /* @@ -91,7 +95,8 @@ static void out (long offset, long segto, void *data, unsigned long type, * OUT_ADDRESS, so there's no work to be done here. */ list->output (offset, data, type); - } else { + } + else { unsigned char p[4], *q = p; /* * This is a non-relocated address, and we're going to @@ -100,90 +105,105 @@ static void out (long offset, long segto, void *data, unsigned long type, if ((type & OUT_SIZMASK) == 4) { WRITELONG (q, * (long *) data); list->output (offset, p, OUT_RAWDATA+4); - } else { + } + else { WRITESHORT (q, * (long *) data); list->output (offset, p, OUT_RAWDATA+2); } } - } else if ((type & OUT_TYPMASK) == OUT_RAWDATA) { + } + else if ((type & OUT_TYPMASK) == OUT_RAWDATA) { list->output (offset, data, type); - } else if ((type & OUT_TYPMASK) == OUT_RESERVE) { + } + else if ((type & OUT_TYPMASK) == OUT_RESERVE) { list->output (offset, NULL, type); - } else if ((type & OUT_TYPMASK) == OUT_REL2ADR || + } + else if ((type & OUT_TYPMASK) == OUT_REL2ADR || (type & OUT_TYPMASK) == OUT_REL4ADR) { list->output (offset, data, type); } + if (src_get(&lineno,&lnfname)) + outfmt->current_dfmt->linenum(lnfname,lineno,segto); + outfmt->output (segto, data, type, segment, wrt); } long assemble (long segment, long offset, int bits, insn *instruction, struct ofmt *output, efunc error, - ListGen *listgen) { - int j, size_prob; - long insn_end, itimes; - long start = offset; + ListGen *listgen) +{ struct itemplate *temp; + int j; + int size_prob; + long insn_end; + long itimes; + long start = offset; + long wsize = 0; /* size for DB etc. */ errfunc = error; /* to pass to other functions */ outfmt = output; /* likewise */ list = listgen; /* and again */ - if (instruction->opcode == -1) - return 0; - - if (instruction->opcode == I_DB || - instruction->opcode == I_DW || - instruction->opcode == I_DD || - instruction->opcode == I_DQ || - instruction->opcode == I_DT) { - extop *e; - long wsize = 0; /* placate gcc */ - long t = instruction->times; - - switch (instruction->opcode) { - case I_DB: wsize = 1; break; - case I_DW: wsize = 2; break; - case I_DD: wsize = 4; break; - case I_DQ: wsize = 8; break; - case I_DT: wsize = 10; break; - } + switch (instruction->opcode) + { + case -1: return 0; + case I_DB: wsize = 1; break; + case I_DW: wsize = 2; break; + case I_DD: wsize = 4; break; + case I_DQ: wsize = 8; break; + case I_DT: wsize = 10; break; + } - while (t--) { - for (e = instruction->eops; e; e = e->next) { - if (e->type == EOT_DB_NUMBER) { + if (wsize) { + extop * e; + long t = instruction->times; + if (t < 0) + errfunc(ERR_PANIC, "instruction->times < 0 (%ld) in assemble()",t); + + while (t--) /* repeat TIMES times */ + { + for (e = instruction->eops; e; e = e->next) + { + if (e->type == EOT_DB_NUMBER) + { if (wsize == 1) { if (e->segment != NO_SEG) errfunc (ERR_NONFATAL, "one-byte relocation attempted"); else { - unsigned char c = e->offset; - out (offset, segment, &c, OUT_RAWDATA+1, + out (offset, segment, &e->offset, OUT_RAWDATA+1, NO_SEG, NO_SEG); } - } else if (wsize > 5) { + } + else if (wsize > 5) { errfunc (ERR_NONFATAL, "integer supplied to a D%c" " instruction", wsize==8 ? 'Q' : 'T'); - } else + } + else out (offset, segment, &e->offset, OUT_ADDRESS+wsize, e->segment, e->wrt); offset += wsize; - } else if (e->type == EOT_DB_STRING) { + } + else if (e->type == EOT_DB_STRING) + { int align; - align = (-e->stringlen) % wsize; - if (align < 0) - align += wsize; out (offset, segment, e->stringval, OUT_RAWDATA+e->stringlen, NO_SEG, NO_SEG); - if (align) - out (offset, segment, "\0\0\0\0", + align = e->stringlen % wsize; + + if (align) { + align = wsize - align; + out (offset, segment, "\0\0\0\0\0\0\0\0", OUT_RAWDATA+align, NO_SEG, NO_SEG); + } offset += e->stringlen + align; } } - if (t > 0 && t == instruction->times-1) { + if (t > 0 && t == instruction->times-1) + { /* * Dummy call to list->output to give the offset to the * listing module. @@ -197,29 +217,33 @@ long assemble (long segment, long offset, int bits, return offset - start; } - if (instruction->opcode == I_INCBIN) { + if (instruction->opcode == I_INCBIN) + { static char fname[FILENAME_MAX]; - FILE *fp; - long len; + FILE * fp; + long len; len = FILENAME_MAX-1; if (len > instruction->eops->stringlen) len = instruction->eops->stringlen; strncpy (fname, instruction->eops->stringval, len); fname[len] = '\0'; - if (!(fp = fopen(fname, "rb"))) + + if ( (fp = fopen(fname, "rb")) == NULL) error (ERR_NONFATAL, "`incbin': unable to open file `%s'", fname); else if (fseek(fp, 0L, SEEK_END) < 0) error (ERR_NONFATAL, "`incbin': unable to seek on file `%s'", fname); - else { + else + { static char buf[2048]; long t = instruction->times; - long l; + long base = 0; len = ftell (fp); if (instruction->eops->next) { - len -= instruction->eops->next->offset; + base = instruction->eops->next->offset; + len -= base; if (instruction->eops->next->next && len > instruction->eops->next->next->offset) len = instruction->eops->next->next->offset; @@ -230,11 +254,11 @@ long assemble (long segment, long offset, int bits, */ list->output (offset, NULL, OUT_RAWDATA); list->uplevel(LIST_INCBIN); - while (t--) { - fseek (fp, - (instruction->eops->next ? - instruction->eops->next->offset : 0), - SEEK_SET); + while (t--) + { + long l; + + fseek (fp, base, SEEK_SET); l = len; while (l > 0) { long m = fread (buf, 1, (l>sizeof(buf)?sizeof(buf):l), @@ -247,7 +271,8 @@ long assemble (long segment, long offset, int bits, */ error (ERR_NONFATAL, "`incbin': unexpected EOF while" " reading file `%s'", fname); - return 0; /* it doesn't much matter... */ + t=0; /* Try to exit cleanly */ + break; } out (offset, segment, buf, OUT_RAWDATA+m, NO_SEG, NO_SEG); @@ -274,7 +299,9 @@ long assemble (long segment, long offset, int bits, temp = nasm_instructions[instruction->opcode]; while (temp->opcode != -1) { int m = matches (temp, instruction); - if (m == 100) { /* matches! */ + + if (m == 100) /* matches! */ + { char *codes = temp->code; long insn_size = calcsize(segment, offset, bits, instruction, codes); @@ -284,7 +311,7 @@ long assemble (long segment, long offset, int bits, else while (itimes--) { insn_end = offset + insn_size; for (j=0; jnprefix; 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; ioperands; 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/c16.mac b/c16.mac new file mode 100644 index 00000000..81a9c5e2 --- /dev/null +++ b/c16.mac @@ -0,0 +1,41 @@ +; NASM macro set to make interfacing to 16-bit programs easier -*- nasm -*- + +%imacro proc 1 ; begin a procedure definition +%push proc + global %1 +%1: push bp + mov bp,sp +%ifdef FARCODE PASCAL ; arguments may start at bp+4 or bp+6 +%assign %$arg 6 +%define %$firstarg 6 +%else +%assign %$arg 4 +%define %$firstarg 4 +%endif +%define %$procname %1 +%endmacro + +%imacro arg 0-1 2 ; used with the argument name as a label +%00 equ %$arg + ; we could possibly be adding some + ; debug information at this point...? +%assign %$arg %1+%$arg +%endmacro + +%imacro endproc 0 +%ifnctx proc +%error Mismatched `endproc'/`proc' +%else + mov sp,bp + pop bp +%ifdef PASCAL + retf %$arg - %$firstarg +%elifdef FARCODE + retf +%else + retn +%endif +__end_%$procname: ; useful for calculating function size +%pop +%endif +%endmacro diff --git a/c32.mac b/c32.mac new file mode 100644 index 00000000..b187b470 --- /dev/null +++ b/c32.mac @@ -0,0 +1,26 @@ +; NASM macro set to make interfacing to 32-bit programs easier -*- nasm -*- + +%imacro proc 1 ; begin a procedure definition +%push proc + global %1 +%1: push ebp + mov ebp,esp +%assign %$arg 8 +%define %$procname %1 +%endmacro + +%imacro arg 0-1 4 ; used with the argument name as a label +%00 equ %$arg +%assign %$arg %1+%$arg +%endmacro + +%imacro endproc 0 +%ifnctx proc +%error Mismatched `endproc'/`proc' +%else + leave + ret +__end_%$procname: ; useful for calculating function size +%pop +%endif +%endmacro diff --git a/changes.asm b/changes.asm new file mode 100644 index 00000000..7b9dd491 --- /dev/null +++ b/changes.asm @@ -0,0 +1,292 @@ +;This file demonstrates many of the differences between NASM version X and NASM +;version 0.97 +; +; changes.asm is copyright (C) 1998 John S. Fine +; +; It may be redistributed under the same conditions as NASM as described in +; Licence file in the NASM archive +;_________________________________ +; +; nasm changes.asm -l changes.lst +; +; When assembled without any -d switches, it includes examples which: +; Work correctly in version X +; and Work incorrectly and/or display warnings in version 0.97 +; and Do not prevent the generation of output in version 0.97 +; +; Not all the differences can be seen in the .lst file. I suggest that you use +; "ndisasm changes" to examine the code actually generated. +;_________________________________ +; +; nasm changes.asm -l changes.lst -doldmsg +; +; When assembled with -doldmsg, it adds examples which: +; Work correctly in version X +; and Generate error messages in version 0.97 and do not generate output +;_________________________________ +; +; nasm changes.asm -l changes.lst -doldcrash +; +; When assembled with -doldcrash, it adds examples which: +; Work correctly in version X +; and Cause NASM to crash in version 0.97 +;_________________________________ +; +; nasm changes.asm -l changes.lst -dnewmsg +; +; When assembled with -dnewmsg, it adds examples which: +; Generate error messages in version X +; and Generate wrong output without warning or error message in version 0.97 +;----------------------------------------------------------------------------- + +; Please note that I have reported the name of the person who made the +; correction based on very limited information. In several cases, I am sure I +; will identify the wrong author. Please send me any corrections; I don't +; intend to insult or exclude anyone. + +;----------------------------------------------------------------------------- +; Bug fixed by Simon in assemble() +; +; The following generated "call next" / "call next-1" instead of +; two copies of "call next" +; + times 2 a16 call next +next: + +;----------------------------------------------------------------------------- +; Bug fixed by John in parse_line() (and other routines) +; +; This used to jmp to prior.1, when it should be here.1 +; +prior: +.1: +here: jmp .1 +.1: + +;----------------------------------------------------------------------------- +; Bug fixed by John in assemble() +; +; Strings used in dq and dt were not zero filled correctly +; + dq 'b' + + +;----------------------------------------------------------------------------- +; Bug fixed by Simon in isn_names[] +; +; Was not recognised as an instruction +; + int01 + +;----------------------------------------------------------------------------- +; Bug fixed by Jim Hague in ??? +; +; Forward references were instruction level rather than per operand +; + shr word [forwardref],1 +forwardref: + +;----------------------------------------------------------------------------- +; Bug fixed by John in preproc.c +; +; It used to silently discard id characters appended to a multi-line +; macro parameter (such as the x in %1x below). +; +%macro xxx 1 +%1: nop +%{1}x: jmp %1x +%endmacro +xxx yyy + +%ifdef oldmsg +;*************************************************************** +; +; The following examples will generate error messages in 0.97 and will generate +; correct output in the new version. + +;----------------------------------------------------------------------------- +; Bug fixed by Simon in isns.dat +; +; The optional "near" was not permitted on JMP and CALL +; + jmp near here + +;----------------------------------------------------------------------------- +; Feature added by Simon in stdscan() +; +; You can now use the numeric value of strings in %assign +; +%assign xxx 'ABCD' + dd xxx + +;----------------------------------------------------------------------------- +; Feature added by John in add_vectors() +; +; Stranger address expressions are now supported as long as they resolve to +; something valid. +; + mov ax, [eax + ebx + ecx - eax] + +;----------------------------------------------------------------------------- +; Bug fixed by Simon in ??? +; +; The EQU directive affected local labels in a way that was inconsistent +; between passes +; +.local: +neither equ $ + jmp .local + +;----------------------------------------------------------------------------- +; Feature added by Jules in parse_line +; +; You can override a size specifier +; +%define arg1 dword [bp+4] + cmp word arg1, 2 + +;----------------------------------------------------------------------------- +; Bug fixed by John in preproc.c +; +; You could not use a label on the same line with a macro invocation, if the +; macro definition began with a preprocessor directive. +; + struc mytype +.long resd 1 + endstruc + +lbl istruc mytype + at mytype.long, dd 'ABCD' + iend + +;----------------------------------------------------------------------------- +; Warning removed by John in preproc.c +; +; In order to allow macros that extend the definition of instructions, I +; disabled the warning on a multi-line macro referencing itself. +; +%endif ;NASM 0.97 doesn't handle %0 etc. inside false %if +%macro push 1-* ; +%rep %0 ; +push %1 ; +%rotate 1 ; +%endrep ; +%endmacro ; +%ifdef oldmsg ; + + push ax,bx + +;----------------------------------------------------------------------------- +; Warning removed by John in preproc.c +; +; To support other types of macros that extend the definition of instructions, +; I disabled the warning on a multi-line macro called with the wrong number of +; parameters. PUSH and POP can be extended equally well by either method, but +; other intruction extensions may need one method or the other, so I made both +; work. +; +; Note that neither of these warnings was really needed, because a later stage +; of NASM would almost always give an adequate error message if the macro use +; really was wrong. +; +%endif +%macro pop 2-* +%rep %0 +pop %1 +%rotate 1 +%endrep +%endmacro +%ifdef oldmsg + + pop ax,bx +%endif + + +%ifdef newmsg ;*************************************************************** + +;----------------------------------------------------------------------------- +; Bug fixed by John in parse_line() (and other routines) +; +; This invalid code used to assemble without errors +; +myself equ myself+1 + jmp myself + +;----------------------------------------------------------------------------- +; Change made by John in preproc.c +; +; In 0.97, an id that appears as a label on a macro invocation was always +; prepended to the first line of the macro expansion. That caused several +; bugs, but also could be used in tricks like the arg macro in c16.mac and +; c32.mac. +; +; In version X, an id that appears as a label on a macro invocation will +; normally be defined as a label for the address at which the macro is +; invoked, regardless of whether the first line of the macro expansion is +; something that can take a label. The new token %00 may be used for any +; of the situations in which the old prepend behavior was doing something +; tricky but useful. %00 can also be used more than once and in places +; other than the start of the expansion. +; +%endif +%assign arg_off 0 + +%imacro arg 0-1 2 ;arg defined the old way + equ arg_off +%assign arg_off %1+arg_off +%endmacro + +%ifdef newmsg +arg_example arg +%endif + +%imacro arg2 0-1 2 ;arg defined the new way +%00 equ arg_off +%assign arg_off %1+arg_off +%endmacro + +%ifdef oldmsg +arg_example2 arg2 + +;----------------------------------------------------------------------------- +; Change made by Jules and John in INSNS.DAT +; +; Various instruction in which the size of an immediate is built-in to the +; instruction set, now allow you to redundantly specify that size as long +; as you specify it correctly +; + AAD byte 5 + AAM byte 5 + BT bx, byte 3 + BTC cx, byte 4 + BTR dx, byte 5 + BTS si, byte 6 + IN eax, byte 0x40 + INT byte 21h + OUT byte 70h, ax + RET word 2 + RETN word 2 + RETF word 4 + +; note "ENTER" has not been changed yet. + +%endif + +%ifdef oldcrash ;************************************************************* + +This_label_is_256_characters_long__There_used_to_be_a_bug_in_stdscan_which_made_it_crash_when_it_did_a_keyword_search_on_any_label_longer_than_255_characters__Now_anything_longer_than_MAX_KEYWORD_is_always_a_symbol__It_will_not_even_try_a_keyword_search___ + +;----------------------------------------------------------------------------- +; Bug fixed by John in preproc.c +; +; Builds of NASM that prohibit dereferencing a NULL pointer used to crash if a +; macro that started with a blank line was invoked with a label +; +%macro empty_macro 0 + +%endm + +emlabel empty_macro + jmp emlabel + +%endif diff --git a/disasm.c b/disasm.c index 3dded0d9..4764bc16 100644 --- a/disasm.c +++ b/disasm.c @@ -33,7 +33,8 @@ extern struct itemplate **itable[]; #define SEG_NODISP 64 #define SEG_SIGNED 128 -static int whichreg(long regflags, int regval) { +static int whichreg(long regflags, int regval) +{ static int reg32[] = { R_EAX, R_ECX, R_EDX, R_EBX, R_ESP, R_EBP, R_ESI, R_EDI }; static int reg16[] = { @@ -98,7 +99,8 @@ static int whichreg(long regflags, int regval) { return 0; } -static char *whichcond(int condval) { +static char *whichcond(int condval) +{ static int conds[] = { C_O, C_NO, C_C, C_NC, C_Z, C_NZ, C_NA, C_A, C_S, C_NS, C_PE, C_PO, C_L, C_NL, C_NG, C_G @@ -110,7 +112,8 @@ static char *whichcond(int condval) { * Process an effective address (ModRM) specification. */ static unsigned char *do_ea (unsigned char *data, int modrm, int asize, - int segsize, operand *op) { + int segsize, operand *op) +{ int mod, rm, scale, index, base; mod = (modrm >> 6) & 03; @@ -249,11 +252,13 @@ static unsigned char *do_ea (unsigned char *data, int modrm, int asize, * stream in data. Return the number of bytes matched if so. */ static int matches (unsigned char *r, unsigned char *data, int asize, - int osize, int segsize, insn *ins) { - unsigned char *origdata = data; - int a_used = FALSE, o_used = FALSE; + int osize, int segsize, insn *ins) +{ + unsigned char * origdata = data; + int a_used = FALSE, o_used = FALSE; - while (*r) { + while (*r) + { int c = *r++; if (c >= 01 && c <= 03) { while (c--) @@ -440,7 +445,8 @@ static int matches (unsigned char *r, unsigned char *data, int asize, } long disasm (unsigned char *data, char *output, int segsize, long offset, - int autosync) { + int autosync) +{ struct itemplate **p; int length = 0; char *segover; @@ -486,7 +492,8 @@ long disasm (unsigned char *data, char *output, int segsize, long offset, works = TRUE; for (p = itable[*data]; *p; p++) if ( (length = matches((unsigned char *)((*p)->code), data, - asize, osize, segsize, &ins)) ) { + asize, osize, segsize, &ins)) ) + { works = TRUE; /* * Final check to make sure the types of r/m match up. @@ -507,11 +514,17 @@ long disasm (unsigned char *data, char *output, int segsize, long offset, ((((*p)->opd[i] & (REGISTER | FPUREG)) || (ins.oprs[i].segment & SEG_RMREG)) && !whichreg ((*p)->opd[i], ins.oprs[i].basereg))) - + { works = FALSE; + /* + * FIXME: can we do a break here? + */ + } + if (works) break; } + if (!length || !works) return 0; /* no instruction was matched */ @@ -570,9 +583,12 @@ long disasm (unsigned char *data, char *output, int segsize, long offset, colon = FALSE; if (((*p)->opd[i] & (REGISTER | FPUREG)) || - (ins.oprs[i].segment & SEG_RMREG)) { + (ins.oprs[i].segment & SEG_RMREG)) + { ins.oprs[i].basereg = whichreg ((*p)->opd[i], ins.oprs[i].basereg); + if ( (*p)->opd[i] & TO ) + slen += sprintf(output+slen, "to "); slen += sprintf(output+slen, "%s", reg_names[ins.oprs[i].basereg-EXPR_REG_START]); } else if (!(UNITY & ~(*p)->opd[i])) { @@ -680,7 +696,8 @@ long disasm (unsigned char *data, char *output, int segsize, long offset, return length; } -long eatbyte (unsigned char *data, char *output) { +long eatbyte (unsigned char *data, char *output) +{ sprintf(output, "db 0x%02X", *data); return 1; } diff --git a/eval.c b/eval.c index 0e81c928..edb51b12 100644 --- a/eval.c +++ b/eval.c @@ -17,37 +17,56 @@ #include "nasm.h" #include "nasmlib.h" #include "eval.h" +#include "labels.h" -static expr **tempexprs = NULL; -static int ntempexprs, tempexprs_size = 0; #define TEMPEXPRS_DELTA 128 - -static expr *tempexpr; -static int ntempexpr, tempexpr_size; #define TEMPEXPR_DELTA 8 -static scanner scan; +static scanner scan; /* Address of scanner routine */ +static efunc error; /* Address of error reporting routine */ +static lfunc labelfunc; /* Address of label routine */ + +static struct ofmt *outfmt; /* Structure of addresses of output routines */ + +static expr **tempexprs = NULL; +static int ntempexprs; +static int tempexprs_size = 0; + +static expr *tempexpr; +static int ntempexpr; +static int tempexpr_size; + +static struct tokenval *tokval; /* The current token */ +static int i; /* The t_type of tokval */ + static void *scpriv; -static struct tokenval *tokval; -static efunc error; -static int i; -static int seg, ofs; -static char *label = NULL, special_empty_string[] = ""; -static lfunc labelfunc; -static struct ofmt *outfmt; -static int *forward; +static loc_t *location; /* Pointer to current line's segment,offset */ +static int *opflags; static struct eval_hints *hint; +/* + * Unimportant cleanup is done to avoid confusing people who are trying + * to debug real memory leaks + */ +void eval_cleanup(void) +{ + while (ntempexprs) + nasm_free (tempexprs[--ntempexprs]); + nasm_free (tempexprs); +} + /* * Construct a temporary expression. */ -static void begintemp(void) { +static void begintemp(void) +{ tempexpr = NULL; tempexpr_size = ntempexpr = 0; } -static void addtotemp(long type, long value) { +static void addtotemp(long type, long value) +{ while (ntempexpr >= tempexpr_size) { tempexpr_size += TEMPEXPR_DELTA; tempexpr = nasm_realloc(tempexpr, @@ -57,7 +76,8 @@ static void addtotemp(long type, long value) { tempexpr[ntempexpr++].value = value; } -static expr *finishtemp(void) { +static expr *finishtemp(void) +{ addtotemp (0L, 0L); /* terminate */ while (ntempexprs >= tempexprs_size) { tempexprs_size += TEMPEXPRS_DELTA; @@ -72,7 +92,8 @@ static expr *finishtemp(void) { * absolute segment types: we preserve them during addition _only_ * if one of the segments is a truly pure scalar. */ -static expr *add_vectors(expr *p, expr *q) { +static expr *add_vectors(expr *p, expr *q) +{ int preserve; preserve = is_really_simple(p) || is_really_simple(q); @@ -81,7 +102,8 @@ static expr *add_vectors(expr *p, expr *q) { while (p->type && q->type && p->type < EXPR_SEGBASE+SEG_ABS && - q->type < EXPR_SEGBASE+SEG_ABS) { + q->type < EXPR_SEGBASE+SEG_ABS) + { int lasttype; if (p->type > q->type) { @@ -91,7 +113,9 @@ static expr *add_vectors(expr *p, expr *q) { addtotemp(p->type, p->value); lasttype = p++->type; } else { /* *p and *q have same type */ - addtotemp(p->type, p->value + q->value); + long sum = p->value + q->value; + if (sum) + addtotemp(p->type, sum); lasttype = p->type; p++, q++; } @@ -100,12 +124,14 @@ static expr *add_vectors(expr *p, expr *q) { } } while (p->type && - (preserve || p->type < EXPR_SEGBASE+SEG_ABS)) { + (preserve || p->type < EXPR_SEGBASE+SEG_ABS)) + { addtotemp(p->type, p->value); p++; } while (q->type && - (preserve || q->type < EXPR_SEGBASE+SEG_ABS)) { + (preserve || q->type < EXPR_SEGBASE+SEG_ABS)) + { addtotemp(q->type, q->value); q++; } @@ -125,7 +151,8 @@ static expr *add_vectors(expr *p, expr *q) { * multiplied. This allows [eax*1+ebx] to hint EBX rather than EAX * as the base register. */ -static expr *scalar_mult(expr *vect, long scalar, int affect_hints) { +static expr *scalar_mult(expr *vect, long scalar, int affect_hints) +{ expr *p = vect; while (p->type && p->type < EXPR_SEGBASE+SEG_ABS) { @@ -140,13 +167,15 @@ static expr *scalar_mult(expr *vect, long scalar, int affect_hints) { return vect; } -static expr *scalarvect (long scalar) { +static expr *scalarvect (long scalar) +{ begintemp(); addtotemp(EXPR_SIMPLE, scalar); return finishtemp(); } -static expr *unknown_expr (void) { +static expr *unknown_expr (void) +{ begintemp(); addtotemp(EXPR_UNKNOWN, 1L); return finishtemp(); @@ -157,7 +186,8 @@ static expr *unknown_expr (void) { * value. Return NULL, as usual, if an error occurs. Report the * error too. */ -static expr *segment_part (expr *e) { +static expr *segment_part (expr *e) +{ long seg; if (is_unknown(e)) @@ -228,22 +258,27 @@ static expr *expr4(int), *expr5(int), *expr6(int); static expr *(*bexpr)(int); -static expr *rexp0(int critical) { +static expr *rexp0(int critical) +{ expr *e, *f; e = rexp1(critical); if (!e) return NULL; - while (i == TOKEN_DBL_OR) { + + while (i == TOKEN_DBL_OR) + { i = scan(scpriv, tokval); f = rexp1(critical); if (!f) return NULL; if (!(is_simple(e) || is_just_unknown(e)) || - !(is_simple(f) || is_just_unknown(f))) { - error(ERR_NONFATAL, "`|' operator may only be applied to" - " scalar values"); - } + !(is_simple(f) || is_just_unknown(f))) + { + error(ERR_NONFATAL, "`|' operator may only be applied to" + " scalar values"); + } + if (is_just_unknown(e) || is_just_unknown(f)) e = unknown_expr(); else @@ -252,22 +287,27 @@ static expr *rexp0(int critical) { return e; } -static expr *rexp1(int critical) { +static expr *rexp1(int critical) +{ expr *e, *f; e = rexp2(critical); if (!e) return NULL; - while (i == TOKEN_DBL_XOR) { + + while (i == TOKEN_DBL_XOR) + { i = scan(scpriv, tokval); f = rexp2(critical); if (!f) return NULL; if (!(is_simple(e) || is_just_unknown(e)) || - !(is_simple(f) || is_just_unknown(f))) { + !(is_simple(f) || is_just_unknown(f))) + { error(ERR_NONFATAL, "`^' operator may only be applied to" " scalar values"); } + if (is_just_unknown(e) || is_just_unknown(f)) e = unknown_expr(); else @@ -276,19 +316,22 @@ static expr *rexp1(int critical) { return e; } -static expr *rexp2(int critical) { +static expr *rexp2(int critical) +{ expr *e, *f; e = rexp3(critical); if (!e) return NULL; - while (i == TOKEN_DBL_AND) { + while (i == TOKEN_DBL_AND) + { i = scan(scpriv, tokval); f = rexp3(critical); if (!f) return NULL; if (!(is_simple(e) || is_just_unknown(e)) || - !(is_simple(f) || is_just_unknown(f))) { + !(is_simple(f) || is_just_unknown(f))) + { error(ERR_NONFATAL, "`&' operator may only be applied to" " scalar values"); } @@ -300,22 +343,28 @@ static expr *rexp2(int critical) { return e; } -static expr *rexp3(int critical) { +static expr *rexp3(int critical) +{ expr *e, *f; long v; e = expr0(critical); if (!e) return NULL; + while (i == TOKEN_EQ || i == TOKEN_LT || i == TOKEN_GT || - i == TOKEN_NE || i == TOKEN_LE || i == TOKEN_GE) { + i == TOKEN_NE || i == TOKEN_LE || i == TOKEN_GE) + { int j = i; i = scan(scpriv, tokval); f = expr0(critical); if (!f) return NULL; + e = add_vectors (e, scalar_mult(f, -1L, FALSE)); - switch (j) { + + switch (j) + { case TOKEN_EQ: case TOKEN_NE: if (is_unknown(e)) v = -1; /* means unknown */ @@ -343,6 +392,7 @@ static expr *rexp3(int critical) { } break; } + if (v == -1) e = unknown_expr(); else @@ -351,22 +401,26 @@ static expr *rexp3(int critical) { return e; } -static expr *expr0(int critical) { +static expr *expr0(int critical) +{ expr *e, *f; e = expr1(critical); if (!e) return NULL; - while (i == '|') { + + while (i == '|') + { i = scan(scpriv, tokval); f = expr1(critical); if (!f) return NULL; if (!(is_simple(e) || is_just_unknown(e)) || - !(is_simple(f) || is_just_unknown(f))) { - error(ERR_NONFATAL, "`|' operator may only be applied to" - " scalar values"); - } + !(is_simple(f) || is_just_unknown(f))) + { + error(ERR_NONFATAL, "`|' operator may only be applied to" + " scalar values"); + } if (is_just_unknown(e) || is_just_unknown(f)) e = unknown_expr(); else @@ -375,19 +429,22 @@ static expr *expr0(int critical) { return e; } -static expr *expr1(int critical) { +static expr *expr1(int critical) +{ expr *e, *f; e = expr2(critical); if (!e) return NULL; + while (i == '^') { i = scan(scpriv, tokval); f = expr2(critical); if (!f) return NULL; if (!(is_simple(e) || is_just_unknown(e)) || - !(is_simple(f) || is_just_unknown(f))) { + !(is_simple(f) || is_just_unknown(f))) + { error(ERR_NONFATAL, "`^' operator may only be applied to" " scalar values"); } @@ -399,19 +456,22 @@ static expr *expr1(int critical) { return e; } -static expr *expr2(int critical) { +static expr *expr2(int critical) +{ expr *e, *f; e = expr3(critical); if (!e) return NULL; + while (i == '&') { i = scan(scpriv, tokval); f = expr3(critical); if (!f) return NULL; if (!(is_simple(e) || is_just_unknown(e)) || - !(is_simple(f) || is_just_unknown(f))) { + !(is_simple(f) || is_just_unknown(f))) + { error(ERR_NONFATAL, "`&' operator may only be applied to" " scalar values"); } @@ -423,20 +483,24 @@ static expr *expr2(int critical) { return e; } -static expr *expr3(int critical) { +static expr *expr3(int critical) +{ expr *e, *f; e = expr4(critical); if (!e) return NULL; - while (i == TOKEN_SHL || i == TOKEN_SHR) { + + while (i == TOKEN_SHL || i == TOKEN_SHR) + { int j = i; i = scan(scpriv, tokval); f = expr4(critical); if (!f) return NULL; if (!(is_simple(e) || is_just_unknown(e)) || - !(is_simple(f) || is_just_unknown(f))) { + !(is_simple(f) || is_just_unknown(f))) + { error(ERR_NONFATAL, "shift operator may only be applied to" " scalar values"); } else if (is_just_unknown(e) || is_just_unknown(f)) { @@ -454,13 +518,15 @@ static expr *expr3(int critical) { return e; } -static expr *expr4(int critical) { +static expr *expr4(int critical) +{ expr *e, *f; e = expr5(critical); if (!e) return NULL; - while (i == '+' || i == '-') { + while (i == '+' || i == '-') + { int j = i; i = scan(scpriv, tokval); f = expr5(critical); @@ -478,21 +544,24 @@ static expr *expr4(int critical) { return e; } -static expr *expr5(int critical) { +static expr *expr5(int critical) +{ expr *e, *f; e = expr6(critical); if (!e) return NULL; while (i == '*' || i == '/' || i == '%' || - i == TOKEN_SDIV || i == TOKEN_SMOD) { + i == TOKEN_SDIV || i == TOKEN_SMOD) + { int j = i; i = scan(scpriv, tokval); f = expr6(critical); if (!f) return NULL; if (j != '*' && (!(is_simple(e) || is_just_unknown(e)) || - !(is_simple(f) || is_just_unknown(f)))) { + !(is_simple(f) || is_just_unknown(f)))) + { error(ERR_NONFATAL, "division operator may only be applied to" " scalar values"); return NULL; @@ -548,7 +617,8 @@ static expr *expr5(int critical) { return e; } -static expr *expr6(int critical) { +static expr *expr6(int critical) +{ long type; expr *e; long label_seg, label_ofs; @@ -597,8 +667,10 @@ static expr *expr6(int critical) { } i = scan(scpriv, tokval); return e; - } else if (i == TOKEN_NUM || i == TOKEN_REG || i == TOKEN_ID || - i == TOKEN_HERE || i == TOKEN_BASE) { + } + else if (i == TOKEN_NUM || i == TOKEN_REG || i == TOKEN_ID || + i == TOKEN_HERE || i == TOKEN_BASE) + { begintemp(); switch (i) { case TOKEN_NUM: @@ -613,11 +685,11 @@ static expr *expr6(int critical) { case TOKEN_HERE: case TOKEN_BASE: /* - * If "label" begins with "%", this indicates that no + * If !location->known, this indicates that no * symbol, Here or Base references are valid because we * are in preprocess-only mode. */ - if (*label == '%') { + if (!location->known) { error(ERR_NONFATAL, "%s not supported in preprocess-only mode", (i == TOKEN_ID ? "symbol references" : @@ -626,42 +698,36 @@ static expr *expr6(int critical) { break; } - /* - * Since the whole line is parsed before the label it - * defines is given to the label manager, we have - * problems with lines such as - * - * end: TIMES 512-(end-start) DB 0 - * - * where `end' is not known on pass one, despite not - * really being a forward reference, and due to - * criticality it is _needed_. Hence we check our label - * against the currently defined one, and do our own - * resolution of it if we have to. - */ type = EXPR_SIMPLE; /* might get overridden by UNKNOWN */ - if (i == TOKEN_BASE) { - label_seg = seg; + if (i == TOKEN_BASE) + { + label_seg = location->segment; label_ofs = 0; - } else if (i == TOKEN_HERE || !strcmp(tokval->t_charptr, label)) { - label_seg = seg; - label_ofs = ofs; - } else if (!labelfunc(tokval->t_charptr,&label_seg,&label_ofs)) { - if (critical == 2) { - error (ERR_NONFATAL, "symbol `%s' undefined", - tokval->t_charptr); - return NULL; - } else if (critical == 1) { - error (ERR_NONFATAL, "symbol `%s' not defined before use", - tokval->t_charptr); - return NULL; - } else { - if (forward) - *forward = TRUE; - type = EXPR_UNKNOWN; - label_seg = NO_SEG; - label_ofs = 1; + } else if (i == TOKEN_HERE) { + label_seg = location->segment; + label_ofs = location->offset; + } else { + if (!labelfunc(tokval->t_charptr,&label_seg,&label_ofs)) + { + if (critical == 2) { + error (ERR_NONFATAL, "symbol `%s' undefined", + tokval->t_charptr); + return NULL; + } else if (critical == 1) { + error (ERR_NONFATAL, + "symbol `%s' not defined before use", + tokval->t_charptr); + return NULL; + } else { + if (opflags) + *opflags |= 1; + type = EXPR_UNKNOWN; + label_seg = NO_SEG; + label_ofs = 1; + } } + if (opflags && is_extern (tokval->t_charptr)) + *opflags |= OPFLAG_EXTERN; } addtotemp(type, label_ofs); if (label_seg!=NO_SEG) @@ -676,26 +742,17 @@ static expr *expr6(int critical) { } } -void eval_global_info (struct ofmt *output, lfunc lookup_label) { +void eval_global_info (struct ofmt *output, lfunc lookup_label, loc_t *locp) +{ outfmt = output; labelfunc = lookup_label; -} - -void eval_info (char *labelname, long segment, long offset) { - if (label != special_empty_string) - nasm_free (label); - if (labelname) - label = nasm_strdup(labelname); - else { - label = special_empty_string; - seg = segment; - ofs = offset; - } + location = locp; } expr *evaluate (scanner sc, void *scprivate, struct tokenval *tv, int *fwref, int critical, efunc report_error, - struct eval_hints *hints) { + struct eval_hints *hints) +{ expr *e; expr *f = NULL; @@ -713,7 +770,7 @@ expr *evaluate (scanner sc, void *scprivate, struct tokenval *tv, scpriv = scprivate; tokval = tv; error = report_error; - forward = fwref; + opflags = fwref; if (tokval->t_type == TOKEN_INVALID) i = scan(scpriv, tokval); @@ -748,7 +805,8 @@ expr *evaluate (scanner sc, void *scprivate, struct tokenval *tv, value = reloc_seg(f); if (value == NO_SEG) value = reloc_value(f) | SEG_ABS; - else if (!(value & SEG_ABS) && !(value % 2) && critical) { + else if (!(value & SEG_ABS) && !(value % 2) && critical) + { error(ERR_NONFATAL, "invalid right-hand operand to WRT"); return NULL; } diff --git a/eval.h b/eval.h index 26bde15a..a933cbfd 100644 --- a/eval.h +++ b/eval.h @@ -14,15 +14,7 @@ * providing segment-base details, and what function can be used to * look labels up. */ -void eval_global_info (struct ofmt *output, lfunc lookup_label); - -/* - * Called to set the information the evaluator needs: the value of - * $ is set from `segment' and `offset' if `labelname' is NULL, and - * otherwise the name of the current line's label is set from - * `labelname' instead. - */ -void eval_info (char *labelname, long segment, long offset); +void eval_global_info (struct ofmt *output, lfunc lookup_label, loc_t *locp); /* * The evaluator itself. @@ -31,4 +23,6 @@ expr *evaluate (scanner sc, void *scprivate, struct tokenval *tv, int *fwref, int critical, efunc report_error, struct eval_hints *hints); +void eval_cleanup(void); + #endif diff --git a/exebin.mac b/exebin.mac new file mode 100644 index 00000000..8d1eaf8c --- /dev/null +++ b/exebin.mac @@ -0,0 +1,57 @@ +; -*- nasm -*- +; NASM macro file to allow the `bin' output format to generate +; simple .EXE files by constructing the EXE header by hand. +; Adapted from a contribution by Yann Guidon + +%define EXE_stack_size EXE_realstacksize + +%macro EXE_begin 0 + ORG 0E0h + section .text + +header_start: + db 4Dh,5Ah ; EXE file signature + dw EXE_allocsize % 512 + dw (EXE_allocsize + 511) / 512 + dw 0 ; relocation information: none + dw (header_end-header_start)/16 ; header size in paragraphs + dw (EXE_absssize + EXE_realstacksize) / 16 ; min extra mem + dw (EXE_absssize + EXE_realstacksize) / 16 ; max extra mem + dw -10h ; Initial SS (before fixup) + dw EXE_endbss + EXE_realstacksize ; Initial SP (1K DPMI+1K STACK) + dw 0 ; (no) Checksum + dw 100h ; Initial IP - start just after the header + dw -10h ; Initial CS (before fixup) + dw 0 ; file offset to relocation table: none + dw 0 ; (no overlay) + align 16,db 0 +header_end: + +EXE_startcode: + section .data +EXE_startdata: + section .bss +EXE_startbss: +%endmacro + +%macro EXE_stack 1 +EXE_realstacksize equ %1 +%define EXE_stack_size EXE_bogusstacksize ; defeat EQU in EXE_end +%endmacro + +%macro EXE_end 0 + section .text +EXE_endcode: + section .data +EXE_enddata: + section .bss + alignb 4 +EXE_endbss: + +EXE_acodesize equ (EXE_endcode-EXE_startcode+3) & (~3) +EXE_datasize equ EXE_enddata-EXE_startdata +EXE_absssize equ (EXE_endbss-EXE_startbss+3) & (~3) +EXE_allocsize equ EXE_acodesize + EXE_datasize + +EXE_stack_size equ 0x800 ; default if nothing else was used +%endmacro diff --git a/float.c b/float.c index 1f66ca61..545ae773 100644 --- a/float.c +++ b/float.c @@ -25,9 +25,10 @@ * => we only have to worry about _one_ bit shift to the left */ -static int multiply(unsigned short *to, unsigned short *from) { +static int multiply(unsigned short *to, unsigned short *from) +{ unsigned long temp[MANT_WORDS*2]; - int i, j; + int i, j; for (i=0; i>8) ) static int to_double(char *str, long sign, unsigned char *result, - efunc error) { + efunc error) +{ unsigned short mant[MANT_WORDS]; long exponent; @@ -267,7 +274,8 @@ static int to_double(char *str, long sign, unsigned char *result, } static int to_float(char *str, long sign, unsigned char *result, - efunc error) { + efunc error) +{ unsigned short mant[MANT_WORDS]; long exponent; @@ -320,7 +328,8 @@ static int to_float(char *str, long sign, unsigned char *result, } static int to_ldoub(char *str, long sign, unsigned char *result, - efunc error) { + efunc error) +{ unsigned short mant[MANT_WORDS]; long exponent; @@ -379,7 +388,8 @@ static int to_ldoub(char *str, long sign, unsigned char *result, } int float_const (char *number, long sign, unsigned char *result, int bytes, - efunc error) { + efunc error) +{ if (bytes == 4) return to_float (number, sign, result, error); else if (bytes == 8) diff --git a/insns.dat b/insns.dat index 27436f1b..441f4654 100644 --- a/insns.dat +++ b/insns.dat @@ -14,9 +14,9 @@ AAA void \1\x37 8086 AAD void \2\xD5\x0A 8086 -AAD imm \1\xD5\24 8086 +AAD imm \1\xD5\24 8086,SB AAM void \2\xD4\x0A 8086 -AAM imm \1\xD4\24 8086 +AAM imm \1\xD4\24 8086,SB AAS void \1\x3F 8086 ADC mem,reg8 \300\1\x10\101 8086,SM ADC reg8,reg8 \300\1\x10\101 8086 @@ -104,27 +104,28 @@ BT mem,reg16 \320\300\2\x0F\xA3\101 386,SM BT reg16,reg16 \320\300\2\x0F\xA3\101 386 BT mem,reg32 \321\300\2\x0F\xA3\101 386,SM BT reg32,reg32 \321\300\2\x0F\xA3\101 386 -BT rm16,imm \320\300\2\x0F\xBA\204\25 386 -BT rm32,imm \321\300\2\x0F\xBA\204\25 386 +BT rm16,imm \320\300\2\x0F\xBA\204\25 386,SB +BT rm32,imm \321\300\2\x0F\xBA\204\25 386,SB BTC mem,reg16 \320\300\2\x0F\xBB\101 386,SM BTC reg16,reg16 \320\300\2\x0F\xBB\101 386 BTC mem,reg32 \321\300\2\x0F\xBB\101 386,SM BTC reg32,reg32 \321\300\2\x0F\xBB\101 386 -BTC rm16,imm \320\300\2\x0F\xBA\207\25 386 -BTC rm32,imm \321\300\2\x0F\xBA\207\25 386 +BTC rm16,imm \320\300\2\x0F\xBA\207\25 386,SB +BTC rm32,imm \321\300\2\x0F\xBA\207\25 386,SB BTR mem,reg16 \320\300\2\x0F\xB3\101 386,SM BTR reg16,reg16 \320\300\2\x0F\xB3\101 386 BTR mem,reg32 \321\300\2\x0F\xB3\101 386,SM BTR reg32,reg32 \321\300\2\x0F\xB3\101 386 -BTR rm16,imm \320\300\2\x0F\xBA\206\25 386 -BTR rm32,imm \321\300\2\x0F\xBA\206\25 386 +BTR rm16,imm \320\300\2\x0F\xBA\206\25 386,SB +BTR rm32,imm \321\300\2\x0F\xBA\206\25 386,SB BTS mem,reg16 \320\300\2\x0F\xAB\101 386,SM BTS reg16,reg16 \320\300\2\x0F\xAB\101 386 BTS mem,reg32 \321\300\2\x0F\xAB\101 386,SM BTS reg32,reg32 \321\300\2\x0F\xAB\101 386 -BTS rm16,imm \320\300\2\x0F\xBA\205\25 386 -BTS rm32,imm \321\300\2\x0F\xBA\205\25 386 +BTS rm16,imm \320\300\2\x0F\xBA\205\25 386,SB +BTS rm32,imm \321\300\2\x0F\xBA\205\25 386,SB CALL imm \322\1\xE8\64 8086 +CALL imm|near \322\1\xE8\64 8086 CALL imm|far \322\1\x9A\34\37 8086,ND CALL imm:imm \322\1\x9A\35\30 8086 CALL imm16:imm \320\1\x9A\31\30 8086 @@ -274,6 +275,7 @@ FDIVR fpureg \1\xD8\10\xF8 8086,FPU FDIVR fpu0,fpureg \1\xD8\11\xF8 8086,FPU FDIVRP fpureg \1\xDE\10\xF0 8086,FPU FDIVRP fpureg,fpu0 \1\xDE\10\xF0 8086,FPU +FEMMS void \2\x0F\x0E PENT,MMX,FPU FENI void \3\x9B\xDB\xE0 8086,FPU FFREE fpureg \1\xDD\10\xC0 8086,FPU FIADD mem32 \300\1\xDA\200 8086,FPU @@ -418,9 +420,9 @@ IMUL reg16,imm8 \320\1\x6B\100\15 286 IMUL reg16,imm \320\1\x69\100\31 286,SM IMUL reg32,imm8 \321\1\x6B\100\15 386 IMUL reg32,imm \321\1\x69\100\41 386,SM -IN reg_al,imm \1\xE4\25 8086 -IN reg_ax,imm \320\1\xE5\25 8086 -IN reg_eax,imm \321\1\xE5\25 386 +IN reg_al,imm \1\xE4\25 8086,SB +IN reg_ax,imm \320\1\xE5\25 8086,SB +IN reg_eax,imm \321\1\xE5\25 386,SB IN reg_al,reg_dx \1\xEC 8086 IN reg_ax,reg_dx \320\1\xED 8086 IN reg_eax,reg_dx \321\1\xED 386 @@ -433,7 +435,7 @@ INCBIN ignore ignore ignore INSB void \1\x6C 186 INSD void \321\1\x6D 386 INSW void \320\1\x6D 186 -INT imm \1\xCD\24 8086 +INT imm \1\xCD\24 8086,SB INT01 void \1\xF1 P6,ND INT1 void \1\xF1 P6 INT3 void \1\xCC 8086 @@ -447,6 +449,7 @@ JCXZ imm \320\1\xE3\50 8086 JECXZ imm \321\1\xE3\50 386 JMP imm|short \1\xEB\50 8086 JMP imm \322\1\xE9\64 8086 +JMP imm|near \322\1\xE9\64 8086 JMP imm|far \322\1\xEA\34\37 8086,ND JMP imm:imm \322\1\xEA\35\30 8086 JMP imm16:imm \320\1\xEA\31\30 8086 @@ -619,9 +622,9 @@ OR rm32,imm \321\300\1\x81\201\41 386,SM OR mem,imm8 \300\1\x80\201\21 8086,SM OR mem,imm16 \320\300\1\x81\201\31 8086,SM OR mem,imm32 \321\300\1\x81\201\41 386,SM -OUT imm,reg_al \1\xE6\24 8086 -OUT imm,reg_ax \320\1\xE7\24 8086 -OUT imm,reg_eax \321\1\xE7\24 386 +OUT imm,reg_al \1\xE6\24 8086,SB +OUT imm,reg_ax \320\1\xE7\24 8086,SB +OUT imm,reg_eax \321\1\xE7\24 386,SB OUT reg_dx,reg_al \1\xEE 8086 OUT reg_dx,reg_ax \320\1\xEF 8086 OUT reg_dx,reg_eax \321\1\xEF 386 @@ -656,6 +659,8 @@ PANDN mmxreg,mem \301\2\x0F\xDF\110 PENT,MMX,SM PANDN mmxreg,mmxreg \2\x0F\xDF\110 PENT,MMX PAVEB mmxreg,mem \301\2\x0F\x50\110 PENT,MMX,SM,CYRIX PAVEB mmxreg,mmxreg \2\x0F\x50\110 PENT,MMX,CYRIX +PAVGUSB mmxreg,mem \301\2\x0F\x0F\110\01\xBF PENT,MMX,SM,FPU +PAVGUSB mmxreg,mmxreg \2\x0F\x0F\110\01\xBF PENT,MMX,FPU PCMPEQB mmxreg,mem \301\2\x0F\x74\110 PENT,MMX,SM PCMPEQB mmxreg,mmxreg \2\x0F\x74\110 PENT,MMX PCMPEQD mmxreg,mem \301\2\x0F\x76\110 PENT,MMX,SM @@ -669,15 +674,51 @@ PCMPGTD mmxreg,mmxreg \2\x0F\x66\110 PENT,MMX PCMPGTW mmxreg,mem \301\2\x0F\x65\110 PENT,MMX,SM PCMPGTW mmxreg,mmxreg \2\x0F\x65\110 PENT,MMX PDISTIB mmxreg,mem \301\2\x0F\x54\110 PENT,MMX,SM,CYRIX +PF2ID mmxreg,mem \301\2\x0F\x0F\110\01\x1D PENT,MMX,SM,FPU +PF2ID mmxreg,mmxreg \2\x0F\x0F\110\01\x1D PENT,MMX,FPU +PFACC mmxreg,mem \301\2\x0F\x0F\110\01\xAE PENT,MMX,SM,FPU +PFACC mmxreg,mmxreg \2\x0F\x0F\110\01\xAE PENT,MMX,FPU +PFADD mmxreg,mem \301\2\x0F\x0F\110\01\x9E PENT,MMX,SM,FPU +PFADD mmxreg,mmxreg \2\x0F\x0F\110\01\x9E PENT,MMX,FPU +PFCMPEQ mmxreg,mem \301\2\x0F\x0F\110\01\xB0 PENT,MMX,SM,FPU +PFCMPEQ mmxreg,mmxreg \2\x0F\x0F\110\01\xB0 PENT,MMX,FPU +PFCMPGE mmxreg,mem \301\2\x0F\x0F\110\01\x90 PENT,MMX,SM,FPU +PFCMPGE mmxreg,mmxreg \2\x0F\x0F\110\01\x90 PENT,MMX,FPU +PFCMPGT mmxreg,mem \301\2\x0F\x0F\110\01\xA0 PENT,MMX,SM,FPU +PFCMPGT mmxreg,mmxreg \2\x0F\x0F\110\01\xA0 PENT,MMX,FPU +PFMAX mmxreg,mem \301\2\x0F\x0F\110\01\xA4 PENT,MMX,SM,FPU +PFMAX mmxreg,mmxreg \2\x0F\x0F\110\01\xA4 PENT,MMX,FPU +PFMIN mmxreg,mem \301\2\x0F\x0F\110\01\x94 PENT,MMX,SM,FPU +PFMIN mmxreg,mmxreg \2\x0F\x0F\110\01\x94 PENT,MMX,FPU +PFMUL mmxreg,mem \301\2\x0F\x0F\110\01\xB4 PENT,MMX,SM,FPU +PFMUL mmxreg,mmxreg \2\x0F\x0F\110\01\xB4 PENT,MMX,FPU +PFRCP mmxreg,mem \301\2\x0F\x0F\110\01\x96 PENT,MMX,SM,FPU +PFRCP mmxreg,mmxreg \2\x0F\x0F\110\01\x96 PENT,MMX,FPU +PFRCPIT1 mmxreg,mem \301\2\x0F\x0F\110\01\xA6 PENT,MMX,SM,FPU +PFRCPIT1 mmxreg,mmxreg \2\x0F\x0F\110\01\xA6 PENT,MMX,FPU +PFRCPIT2 mmxreg,mem \301\2\x0F\x0F\110\01\xB6 PENT,MMX,SM,FPU +PFRCPIT2 mmxreg,mmxreg \2\x0F\x0F\110\01\xB6 PENT,MMX,FPU +PFRSQIT1 mmxreg,mem \301\2\x0F\x0F\110\01\xA7 PENT,MMX,SM,FPU +PFRSQIT1 mmxreg,mmxreg \2\x0F\x0F\110\01\xA7 PENT,MMX,FPU +PFRSQRT mmxreg,mem \301\2\x0F\x0F\110\01\x97 PENT,MMX,SM,FPU +PFRSQRT mmxreg,mmxreg \2\x0F\x0F\110\01\x97 PENT,MMX,FPU +PFSUB mmxreg,mem \301\2\x0F\x0F\110\01\x9A PENT,MMX,SM,FPU +PFSUB mmxreg,mmxreg \2\x0F\x0F\110\01\x9A PENT,MMX,FPU +PFSUBR mmxreg,mem \301\2\x0F\x0F\110\01\xAA PENT,MMX,SM,FPU +PFSUBR mmxreg,mmxreg \2\x0F\x0F\110\01\xAA PENT,MMX,FPU +PI2FD mmxreg,mem \301\2\x0F\x0F\110\01\x0D PENT,MMX,SM,FPU +PI2FD mmxreg,mmxreg \2\x0F\x0F\110\01\x0D PENT,MMX,FPU PMACHRIW mmxreg,mem \301\2\x0F\x5E\110 PENT,MMX,SM,CYRIX PMADDWD mmxreg,mem \301\2\x0F\xF5\110 PENT,MMX,SM PMADDWD mmxreg,mmxreg \2\x0F\xF5\110 PENT,MMX PMAGW mmxreg,mem \301\2\x0F\x52\110 PENT,MMX,SM,CYRIX PMAGW mmxreg,mmxreg \2\x0F\x52\110 PENT,MMX,CYRIX -PMULHRW mmxreg,mem \301\2\x0F\x59\110 PENT,MMX,SM,CYRIX -PMULHRW mmxreg,mmxreg \2\x0F\x59\110 PENT,MMX,CYRIX PMULHRIW mmxreg,mem \301\2\x0F\x5D\110 PENT,MMX,SM,CYRIX PMULHRIW mmxreg,mmxreg \2\x0F\x5D\110 PENT,MMX,CYRIX +PMULHRWA mmxreg,mem \301\2\x0F\x0F\110\1\xB7 PENT,MMX,SM,FPU +PMULHRWA mmxreg,mmxreg \2\x0F\x0F\110\1\xB7 PENT,MMX,FPU +PMULHRWC mmxreg,mem \301\2\x0F\x59\110 PENT,MMX,SM,CYRIX +PMULHRWC mmxreg,mmxreg \2\x0F\x59\110 PENT,MMX,CYRIX PMULHW mmxreg,mem \301\2\x0F\xE5\110 PENT,MMX,SM PMULHW mmxreg,mmxreg \2\x0F\xE5\110 PENT,MMX PMULLW mmxreg,mem \301\2\x0F\xD5\110 PENT,MMX,SM @@ -701,6 +742,8 @@ POPFD void \321\1\x9D 386 POPFW void \320\1\x9D 186 POR mmxreg,mem \301\2\x0F\xEB\110 PENT,MMX,SM POR mmxreg,mmxreg \2\x0F\xEB\110 PENT,MMX +PREFETCH mem \2\x0F\x0D\200 PENT,MMX,SM,FPU +PREFETCHW mem \2\x0F\x0D\201 PENT,MMX,SM,FPU PSLLD mmxreg,mem \301\2\x0F\xF2\110 PENT,MMX,SM PSLLD mmxreg,mmxreg \2\x0F\xF2\110 PENT,MMX PSLLD mmxreg,imm \2\x0F\x72\206\25 PENT,MMX @@ -772,19 +815,19 @@ PXOR mmxreg,mem \301\2\x0F\xEF\110 PENT,MMX,SM PXOR mmxreg,mmxreg \2\x0F\xEF\110 PENT,MMX RCL rm8,unity \300\1\xD0\202 8086 RCL rm8,reg_cl \300\1\xD2\202 8086 -RCL rm8,imm \300\1\xC0\202\25 286,SB +RCL rm8,imm \300\1\xC0\202\25 186,SB RCL rm16,unity \320\300\1\xD1\202 8086 RCL rm16,reg_cl \320\300\1\xD3\202 8086 -RCL rm16,imm \320\300\1\xC1\202\25 286,SB +RCL rm16,imm \320\300\1\xC1\202\25 186,SB RCL rm32,unity \321\300\1\xD1\202 386 RCL rm32,reg_cl \321\300\1\xD3\202 386 RCL rm32,imm \321\300\1\xC1\202\25 386,SB RCR rm8,unity \300\1\xD0\203 8086 RCR rm8,reg_cl \300\1\xD2\203 8086 -RCR rm8,imm \300\1\xC0\203\25 286,SB +RCR rm8,imm \300\1\xC0\203\25 186,SB RCR rm16,unity \320\300\1\xD1\203 8086 RCR rm16,reg_cl \320\300\1\xD3\203 8086 -RCR rm16,imm \320\300\1\xC1\203\25 286,SB +RCR rm16,imm \320\300\1\xC1\203\25 186,SB RCR rm32,unity \321\300\1\xD1\203 386 RCR rm32,reg_cl \321\300\1\xD3\203 386 RCR rm32,imm \321\300\1\xC1\203\25 386,SB @@ -797,26 +840,26 @@ RESQ ignore ignore ignore REST ignore ignore ignore RESW ignore ignore ignore RET void \1\xC3 8086 -RET imm \1\xC2\30 8086 +RET imm \1\xC2\30 8086,SW RETF void \1\xCB 8086 -RETF imm \1\xCA\30 8086 +RETF imm \1\xCA\30 8086,SW RETN void \1\xC3 8086 -RETN imm \1\xC2\30 8086 +RETN imm \1\xC2\30 8086,SW ROL rm8,unity \300\1\xD0\200 8086 ROL rm8,reg_cl \300\1\xD2\200 8086 -ROL rm8,imm \300\1\xC0\200\25 286,SB +ROL rm8,imm \300\1\xC0\200\25 186,SB ROL rm16,unity \320\300\1\xD1\200 8086 ROL rm16,reg_cl \320\300\1\xD3\200 8086 -ROL rm16,imm \320\300\1\xC1\200\25 286,SB +ROL rm16,imm \320\300\1\xC1\200\25 186,SB ROL rm32,unity \321\300\1\xD1\200 386 ROL rm32,reg_cl \321\300\1\xD3\200 386 ROL rm32,imm \321\300\1\xC1\200\25 386,SB ROR rm8,unity \300\1\xD0\201 8086 ROR rm8,reg_cl \300\1\xD2\201 8086 -ROR rm8,imm \300\1\xC0\201\25 286,SB +ROR rm8,imm \300\1\xC0\201\25 186,SB ROR rm16,unity \320\300\1\xD1\201 8086 ROR rm16,reg_cl \320\300\1\xD3\201 8086 -ROR rm16,imm \320\300\1\xC1\201\25 286,SB +ROR rm16,imm \320\300\1\xC1\201\25 186,SB ROR rm32,unity \321\300\1\xD1\201 386 ROR rm32,reg_cl \321\300\1\xD3\201 386 ROR rm32,imm \321\300\1\xC1\201\25 386,SB @@ -824,20 +867,20 @@ RSM void \2\x0F\xAA PENT SAHF void \1\x9E 8086 SAL rm8,unity \300\1\xD0\204 8086,ND SAL rm8,reg_cl \300\1\xD2\204 8086,ND -SAL rm8,imm \300\1\xC0\204\25 286,ND,SB +SAL rm8,imm \300\1\xC0\204\25 186,ND,SB SAL rm16,unity \320\300\1\xD1\204 8086,ND SAL rm16,reg_cl \320\300\1\xD3\204 8086,ND -SAL rm16,imm \320\300\1\xC1\204\25 286,ND,SB +SAL rm16,imm \320\300\1\xC1\204\25 186,ND,SB SAL rm32,unity \321\300\1\xD1\204 386,ND SAL rm32,reg_cl \321\300\1\xD3\204 386,ND SAL rm32,imm \321\300\1\xC1\204\25 386,ND,SB SALC void \1\xD6 8086,UNDOC SAR rm8,unity \300\1\xD0\207 8086 SAR rm8,reg_cl \300\1\xD2\207 8086 -SAR rm8,imm \300\1\xC0\207\25 286,SB +SAR rm8,imm \300\1\xC0\207\25 186,SB SAR rm16,unity \320\300\1\xD1\207 8086 SAR rm16,reg_cl \320\300\1\xD3\207 8086 -SAR rm16,imm \320\300\1\xC1\207\25 286,SB +SAR rm16,imm \320\300\1\xC1\207\25 186,SB SAR rm32,unity \321\300\1\xD1\207 386 SAR rm32,reg_cl \321\300\1\xD3\207 386 SAR rm32,imm \321\300\1\xC1\207\25 386,SB @@ -870,10 +913,10 @@ SCASW void \320\1\xAF 8086 SGDT mem \300\2\x0F\x01\200 286,PRIV SHL rm8,unity \300\1\xD0\204 8086 SHL rm8,reg_cl \300\1\xD2\204 8086 -SHL rm8,imm \300\1\xC0\204\25 286,SB +SHL rm8,imm \300\1\xC0\204\25 186,SB SHL rm16,unity \320\300\1\xD1\204 8086 SHL rm16,reg_cl \320\300\1\xD3\204 8086 -SHL rm16,imm \320\300\1\xC1\204\25 286,SB +SHL rm16,imm \320\300\1\xC1\204\25 186,SB SHL rm32,unity \321\300\1\xD1\204 386 SHL rm32,reg_cl \321\300\1\xD3\204 386 SHL rm32,imm \321\300\1\xC1\204\25 386,SB @@ -887,10 +930,10 @@ SHLD mem,reg32,reg_cl \300\321\2\x0F\xA5\101 386,SM SHLD reg32,reg32,reg_cl \300\321\2\x0F\xA5\101 386 SHR rm8,unity \300\1\xD0\205 8086 SHR rm8,reg_cl \300\1\xD2\205 8086 -SHR rm8,imm \300\1\xC0\205\25 286,SB +SHR rm8,imm \300\1\xC0\205\25 186,SB SHR rm16,unity \320\300\1\xD1\205 8086 SHR rm16,reg_cl \320\300\1\xD3\205 8086 -SHR rm16,imm \320\300\1\xC1\205\25 286,SB +SHR rm16,imm \320\300\1\xC1\205\25 186,SB SHR rm32,unity \321\300\1\xD1\205 386 SHR rm32,reg_cl \321\300\1\xD3\205 386 SHR rm32,imm \321\300\1\xC1\205\25 386,SB @@ -948,6 +991,9 @@ TEST mem,reg16 \320\300\1\x85\101 8086,SM TEST reg16,reg16 \320\300\1\x85\101 8086 TEST mem,reg32 \321\300\1\x85\101 386,SM TEST reg32,reg32 \321\300\1\x85\101 386 +TEST reg8,mem \301\1\x84\110 8086,SM +TEST reg16,mem \320\301\1\x85\110 8086,SM +TEST reg32,mem \321\301\1\x85\110 386,SM TEST reg_al,imm \1\xA8\21 8086,SM TEST reg_ax,imm \320\1\xA9\31 8086,SM TEST reg_eax,imm \321\1\xA9\41 386,SM diff --git a/labels.c b/labels.c index 2c17c7c8..dc7e0759 100644 --- a/labels.c +++ b/labels.c @@ -43,7 +43,7 @@ union label { /* actual label structures */ struct { long segment, offset; char *label, *special; - int is_global; + int is_global, is_norm; } defn; struct { long movingon, dummy; @@ -74,7 +74,8 @@ static int initialised = FALSE; * given label name. Creates a new one, if it isn't found, and if * `create' is TRUE. */ -static union label *find_label (char *label, int create) { +static union label *find_label (char *label, int create) +{ int hash = 0; char *p, *prev; int prevlen; @@ -117,11 +118,13 @@ static union label *find_label (char *label, int create) { lfree[hash]->defn.special = NULL; lfree[hash]->defn.is_global = NOT_DEFINED_YET; return lfree[hash]++; - } else + } + else return NULL; } -int lookup_label (char *label, long *segment, long *offset) { +int lookup_label (char *label, long *segment, long *offset) +{ union label *lptr; if (!initialised) @@ -132,11 +135,13 @@ int lookup_label (char *label, long *segment, long *offset) { *segment = lptr->defn.segment; *offset = lptr->defn.offset; return 1; - } else + } + else return 0; } -int is_extern (char *label) { +int is_extern (char *label) +{ union label *lptr; if (!initialised) @@ -149,22 +154,48 @@ int is_extern (char *label) { return 0; } -void define_label_stub (char *label, efunc error) { +void redefine_label (char *label, long segment, long offset, char *special, + int is_norm, int isextrn, struct ofmt *ofmt, efunc error) +{ union label *lptr; + /* This routine possibly ought to check for phase errors. Most assemblers + * check for phase errors at this point. I don't know whether phase errors + * are even possible, nor whether they are checked somewhere else + */ + + (void) segment; /* Don't warn that this parameter is unused */ + (void) offset; /* Don't warn that this parameter is unused */ + (void) special; /* Don't warn that this parameter is unused */ + (void) is_norm; /* Don't warn that this parameter is unused */ + (void) isextrn; /* Don't warn that this parameter is unused */ + (void) ofmt; /* Don't warn that this parameter is unused */ + +#ifdef DEBUG + if (!strncmp(label, "debugdump", 9)) + fprintf(stderr, "debug: redefine_label (%s, %ld, %08lx, %s, %d, %d)\n", + label, segment, offset, special, is_norm, isextrn); +#endif + if (!islocal(label)) { lptr = find_label (label, 1); if (!lptr) error (ERR_PANIC, "can't find label `%s' on pass two", label); - if (*label != '.') + if (*label != '.' && lptr->defn.is_norm) prevlabel = lptr->defn.label; } } void define_label (char *label, long segment, long offset, char *special, - int is_norm, int isextrn, struct ofmt *ofmt, efunc error) { + int is_norm, int isextrn, struct ofmt *ofmt, efunc error) +{ union label *lptr; +#ifdef DEBUG + if (!strncmp(label, "debugdump", 9)) + fprintf(stderr, "debug: define_label (%s, %ld, %08lx, %s, %d, %d)\n", + label, segment, offset, special, is_norm, isextrn); +#endif lptr = find_label (label, 1); if (lptr->defn.is_global & DEFINED_BIT) { error(ERR_NONFATAL, "symbol `%s' redefined", label); @@ -182,14 +213,19 @@ void define_label (char *label, long segment, long offset, char *special, lptr->defn.segment = segment; lptr->defn.offset = offset; + lptr->defn.is_norm = (label[0] != '.' && is_norm); ofmt->symdef (lptr->defn.label, segment, offset, !!(lptr->defn.is_global & GLOBAL_BIT), special ? special : lptr->defn.special); + ofmt->current_dfmt->debug_deflabel (label, segment, offset, + !!(lptr->defn.is_global & GLOBAL_BIT), + special ? special : lptr->defn.special); } void define_common (char *label, long segment, long size, char *special, - struct ofmt *ofmt, efunc error) { + struct ofmt *ofmt, efunc error) +{ union label *lptr; lptr = find_label (label, 1); @@ -210,9 +246,12 @@ void define_common (char *label, long segment, long size, char *special, ofmt->symdef (lptr->defn.label, segment, size, 2, special ? special : lptr->defn.special); + ofmt->current_dfmt->debug_deflabel(lptr->defn.label, segment, size, 2, + special ? special : lptr->defn.special); } -void declare_as_global (char *label, char *special, efunc error) { +void declare_as_global (char *label, char *special, efunc error) +{ union label *lptr; if (islocal(label)) { @@ -237,7 +276,8 @@ void declare_as_global (char *label, char *special, efunc error) { } } -int init_labels (void) { +int init_labels (void) +{ int i; for (i=0; idata + perm_tail->usage; while ( (*q = *string1++) ) q++; - while ( (*q++ = *string2++) ); + while ( (*q++ = *string2++) ) ; perm_tail->usage = q - perm_tail->data; return p; } + +/* + * Notes regarding bug involving redefinition of external segments. + * + * Up to and including v0.97, the following code didn't work. From 0.97 + * developers release 2 onwards, it will generate an error. + * + * EXTERN extlabel + * newlabel EQU extlabel + 1 + * + * The results of allowing this code through are that two import records + * are generated, one for 'extlabel' and one for 'newlabel'. + * + * The reason for this is an inadequacy in the defined interface between + * the label manager and the output formats. The problem lies in how the + * output format driver tells that a label is an external label for which + * a label import record must be produced. Most (all except bin?) produce + * the record if the segment number of the label is not one of the internal + * segments that the output driver is producing. + * + * A simple fix to this would be to make the output formats keep track of + * which symbols they've produced import records for, and make them not + * produce import records for segments that are already defined. + * + * The best way, which is slightly harder but reduces duplication of code + * and should therefore make the entire system smaller and more stable is + * to change the interface between assembler, define_label(), and + * the output module. The changes that are needed are: + * + * The semantics of the 'isextern' flag passed to define_label() need + * examining. This information may or may not tell us what we need to + * know (ie should we be generating an import record at this point for this + * label). If these aren't the semantics, the semantics should be changed + * to this. + * + * The output module interface needs changing, so that the `isextern' flag + * is passed to the module, so that it can be easily tested for. + */ diff --git a/labels.h b/labels.h index 111104bf..b78c8564 100644 --- a/labels.h +++ b/labels.h @@ -10,9 +10,10 @@ int lookup_label (char *label, long *segment, long *offset); int is_extern (char *label); void define_label (char *label, long segment, long offset, char *special, int is_norm, int isextrn, struct ofmt *ofmt, efunc error); +void redefine_label (char *label, long segment, long offset, char *special, + int is_norm, int isextrn, struct ofmt *ofmt, efunc error); void define_common (char *label, long segment, long size, char *special, struct ofmt *ofmt, efunc error); -void define_label_stub (char *label, efunc error); void declare_as_global (char *label, char *special, efunc error); int init_labels (void); void cleanup_labels (void); diff --git a/listing.c b/listing.c index 89b722a6..af8a9bf8 100644 --- a/listing.c +++ b/listing.c @@ -50,31 +50,39 @@ static int listlevel, listlevel_e; static FILE *listfp; -static void list_emit (void) { +static void list_emit (void) +{ if (!listlinep && !listdata[0]) return; + fprintf(listfp, "%6ld ", ++listlineno); + if (listdata[0]) fprintf(listfp, "%08lX %-*s", listoffset, LIST_HEXBIT+1, listdata); else fprintf(listfp, "%*s", LIST_HEXBIT+10, ""); + if (listlevel_e) fprintf(listfp, "%s<%d>", (listlevel < 10 ? " " : ""), listlevel_e); else if (listlinep) fprintf(listfp, " "); + if (listlinep) fprintf(listfp, " %s", listline); + fputc('\n', listfp); listlinep = FALSE; listdata[0] = '\0'; } -static void list_init (char *fname, efunc error) { +static void list_init (char *fname, efunc error) +{ listfp = fopen (fname, "w"); if (!listfp) { error (ERR_NONFATAL, "unable to open listing file `%s'", fname); return; } + *listline = '\0'; listlineno = 0; listp = TRUE; @@ -86,19 +94,23 @@ static void list_init (char *fname, efunc error) { mistack->inhibiting = TRUE; } -static void list_cleanup (void) { +static void list_cleanup (void) +{ if (!listp) return; + while (mistack) { MacroInhibit *temp = mistack; mistack = temp->next; nasm_free (temp); } + list_emit(); fclose (listfp); } -static void list_out (long offset, char *str) { +static void list_out (long offset, char *str) +{ if (strlen(listdata) + strlen(str) > LIST_HEXBIT) { strcat(listdata, "-"); list_emit(); @@ -108,7 +120,8 @@ static void list_out (long offset, char *str) { strcat(listdata, str); } -static void list_output (long offset, void *data, unsigned long type) { +static void list_output (long offset, void *data, unsigned long type) +{ long typ, size; if (!listp || suppress) @@ -117,20 +130,25 @@ static void list_output (long offset, void *data, unsigned long type) { typ = type & OUT_TYPMASK; size = type & OUT_SIZMASK; - if (typ == OUT_RAWDATA) { + if (typ == OUT_RAWDATA) + { unsigned char *p = data; char q[3]; - while (size--) { + while (size--) + { HEX (q, *p); q[2] = '\0'; list_out (offset++, q); p++; } - } else if (typ == OUT_ADDRESS) { + } + else if (typ == OUT_ADDRESS) + { unsigned long d = *(long *)data; char q[11]; unsigned char p[4], *r = p; - if (size == 4) { + if (size == 4) + { q[0] = '['; q[9] = ']'; q[10] = '\0'; WRITELONG (r, d); HEX (q+1, p[0]); @@ -138,14 +156,17 @@ static void list_output (long offset, void *data, unsigned long type) { HEX (q+5, p[2]); HEX (q+7, p[3]); list_out (offset, q); - } else { + } + else { q[0] = '['; q[5] = ']'; q[6] = '\0'; WRITESHORT (r, d); HEX (q+1, p[0]); HEX (q+3, p[1]); list_out (offset, q); } - } else if (typ == OUT_REL2ADR) { + } + else if (typ == OUT_REL2ADR) + { unsigned long d = *(long *)data; char q[11]; unsigned char p[4], *r = p; @@ -154,7 +175,9 @@ static void list_output (long offset, void *data, unsigned long type) { HEX (q+1, p[0]); HEX (q+3, p[1]); list_out (offset, q); - } else if (typ == OUT_REL4ADR) { + } + else if (typ == OUT_REL4ADR) + { unsigned long d = *(long *)data; char q[11]; unsigned char p[4], *r = p; @@ -165,17 +188,22 @@ static void list_output (long offset, void *data, unsigned long type) { HEX (q+5, p[2]); HEX (q+7, p[3]); list_out (offset, q); - } else if (typ == OUT_RESERVE) { + } + else if (typ == OUT_RESERVE) + { char q[20]; sprintf(q, "", 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 ? "" : ""); return; } + listlevel++; - if (mistack && mistack->inhibiting && type == LIST_INCLUDE) { + + if (mistack && mistack->inhibiting && type == LIST_INCLUDE) + { MacroInhibit *temp = nasm_malloc(sizeof(MacroInhibit)); temp->next = mistack; temp->level = listlevel; temp->inhibiting = FALSE; mistack = temp; - } else if (type == LIST_MACRO_NOLIST) { + } + else if (type == LIST_MACRO_NOLIST) + { MacroInhibit *temp = nasm_malloc(sizeof(MacroInhibit)); temp->next = mistack; temp->level = listlevel; @@ -215,15 +250,20 @@ static void list_uplevel (int type) { } } -static void list_downlevel (int type) { +static void list_downlevel (int type) +{ if (!listp) return; - if (type == LIST_INCBIN || type == LIST_TIMES) { + + if (type == LIST_INCBIN || type == LIST_TIMES) + { suppress &= ~(type == LIST_INCBIN ? 1 : 2); return; } + listlevel--; - while (mistack && mistack->level > listlevel) { + while (mistack && mistack->level > listlevel) + { MacroInhibit *temp = mistack; mistack = temp->next; nasm_free (temp); diff --git a/macros.c b/macros.c index ea02959a..ed70a75e 100644 --- a/macros.c +++ b/macros.c @@ -2,7 +2,7 @@ static char *stdmac[] = { "%define __NASM_MAJOR__ 0", - "%define __NASM_MINOR__ 97", + "%define __NASM_MINOR__ 98", "%define __FILE__", "%define __LINE__", "%define __SECT__", diff --git a/names.c b/names.c index 218ce5aa..cc168452 100644 --- a/names.c +++ b/names.c @@ -28,7 +28,9 @@ static char *insn_names[] = { /* instruction names, as strings */ "fcmovbe", "fcmove", "fcmovnb", "fcmovnbe", "fcmovne", "fcmovnu", "fcmovu", "fcom", "fcomi", "fcomip", "fcomp", "fcompp", "fcos", "fdecstp", "fdisi", "fdiv", "fdivp", "fdivr", - "fdivrp", "feni", "ffree", "fiadd", "ficom", "ficomp", "fidiv", + "fdivrp", + "femms", + "feni", "ffree", "fiadd", "ficom", "ficomp", "fidiv", "fidivr", "fild", "fimul", "fincstp", "finit", "fist", "fistp", "fisub", "fisubr", "fld", "fld1", "fldcw", "fldenv", "fldl2e", "fldl2t", "fldlg2", "fldln2", "fldpi", "fldz", "fmul", "fmulp", @@ -40,7 +42,7 @@ static char *insn_names[] = { /* instruction names, as strings */ "fucomi", "fucomip", "fucomp", "fucompp", "fxam", "fxch", "fxtract", "fyl2x", "fyl2xp1", "hlt", "ibts", "icebp", "idiv", "imul", "in", "inc", "incbin", "insb", "insd", "insw", "int", - "int1", "int01", "int3", "into", "invd", "invlpg", "iret", + "int01", "int1", "int3", "into", "invd", "invlpg", "iret", "iretd", "iretw", "jcxz", "jecxz", "jmp", "lahf", "lar", "lds", "lea", "leave", "les", "lfs", "lgdt", "lgs", "lidt", "lldt", "lmsw", "loadall", "loadall286", "lodsb", "lodsd", "lodsw", @@ -49,12 +51,18 @@ static char *insn_names[] = { /* instruction names, as strings */ "movsx", "movzx", "mul", "neg", "nop", "not", "or", "out", "outsb", "outsd", "outsw", "packssdw", "packsswb", "packuswb", "paddb", "paddd", "paddsb", "paddsiw", "paddsw", "paddusb", - "paddusw", "paddw", "pand", "pandn", "paveb", "pcmpeqb", + "paddusw", "paddw", "pand", "pandn", "paveb", + "pavgusb", "pcmpeqb", "pcmpeqd", "pcmpeqw", "pcmpgtb", "pcmpgtd", "pcmpgtw", - "pdistib", "pmachriw", "pmaddwd", "pmagw", "pmulhrw", - "pmulhriw", "pmulhw", "pmullw", "pmvgezb", "pmvlzb", "pmvnzb", + "pdistib", + "pf2id", "pfacc", "pfadd", "pfcmpeq", "pfcmpge", "pfcmpgt", + "pfmax", "pfmin", "pfmul", "pfrcp", "pfrcpit1", "pfrcpit2", + "pfrsqit1", "pfrsqrt", "pfsub", "pfsubr", "pi2fd", + "pmachriw", "pmaddwd", "pmagw", "pmulhriw", "pmulhrwa", "pmulhrwc", + "pmulhw", "pmullw", "pmvgezb", "pmvlzb", "pmvnzb", "pmvzb", "pop", "popa", "popad", "popaw", "popf", "popfd", - "popfw", "por", "pslld", "psllq", "psllw", "psrad", "psraw", + "popfw", "por", + "prefetch", "prefetchw", "pslld", "psllq", "psllw", "psrad", "psraw", "psrld", "psrlq", "psrlw", "psubb", "psubd", "psubsb", "psubsiw", "psubsw", "psubusb", "psubusw", "psubw", "punpckhbw", "punpckhdq", "punpckhwd", "punpcklbw", "punpckldq", "punpcklwd", diff --git a/nasm.c b/nasm.c index a1e4dd8a..1404db15 100644 --- a/nasm.c +++ b/nasm.c @@ -22,6 +22,11 @@ #include "outform.h" #include "listing.h" +struct forwrefinfo { /* info held on forward refs. */ + int lineno; + int operand; +}; + static void report_error (int, char *, ...); static void parse_cmdline (int, char **); static void assemble_file (char *); @@ -29,12 +34,11 @@ static int getkw (char *buf, char **value); static void register_output_formats(void); static void usage(void); -static char *obuf; +static int using_debug_info; + static char inname[FILENAME_MAX]; static char outname[FILENAME_MAX]; static char listname[FILENAME_MAX]; -static int lineno; /* for error reporting */ -static int lineinc; /* set by [LINE] or [ONELINE] */ static int globallineno; /* for forward-reference tracking */ static int pass; static struct ofmt *ofmt = NULL; @@ -42,27 +46,27 @@ static struct ofmt *ofmt = NULL; static FILE *ofile = NULL; static int sb = 16; /* by default */ -static int use_stdout = FALSE; /* by default, errors to stderr */ +static loc_t location; +int in_abs_seg; /* Flag we are in ABSOLUTE seg */ +static long abs_seg; -static long current_seg, abs_seg; static struct RAA *offsets; static long abs_offset; static struct SAA *forwrefs; /* keep track of forward references */ -static int forwline; +static struct forwrefinfo *forwref; static Preproc *preproc; static int preprocess_only; /* used by error function to report location */ -static char currentfile[FILENAME_MAX]; /* * Which of the suppressible warnings are suppressed. Entry zero * doesn't do anything. Initial defaults are given here. */ static char suppressed[1+ERR_WARN_MAX] = { - 0, FALSE, TRUE, FALSE + 0, TRUE, TRUE, FALSE }; /* @@ -101,20 +105,30 @@ static Preproc no_pp = { /* * get/set current offset... */ -#define get_curr_ofs (current_seg==NO_SEG?abs_offset:\ - raa_read(offsets,current_seg)) -#define set_curr_ofs(x) (current_seg==NO_SEG?(void)(abs_offset=(x)):\ - (void)(offsets=raa_write(offsets,current_seg,(x)))) +#define get_curr_ofs (in_abs_seg?abs_offset:\ + raa_read(offsets,location.segment)) +#define set_curr_ofs(x) (in_abs_seg?(void)(abs_offset=(x)):\ + (void)(offsets=raa_write(offsets,location.segment,(x)))) static int want_usage; static int terminate_after_phase; -int main(int argc, char **argv) { +static void nasm_fputs(char *line, FILE *ofile) +{ + if (ofile) { + fputs(line, ofile); + fputc('\n', ofile); + } else + puts(line); +} + +int main(int argc, char **argv) +{ want_usage = terminate_after_phase = FALSE; nasm_set_malloc_error (report_error); offsets = raa_init(); - forwrefs = saa_init ((long)sizeof(int)); + forwrefs = saa_init ((long)sizeof(struct forwrefinfo)); preproc = &nasmpp; preprocess_only = FALSE; @@ -125,7 +139,8 @@ int main(int argc, char **argv) { parse_cmdline(argc, argv); - if (terminate_after_phase) { + if (terminate_after_phase) + { if (want_usage) usage(); return 1; @@ -133,10 +148,15 @@ int main(int argc, char **argv) { if (ofmt->stdmac) pp_extra_stdmac (ofmt->stdmac); - eval_global_info (ofmt, lookup_label); + parser_global_info (ofmt, &location); + eval_global_info (ofmt, lookup_label, &location); - if (preprocess_only) { + if (preprocess_only) + { char *line; + char *file_name = NULL; + long prior_linnum=0; + int lineinc=0; if (*outname) { ofile = fopen(outname, "w"); @@ -146,41 +166,37 @@ int main(int argc, char **argv) { } else ofile = NULL; - eval_info ("%", 0L, 0L); /* disallow labels, $ or $$ in exprs */ + location.known = FALSE; preproc->reset (inname, 2, report_error, evaluate, &nasmlist); - strcpy(currentfile,inname); - lineno = 0; - lineinc = 1; while ( (line = preproc->getline()) ) { - int ln, li; - char buf[FILENAME_MAX]; - - lineno += lineinc; /* - * We must still check for %line directives, so that we - * can report errors accurately. + * We generate %line directives if needed for later programs */ - if (!strncmp(line, "%line", 5) && - sscanf(line, "%%line %d+%d %s", &ln, &li, buf) == 3) { - lineno = ln - li; - lineinc = li; - strncpy (currentfile, buf, FILENAME_MAX-1); - currentfile[FILENAME_MAX-1] = '\0'; + long linnum = prior_linnum += lineinc; + int altline = src_get(&linnum, &file_name); + if (altline) { + if (altline==1 && lineinc==1) + nasm_fputs("", ofile); + else { + lineinc = (altline != -1 || lineinc!=1); + fprintf(ofile ? ofile : stdout, "%%line %ld+%d %s\n", + linnum, lineinc, file_name); + } + prior_linnum = linnum; } - if (ofile) { - fputs(line, ofile); - fputc('\n', ofile); - } else - puts(line); + nasm_fputs(line, ofile); nasm_free (line); } + nasm_free(file_name); preproc->cleanup(); if (ofile) fclose(ofile); if (ofile && terminate_after_phase) remove(outname); - } else { + } + else /* NOT preprocess only */ + { /* * We must call ofmt->filename _anyway_, even if the user * has specified their own output file, because some @@ -195,25 +211,31 @@ int main(int argc, char **argv) { report_error (ERR_FATAL | ERR_NOFILE, "unable to open output file `%s'", outname); } + /* * We must call init_labels() before ofmt->init() since * some object formats will want to define labels in their * init routines. (eg OS/2 defines the FLAT group) */ init_labels (); + ofmt->init (ofile, report_error, define_label, evaluate); + assemble_file (inname); + if (!terminate_after_phase) { - ofmt->cleanup (); + ofmt->cleanup (using_debug_info); cleanup_labels (); } - /* - * We had an fclose on the output file here, but we - * actually do that in all the object file drivers as well, - * so we're leaving out the one here. - * fclose (ofile); - */ - if (terminate_after_phase) { + else { + + /* + * We had an fclose on the output file here, but we + * actually do that in all the object file drivers as well, + * so we're leaving out the one here. + * fclose (ofile); + */ + remove(outname); if (listname[0]) remove(listname); @@ -222,8 +244,11 @@ int main(int argc, char **argv) { if (want_usage) usage(); + raa_free (offsets); saa_free (forwrefs); + eval_cleanup (); + nasmlib_cleanup (); if (terminate_after_phase) return 1; @@ -231,43 +256,70 @@ int main(int argc, char **argv) { return 0; } -static int process_arg (char *p, char *q) { + +/* + * Get a parameter for a command line option. + * First arg must be in the form of e.g. -f... + */ +static char *get_param (char *p, char *q, int *advance) +{ + *advance = 0; + if (p[2]) /* the parameter's in the option */ + { + p += 2; + while (isspace(*p)) + p++; + return p; + } + if (q && q[0]) + { + *advance = 1; + return q; + } + report_error (ERR_NONFATAL | ERR_NOFILE | ERR_USAGE, + "option `-%c' requires an argument", + p[1]); + return NULL; +} + +int stopoptions = 0; +static int process_arg (char *p, char *q) +{ char *param; - int i; - int advance = 0; + int i, advance = 0; if (!p || !p[0]) return 0; - if (p[0]=='-') { + if (p[0]=='-' && ! stopoptions) + { switch (p[1]) { - case 's': - use_stdout = TRUE; - break; + case '-': /* -- => stop processing options */ + stopoptions = 1; + break; + case 's': /* silently ignored for compatibility */ + break; case 'o': /* these parameters take values */ case 'f': case 'p': case 'd': case 'i': case 'l': - if (p[2]) /* the parameter's in the option */ - param = p+2; - else if (!q) { - report_error (ERR_NONFATAL | ERR_NOFILE | ERR_USAGE, - "option `-%c' requires an argument", - p[1]); + case 'F': + if ( !(param = get_param (p, q, &advance)) ) break; - } else - advance = 1, param = q; if (p[1]=='o') { /* output file */ strcpy (outname, param); } else if (p[1]=='f') { /* output format */ ofmt = ofmt_find(param); if (!ofmt) { report_error (ERR_FATAL | ERR_NOFILE | ERR_USAGE, - "unrecognised output format `%s'", + "unrecognised output format `%s' - " + "use -hf for a list", param); } + else + ofmt->current_dfmt = ofmt->debug_formats[0]; } else if (p[1]=='p') { /* pre-include */ pp_pre_include (param); } else if (p[1]=='d') { /* pre-define */ @@ -276,40 +328,63 @@ static int process_arg (char *p, char *q) { pp_include_path (param); } else if (p[1]=='l') { /* listing file */ strcpy (listname, param); - } + } else if (p[1] == 'F') { /* specify debug format */ + ofmt->current_dfmt = dfmt_find(ofmt, param); + if (!ofmt->current_dfmt) { + report_error (ERR_FATAL | ERR_NOFILE | ERR_USAGE, + "unrecognized debug format `%s' for" + " output format `%s'", + param, ofmt->shortname); + } + } + break; + case 'g': + using_debug_info = TRUE; break; case 'h': - fprintf(use_stdout ? stdout : stderr, - "usage: nasm [-o outfile] [-f format] [-l listfile]" - " [options...] filename\n"); - fprintf(use_stdout ? stdout : stderr, - " or nasm -r for version info\n\n"); - fprintf(use_stdout ? stdout : stderr, - " -e means preprocess only; " - "-a means don't preprocess\n"); - fprintf(use_stdout ? stdout : stderr, - " -s means send errors to stdout not stderr\n"); - fprintf(use_stdout ? stdout : stderr, - " -i adds a pathname to the include file" - " path\n -p pre-includes a file;" - " -d[= adds a pathname to the include file path\n" + " -p pre-includes a file\n" + " -d[=] 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
-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; ilineno = 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= 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, ¤tfile); + fprintf (stdout, "%s:%ld: ", currentfile, lineno); + nasm_free (currentfile); + } if ( (severity & ERR_MASK) == ERR_WARNING) - fputs ("warning: ", use_stdout ? stdout : stderr); + fputs ("warning: ", stdout); else if ( (severity & ERR_MASK) == ERR_PANIC) - fputs ("panic: ", use_stdout ? stdout : stderr); + fputs ("panic: ", stdout); va_start (ap, fmt); - vfprintf (use_stdout ? stdout : stderr, fmt, ap); - fputc ('\n', use_stdout ? stdout : stderr); + vfprintf (stdout, fmt, ap); + fputc ('\n', stdout); if (severity & ERR_USAGE) want_usage = TRUE; @@ -965,80 +1208,14 @@ static void report_error (int severity, char *fmt, ...) { } } -static void usage(void) { - fputs("type `nasm -h' for help\n", use_stdout ? stdout : stderr); +static void usage(void) +{ + fputs("type `nasm -h' for help\n", stdout); } -static void register_output_formats(void) { - /* Flat-form binary format */ -#ifdef OF_BIN - extern struct ofmt of_bin; -#endif - /* Unix formats: a.out, COFF, ELF */ -#ifdef OF_AOUT - extern struct ofmt of_aout; -#endif -#ifdef OF_AOUTB - extern struct ofmt of_aoutb; -#endif -#ifdef OF_COFF - extern struct ofmt of_coff; -#endif -#ifdef OF_ELF - extern struct ofmt of_elf; -#endif - /* Linux strange format: as86 */ -#ifdef OF_AS86 - extern struct ofmt of_as86; -#endif - /* DOS and DOS-ish formats: OBJ, OS/2, Win32 */ -#ifdef OF_OBJ - extern struct ofmt of_obj; -#endif -#ifdef OF_WIN32 - extern struct ofmt of_win32; -#endif -#ifdef OF_RDF - extern struct ofmt of_rdf; -#endif -#ifdef OF_DBG /* debug format must be included specifically */ - extern struct ofmt of_dbg; -#endif - -#ifdef OF_BIN - ofmt_register (&of_bin); -#endif -#ifdef OF_AOUT - ofmt_register (&of_aout); -#endif -#ifdef OF_AOUTB - ofmt_register (&of_aoutb); -#endif -#ifdef OF_COFF - ofmt_register (&of_coff); -#endif -#ifdef OF_ELF - ofmt_register (&of_elf); -#endif -#ifdef OF_AS86 - ofmt_register (&of_as86); -#endif -#ifdef OF_OBJ - ofmt_register (&of_obj); -#endif -#ifdef OF_WIN32 - ofmt_register (&of_win32); -#endif -#ifdef OF_RDF - ofmt_register (&of_rdf); -#endif -#ifdef OF_DBG - ofmt_register (&of_dbg); -#endif - /* - * set the default format - */ - ofmt = &OF_DEFAULT; +static void register_output_formats(void) +{ + ofmt = ofmt_register (report_error); } #define BUF_DELTA 512 @@ -1046,9 +1223,14 @@ static void register_output_formats(void) { static FILE *no_pp_fp; static efunc no_pp_err; static ListGen *no_pp_list; +static long no_pp_lineinc; static void no_pp_reset (char *file, int pass, efunc error, evalfunc eval, - ListGen *listgen) { + ListGen *listgen) +{ + src_set_fname(nasm_strdup(file)); + src_set_linnum(0); + no_pp_lineinc = 1; no_pp_err = error; no_pp_fp = fopen(file, "r"); if (!no_pp_fp) @@ -1059,49 +1241,66 @@ static void no_pp_reset (char *file, int pass, efunc error, evalfunc eval, (void) eval; /* placate compilers */ } -static char *no_pp_getline (void) { +static char *no_pp_getline (void) +{ char *buffer, *p, *q; int bufsize; bufsize = BUF_DELTA; buffer = nasm_malloc(BUF_DELTA); - p = buffer; - while (1) { - q = fgets(p, bufsize-(p-buffer), no_pp_fp); - if (!q) - break; - p += strlen(p); - if (p > buffer && p[-1] == '\n') - break; - if (p-buffer > bufsize-10) { - bufsize += BUF_DELTA; - buffer = nasm_realloc(buffer, bufsize); - } - } + src_set_linnum(src_get_linnum() + no_pp_lineinc); - if (!q && p == buffer) { - nasm_free (buffer); - return NULL; - } + while (1) { /* Loop to handle %line */ - /* - * Play safe: remove CRs as well as LFs, if any of either are - * present at the end of the line. - */ - while (p > buffer && (p[-1] == '\n' || p[-1] == '\r')) - *--p = '\0'; + p = buffer; + while (1) { /* Loop to handle long lines */ + q = fgets(p, bufsize-(p-buffer), no_pp_fp); + if (!q) + break; + p += strlen(p); + if (p > buffer && p[-1] == '\n') + break; + if (p-buffer > bufsize-10) { + int offset; + offset = p - buffer; + bufsize += BUF_DELTA; + buffer = nasm_realloc(buffer, bufsize); + p = buffer + offset; + } + } - /* - * Handle spurious ^Z, which may be inserted into source files - * by some file transfer utilities. - */ - buffer[strcspn(buffer, "\032")] = '\0'; + if (!q && p == buffer) { + nasm_free (buffer); + return NULL; + } + + /* + * Play safe: remove CRs, LFs and any spurious ^Zs, if any of + * them are present at the end of the line. + */ + buffer[strcspn(buffer, "\r\n\032")] = '\0'; + + if (!strncmp(buffer, "%line", 5)) { + long ln; + int li; + char *nm = nasm_malloc(strlen(buffer)); + if (sscanf(buffer+5, "%ld+%d %s", &ln, &li, nm) == 3) { + nasm_free( src_set_fname(nm) ); + src_set_linnum(ln); + no_pp_lineinc = li; + continue; + } + nasm_free(nm); + } + break; + } no_pp_list->line (LIST_READ, buffer); return buffer; } -static void no_pp_cleanup (void) { +static void no_pp_cleanup (void) +{ fclose(no_pp_fp); } diff --git a/nasm.h b/nasm.h index 8dafac5d..93c41a77 100644 --- a/nasm.h +++ b/nasm.h @@ -12,8 +12,8 @@ #define NASM_NASM_H #define NASM_MAJOR_VER 0 -#define NASM_MINOR_VER 97 -#define NASM_VER "0.97" +#define NASM_MINOR_VER 98 +#define NASM_VER "0.98 pre-release J4" #ifndef NULL #define NULL 0 @@ -72,9 +72,6 @@ typedef void (*efunc) (int severity, char *fmt, ...); #define ERR_MASK 0x0F /* mask off the above codes */ #define ERR_NOFILE 0x10 /* don't give source file name/line */ #define ERR_USAGE 0x20 /* print a usage message */ -#define ERR_OFFBY1 0x40 /* report error as being on the line - * we're just _about_ to read, not - * the one we've just read */ #define ERR_PASS1 0x80 /* only print this error on pass one */ /* @@ -205,6 +202,12 @@ enum { /* token types, other than chars */ TOKEN_FLOAT /* floating-point constant */ }; +typedef struct { + long segment; + long offset; + int known; +} loc_t; + /* * Expression-evaluator datatype. Expressions, within the * evaluator, are stored as an array of these beasts, terminated by @@ -260,13 +263,6 @@ typedef expr *(*evalfunc) (scanner sc, void *scprivate, struct tokenval *tv, int *fwref, int critical, efunc error, struct eval_hints *hints); -/* - * There's also an auxiliary routine through which the evaluator - * needs to hear about the value of $ and the label (if any) - * defined on the current line. - */ -typedef void (*evalinfofunc) (char *labelname, long segment, long offset); - /* * Special values for expr->type. ASSUMPTION MADE HERE: the number * of distinct register names (i.e. possible "type" fields for an @@ -311,11 +307,13 @@ typedef struct { * ---------------------------------------------------------------- */ -/* isidstart matches any character that may start an identifier, and isidchar +/* + * isidstart matches any character that may start an identifier, and isidchar * matches any character that may appear at places other than the start of an * identifier. E.g. a period may only appear at the start of an identifier * (for local labels), whereas a number may appear anywhere *but* at the - * start. */ + * start. + */ #define isidstart(c) ( isalpha(c) || (c)=='_' || (c)=='.' || (c)=='?' \ || (c)=='@' ) @@ -439,7 +437,9 @@ enum { /* instruction names */ I_FCMOVBE, I_FCMOVE, I_FCMOVNB, I_FCMOVNBE, I_FCMOVNE, I_FCMOVNU, I_FCMOVU, I_FCOM, I_FCOMI, I_FCOMIP, I_FCOMP, I_FCOMPP, I_FCOS, I_FDECSTP, I_FDISI, I_FDIV, I_FDIVP, I_FDIVR, - I_FDIVRP, I_FENI, I_FFREE, I_FIADD, I_FICOM, I_FICOMP, I_FIDIV, + I_FDIVRP, + I_FEMMS, + I_FENI, I_FFREE, I_FIADD, I_FICOM, I_FICOMP, I_FIDIV, I_FIDIVR, I_FILD, I_FIMUL, I_FINCSTP, I_FINIT, I_FIST, I_FISTP, I_FISUB, I_FISUBR, I_FLD, I_FLD1, I_FLDCW, I_FLDENV, I_FLDL2E, I_FLDL2T, I_FLDLG2, I_FLDLN2, I_FLDPI, I_FLDZ, I_FMUL, I_FMULP, @@ -451,7 +451,7 @@ enum { /* instruction names */ I_FUCOMI, I_FUCOMIP, I_FUCOMP, I_FUCOMPP, I_FXAM, I_FXCH, I_FXTRACT, I_FYL2X, I_FYL2XP1, I_HLT, I_IBTS, I_ICEBP, I_IDIV, I_IMUL, I_IN, I_INC, I_INCBIN, I_INSB, I_INSD, I_INSW, I_INT, - I_INT1, I_INT01, I_INT3, I_INTO, I_INVD, I_INVLPG, I_IRET, + I_INT01, I_INT1, I_INT3, I_INTO, I_INVD, I_INVLPG, I_IRET, I_IRETD, I_IRETW, I_JCXZ, I_JECXZ, I_JMP, I_LAHF, I_LAR, I_LDS, I_LEA, I_LEAVE, I_LES, I_LFS, I_LGDT, I_LGS, I_LIDT, I_LLDT, I_LMSW, I_LOADALL, I_LOADALL286, I_LODSB, I_LODSD, I_LODSW, @@ -460,12 +460,18 @@ enum { /* instruction names */ I_MOVSX, I_MOVZX, I_MUL, I_NEG, I_NOP, I_NOT, I_OR, I_OUT, I_OUTSB, I_OUTSD, I_OUTSW, I_PACKSSDW, I_PACKSSWB, I_PACKUSWB, I_PADDB, I_PADDD, I_PADDSB, I_PADDSIW, I_PADDSW, I_PADDUSB, - I_PADDUSW, I_PADDW, I_PAND, I_PANDN, I_PAVEB, I_PCMPEQB, + I_PADDUSW, I_PADDW, I_PAND, I_PANDN, I_PAVEB, + I_PAVGUSB, I_PCMPEQB, I_PCMPEQD, I_PCMPEQW, I_PCMPGTB, I_PCMPGTD, I_PCMPGTW, - I_PDISTIB, I_PMACHRIW, I_PMADDWD, I_PMAGW, I_PMULHRW, - I_PMULHRIW, I_PMULHW, I_PMULLW, I_PMVGEZB, I_PMVLZB, I_PMVNZB, + I_PDISTIB, + I_PF2ID, I_PFACC, I_PFADD, I_PFCMPEQ, I_PFCMPGE, I_PFCMPGT, + I_PFMAX, I_PFMIN, I_PFMUL, I_PFRCP, I_PFRCPIT1, I_PFRCPIT2, + I_PFRSQIT1, I_PFRSQRT, I_PFSUB, I_PFSUBR, I_PI2FD, + I_PMACHRIW, I_PMADDWD, I_PMAGW, I_PMULHRIW, I_PMULHRWA, + I_PMULHRWC, I_PMULHW, I_PMULLW, I_PMVGEZB, I_PMVLZB, I_PMVNZB, I_PMVZB, I_POP, I_POPA, I_POPAD, I_POPAW, I_POPF, I_POPFD, - I_POPFW, I_POR, I_PSLLD, I_PSLLQ, I_PSLLW, I_PSRAD, I_PSRAW, + I_POPFW, I_POR, I_PREFETCH, I_PREFETCHW, + I_PSLLD, I_PSLLQ, I_PSLLW, I_PSRAD, I_PSRAW, I_PSRLD, I_PSRLQ, I_PSRLW, I_PSUBB, I_PSUBD, I_PSUBSB, I_PSUBSIW, I_PSUBSW, I_PSUBUSB, I_PSUBUSW, I_PSUBW, I_PUNPCKHBW, I_PUNPCKHDQ, I_PUNPCKHWD, I_PUNPCKLBW, I_PUNPCKLDQ, I_PUNPCKLWD, @@ -480,6 +486,8 @@ enum { /* instruction names */ I_XOR, I_CMOVcc, I_Jcc, I_SETcc }; +#define MAX_KEYWORD 9 /* max length of any instruction, register name etc. */ + enum { /* condition code names */ C_A, C_AE, C_B, C_BE, C_C, C_E, C_G, C_GE, C_L, C_LE, C_NA, C_NAE, C_NB, C_NBE, C_NC, C_NE, C_NG, C_NGE, C_NL, C_NLE, C_NO, C_NP, @@ -522,8 +530,12 @@ typedef struct { /* operand to an instruction */ long offset; /* any immediate number */ long wrt; /* segment base it's relative to */ int eaflags; /* special EA flags */ + int opflags; /* see OPFLAG_* defines below */ } operand; +#define OPFLAG_FORWARD 1 /* operand is a forward reference */ +#define OPFLAG_EXTERN 2 /* operand is an external reference */ + typedef struct extop { /* extended operand */ struct extop *next; /* linked list */ long type; /* defined above */ @@ -542,13 +554,16 @@ typedef struct { /* an instruction itself */ int nprefix; /* number of entries in above */ int opcode; /* the opcode - not just the string */ int condition; /* the condition code, if Jcc/SETcc */ - int operands; /* how many operands? 0-3 */ + int operands; /* how many operands? 0-3 + * (more if db et al) */ operand oprs[3]; /* the operands, defined as above */ extop *eops; /* extended operands */ + int eops_float; /* true if DD and floating */ long times; /* repeat count (TIMES prefix) */ int forw_ref; /* is there a forward reference? */ } insn; +enum geninfo { GI_SWITCH }; /* * ------------------------------------------------------------ * The data structure defining an output format driver, and the @@ -568,6 +583,27 @@ struct ofmt { */ char *shortname; + /* + * this is reserved for out module specific help. + * It is set to NULL in all the out modules but is not implemented + * in the main program + */ + char *helpstring; + + /* + * this is a pointer to the first element of the debug information + */ + struct dfmt **debug_formats; + + /* + * and a pointer to the element that is being used + * note: this is set to the default at compile time and changed if the + * -F option is selected. If developing a set of new debug formats for + * an output format, be sure to set this to whatever default you want + * + */ + struct dfmt *current_dfmt; + /* * This, if non-NULL, is a NULL-terminated list of `char *'s * pointing to extra standard macros supplied by the object @@ -586,6 +622,15 @@ struct ofmt { */ void (*init) (FILE *fp, efunc error, ldfunc ldef, evalfunc eval); + /* + * This procedure is called to pass generic information to the + * object file. The first parameter gives the information type + * (currently only command line switches) + * and the second parameter gives the value. This function returns + * 1 if recognized, 0 if unrecognized + */ + int (*setinfo)(enum geninfo type, char **string); + /* * This procedure is called by assemble() to write actual * generated code or data to the object file. Typically it @@ -705,7 +750,7 @@ struct ofmt { * One thing the cleanup routine should always do is to close * the output file pointer. */ - void (*cleanup) (void); + void (*cleanup) (int debuginfo); }; /* @@ -734,6 +779,103 @@ struct ofmt { #define OUT_TYPMASK 0xF0000000UL #define OUT_SIZMASK 0x0FFFFFFFUL +/* + * ------------------------------------------------------------ + * The data structure defining a debug format driver, and the + * interfaces to the functions therein. + * ------------------------------------------------------------ + */ + +struct dfmt { + + /* + * This is a short (one-liner) description of the type of + * output generated by the driver. + */ + char *fullname; + + /* + * This is a single keyword used to select the driver. + */ + char *shortname; + + + /* + * init - called initially to set up local pointer to object format, + * void pointer to implementation defined data, file pointer (which + * probably won't be used, but who knows?), and error function. + */ + void (*init) (struct ofmt * of, void * id, FILE * fp, efunc error); + + /* + * linenum - called any time there is output with a change of + * line number or file. + */ + void (*linenum) (const char * filename, long linenumber, long segto); + + /* + * debug_deflabel - called whenever a label is defined. Parameters + * are the same as to 'symdef()' in the output format. This function + * would be called before the output format version. + */ + + void (*debug_deflabel) (char * name, long segment, long offset, + int is_global, char * special); + /* + * debug_directive - called whenever a DEBUG directive other than 'LINE' + * is encountered. 'directive' contains the first parameter to the + * DEBUG directive, and params contains the rest. For example, + * 'DEBUG VAR _somevar:int' would translate to a call to this + * function with 'directive' equal to "VAR" and 'params' equal to + * "_somevar:int". + */ + void (*debug_directive) (const char * directive, const char * params); + + /* + * typevalue - called whenever the assembler wishes to register a type + * for the last defined label. This routine MUST detect if a type was + * already registered and not re-register it. + */ + void (*debug_typevalue) (long type); + + /* + * debug_output - called whenever output is required + * 'type' is the type of info required, and this is format-specific + */ + void (*debug_output) (int type, void *param); + + /* + * cleanup - called after processing of file is complete + */ + void (*cleanup) (void); + +}; +/* + * The type definition macros + * for debugging + * + * low 3 bits: reserved + * next 5 bits: type + * next 24 bits: number of elements for arrays (0 for labels) + */ + +#define TY_UNKNOWN 0x00 +#define TY_LABEL 0x08 +#define TY_BYTE 0x10 +#define TY_WORD 0x18 +#define TY_DWORD 0x20 +#define TY_FLOAT 0x28 +#define TY_QWORD 0x30 +#define TY_TBYTE 0x38 +#define TY_COMMON 0xE0 +#define TY_SEG 0xE8 +#define TY_EXTERN 0xF0 +#define TY_EQU 0xF8 + +#define TYM_TYPE(x) ((x) & 0xF8) +#define TYM_ELEMENTS(x) (((x) & 0xFFFFFF00) >> 8) + +#define TYS_ELEMENTS(x) ((x) << 8) /* * ----- * Other diff --git a/nasmlib.c b/nasmlib.c index 4508fec4..86ed6c47 100644 --- a/nasmlib.c +++ b/nasmlib.c @@ -20,7 +20,8 @@ static efunc nasm_malloc_error; static FILE *logfp; #endif -void nasm_set_malloc_error (efunc error) { +void nasm_set_malloc_error (efunc error) +{ nasm_malloc_error = error; #ifdef LOGALLOC logfp = fopen ("malloc.log", "w"); @@ -124,7 +125,8 @@ char *nasm_strndup (char *s, size_t len) return p; } -int nasm_stricmp (char *s1, char *s2) { +int nasm_stricmp (const char *s1, const char *s2) +{ while (*s1 && toupper(*s1) == toupper(*s2)) s1++, s2++; if (!*s1 && !*s2) @@ -135,7 +137,8 @@ int nasm_stricmp (char *s1, char *s2) { return 1; } -int nasm_strnicmp (char *s1, char *s2, int n) { +int nasm_strnicmp (const char *s1, const char *s2, int n) +{ while (n > 0 && *s1 && toupper(*s1) == toupper(*s2)) s1++, s2++, n--; if ((!*s1 && !*s2) || n==0) @@ -149,15 +152,29 @@ int nasm_strnicmp (char *s1, char *s2, int n) { #define lib_isnumchar(c) ( isalnum(c) || (c) == '$') #define numvalue(c) ((c)>='a' ? (c)-'a'+10 : (c)>='A' ? (c)-'A'+10 : (c)-'0') -long readnum (char *str, int *error) { +long readnum (char *str, int *error) +{ char *r = str, *q; long radix; unsigned long result, checklimit; + int digit, last; int warn = FALSE; + int sign = 1; *error = FALSE; while (isspace(*r)) r++; /* find start of number */ + + /* + * If the number came from make_tok_num (as a result of an %assign), it + * might have a '-' built into it (rather than in a preceeding token). + */ + if (*r == '-') + { + r++; + sign = -1; + } + q = r; while (lib_isnumchar(*q)) q++; /* find end of number */ @@ -199,15 +216,26 @@ long readnum (char *str, int *error) { */ checklimit = 0x80000000UL / (radix>>1); + /* + * Calculate the highest allowable value for the last digit + * of a 32 bit constant... in radix 10, it is 6, otherwise it is 0 + */ + last = (radix == 10 ? 6 : 0); + result = 0; while (*r && r < q) { - if (*r<'0' || (*r>'9' && *r<'A') || numvalue(*r)>=radix) { + if (*r<'0' || (*r>'9' && *r<'A') || (digit = numvalue(*r)) >= radix) + { *error = TRUE; return 0; } - if (result >= checklimit) + if (result > checklimit || + (result == checklimit && digit >= last)) + { warn = TRUE; - result = radix * result + numvalue(*r); + } + + result = radix * result + digit; r++; } @@ -216,25 +244,46 @@ long readnum (char *str, int *error) { "numeric constant %s does not fit in 32 bits", str); - return result; + return result*sign; +} + +long readstrnum (char *str, int length, int *warn) +{ + long charconst = 0; + int i; + + *warn = FALSE; + + str += length; + for (i=0; i> 8) & 255), fp); } -void fwritelong (long data, FILE *fp) { +void fwritelong (long data, FILE *fp) +{ fputc ((int) (data & 255), fp); fputc ((int) ((data >> 8) & 255), fp); fputc ((int) ((data >> 16) & 255), fp); @@ -242,7 +291,8 @@ void fwritelong (long data, FILE *fp) { } void standard_extension (char *inname, char *outname, char *extension, - efunc error) { + efunc error) +{ char *p, *q; if (*outname) /* file name already exists, */ @@ -268,47 +318,13 @@ void standard_extension (char *inname, char *outname, char *extension, strcpy(p, extension); } -#define RAA_BLKSIZE 4096 /* this many longs allocated at once */ -#define RAA_LAYERSIZE 1024 /* this many _pointers_ allocated */ - -typedef struct RAA RAA; -typedef union RAA_UNION RAA_UNION; -typedef struct RAA_LEAF RAA_LEAF; -typedef struct RAA_BRANCH RAA_BRANCH; - -struct RAA { - /* - * Number of layers below this one to get to the real data. 0 - * means this structure is a leaf, holding RAA_BLKSIZE real - * data items; 1 and above mean it's a branch, holding - * RAA_LAYERSIZE pointers to the next level branch or leaf - * structures. - */ - int layers; - /* - * Number of real data items spanned by one position in the - * `data' array at this level. This number is 1, trivially, for - * a leaf (level 0): for a level 1 branch it should be - * RAA_BLKSIZE, and for a level 2 branch it's - * RAA_LAYERSIZE*RAA_BLKSIZE. - */ - long stepsize; - union RAA_UNION { - struct RAA_LEAF { - long data[RAA_BLKSIZE]; - } l; - struct RAA_BRANCH { - struct RAA *data[RAA_LAYERSIZE]; - } b; - } u; -}; - #define LEAFSIZ (sizeof(RAA)-sizeof(RAA_UNION)+sizeof(RAA_LEAF)) #define BRANCHSIZ (sizeof(RAA)-sizeof(RAA_UNION)+sizeof(RAA_BRANCH)) #define LAYERSIZ(r) ( (r)->layers==0 ? RAA_BLKSIZE : RAA_LAYERSIZE ) -static struct RAA *real_raa_init (int layers) { +static struct RAA *real_raa_init (int layers) +{ struct RAA *r; if (layers == 0) { @@ -327,11 +343,13 @@ static struct RAA *real_raa_init (int layers) { return r; } -struct RAA *raa_init (void) { +struct RAA *raa_init (void) +{ return real_raa_init (0); } -void raa_free (struct RAA *r) { +void raa_free (struct RAA *r) +{ if (r->layers == 0) nasm_free (r); else { @@ -342,7 +360,8 @@ void raa_free (struct RAA *r) { } } -long raa_read (struct RAA *r, long posn) { +long raa_read (struct RAA *r, long posn) +{ if (posn > r->stepsize * LAYERSIZ(r)) return 0L; while (r->layers > 0) { @@ -356,7 +375,8 @@ long raa_read (struct RAA *r, long posn) { return r->u.l.data[posn]; } -struct RAA *raa_write (struct RAA *r, long posn, long value) { +struct RAA *raa_write (struct RAA *r, long posn, long value) +{ struct RAA *result; if (posn < 0) @@ -396,17 +416,8 @@ struct RAA *raa_write (struct RAA *r, long posn, long value) { #define SAA_MAXLEN 8192 -struct SAA { - /* - * members `end' and `elem_len' are only valid in first link in - * list; `rptr' and `rpos' are used for reading - */ - struct SAA *next, *end, *rptr; - long elem_len, length, posn, start, rpos; - char *data; -}; - -struct SAA *saa_init (long elem_len) { +struct SAA *saa_init (long elem_len) +{ struct SAA *s; if (elem_len > SAA_MAXLEN) @@ -423,7 +434,8 @@ struct SAA *saa_init (long elem_len) { return s; } -void saa_free (struct SAA *s) { +void saa_free (struct SAA *s) +{ struct SAA *t; while (s) { @@ -434,7 +446,8 @@ void saa_free (struct SAA *s) { } } -void *saa_wstruct (struct SAA *s) { +void *saa_wstruct (struct SAA *s) +{ void *p; if (s->end->length - s->end->posn < s->elem_len) { @@ -452,7 +465,8 @@ void *saa_wstruct (struct SAA *s) { return p; } -void saa_wbytes (struct SAA *s, void *data, long len) { +void saa_wbytes (struct SAA *s, void *data, long len) +{ char *d = data; while (len > 0) { @@ -480,12 +494,14 @@ void saa_wbytes (struct SAA *s, void *data, long len) { } } -void saa_rewind (struct SAA *s) { +void saa_rewind (struct SAA *s) +{ s->rptr = s; s->rpos = 0L; } -void *saa_rstruct (struct SAA *s) { +void *saa_rstruct (struct SAA *s) +{ void *p; if (!s->rptr) @@ -503,7 +519,8 @@ void *saa_rstruct (struct SAA *s) { return p; } -void *saa_rbytes (struct SAA *s, long *len) { +void *saa_rbytes (struct SAA *s, long *len) +{ void *p; if (!s->rptr) @@ -516,7 +533,8 @@ void *saa_rbytes (struct SAA *s, long *len) { return p; } -void saa_rnbytes (struct SAA *s, void *data, long len) { +void saa_rnbytes (struct SAA *s, void *data, long len) +{ char *d = data; while (len > 0) { @@ -541,26 +559,27 @@ void saa_rnbytes (struct SAA *s, void *data, long len) { } } -void saa_fread (struct SAA *s, long posn, void *data, long len) { +void saa_fread (struct SAA *s, long posn, void *data, long len) +{ struct SAA *p; long pos; char *cdata = data; - if (!s->rptr || posn > s->rptr->start + s->rpos) + if (!s->rptr || posn < s->rptr->start) saa_rewind (s); - while (posn >= s->rptr->start + s->rptr->posn) { - s->rptr = s->rptr->next; - if (!s->rptr) + p = s->rptr; + while (posn >= p->start + p->posn) { + p = p->next; + if (!p) return; /* what else can we do?! */ } - p = s->rptr; - pos = posn - s->rptr->start; + pos = posn - p->start; while (len) { - long l = s->rptr->posn - pos; + long l = p->posn - pos; if (l > len) l = len; - memcpy (cdata, s->rptr->data+pos, l); + memcpy (cdata, p->data+pos, l); len -= l; cdata += l; p = p->next; @@ -568,28 +587,30 @@ void saa_fread (struct SAA *s, long posn, void *data, long len) { return; pos = 0L; } + s->rptr = p; } -void saa_fwrite (struct SAA *s, long posn, void *data, long len) { +void saa_fwrite (struct SAA *s, long posn, void *data, long len) +{ struct SAA *p; long pos; char *cdata = data; - if (!s->rptr || posn > s->rptr->start + s->rpos) + if (!s->rptr || posn < s->rptr->start) saa_rewind (s); - while (posn >= s->rptr->start + s->rptr->posn) { - s->rptr = s->rptr->next; - if (!s->rptr) + p = s->rptr; + while (posn >= p->start + p->posn) { + p = p->next; + if (!p) return; /* what else can we do?! */ } - p = s->rptr; - pos = posn - s->rptr->start; + pos = posn - p->start; while (len) { - long l = s->rptr->posn - pos; + long l = p->posn - pos; if (l > len) l = len; - memcpy (s->rptr->data+pos, cdata, l); + memcpy (p->data+pos, cdata, l); len -= l; cdata += l; p = p->next; @@ -597,9 +618,11 @@ void saa_fwrite (struct SAA *s, long posn, void *data, long len) { return; pos = 0L; } + s->rptr = p; } -void saa_fpwrite (struct SAA *s, FILE *fp) { +void saa_fpwrite (struct SAA *s, FILE *fp) +{ char *data; long len; @@ -632,16 +655,29 @@ static char **stdscan_tempstorage = NULL; static int stdscan_tempsize = 0, stdscan_templen = 0; #define STDSCAN_TEMP_DELTA 256 -static void stdscan_pop(void) { +static void stdscan_pop(void) +{ nasm_free (stdscan_tempstorage[--stdscan_templen]); } -void stdscan_reset(void) { +void stdscan_reset(void) +{ while (stdscan_templen > 0) stdscan_pop(); } -static char *stdscan_copy(char *p, int len) { +/* + * Unimportant cleanup is done to avoid confusing people who are trying + * to debug real memory leaks + */ +void nasmlib_cleanup (void) +{ + stdscan_reset(); + nasm_free (stdscan_tempstorage); +} + +static char *stdscan_copy(char *p, int len) +{ char *text; text = nasm_malloc(len+1); @@ -659,8 +695,11 @@ static char *stdscan_copy(char *p, int len) { } char *stdscan_bufptr = NULL; -int stdscan (void *private_data, struct tokenval *tv) { - char ourcopy[256], *r, *s; +int stdscan (void *private_data, struct tokenval *tv) +{ + char ourcopy[MAX_KEYWORD+1], *r, *s; + + (void) private_data; /* Don't warn that this parameter is unused */ while (isspace(*stdscan_bufptr)) stdscan_bufptr++; if (!*stdscan_bufptr) @@ -682,11 +721,12 @@ int stdscan (void *private_data, struct tokenval *tv) { while (isidchar(*stdscan_bufptr)) stdscan_bufptr++; tv->t_charptr = stdscan_copy(r, stdscan_bufptr - r); + if (is_sym || stdscan_bufptr-r > MAX_KEYWORD) + return tv->t_type = TOKEN_ID;/* bypass all other checks */ + for (s=tv->t_charptr, r=ourcopy; *s; s++) *r++ = tolower (*s); *r = '\0'; - if (is_sym) - return tv->t_type = TOKEN_ID;/* bypass all other checks */ /* right, so we have an identifier sitting in temp storage. now, * is it actually a register or instruction name, or what? */ if ((tv->t_integer=bsi(ourcopy, reg_names, @@ -743,7 +783,10 @@ int stdscan (void *private_data, struct tokenval *tv) { * a floating point constant */ stdscan_bufptr++; - while (isnumchar(*stdscan_bufptr)) { + while (isnumchar(*stdscan_bufptr) || + ((stdscan_bufptr[-1] == 'e' || stdscan_bufptr[-1] == 'E') + && (*stdscan_bufptr == '-' || *stdscan_bufptr == '+')) ) + { stdscan_bufptr++; } tv->t_charptr = stdscan_copy(r, stdscan_bufptr - r); @@ -759,16 +802,15 @@ int stdscan (void *private_data, struct tokenval *tv) { } else if (*stdscan_bufptr == '\'' || *stdscan_bufptr == '"') {/* a char constant */ char quote = *stdscan_bufptr++, *r; + int rn_warn; r = tv->t_charptr = stdscan_bufptr; while (*stdscan_bufptr && *stdscan_bufptr != quote) stdscan_bufptr++; tv->t_inttwo = stdscan_bufptr - r; /* store full version */ if (!*stdscan_bufptr) return tv->t_type = TOKEN_ERRNUM; /* unmatched quotes */ - tv->t_integer = 0; - r = stdscan_bufptr++; /* skip over final quote */ - while (quote != *--r) { - tv->t_integer = (tv->t_integer<<8) + (unsigned char) *r; - } + stdscan_bufptr++; /* skip over final quote */ + tv->t_integer = readstrnum(r, tv->t_inttwo, &rn_warn); + /* FIXME: rn_warn is not checked! */ return tv->t_type = TOKEN_NUM; } else if (*stdscan_bufptr == ';') { /* a comment has happened - stay */ return tv->t_type = 0; @@ -816,7 +858,8 @@ int stdscan (void *private_data, struct tokenval *tv) { * Return TRUE if the argument is a simple scalar. (Or a far- * absolute, which counts.) */ -int is_simple (expr *vect) { +int is_simple (expr *vect) +{ while (vect->type && !vect->value) vect++; if (!vect->type) @@ -834,7 +877,8 @@ int is_simple (expr *vect) { * Return TRUE if the argument is a simple scalar, _NOT_ a far- * absolute. */ -int is_really_simple (expr *vect) { +int is_really_simple (expr *vect) +{ while (vect->type && !vect->value) vect++; if (!vect->type) @@ -852,7 +896,8 @@ int is_really_simple (expr *vect) { * Return TRUE if the argument is relocatable (i.e. a simple * scalar, plus at most one segment-base, plus possibly a WRT). */ -int is_reloc (expr *vect) { +int is_reloc (expr *vect) +{ while (vect->type && !vect->value) /* skip initial value-0 terms */ vect++; if (!vect->type) /* trivially return TRUE if nothing */ @@ -886,7 +931,8 @@ int is_reloc (expr *vect) { /* * Return TRUE if the argument contains an `unknown' part. */ -int is_unknown(expr *vect) { +int is_unknown(expr *vect) +{ while (vect->type && vect->type < EXPR_UNKNOWN) vect++; return (vect->type == EXPR_UNKNOWN); @@ -896,7 +942,8 @@ int is_unknown(expr *vect) { * Return TRUE if the argument contains nothing but an `unknown' * part. */ -int is_just_unknown(expr *vect) { +int is_just_unknown(expr *vect) +{ while (vect->type && !vect->value) vect++; return (vect->type == EXPR_UNKNOWN); @@ -906,7 +953,8 @@ int is_just_unknown(expr *vect) { * Return the scalar part of a relocatable vector. (Including * simple scalar vectors - those qualify as relocatable.) */ -long reloc_value (expr *vect) { +long reloc_value (expr *vect) +{ while (vect->type && !vect->value) vect++; if (!vect->type) return 0; @@ -920,7 +968,8 @@ long reloc_value (expr *vect) { * Return the segment number of a relocatable vector, or NO_SEG for * simple scalars. */ -long reloc_seg (expr *vect) { +long reloc_seg (expr *vect) +{ while (vect->type && (vect->type == EXPR_WRT || !vect->value)) vect++; if (vect->type == EXPR_SIMPLE) { @@ -938,7 +987,8 @@ long reloc_seg (expr *vect) { * Return the WRT segment number of a relocatable vector, or NO_SEG * if no WRT part is present. */ -long reloc_wrt (expr *vect) { +long reloc_wrt (expr *vect) +{ while (vect->type && vect->type < EXPR_WRT) vect++; if (vect->type == EXPR_WRT) { @@ -950,7 +1000,8 @@ long reloc_wrt (expr *vect) { /* * Binary search. */ -int bsi (char *string, char **array, int size) { +int bsi (char *string, char **array, int size) +{ int i = -1, j = size; /* always, i < index < j */ while (j-i >= 2) { int k = (i+j)/2; @@ -964,3 +1015,88 @@ int bsi (char *string, char **array, int size) { } return -1; /* we haven't got it :( */ } + +static char *file_name = NULL; +static long line_number = 0; + +char *src_set_fname(char *newname) +{ + char *oldname = file_name; + file_name = newname; + return oldname; +} + +long src_set_linnum(long newline) +{ + long oldline = line_number; + line_number = newline; + return oldline; +} + +long src_get_linnum(void) +{ + return line_number; +} + +int src_get(long *xline, char **xname) +{ + if (!file_name || !*xname || strcmp(*xname, file_name)) + { + nasm_free(*xname); + *xname = file_name ? nasm_strdup(file_name) : NULL; + *xline = line_number; + return -2; + } + if (*xline != line_number) + { + long tmp = line_number - *xline; + *xline = line_number; + return tmp; + } + return 0; +} + +void nasm_quote(char **str) +{ + int ln=strlen(*str); + char q=(*str)[0]; + char *p; + if (ln>1 && (*str)[ln-1]==q && (q=='"' || q=='\'')) + return; + q = '"'; + if (strchr(*str,q)) + q = '\''; + p = nasm_malloc(ln+3); + strcpy(p+1, *str); + nasm_free(*str); + p[ln+1] = p[0] = q; + p[ln+2] = 0; + *str = p; +} + +char *nasm_strcat(char *one, char *two) +{ + char *rslt; + int l1=strlen(one); + rslt = nasm_malloc(l1+strlen(two)+1); + strcpy(rslt, one); + strcpy(rslt+l1, two); + return rslt; +} + +void null_debug_routine() +{ +} +struct dfmt null_debug_form = { + "Null debug format", + "null", + null_debug_routine, + null_debug_routine, + null_debug_routine, + null_debug_routine, + null_debug_routine, + null_debug_routine, + null_debug_routine, +}; + +struct dfmt *null_debug_arr[2] = { &null_debug_form, NULL }; diff --git a/nasmlib.h b/nasmlib.h index 9168f183..d2997b18 100644 --- a/nasmlib.h +++ b/nasmlib.h @@ -1,4 +1,4 @@ -/* nasmlib.c header file for nasmlib.h +/* nasmlib.h header file for nasmlib.c * * The Netwide Assembler is copyright (C) 1996 Simon Tatham and * Julian Hall. All rights reserved. The software is @@ -51,8 +51,8 @@ char *nasm_strndup_log (char *, int, char *, size_t); * ANSI doesn't guarantee the presence of `stricmp' or * `strcasecmp'. */ -int nasm_stricmp (char *, char *); -int nasm_strnicmp (char *, char *, int); +int nasm_stricmp (const char *, const char *); +int nasm_strnicmp (const char *, const char *, int); /* * Convert a string into a number, using NASM number rules. Sets @@ -60,6 +60,14 @@ int nasm_strnicmp (char *, char *, int); */ long readnum(char *str, int *error); +/* + * Convert a character constant into a number. Sets + * `*warn' to TRUE if an overflow occurs, and FALSE otherwise. + * str points to and length covers the middle of the string, + * without the quotes. + */ +long readstrnum(char *str, int length, int *warn); + /* * seg_init: Initialise the segment-number allocator. * seg_alloc: allocate a hitherto unused segment number. @@ -108,7 +116,41 @@ void fwritelong (long data, FILE *fp); * chunk. */ -struct RAA; +#define RAA_BLKSIZE 4096 /* this many longs allocated at once */ +#define RAA_LAYERSIZE 1024 /* this many _pointers_ allocated */ + +typedef struct RAA RAA; +typedef union RAA_UNION RAA_UNION; +typedef struct RAA_LEAF RAA_LEAF; +typedef struct RAA_BRANCH RAA_BRANCH; + +struct RAA { + /* + * Number of layers below this one to get to the real data. 0 + * means this structure is a leaf, holding RAA_BLKSIZE real + * data items; 1 and above mean it's a branch, holding + * RAA_LAYERSIZE pointers to the next level branch or leaf + * structures. + */ + int layers; + /* + * Number of real data items spanned by one position in the + * `data' array at this level. This number is 1, trivially, for + * a leaf (level 0): for a level 1 branch it should be + * RAA_BLKSIZE, and for a level 2 branch it's + * RAA_LAYERSIZE*RAA_BLKSIZE. + */ + long stepsize; + union RAA_UNION { + struct RAA_LEAF { + long data[RAA_BLKSIZE]; + } l; + struct RAA_BRANCH { + struct RAA *data[RAA_LAYERSIZE]; + } b; + } u; +}; + struct RAA *raa_init (void); void raa_free (struct RAA *); @@ -125,7 +167,15 @@ struct RAA *raa_write (struct RAA *r, long posn, long value); * of a given size. */ -struct SAA; +struct SAA { + /* + * members `end' and `elem_len' are only valid in first link in + * list; `rptr' and `rpos' are used for reading + */ + struct SAA *next, *end, *rptr; + long elem_len, length, posn, start, rpos; + char *data; +}; struct SAA *saa_init (long elem_len); /* 1 == byte */ void saa_free (struct SAA *); @@ -169,4 +219,23 @@ long reloc_wrt(expr *); */ int bsi (char *string, char **array, int size); + +char *src_set_fname(char *newname); +long src_set_linnum(long newline); +long src_get_linnum(void); +/* + * src_get may be used if you simply want to know the source file and line. + * It is also used if you maintain private status about the source location + * It return 0 if the information was the same as the last time you + * checked, -1 if the name changed and (new-old) if just the line changed. + */ +int src_get(long *xline, char **xname); + +void nasm_quote(char **str); +char *nasm_strcat(char *one, char *two); +void nasmlib_cleanup(void); + +void null_debug_routine(); +extern struct dfmt null_debug_form; +extern struct dfmt *null_debug_arr[2]; #endif diff --git a/ndisasm.c b/ndisasm.c index 90639e90..a07a2781 100644 --- a/ndisasm.c +++ b/ndisasm.c @@ -33,7 +33,8 @@ static const char *help = static void output_ins (unsigned long, unsigned char *, int, char *); static void skip (unsigned long dist, FILE *fp); -int main(int argc, char **argv) { +int main(int argc, char **argv) +{ unsigned char buffer[INSN_MAX * 2], *p, *q; char outbuf[256]; char *pname = *argv; @@ -52,7 +53,7 @@ int main(int argc, char **argv) { while (--argc) { char *v, *vv, *p = *++argv; - if (*p == '-') { + if (*p == '-' && p[1]) { p++; while (*p) switch (tolower(*p)) { case 'a': /* auto or intelligent sync */ @@ -170,12 +171,16 @@ int main(int argc, char **argv) { return 0; } - fp = fopen(filename, "rb"); - if (!fp) { - fprintf(stderr, "%s: unable to open `%s': %s\n", - pname, filename, strerror(errno)); - return 1; - } + if (strcmp(filename, "-")) { + fp = fopen(filename, "rb"); + if (!fp) { + fprintf(stderr, "%s: unable to open `%s': %s\n", + pname, filename, strerror(errno)); + return 1; + } + } else + fp = stdin; + if (initskip > 0) skip (initskip, fp); @@ -191,9 +196,12 @@ int main(int argc, char **argv) { unsigned long to_read = buffer+sizeof(buffer)-p; if (to_read > nextsync-offset-(p-q)) to_read = nextsync-offset-(p-q); - lenread = fread (p, 1, to_read, fp); - if (lenread == 0) - eof = TRUE; /* help along systems with bad feof */ + if (to_read) { + lenread = fread (p, 1, to_read, fp); + if (lenread == 0) + eof = TRUE; /* help along systems with bad feof */ + } else + lenread = 0; p += lenread; if (offset == nextsync) { if (synclen) { @@ -222,12 +230,16 @@ int main(int argc, char **argv) { q = buffer; } } while (lenread > 0 || !(eof || feof(fp))); - fclose (fp); + + if (fp != stdin) + fclose (fp); + return 0; } static void output_ins (unsigned long offset, unsigned char *data, - int datalen, char *insn) { + int datalen, char *insn) +{ int bytes; printf("%08lX ", offset); @@ -256,7 +268,8 @@ static void output_ins (unsigned long offset, unsigned char *data, * Skip a certain amount of data in a file, either by seeking if * possible, or if that fails then by reading and discarding. */ -static void skip (unsigned long dist, FILE *fp) { +static void skip (unsigned long dist, FILE *fp) +{ char buffer[256]; /* should fit on most stacks :-) */ /* diff --git a/outaout.c b/outaout.c index e4c7610c..b82109a9 100644 --- a/outaout.c +++ b/outaout.c @@ -116,7 +116,8 @@ static long aout_gotpc_sect, aout_gotoff_sect; static long aout_got_sect, aout_plt_sect; static long aout_sym_sect; -static void aoutg_init(FILE *fp, efunc errfunc, ldfunc ldef, evalfunc eval) { +static void aoutg_init(FILE *fp, efunc errfunc, ldfunc ldef, evalfunc eval) +{ aoutfp = fp; error = errfunc; evaluate = eval; @@ -140,7 +141,8 @@ static void aoutg_init(FILE *fp, efunc errfunc, ldfunc ldef, evalfunc eval) { #ifdef OF_AOUT -static void aout_init(FILE *fp, efunc errfunc, ldfunc ldef, evalfunc eval) { +static void aout_init(FILE *fp, efunc errfunc, ldfunc ldef, evalfunc eval) +{ bsd = FALSE; aoutg_init (fp, errfunc, ldef, eval); @@ -154,7 +156,8 @@ static void aout_init(FILE *fp, efunc errfunc, ldfunc ldef, evalfunc eval) { extern struct ofmt of_aoutb; -static void aoutb_init(FILE *fp, efunc errfunc, ldfunc ldef, evalfunc eval) { +static void aoutb_init(FILE *fp, efunc errfunc, ldfunc ldef, evalfunc eval) +{ bsd = TRUE; aoutg_init (fp, errfunc, ldef, eval); @@ -174,9 +177,12 @@ static void aoutb_init(FILE *fp, efunc errfunc, ldfunc ldef, evalfunc eval) { #endif -static void aout_cleanup(void) { +static void aout_cleanup(int debuginfo) +{ struct Reloc *r; + (void) debuginfo; + aout_pad_sections(); aout_fixup_relocs(&stext); aout_fixup_relocs(&sdata); @@ -199,7 +205,8 @@ static void aout_cleanup(void) { saa_free (strs); } -static long aout_section_names (char *name, int pass, int *bits) { +static long aout_section_names (char *name, int pass, int *bits) +{ /* * Default to 32 bits. */ @@ -220,7 +227,8 @@ static long aout_section_names (char *name, int pass, int *bits) { } static void aout_deflabel (char *name, long segment, long offset, - int is_global, char *special) { + int is_global, char *special) +{ int pos = strslen+4; struct Symbol *sym; int special_used = FALSE; @@ -384,7 +392,8 @@ static void aout_deflabel (char *name, long segment, long offset, } static void aout_add_reloc (struct Section *sect, long segment, - int reltype, int bytes) { + int reltype, int bytes) +{ struct Reloc *r; r = *sect->tail = nasm_malloc(sizeof(struct Reloc)); @@ -429,7 +438,8 @@ static void aout_add_reloc (struct Section *sect, long segment, */ static long aout_add_gsym_reloc (struct Section *sect, long segment, long offset, - int type, int bytes, int exact) { + int type, int bytes, int exact) +{ struct Symbol *sym, *sm, *shead; struct Reloc *r; @@ -500,7 +510,8 @@ static long aout_add_gsym_reloc (struct Section *sect, * offset from the `asym' symbol rather than the section. */ static long aout_add_gotoff_reloc (struct Section *sect, long segment, - long offset, int bytes) { + long offset, int bytes) +{ struct Reloc *r; struct Symbol *asym; @@ -534,7 +545,8 @@ static long aout_add_gotoff_reloc (struct Section *sect, long segment, } static void aout_out (long segto, void *data, unsigned long type, - long segment, long wrt) { + long segment, long wrt) +{ struct Section *s; long realbytes = type & OUT_SIZMASK; long addr; @@ -695,7 +707,8 @@ static void aout_out (long segto, void *data, unsigned long type, } } -static void aout_pad_sections(void) { +static void aout_pad_sections(void) +{ static unsigned char pad[] = { 0x90, 0x90, 0x90, 0x90 }; /* * Pad each of the text and data sections with NOPs until their @@ -716,7 +729,8 @@ static void aout_pad_sections(void) { * the relocation table, _after_ the final size of each section is * known, and fix up the relocations pointed to. */ -static void aout_fixup_relocs(struct Section *sect) { +static void aout_fixup_relocs(struct Section *sect) +{ struct Reloc *r; saa_rewind (sect->data); @@ -748,7 +762,8 @@ static void aout_fixup_relocs(struct Section *sect) { } } -static void aout_write(void) { +static void aout_write(void) +{ /* * Emit the a.out header. */ @@ -786,7 +801,8 @@ static void aout_write(void) { saa_fpwrite (strs, aoutfp); } -static void aout_write_relocs (struct Reloc *r) { +static void aout_write_relocs (struct Reloc *r) +{ while (r) { unsigned long word2; @@ -805,7 +821,8 @@ static void aout_write_relocs (struct Reloc *r) { } } -static void aout_write_syms (void) { +static void aout_write_syms (void) +{ int i; saa_rewind (syms); @@ -835,28 +852,38 @@ static void aout_write_syms (void) { } static void aout_sect_write (struct Section *sect, - unsigned char *data, unsigned long len) { + unsigned char *data, unsigned long len) +{ saa_wbytes (sect->data, data, len); sect->len += len; } -static long aout_segbase (long segment) { +static long aout_segbase (long segment) +{ return segment; } -static int aout_directive (char *directive, char *value, int pass) { +static int aout_directive (char *directive, char *value, int pass) +{ return 0; } -static void aout_filename (char *inname, char *outname, efunc error) { +static void aout_filename (char *inname, char *outname, efunc error) +{ standard_extension (inname, outname, ".o", error); } static char *aout_stdmac[] = { "%define __SECT__ [section .text]", + "%macro __NASM_CDecl__ 1", + "%endmacro", NULL }; +static int aout_set_info(enum geninfo type, char **val) +{ + return 0; +} #endif /* OF_AOUT || OF_AOUTB */ #ifdef OF_AOUT @@ -864,8 +891,12 @@ static char *aout_stdmac[] = { struct ofmt of_aout = { "Linux a.out object files", "aout", + NULL, + null_debug_arr, + &null_debug_form, aout_stdmac, aout_init, + aout_set_info, aout_out, aout_deflabel, aout_section_names, @@ -882,8 +913,12 @@ struct ofmt of_aout = { struct ofmt of_aoutb = { "NetBSD/FreeBSD a.out object files", "aoutb", + NULL, + null_debug_arr, + &null_debug_form, aout_stdmac, aoutb_init, + aout_set_info, aout_out, aout_deflabel, aout_section_names, diff --git a/outas86.c b/outas86.c index f214d866..eb02186b 100644 --- a/outas86.c +++ b/outas86.c @@ -80,7 +80,8 @@ static void as86_write_section (struct Section *, int); static int as86_add_string (char *name); static void as86_sect_write(struct Section *, unsigned char *, unsigned long); -static void as86_init(FILE *fp, efunc errfunc, ldfunc ldef, evalfunc eval) { +static void as86_init(FILE *fp, efunc errfunc, ldfunc ldef, evalfunc eval) +{ as86fp = fp; error = errfunc; (void) ldef; /* placate optimisers */ @@ -105,9 +106,12 @@ static void as86_init(FILE *fp, efunc errfunc, ldfunc ldef, evalfunc eval) { as86_add_string (as86_module); } -static void as86_cleanup(void) { +static void as86_cleanup(int debuginfo) +{ struct Piece *p; + (void) debuginfo; + as86_write(); fclose (as86fp); saa_free (stext.data); @@ -127,7 +131,8 @@ static void as86_cleanup(void) { saa_free (strs); } -static long as86_section_names (char *name, int pass, int *bits) { +static long as86_section_names (char *name, int pass, int *bits) +{ /* * Default is 16 bits. */ @@ -147,7 +152,8 @@ static long as86_section_names (char *name, int pass, int *bits) { return NO_SEG; } -static int as86_add_string (char *name) { +static int as86_add_string (char *name) +{ int pos = strslen; int length = strlen(name); @@ -158,7 +164,8 @@ static int as86_add_string (char *name) { } static void as86_deflabel (char *name, long segment, long offset, - int is_global, char *special) { + int is_global, char *special) +{ struct Symbol *sym; if (special) @@ -207,7 +214,8 @@ static void as86_deflabel (char *name, long segment, long offset, } static void as86_add_piece (struct Section *sect, int type, long offset, - long segment, long bytes, int relative) { + long segment, long bytes, int relative) +{ struct Piece *p; sect->len += bytes; @@ -237,7 +245,8 @@ static void as86_add_piece (struct Section *sect, int type, long offset, } static void as86_out (long segto, void *data, unsigned long type, - long segment, long wrt) { + long segment, long wrt) +{ struct Section *s; long realbytes = type & OUT_SIZMASK; long offset; @@ -339,7 +348,8 @@ static void as86_out (long segto, void *data, unsigned long type, } } -static void as86_write(void) { +static void as86_write(void) +{ int i; long symlen, seglen, segsize; @@ -430,7 +440,8 @@ static void as86_write(void) { fputc (0, as86fp); /* termination */ } -static void as86_set_rsize (int size) { +static void as86_set_rsize (int size) +{ if (as86_reloc_size != size) { switch (as86_reloc_size = size) { case 1: fputc (0x01, as86fp); break; @@ -441,7 +452,8 @@ static void as86_set_rsize (int size) { } } -static void as86_write_section (struct Section *sect, int index) { +static void as86_write_section (struct Section *sect, int index) +{ struct Piece *p; unsigned long s; long length; @@ -512,20 +524,24 @@ static void as86_write_section (struct Section *sect, int index) { } static void as86_sect_write (struct Section *sect, - unsigned char *data, unsigned long len) { + unsigned char *data, unsigned long len) +{ saa_wbytes (sect->data, data, len); sect->datalen += len; } -static long as86_segbase (long segment) { +static long as86_segbase (long segment) +{ return segment; } -static int as86_directive (char *directive, char *value, int pass) { +static int as86_directive (char *directive, char *value, int pass) +{ return 0; } -static void as86_filename (char *inname, char *outname, efunc error) { +static void as86_filename (char *inname, char *outname, efunc error) +{ char *p; if ( (p = strrchr (inname, '.')) != NULL) { @@ -539,16 +555,30 @@ static void as86_filename (char *inname, char *outname, efunc error) { static char *as86_stdmac[] = { "%define __SECT__ [section .text]", + "%macro __NASM_CDecl__ 1", + "%endmacro", NULL }; +static int as86_set_info(enum geninfo type, char **val) +{ + return 0; +} +void as86_linenumber (char *name, long segment, long offset, int is_main, + int lineno) +{ +} struct ofmt of_as86 = { "Linux as86 (bin86 version 0.3) object files", "as86", + NULL, + null_debug_arr, + &null_debug_form, as86_stdmac, as86_init, + as86_set_info, as86_out, - as86_deflabel, + as86_deflabel, as86_section_names, as86_segbase, as86_directive, diff --git a/outbin.c b/outbin.c index 3540739f..a3289cfc 100644 --- a/outbin.c +++ b/outbin.c @@ -42,7 +42,8 @@ static long data_align, bss_align; static long start_point; static void add_reloc (struct Section *s, long bytes, long secref, - long secrel) { + long secrel) +{ struct Reloc *r; r = *reloctail = nasm_malloc(sizeof(struct Reloc)); @@ -55,9 +56,12 @@ static void add_reloc (struct Section *s, long bytes, long secref, r->target = s; } -static void bin_init (FILE *afp, efunc errfunc, ldfunc ldef, evalfunc eval) { +static void bin_init (FILE *afp, efunc errfunc, ldfunc ldef, evalfunc eval) +{ fp = afp; + (void) eval; /* Don't warn that this parameter is unused */ + error = errfunc; (void) ldef; /* placate optimisers */ @@ -74,10 +78,13 @@ static void bin_init (FILE *afp, efunc errfunc, ldfunc ldef, evalfunc eval) { data_align = bss_align = 4; } -static void bin_cleanup (void) { +static void bin_cleanup (int debuginfo) +{ struct Reloc *r; long datapos, datagap, bsspos; + (void) debuginfo; + datapos = start_point + textsect.length; datapos = (datapos + data_align-1) & ~(data_align-1); datagap = datapos - (start_point + textsect.length); @@ -87,7 +94,8 @@ static void bin_cleanup (void) { saa_rewind (textsect.contents); saa_rewind (datasect.contents); - for (r = relocs; r; r = r->next) { + for (r = relocs; r; r = r->next) + { unsigned char *p, *q, mydata[4]; long l; @@ -141,7 +149,8 @@ static void bin_cleanup (void) { } static void bin_out (long segto, void *data, unsigned long type, - long segment, long wrt) { + long segment, long wrt) +{ unsigned char *p, mydata[4]; struct Section *s; long realbytes; @@ -221,8 +230,10 @@ static void bin_out (long segto, void *data, unsigned long type, s->length += type; } else bsslen += type; - } else if ((type & OUT_TYPMASK) == OUT_REL2ADR || - (type & OUT_TYPMASK) == OUT_REL4ADR) { + } + else if ((type & OUT_TYPMASK) == OUT_REL2ADR || + (type & OUT_TYPMASK) == OUT_REL4ADR) + { realbytes = ((type & OUT_TYPMASK) == OUT_REL4ADR ? 4 : 2); if (segment != NO_SEG && segment != textsect.index && @@ -251,7 +262,11 @@ static void bin_out (long segto, void *data, unsigned long type, } static void bin_deflabel (char *name, long segment, long offset, - int is_global, char *special) { + int is_global, char *special) +{ + + (void) segment; /* Don't warn that this parameter is unused */ + (void) offset; /* Don't warn that this parameter is unused */ if (special) error (ERR_NONFATAL, "binary format does not support any" @@ -268,11 +283,14 @@ static void bin_deflabel (char *name, long segment, long offset, } } -static long bin_secname (char *name, int pass, int *bits) { +static long bin_secname (char *name, int pass, int *bits) +{ int sec_index; long *sec_align; char *p; + (void) pass; /* Don't warn that this parameter is unused */ + /* * Default is 16 bits. */ @@ -318,13 +336,17 @@ static long bin_secname (char *name, int pass, int *bits) { return sec_index; } -static long bin_segbase (long segment) { +static long bin_segbase (long segment) +{ return segment; } -static int bin_directive (char *directive, char *value, int pass) { +static int bin_directive (char *directive, char *value, int pass) +{ int rn_error; + (void) pass; /* Don't warn that this parameter is unused */ + if (!strcmp(directive, "org")) { start_point = readnum (value, &rn_error); if (rn_error) @@ -334,7 +356,8 @@ static int bin_directive (char *directive, char *value, int pass) { return 0; } -static void bin_filename (char *inname, char *outname, efunc error) { +static void bin_filename (char *inname, char *outname, efunc error) +{ standard_extension (inname, outname, "", error); } @@ -343,14 +366,24 @@ static char *bin_stdmac[] = { "%imacro org 1+.nolist", "[org %1]", "%endmacro", + "%macro __NASM_CDecl__ 1", + "%endmacro", NULL }; +static int bin_set_info(enum geninfo type, char **val) +{ + return 0; +} struct ofmt of_bin = { "flat-form binary files (e.g. DOS .COM, .SYS)", "bin", + NULL, + null_debug_arr, + &null_debug_form, bin_stdmac, bin_init, + bin_set_info, bin_out, bin_deflabel, bin_secname, diff --git a/outcoff.c b/outcoff.c index 09e886ce..f546a8e0 100644 --- a/outcoff.c +++ b/outcoff.c @@ -127,21 +127,24 @@ static void coff_section_header (char *, long, long, long, long, int, long); static void coff_write_relocs (struct Section *); static void coff_write_symbols (void); -static void coff_win32_init(FILE *fp, efunc errfunc, - ldfunc ldef, evalfunc eval) { +static void coff_win32_init(FILE *fp, efunc errfunc, + ldfunc ldef, evalfunc eval) +{ win32 = TRUE; (void) ldef; /* placate optimisers */ coff_gen_init(fp, errfunc); } -static void coff_std_init(FILE *fp, efunc errfunc, - ldfunc ldef, evalfunc eval) { +static void coff_std_init(FILE *fp, efunc errfunc, ldfunc ldef, evalfunc eval) +{ win32 = FALSE; (void) ldef; /* placate optimisers */ coff_gen_init(fp, errfunc); } -static void coff_gen_init(FILE *fp, efunc errfunc) { +static void coff_gen_init(FILE *fp, efunc errfunc) +{ + coffp = fp; error = errfunc; sects = NULL; @@ -155,10 +158,13 @@ static void coff_gen_init(FILE *fp, efunc errfunc) { def_seg = seg_alloc(); } -static void coff_cleanup(void) { +static void coff_cleanup(int debuginfo) +{ struct Reloc *r; int i; + (void) debuginfo; + coff_write(); fclose (coffp); for (i=0; ihead = sects[i]->head->next; nasm_free (r); } + nasm_free (sects[i]); } nasm_free (sects); saa_free (syms); @@ -177,7 +184,8 @@ static void coff_cleanup(void) { saa_free (strs); } -static int coff_make_section (char *name, unsigned long flags) { +static int coff_make_section (char *name, unsigned long flags) +{ struct Section *s; s = nasm_malloc (sizeof(*s)); @@ -205,7 +213,8 @@ static int coff_make_section (char *name, unsigned long flags) { return nsects-1; } -static long coff_section_names (char *name, int pass, int *bits) { +static long coff_section_names (char *name, int pass, int *bits) +{ char *p; unsigned long flags, align_and = ~0L, align_or = 0L; int i; @@ -225,7 +234,7 @@ static long coff_section_names (char *name, int pass, int *bits) { if (strlen(name) > 8) { error (ERR_WARNING, "COFF section names limited to 8 characters:" " truncating"); - p[8] = '\0'; + name[8] = '\0'; } flags = 0; @@ -306,7 +315,8 @@ static long coff_section_names (char *name, int pass, int *bits) { } static void coff_deflabel (char *name, long segment, long offset, - int is_global, char *special) { + int is_global, char *special) +{ int pos = strslen+4; struct Symbol *sym; @@ -363,7 +373,8 @@ static void coff_deflabel (char *name, long segment, long offset, } static long coff_add_reloc (struct Section *sect, long segment, - int relative) { + int relative) +{ struct Reloc *r; r = *sect->tail = nasm_malloc(sizeof(struct Reloc)); @@ -399,7 +410,8 @@ static long coff_add_reloc (struct Section *sect, long segment, } static void coff_out (long segto, void *data, unsigned long type, - long segment, long wrt) { + long segment, long wrt) +{ struct Section *s; long realbytes = type & OUT_SIZMASK; unsigned char mydata[4], *p; @@ -506,16 +518,19 @@ static void coff_out (long segto, void *data, unsigned long type, } static void coff_sect_write (struct Section *sect, - unsigned char *data, unsigned long len) { + unsigned char *data, unsigned long len) +{ saa_wbytes (sect->data, data, len); sect->len += len; } -static int coff_directives (char *directive, char *value, int pass) { +static int coff_directives (char *directive, char *value, int pass) +{ return 0; } -static void coff_write (void) { +static void coff_write (void) +{ long pos, sympos, vsize; int i; @@ -579,7 +594,8 @@ static void coff_write (void) { static void coff_section_header (char *name, long vsize, long datalen, long datapos, - long relpos, int nrelocs, long flags) { + long relpos, int nrelocs, long flags) +{ char padname[8]; memset (padname, 0, 8); @@ -596,7 +612,8 @@ static void coff_section_header (char *name, long vsize, fwritelong (flags, coffp); } -static void coff_write_relocs (struct Section *s) { +static void coff_write_relocs (struct Section *s) +{ struct Reloc *r; for (r = s->head; r; r = r->next) { @@ -615,7 +632,8 @@ static void coff_write_relocs (struct Section *s) { } static void coff_symbol (char *name, long strpos, long value, - int section, int type, int aux) { + int section, int type, int aux) +{ char padname[8]; if (name) { @@ -633,7 +651,8 @@ static void coff_symbol (char *name, long strpos, long value, fputc (aux, coffp); } -static void coff_write_symbols (void) { +static void coff_write_symbols (void) +{ char filename[18]; int i; @@ -674,34 +693,47 @@ static void coff_write_symbols (void) { } } -static long coff_segbase (long segment) { +static long coff_segbase (long segment) +{ return segment; } -static void coff_std_filename (char *inname, char *outname, efunc error) { +static void coff_std_filename (char *inname, char *outname, efunc error) +{ strcpy(coff_infile, inname); standard_extension (inname, outname, ".o", error); } -static void coff_win32_filename (char *inname, char *outname, efunc error) { +static void coff_win32_filename (char *inname, char *outname, efunc error) +{ strcpy(coff_infile, inname); standard_extension (inname, outname, ".obj", error); } -#endif /* defined(OF_COFF) || defined(OF_WIN32) */ - static char *coff_stdmac[] = { "%define __SECT__ [section .text]", + "%macro __NASM_CDecl__ 1", + "%endmacro", NULL }; +static int coff_set_info(enum geninfo type, char **val) +{ + return 0; +} +#endif /* defined(OF_COFF) || defined(OF_WIN32) */ + #ifdef OF_COFF struct ofmt of_coff = { "COFF (i386) object files (e.g. DJGPP for DOS)", "coff", + NULL, + null_debug_arr, + &null_debug_form, coff_stdmac, coff_std_init, + coff_set_info, coff_out, coff_deflabel, coff_section_names, @@ -718,8 +750,12 @@ struct ofmt of_coff = { struct ofmt of_win32 = { "Microsoft Win32 (i386) object files", "win32", + NULL, + null_debug_arr, + &null_debug_form, coff_stdmac, coff_win32_init, + coff_set_info, coff_out, coff_deflabel, coff_section_names, diff --git a/outdbg.c b/outdbg.c index b3d23a04..723e372d 100644 --- a/outdbg.c +++ b/outdbg.c @@ -27,17 +27,24 @@ struct Section { FILE *dbgf; efunc dbgef; +struct ofmt of_dbg; static void dbg_init(FILE *fp, efunc errfunc, ldfunc ldef, evalfunc eval) { + (void) eval; + dbgf = fp; dbgef = errfunc; dbgsect = NULL; (void) ldef; fprintf(fp,"NASM Output format debug dump\n"); + of_dbg.current_dfmt->init(&of_dbg,0,fp,errfunc); + } -static void dbg_cleanup(void) +static void dbg_cleanup(int debuginfo) { + (void) debuginfo; + of_dbg.current_dfmt->cleanup(); while (dbgsect) { struct Section *tmp = dbgsect; dbgsect = dbgsect->next; @@ -84,7 +91,8 @@ static long dbg_section_names (char *name, int pass, int *bits) } static void dbg_deflabel (char *name, long segment, long offset, - int is_global, char *special) { + int is_global, char *special) +{ fprintf(dbgf,"deflabel %s := %08lx:%08lx %s (%d)%s%s\n", name, segment, offset, is_global == 2 ? "common" : is_global ? "global" : "local", @@ -93,7 +101,8 @@ static void dbg_deflabel (char *name, long segment, long offset, } static void dbg_out (long segto, void *data, unsigned long type, - long segment, long wrt) { + long segment, long wrt) +{ long realbytes = type & OUT_SIZMASK; long ldata; int id; @@ -135,25 +144,99 @@ static void dbg_out (long segto, void *data, unsigned long type, } } -static long dbg_segbase(long segment) { +static long dbg_segbase(long segment) +{ return segment; } -static int dbg_directive (char *directive, char *value, int pass) { +static int dbg_directive (char *directive, char *value, int pass) +{ fprintf(dbgf, "directive [%s] value [%s] (pass %d)\n", directive, value, pass); return 1; } -static void dbg_filename (char *inname, char *outname, efunc error) { +static void dbg_filename (char *inname, char *outname, efunc error) +{ standard_extension (inname, outname, ".dbg", error); } +static int dbg_set_info(enum geninfo type, char **val) +{ + (void) type; + (void) val; + return 0; +} +char *types[] = { + "unknown", "label", "byte","word","dword","float","qword","tbyte" +}; +void dbgdbg_init(struct ofmt * of, void * id, FILE * fp, efunc error) +{ + (void) of; + (void) id; + (void) fp; + (void) error; + fprintf(fp," With debug info\n"); +} +static void dbgdbg_cleanup(void) +{ +} + +static void dbgdbg_linnum (const char *lnfname, long lineno, long segto) +{ + fprintf(dbgf,"dbglinenum %s(%ld) := %08lx\n", + lnfname,lineno,segto); +} +static void dbgdbg_deflabel (char *name, long segment, + long offset, int is_global, char *special) +{ + fprintf(dbgf,"dbglabel %s := %08lx:%08lx %s (%d)%s%s\n", + name, + segment, offset, + is_global == 2 ? "common" : is_global ? "global" : "local", + is_global, + special ? ": " : "", special); +} +static void dbgdbg_define(const char *type, const char *params) +{ + fprintf(dbgf,"dbgdirective [%s] value [%s]\n",type, params); +} +static void dbgdbg_output (int output_type, void *param) +{ + (void) output_type; + (void) param; +} +static void dbgdbg_typevalue(long type) +{ + fprintf(dbgf,"new type: %s(%lX)\n", + types[TYM_TYPE(type) >> 3], TYM_ELEMENTS(type) ); +} +static struct dfmt debug_debug_form = { + "Trace of all info passed to debug stage", + "debug", + dbgdbg_init, + dbgdbg_linnum, + dbgdbg_deflabel, + dbgdbg_define, + dbgdbg_typevalue, + dbgdbg_output, + dbgdbg_cleanup, +}; + +static struct dfmt *debug_debug_arr[3] = { + &debug_debug_form, + &null_debug_form, + NULL +}; struct ofmt of_dbg = { "Trace of all info passed to output stage", "dbg", NULL, + debug_debug_arr, + &null_debug_form, + NULL, dbg_init, + dbg_set_info, dbg_out, dbg_deflabel, dbg_section_names, diff --git a/outelf.c b/outelf.c index 6f6c1be6..0b77c017 100644 --- a/outelf.c +++ b/outelf.c @@ -117,7 +117,7 @@ static struct ELF_SECTDATA { void *data; long len; int is_saa; -} elf_sects[ELF_MAX_SECTIONS]; +} *elf_sects; static int elf_nsect; static long elf_foffs; @@ -139,7 +139,8 @@ static long elf_gotpc_sect, elf_gotoff_sect; static long elf_got_sect, elf_plt_sect; static long elf_sym_sect; -static void elf_init(FILE *fp, efunc errfunc, ldfunc ldef, evalfunc eval) { +static void elf_init(FILE *fp, efunc errfunc, ldfunc ldef, evalfunc eval) +{ elffp = fp; error = errfunc; evaluate = eval; @@ -173,10 +174,13 @@ static void elf_init(FILE *fp, efunc errfunc, ldfunc ldef, evalfunc eval) { def_seg = seg_alloc(); } -static void elf_cleanup(void) { +static void elf_cleanup(int debuginfo) +{ struct Reloc *r; int i; + (void) debuginfo; + elf_write(); fclose (elffp); for (i=0; i shstrtabsize) shstrtab = nasm_realloc (shstrtab, (shstrtabsize += SHSTR_DELTA)); @@ -205,7 +210,8 @@ static void add_sectname (char *firsthalf, char *secondhalf) { shstrtablen += len+1; } -static int elf_make_section (char *name, int type, int flags, int align) { +static int elf_make_section (char *name, int type, int flags, int align) +{ struct Section *s; s = nasm_malloc (sizeof(*s)); @@ -235,18 +241,18 @@ static int elf_make_section (char *name, int type, int flags, int align) { return nsects-1; } -static long elf_section_names (char *name, int pass, int *bits) { +static long elf_section_names (char *name, int pass, int *bits) +{ char *p; int flags_and, flags_or, type, align, i; /* * Default is 32 bits. */ - if (!name) + if (!name) { *bits = 32; - - if (!name) return def_seg; + } p = name; while (*p && !isspace(*p)) p++; @@ -334,7 +340,8 @@ static long elf_section_names (char *name, int pass, int *bits) { } static void elf_deflabel (char *name, long segment, long offset, - int is_global, char *special) { + int is_global, char *special) +{ int pos = strslen; struct Symbol *sym; int special_used = FALSE; @@ -439,9 +446,29 @@ static void elf_deflabel (char *name, long segment, long offset, sym->value = (sym->section == SHN_UNDEF ? 0 : offset); if (sym->type == SYM_GLOBAL) { + /* + * There's a problem here that needs fixing. + * If sym->section == SHN_ABS, then the first line of the + * else section causes a core dump, because its a reference + * beyond the end of the section array. + * This behaviour is exhibited by this code: + * GLOBAL crash_nasm + * crash_nasm equ 0 + * + * I'm not sure how to procede, because I haven't got the + * first clue about how ELF works, so I don't know what to + * do with it. Furthermore, I'm not sure what the rest of this + * section of code does. Help? + * + * For now, I'll see if doing absolutely nothing with it will + * work... + */ if (sym->section == SHN_UNDEF || sym->section == SHN_COMMON) + { bsym = raa_write (bsym, segment, nglobs); - else { + } + else if (sym->section != SHN_ABS) + { /* * This is a global symbol; so we must add it to the linked * list of global symbols in its section. We'll push it on @@ -505,7 +532,8 @@ static void elf_deflabel (char *name, long segment, long offset, } static void elf_add_reloc (struct Section *sect, long segment, - int type) { + int type) +{ struct Reloc *r; r = *sect->tail = nasm_malloc(sizeof(struct Reloc)); @@ -553,7 +581,8 @@ static void elf_add_reloc (struct Section *sect, long segment, */ static long elf_add_gsym_reloc (struct Section *sect, long segment, long offset, - int type, int exact) { + int type, int exact) +{ struct Reloc *r; struct Section *s; struct Symbol *sym, *sm; @@ -617,7 +646,8 @@ static long elf_add_gsym_reloc (struct Section *sect, } static void elf_out (long segto, void *data, unsigned long type, - long segment, long wrt) { + long segment, long wrt) +{ struct Section *s; long realbytes = type & OUT_SIZMASK; long addr; @@ -744,7 +774,8 @@ static void elf_out (long segto, void *data, unsigned long type, } } -static void elf_write(void) { +static void elf_write(void) +{ int nsections, align; char *p; int commlen; @@ -819,6 +850,7 @@ static void elf_write(void) { align = ((elf_foffs+SEG_ALIGN_1) & ~SEG_ALIGN_1) - elf_foffs; elf_foffs += align; elf_nsect = 0; + elf_sects = nasm_malloc(sizeof(*elf_sects) * (2 * nsects + 10)); elf_section_header (0, 0, 0, NULL, FALSE, 0L, 0, 0, 0, 0); /* SHN_UNDEF */ p = shstrtab+1; @@ -853,10 +885,12 @@ static void elf_write(void) { */ elf_write_sections(); + nasm_free (elf_sects); saa_free (symtab); } -static struct SAA *elf_build_symtab (long *len, long *local) { +static struct SAA *elf_build_symtab (long *len, long *local) +{ struct SAA *s = saa_init(1L); struct Symbol *sym; unsigned char entry[16], *p; @@ -968,7 +1002,8 @@ static struct SAA *elf_build_reltab (long *len, struct Reloc *r) { static void elf_section_header (int name, int type, int flags, void *data, int is_saa, long datalen, - int link, int info, int align, int eltsize) { + int link, int info, int align, int eltsize) +{ elf_sects[elf_nsect].data = data; elf_sects[elf_nsect].len = datalen; elf_sects[elf_nsect].is_saa = is_saa; @@ -988,7 +1023,8 @@ static void elf_section_header (int name, int type, int flags, fwritelong ((long)eltsize, elffp); } -static void elf_write_sections (void) { +static void elf_write_sections (void) +{ int i; for (i = 0; i < elf_nsect; i++) if (elf_sects[i].data) { @@ -1004,34 +1040,49 @@ static void elf_write_sections (void) { } static void elf_sect_write (struct Section *sect, - unsigned char *data, unsigned long len) { + unsigned char *data, unsigned long len) +{ saa_wbytes (sect->data, data, len); sect->len += len; } -static long elf_segbase (long segment) { +static long elf_segbase (long segment) +{ return segment; } -static int elf_directive (char *directive, char *value, int pass) { +static int elf_directive (char *directive, char *value, int pass) +{ return 0; } -static void elf_filename (char *inname, char *outname, efunc error) { +static void elf_filename (char *inname, char *outname, efunc error) +{ strcpy(elf_module, inname); standard_extension (inname, outname, ".o", error); } static char *elf_stdmac[] = { "%define __SECT__ [section .text]", + "%macro __NASM_CDecl__ 1", + "%define $_%1 $%1", + "%endmacro", NULL }; +static int elf_set_info(enum geninfo type, char **val) +{ + return 0; +} struct ofmt of_elf = { "ELF32 (i386) object files (e.g. Linux)", "elf", + NULL, + null_debug_arr, + &null_debug_form, elf_stdmac, elf_init, + elf_set_info, elf_out, elf_deflabel, elf_section_names, diff --git a/outform.c b/outform.c index 09202de3..c8b95323 100644 --- a/outform.c +++ b/outform.c @@ -11,9 +11,10 @@ #include #include + +#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; ishortname, drivers[i]->fullname); } +void dfmt_list(struct ofmt *ofmt, FILE *fp) +{ + struct dfmt ** drivers = ofmt->debug_formats; + while (*drivers) { + fprintf(fp, " %c %-10s%s\n", + drivers[0] == ofmt->current_dfmt ? '*' : ' ', + drivers[0]->shortname, + drivers[0]->fullname); + drivers++; + } +} +struct ofmt *ofmt_register (efunc error) { + for (ndrivers=0; drivers[ndrivers] != NULL; ndrivers++); + + if (ndrivers==0) + { + error(ERR_PANIC | ERR_NOFILE, + "No output drivers given at compile time"); + } -void ofmt_register (struct ofmt *info) { - drivers[ndrivers++] = info; + return (&OF_DEFAULT); } diff --git a/outform.h b/outform.h index e23f3c79..2e7a32d0 100644 --- a/outform.h +++ b/outform.h @@ -20,6 +20,9 @@ * OF_UNIX -- ensure that 'aout', 'aoutb', 'coff', 'elf' are in. * OF_OTHERS -- ensure that 'bin', 'as86' & 'rdf' are in. * OF_ALL -- ensure that all formats are included. + * note that this doesn't include 'dbg', which is + * only really useful if you're doing development + * work on NASM. Define OF_DBG if you want this. * * OF_DEFAULT=of_name -- ensure that 'name' is the default format. * @@ -35,12 +38,6 @@ #include "nasm.h" -#define MAX_OUTPUT_FORMATS 16 - -struct ofmt *ofmt_find(char *); -void ofmt_list(struct ofmt *, FILE *); -void ofmt_register (struct ofmt *); - /* -------------- USER MODIFIABLE PART ---------------- */ /* @@ -60,7 +57,7 @@ void ofmt_register (struct ofmt *); /* ====configurable info begins here==== */ /* formats configurable: - * bin,obj,elf,aout,aoutb,coff,win32,as86,rdf */ + * bin,obj,elf,aout,aoutb,coff,win32,as86,rdf,rdf2 */ /* process options... */ @@ -95,8 +92,8 @@ void ofmt_register (struct ofmt *); #ifndef OF_AS86 #define OF_AS86 #endif -#ifndef OF_RDF -#define OF_RDF +#ifndef OF_RDF2 +#define OF_RDF2 #endif #endif /* OF_ALL */ @@ -138,6 +135,9 @@ void ofmt_register (struct ofmt *); #ifndef OF_RDF #define OF_RDF #endif +#ifndef OF_RDF2 +#define OF_RDF2 +#endif #endif /* finally... override any format specifically specifed to be off */ @@ -168,9 +168,75 @@ void ofmt_register (struct ofmt *); #ifdef OF_NO_RDF #undef OF_RDF #endif +#ifdef OF_NO_RDF2 +#undef OF_RDF +#endif #ifndef OF_DEFAULT #define OF_DEFAULT of_bin #endif +#ifdef BUILD_DRIVERS_ARRAY /* only if included from outform.c */ + +/* pull in the externs for the different formats, then make the *drivers + * array based on the above defines */ + +extern struct ofmt of_bin; +extern struct ofmt of_aout; +extern struct ofmt of_aoutb; +extern struct ofmt of_coff; +extern struct ofmt of_elf; +extern struct ofmt of_as86; +extern struct ofmt of_obj; +extern struct ofmt of_win32; +extern struct ofmt of_rdf; +extern struct ofmt of_rdf2; +extern struct ofmt of_dbg; + +struct ofmt *drivers[]={ +#ifdef OF_BIN + &of_bin, +#endif +#ifdef OF_AOUT + &of_aout, +#endif +#ifdef OF_AOUTB + &of_aoutb, +#endif +#ifdef OF_COFF + &of_coff, +#endif +#ifdef OF_ELF + &of_elf, +#endif +#ifdef OF_AS86 + &of_as86, +#endif +#ifdef OF_OBJ + &of_obj, +#endif +#ifdef OF_WIN32 + &of_win32, +#endif +#ifdef OF_RDF + &of_rdf, +#endif +#ifdef OF_RDF2 + &of_rdf2, +#endif +#ifdef OF_DBG + &of_dbg, +#endif + + NULL +}; + +#endif /* BUILD_DRIVERS_ARRAY */ + +struct ofmt *ofmt_find(char *); +struct dfmt *dfmt_find(struct ofmt *, char *); +void ofmt_list(struct ofmt *, FILE *); +void dfmt_list(struct ofmt *ofmt, FILE *fp); +struct ofmt *ofmt_register (efunc error); + #endif /* NASM_OUTFORM_H */ diff --git a/outforms.h b/outforms.h new file mode 100644 index 00000000..2afbbe27 --- /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 f54d2976..0a7544d6 100644 --- a/outobj.c +++ b/outobj.c @@ -1,5 +1,5 @@ /* outobj.c output routines for the Netwide Assembler to produce - * Microsoft 16-bit .OBJ object files + * .OBJ object files * * The Netwide Assembler is copyright (C) 1996 Simon Tatham and * Julian Hall. All rights reserved. The software is @@ -18,8 +18,446 @@ #ifdef OF_OBJ +/* + * outobj.c is divided into two sections. The first section is low level + * routines for creating obj records; It has nearly zero NASM specific + * code. The second section is high level routines for processing calls and + * data structures from the rest of NASM into obj format. + * + * It should be easy (though not zero work) to lift the first section out for + * use as an obj file writer for some other assembler or compiler. + */ + +/* + * These routines are built around the ObjRecord data struture. An ObjRecord + * holds an object file record that may be under construction or complete. + * + * A major function of these routines is to support continuation of an obj + * record into the next record when the maximum record size is exceeded. The + * high level code does not need to worry about where the record breaks occur. + * It does need to do some minor extra steps to make the automatic continuation + * work. Those steps may be skipped for records where the high level knows no + * continuation could be required. + * + * 1) An ObjRecord is allocated and cleared by obj_new, or an existing ObjRecord + * is cleared by obj_clear. + * + * 2) The caller should fill in .type. + * + * 3) If the record is continuable and there is processing that must be done at + * the start of each record then the caller should fill in .ori with the + * address of the record initializer routine. + * + * 4) If the record is continuable and it should be saved (rather than emitted + * immediately) as each record is done, the caller should set .up to be a + * pointer to a location in which the caller keeps the master pointer to the + * ObjRecord. When the record is continued, the obj_bump routine will then + * allocate a new ObjRecord structure and update the master pointer. + * + * 5) If the .ori field was used then the caller should fill in the .parm with + * any data required by the initializer. + * + * 6) The caller uses the routines: obj_byte, obj_word, obj_rword, obj_dword, + * obj_x, obj_index, obj_value and obj_name to fill in the various kinds of + * data required for this record. + * + * 7) If the record is continuable, the caller should call obj_commit at each + * point where breaking the record is permitted. + * + * 8) To write out the record, the caller should call obj_emit2. If the + * caller has called obj_commit for all data written then he can get slightly + * faster code by calling obj_emit instead of obj_emit2. + * + * Most of these routines return an ObjRecord pointer. This will be the input + * pointer most of the time and will be the new location if the ObjRecord + * moved as a result of the call. The caller may ignore the return value in + * three cases: It is a "Never Reallocates" routine; or The caller knows + * continuation is not possible; or The caller uses the master pointer for the + * next operation. + */ + +#define RECORD_MAX 1024 /* maximum size of _any_ record */ +#define OBJ_PARMS 3 /* maximum .parm used by any .ori routine */ + +#define FIX_08_LOW 0x8000 /* location type for various fixup subrecords */ +#define FIX_16_OFFSET 0x8400 +#define FIX_16_SELECTOR 0x8800 +#define FIX_32_POINTER 0x8C00 +#define FIX_08_HIGH 0x9000 +#define FIX_32_OFFSET 0xA400 +#define FIX_48_POINTER 0xAC00 + +enum RecordID { /* record ID codes */ + + THEADR = 0x80, /* module header */ + COMENT = 0x88, /* comment record */ + + LINNUM = 0x94, /* line number record */ + LNAMES = 0x96, /* list of names */ + + SEGDEF = 0x98, /* segment definition */ + GRPDEF = 0x9A, /* group definition */ + EXTDEF = 0x8C, /* external definition */ + PUBDEF = 0x90, /* public definition */ + COMDEF = 0xB0, /* common definition */ + + LEDATA = 0xA0, /* logical enumerated data */ + FIXUPP = 0x9C, /* fixups (relocations) */ + + MODEND = 0x8A /* module end */ +}; + +enum ComentID { /* ID codes for comment records */ + + dEXTENDED = 0xA1, /* tells that we are using translator-specific extensions */ + dLINKPASS = 0xA2, /* link pass 2 marker */ + dTYPEDEF = 0xE3, /* define a type */ + dSYM = 0xE6, /* symbol debug record */ + dFILNAME = 0xE8, /* file name record */ + dCOMPDEF = 0xEA /* compiler type info */ + +}; + +typedef struct ObjRecord ObjRecord; +typedef void ORI(ObjRecord *orp); + +struct ObjRecord { + ORI *ori; /* Initialization routine */ + int used; /* Current data size */ + int committed; /* Data size at last boundary */ + int x_size; /* (see obj_x) */ + unsigned int type; /* Record type */ + ObjRecord *child; /* Associated record below this one */ + ObjRecord **up; /* Master pointer to this ObjRecord */ + ObjRecord *back; /* Previous part of this record */ + unsigned long parm[OBJ_PARMS]; /* Parameters for ori routine */ + unsigned char buf[RECORD_MAX]; +}; + +static void obj_fwrite(ObjRecord *orp); +static void ori_ledata(ObjRecord *orp); +static void ori_pubdef(ObjRecord *orp); +static void ori_null(ObjRecord *orp); +static ObjRecord *obj_commit(ObjRecord *orp); +static void obj_write_fixup (ObjRecord *orp, int bytes, + int segrel, long seg, long wrt); + +static int obj_uppercase; /* Flag: all names in uppercase */ + +/* + * Clear an ObjRecord structure. (Never reallocates). + * To simplify reuse of ObjRecord's, .type, .ori and .parm are not cleared. + */ +static ObjRecord *obj_clear(ObjRecord *orp) +{ + orp->used = 0; + orp->committed = 0; + orp->x_size = 0; + orp->child = NULL; + orp->up = NULL; + orp->back = NULL; + return (orp); +} + +/* + * Emit an ObjRecord structure. (Never reallocates). + * The record is written out preceeded (recursively) by its previous part (if + * any) and followed (recursively) by its child (if any). + * The previous part and the child are freed. The main ObjRecord is cleared, + * not freed. + */ +static ObjRecord *obj_emit(ObjRecord *orp) +{ + if (orp->back) { + obj_emit(orp->back); + nasm_free(orp->back); + } + + if (orp->committed) + obj_fwrite(orp); + + if (orp->child) { + obj_emit(orp->child); + nasm_free(orp->child); + } + + return (obj_clear(orp)); +} + +/* + * Commit and Emit a record. (Never reallocates). + */ +static ObjRecord *obj_emit2(ObjRecord *orp) +{ + obj_commit(orp); + return (obj_emit(orp)); +} + +/* + * Allocate and clear a new ObjRecord; Also sets .ori to ori_null + */ +static ObjRecord *obj_new(void) +{ + ObjRecord *orp; + + orp = obj_clear( nasm_malloc(sizeof(ObjRecord)) ); + orp->ori = ori_null; + return (orp); +} + +/* + * Advance to the next record because the existing one is full or its x_size + * is incompatible. + * Any uncommited data is moved into the next record. + */ +static ObjRecord *obj_bump(ObjRecord *orp) +{ + ObjRecord *nxt; + int used = orp->used; + int committed = orp->committed; + + if (orp->up) { + *orp->up = nxt = obj_new(); + nxt->ori = orp->ori; + nxt->type = orp->type; + nxt->up = orp->up; + nxt->back = orp; + memcpy( nxt->parm, orp->parm, sizeof(orp->parm)); + } else + nxt = obj_emit(orp); + + used -= committed; + if (used) { + nxt->committed = 1; + nxt->ori (nxt); + nxt->committed = nxt->used; + memcpy( nxt->buf + nxt->committed, orp->buf + committed, used); + nxt->used = nxt->committed + used; + } + + return (nxt); +} + +/* + * Advance to the next record if necessary to allow the next field to fit. + */ +static ObjRecord *obj_check(ObjRecord *orp, int size) +{ + if (orp->used + size > RECORD_MAX) + orp = obj_bump(orp); + + if (!orp->committed) { + orp->committed = 1; + orp->ori (orp); + orp->committed = orp->used; + } + + return (orp); +} + +/* + * All data written so far is commited to the current record (won't be moved to + * the next record in case of continuation). + */ +static ObjRecord *obj_commit(ObjRecord *orp) +{ + orp->committed = orp->used; + return (orp); +} + +/* + * Write a byte + */ +static ObjRecord *obj_byte(ObjRecord *orp, unsigned char val) +{ + orp = obj_check(orp, 1); + orp->buf[orp->used] = val; + orp->used++; + return (orp); +} + +/* + * Write a word + */ +static ObjRecord *obj_word(ObjRecord *orp, unsigned int val) +{ + orp = obj_check(orp, 2); + orp->buf[orp->used] = val; + orp->buf[orp->used+1] = val >> 8; + orp->used += 2; + return (orp); +} + +/* + * Write a reversed word + */ +static ObjRecord *obj_rword(ObjRecord *orp, unsigned int val) +{ + orp = obj_check(orp, 2); + orp->buf[orp->used] = val >> 8; + orp->buf[orp->used+1] = val; + orp->used += 2; + return (orp); +} + +/* + * Write a dword + */ +static ObjRecord *obj_dword(ObjRecord *orp, unsigned long val) +{ + orp = obj_check(orp, 4); + orp->buf[orp->used] = val; + orp->buf[orp->used+1] = val >> 8; + orp->buf[orp->used+2] = val >> 16; + orp->buf[orp->used+3] = val >> 24; + orp->used += 4; + return (orp); +} + +/* + * All fields of "size x" in one obj record must be the same size (either 16 + * bits or 32 bits). There is a one bit flag in each record which specifies + * which. + * This routine is used to force the current record to have the desired + * x_size. x_size is normally automatic (using obj_x), so that this + * routine should be used outside obj_x, only to provide compatibility with + * linkers that have bugs in their processing of the size bit. + */ + +static ObjRecord *obj_force(ObjRecord *orp, int x) +{ + if (orp->x_size == (x^48)) + orp = obj_bump(orp); + orp->x_size = x; + return (orp); +} + +/* + * This routine writes a field of size x. The caller does not need to worry at + * all about whether 16-bits or 32-bits are required. + */ +static ObjRecord *obj_x(ObjRecord *orp, unsigned long val) +{ + if (orp->type & 1) + orp->x_size = 32; + if (val > 0xFFFF) + orp = obj_force(orp, 32); + if (orp->x_size == 32) + return (obj_dword(orp, val)); + orp->x_size = 16; + return (obj_word(orp, val)); +} + +/* + * Writes an index + */ +static ObjRecord *obj_index(ObjRecord *orp, unsigned int val) +{ + if (val < 128) + return ( obj_byte(orp, val) ); + return (obj_word(orp, (val>>8) | (val<<8) | 0x80)); +} + +/* + * Writes a variable length value + */ +static ObjRecord *obj_value(ObjRecord *orp, unsigned long val) +{ + if (val <= 128) + return ( obj_byte(orp, val) ); + if (val <= 0xFFFF) { + orp = obj_byte(orp, 129); + return ( obj_word(orp, val) ); + } + if (val <= 0xFFFFFF) + return ( obj_dword(orp, (val<<8) + 132 ) ); + orp = obj_byte(orp, 136); + return ( obj_dword(orp, val) ); +} + +/* + * Writes a counted string + */ +static ObjRecord *obj_name(ObjRecord *orp, char *name) +{ + int len = strlen(name); + unsigned char *ptr; + + orp = obj_check(orp, len+1); + ptr = orp->buf + orp->used; + *ptr++ = len; + orp->used += len+1; + if (obj_uppercase) + while (--len >= 0) { + *ptr++ = toupper(*name); + name++; + } else + memcpy(ptr, name, len); + return (orp); +} + +/* + * Initializer for an LEDATA record. + * parm[0] = offset + * parm[1] = segment index + * During the use of a LEDATA ObjRecord, parm[0] is constantly updated to + * represent the offset that would be required if the record were split at the + * last commit point. + * parm[2] is a copy of parm[0] as it was when the current record was initted. + */ +static void ori_ledata(ObjRecord *orp) +{ + obj_index (orp, orp->parm[1]); + orp->parm[2] = orp->parm[0]; + obj_x (orp, orp->parm[0]); +} + +/* + * Initializer for a PUBDEF record. + * parm[0] = group index + * parm[1] = segment index + * parm[2] = frame (only used when both indexes are zero) + */ +static void ori_pubdef(ObjRecord *orp) +{ + obj_index (orp, orp->parm[0]); + obj_index (orp, orp->parm[1]); + if ( !(orp->parm[0] | orp->parm[1]) ) + obj_word (orp, orp->parm[2]); +} + +/* + * Initializer for a LINNUM record. + * parm[0] = group index + * parm[1] = segment index + */ +static void ori_linnum(ObjRecord *orp) +{ + obj_index (orp, orp->parm[0]); + obj_index (orp, orp->parm[1]); +} +/* + * Initializer for a local vars record. + */ +static void ori_local(ObjRecord *orp) +{ + obj_byte (orp, 0x40); + obj_byte (orp, dSYM); +} + +/* + * Null initializer for records that continue without any header info + */ +static void ori_null(ObjRecord *orp) +{ + (void) orp; /* Do nothing */ +} + +/* + * This concludes the low level section of outobj.c + */ + static char obj_infile[FILENAME_MAX]; -static int obj_uppercase; static efunc error; static evalfunc evaluate; @@ -27,24 +465,46 @@ static ldfunc deflabel; static FILE *ofp; static long first_seg; static int any_segs; +static int passtwo; +static int arrindex; -#define LEDATA_MAX 1024 /* maximum size of LEDATA record */ -#define RECORD_MAX 1024 /* maximum size of _any_ record */ #define GROUP_MAX 256 /* we won't _realistically_ have more * than this many segs in a group */ #define EXT_BLKSIZ 256 /* block size for externals list */ -static unsigned char record[RECORD_MAX], *recptr; - struct Segment; /* need to know these structs exist */ struct Group; +struct LineNumber { + struct LineNumber *next; + struct Segment *segment; + long offset; + long lineno; +}; + +static struct FileName { + struct FileName *next; + char *name; + struct LineNumber *lnhead, **lntail; + int index; +} *fnhead, **fntail; + +static struct Array { + struct Array *next; + unsigned size; + int basetype; +} *arrhead, **arrtail; + +#define ARRAYBOT 31 /* magic number for first array index */ + + static struct Public { struct Public *next; char *name; long offset; long segment; /* only if it's far-absolute */ -} *fpubhead, **fpubtail; + int type; /* only for local debug syms */ +} *fpubhead, **fpubtail, *last_defined; static struct External { struct External *next; @@ -78,7 +538,7 @@ static struct Segment { long index; /* the NASM segment id */ long obj_index; /* the OBJ-file segment index */ struct Group *grp; /* the group it belongs to */ - long currentpos; + unsigned long currentpos; long align; /* can be SEG_ABS + absolute addr */ enum { CMB_PRIVATE = 0, @@ -87,9 +547,10 @@ static struct Segment { CMB_COMMON = 6 } combine; long use32; /* is this segment 32-bit? */ - struct Public *pubhead, **pubtail; + struct Public *pubhead, **pubtail, *lochead, **loctail; char *name; char *segclass, *overlay; /* `class' is a C++ keyword :-) */ + ObjRecord *orp; } *seghead, **segtail, *obj_seg_needs_update; static struct Group { @@ -105,16 +566,6 @@ static struct Group { } segs[GROUP_MAX]; /* ...in this */ } *grphead, **grptail, *obj_grp_needs_update; -static struct ObjData { - struct ObjData *next; - int nonempty; - struct Segment *seg; - long startpos; - int letype, ftype; - unsigned char ledata[LEDATA_MAX], *lptr; - unsigned char fixupp[RECORD_MAX], *fptr; -} *datahead, *datacurr, **datatail; - static struct ImpDef { struct ImpDef *next; char *extname; @@ -138,46 +589,14 @@ static struct ExpDef { static long obj_entry_seg, obj_entry_ofs; -enum RecordID { /* record ID codes */ - - THEADR = 0x80, /* module header */ - COMENT = 0x88, /* comment record */ - - LNAMES = 0x96, /* list of names */ - - SEGDEF = 0x98, /* segment definition */ - GRPDEF = 0x9A, /* group definition */ - EXTDEF = 0x8C, /* external definition */ - PUBDEF = 0x90, /* public definition */ - COMDEF = 0xB0, /* common definition */ +struct ofmt of_obj; - LEDATA = 0xA0, /* logical enumerated data */ - FIXUPP = 0x9C, /* fixups (relocations) */ - - MODEND = 0x8A /* module end */ -}; - -extern struct ofmt of_obj; - -static long obj_ledata_space(struct Segment *); -static int obj_fixup_free(struct Segment *); -static void obj_ledata_new(struct Segment *); -static void obj_ledata_commit(void); -static void obj_write_fixup (struct ObjData *, int, int, long, long, long); static long obj_segment (char *, int, int *); -static void obj_write_file(void); -static unsigned char *obj_write_data(unsigned char *, unsigned char *, int); -static unsigned char *obj_write_byte(unsigned char *, int); -static unsigned char *obj_write_word(unsigned char *, int); -static unsigned char *obj_write_dword(unsigned char *, long); -static unsigned char *obj_write_rword(unsigned char *, int); -static unsigned char *obj_write_name(unsigned char *, char *); -static unsigned char *obj_write_index(unsigned char *, int); -static unsigned char *obj_write_value(unsigned char *, unsigned long); -static void obj_record(int, unsigned char *, unsigned char *); +static void obj_write_file(int debuginfo); static int obj_directive (char *, char *, int); -static void obj_init (FILE *fp, efunc errfunc, ldfunc ldef, evalfunc eval) { +static void obj_init (FILE *fp, efunc errfunc, ldfunc ldef, evalfunc eval) +{ ofp = fp; error = errfunc; evaluate = eval; @@ -200,14 +619,24 @@ static void obj_init (FILE *fp, efunc errfunc, ldfunc ldef, evalfunc eval) { segtail = &seghead; grphead = obj_grp_needs_update = NULL; grptail = &grphead; - datahead = datacurr = NULL; - datatail = &datahead; obj_entry_seg = NO_SEG; obj_uppercase = FALSE; + passtwo = 0; + + of_obj.current_dfmt->init (&of_obj,NULL,fp,errfunc); } -static void obj_cleanup (void) { - obj_write_file(); +static int obj_set_info(enum geninfo type, char **val) +{ + (void) type; + (void) val; + + return 0; +} +static void obj_cleanup (int debuginfo) +{ + obj_write_file(debuginfo); + of_obj.current_dfmt->cleanup(); fclose (ofp); while (seghead) { struct Segment *segtmp = seghead; @@ -218,6 +647,8 @@ static void obj_cleanup (void) { nasm_free (pubtmp->name); nasm_free (pubtmp); } + nasm_free (segtmp->segclass); + nasm_free (segtmp->overlay); nasm_free (segtmp); } while (fpubhead) { @@ -256,14 +687,10 @@ static void obj_cleanup (void) { grphead = grphead->next; nasm_free (grptmp); } - while (datahead) { - struct ObjData *datatmp = datahead; - datahead = datahead->next; - nasm_free (datatmp); - } } -static void obj_ext_set_defwrt (struct External *ext, char *id) { +static void obj_ext_set_defwrt (struct External *ext, char *id) +{ struct Segment *seg; struct Group *grp; @@ -290,7 +717,8 @@ static void obj_ext_set_defwrt (struct External *ext, char *id) { } static void obj_deflabel (char *name, long segment, - long offset, int is_global, char *special) { + long offset, int is_global, char *special) +{ /* * We have three cases: * @@ -376,19 +804,18 @@ static void obj_deflabel (char *name, long segment, error (ERR_PANIC, "strange segment conditions in OBJ driver"); } - for (seg = seghead; seg; seg = seg->next) + for (seg = seghead; seg && is_global; seg = seg->next) if (seg->index == segment) { + struct Public *loc = nasm_malloc (sizeof(*loc)); /* * Case (ii). Maybe MODPUB someday? */ - if (is_global) { - struct Public *pub; - pub = *seg->pubtail = nasm_malloc(sizeof(*pub)); - seg->pubtail = &pub->next; - pub->next = NULL; - pub->name = nasm_strdup(name); - pub->offset = offset; - } + *seg->pubtail = loc; + seg->pubtail = &loc->next; + loc->next = NULL; + loc->name = nasm_strdup(name); + loc->offset = offset; + if (special) error(ERR_NONFATAL, "OBJ supports no special symbol features" " for this symbol type"); @@ -398,16 +825,20 @@ static void obj_deflabel (char *name, long segment, /* * Case (iii). */ - ext = *exttail = nasm_malloc(sizeof(*ext)); - ext->next = NULL; - exttail = &ext->next; - ext->name = name; - ext->defwrt_type = DEFWRT_NONE; - if (is_global == 2) { - ext->commonsize = offset; - ext->commonelem = 1; /* default FAR */ - } else - ext->commonsize = 0; + if (is_global) { + ext = *exttail = nasm_malloc(sizeof(*ext)); + ext->next = NULL; + exttail = &ext->next; + ext->name = name; + ext->defwrt_type = DEFWRT_NONE; + if (is_global == 2) { + ext->commonsize = offset; + ext->commonelem = 1; /* default FAR */ + } else + ext->commonsize = 0; + } + else + return; /* * Now process the special text, if any, to find default-WRT @@ -519,11 +950,13 @@ static void obj_deflabel (char *name, long segment, } static void obj_out (long segto, void *data, unsigned long type, - long segment, long wrt) { + long segment, long wrt) +{ long size, realtype; unsigned char *ucdata; long ldata; struct Segment *seg; + ObjRecord *orp; /* * handle absolute-assembly (structure definitions) @@ -554,26 +987,29 @@ static void obj_out (long segto, void *data, unsigned long type, if (!seg) error (ERR_PANIC, "code directed to nonexistent segment?"); + orp = seg->orp; + orp->parm[0] = seg->currentpos; + size = type & OUT_SIZMASK; realtype = type & OUT_TYPMASK; if (realtype == OUT_RAWDATA) { ucdata = data; while (size > 0) { - long len = obj_ledata_space(seg); - if (len == 0) { - obj_ledata_new(seg); - len = obj_ledata_space(seg); - } + unsigned int len; + orp = obj_check(seg->orp, 1); + len = RECORD_MAX - orp->used; if (len > size) len = size; - datacurr->lptr = obj_write_data (datacurr->lptr, ucdata, len); - datacurr->nonempty = TRUE; + memcpy (orp->buf+orp->used, ucdata, len); + orp->committed = orp->used += len; + orp->parm[0] = seg->currentpos += len; ucdata += len; size -= len; - seg->currentpos += len; } - } else if (realtype == OUT_ADDRESS || realtype == OUT_REL2ADR || - realtype == OUT_REL4ADR) { + } + else if (realtype == OUT_ADDRESS || realtype == OUT_REL2ADR || + realtype == OUT_REL4ADR) + { int rsize; if (segment == NO_SEG && realtype != OUT_ADDRESS) @@ -591,13 +1027,10 @@ static void obj_out (long segto, void *data, unsigned long type, ldata += (size-4); size = 4; } - if (obj_ledata_space(seg) < 4 || !obj_fixup_free(seg)) - obj_ledata_new(seg); if (size == 2) - datacurr->lptr = obj_write_word (datacurr->lptr, ldata); + orp = obj_word (orp, ldata); else - datacurr->lptr = obj_write_dword (datacurr->lptr, ldata); - datacurr->nonempty = TRUE; + orp = obj_dword (orp, ldata); rsize = size; if (segment < SEG_ABS && (segment != NO_SEG && segment % 2) && size == 4) { @@ -614,67 +1047,28 @@ static void obj_out (long segto, void *data, unsigned long type, " dword-size segment base references"); } if (segment != NO_SEG) - obj_write_fixup (datacurr, rsize, - (realtype == OUT_REL2ADR || - realtype == OUT_REL4ADR ? 0 : 0x4000), - segment, wrt, - (seg->currentpos - datacurr->startpos)); + obj_write_fixup (orp, rsize, + (realtype == OUT_ADDRESS ? 0x4000 : 0), + segment, wrt); seg->currentpos += size; } else if (realtype == OUT_RESERVE) { - obj_ledata_commit(); + if (orp->committed) + orp = obj_bump(orp); seg->currentpos += size; } + obj_commit(orp); } -static long obj_ledata_space(struct Segment *segto) { - if (datacurr && datacurr->seg == segto) - return datacurr->ledata + LEDATA_MAX - datacurr->lptr; - else - return 0; -} - -static int obj_fixup_free(struct Segment *segto) { - if (datacurr && datacurr->seg == segto) - return (datacurr->fixupp + RECORD_MAX - datacurr->fptr) > 8; - else - return 0; -} - -static void obj_ledata_new(struct Segment *segto) { - datacurr = *datatail = nasm_malloc(sizeof(*datacurr)); - datacurr->next = NULL; - datatail = &datacurr->next; - datacurr->nonempty = FALSE; - datacurr->lptr = datacurr->ledata; - datacurr->fptr = datacurr->fixupp; - datacurr->seg = segto; - if (segto->use32) - datacurr->letype = LEDATA+1; - else - datacurr->letype = LEDATA; - datacurr->startpos = segto->currentpos; - datacurr->ftype = FIXUPP; - - datacurr->lptr = obj_write_index (datacurr->lptr, segto->obj_index); - if (datacurr->letype == LEDATA) - datacurr->lptr = obj_write_word (datacurr->lptr, segto->currentpos); - else - datacurr->lptr = obj_write_dword (datacurr->lptr, segto->currentpos); -} - -static void obj_ledata_commit(void) { - datacurr = NULL; -} - -static void obj_write_fixup (struct ObjData *data, int bytes, - int segrel, long seg, long wrt, - long offset) { +static void obj_write_fixup (ObjRecord *orp, int bytes, + int segrel, long seg, long wrt) +{ int locat, method; int base; long tidx, fidx; struct Segment *s = NULL; struct Group *g = NULL; struct External *e = NULL; + ObjRecord *forp; if (bytes == 1) { error(ERR_NONFATAL, "`obj' output driver does not support" @@ -682,24 +1076,34 @@ static void obj_write_fixup (struct ObjData *data, int bytes, return; } - locat = 0x8000 | segrel | offset; + forp = orp->child; + if (forp == NULL) { + orp->child = forp = obj_new(); + forp->up = &(orp->child); + forp->type = FIXUPP; + } + if (seg % 2) { base = TRUE; - locat |= 0x800; + locat = FIX_16_SELECTOR; seg--; if (bytes != 2) error(ERR_PANIC, "OBJ: 4-byte segment base fixup got" " through sanity check"); - } else { + } + else { base = FALSE; - if (bytes == 2) - locat |= 0x400; - else { - locat |= 0x2400; - data->ftype = FIXUPP+1; /* need new-style FIXUPP record */ - } + locat = (bytes == 2) ? FIX_16_OFFSET : FIX_32_OFFSET; + if (!segrel) + /* + * There is a bug in tlink that makes it process self relative + * fixups incorrectly if the x_size doesn't match the location + * size. + */ + forp = obj_force(forp, bytes<<3); } - data->fptr = obj_write_rword (data->fptr, locat); + + forp = obj_rword (forp, locat | segrel | (orp->parm[0]-orp->parm[2])); tidx = fidx = -1, method = 0; /* placate optimisers */ @@ -796,13 +1200,15 @@ static void obj_write_fixup (struct ObjData *data, int bytes, } } - data->fptr = obj_write_byte (data->fptr, method); + forp = obj_byte (forp, method); if (fidx != -1) - data->fptr = obj_write_index (data->fptr, fidx); - data->fptr = obj_write_index (data->fptr, tidx); + forp = obj_index (forp, fidx); + forp = obj_index (forp, tidx); + obj_commit (forp); } -static long obj_segment (char *name, int pass, int *bits) { +static long obj_segment (char *name, int pass, int *bits) +{ /* * We call the label manager here to define a name for the new * segment, and when our _own_ label-definition stub gets @@ -876,6 +1282,13 @@ static long obj_segment (char *name, int pass, int *bits) { seg->segclass = seg->overlay = NULL; seg->pubhead = NULL; seg->pubtail = &seg->pubhead; + seg->lochead = NULL; + seg->loctail = &seg->lochead; + seg->orp = obj_new(); + seg->orp->up = &(seg->orp); + seg->orp->ori = ori_ledata; + seg->orp->type = LEDATA; + seg->orp->parm[1] = obj_idx; /* * Process the segment attributes. @@ -1014,6 +1427,7 @@ static long obj_segment (char *name, int pass, int *bits) { while (*extp) { if ((*extp)->defwrt_type == DEFWRT_STRING && !strcmp((*extp)->defwrt_ptr.string, seg->name)) { + nasm_free((*extp)->defwrt_ptr.string); (*extp)->defwrt_type = DEFWRT_SEGMENT; (*extp)->defwrt_ptr.seg = seg; *extp = (*extp)->next_dws; @@ -1029,7 +1443,8 @@ static long obj_segment (char *name, int pass, int *bits) { } } -static int obj_directive (char *directive, char *value, int pass) { +static int obj_directive (char *directive, char *value, int pass) +{ if (!strcmp(directive, "group")) { char *p, *q, *v; if (pass == 1) { @@ -1129,6 +1544,7 @@ static int obj_directive (char *directive, char *value, int pass) { while (*extp) { if ((*extp)->defwrt_type == DEFWRT_STRING && !strcmp((*extp)->defwrt_ptr.string, grp->name)) { + nasm_free((*extp)->defwrt_ptr.string); (*extp)->defwrt_type = DEFWRT_GROUP; (*extp)->defwrt_ptr.grp = grp; *extp = (*extp)->next_dws; @@ -1268,7 +1684,8 @@ static int obj_directive (char *directive, char *value, int pass) { return 0; } -static long obj_segbase (long segment) { +static long obj_segbase (long segment) +{ struct Segment *seg; /* @@ -1301,7 +1718,7 @@ static long obj_segbase (long segment) { return e->defwrt_ptr.seg->index+1; else if (e->defwrt_type == DEFWRT_GROUP) return e->defwrt_ptr.grp->index+1; - else if (e->defwrt_type == DEFWRT_STRING) + else return NO_SEG; /* can't tell what it is */ } @@ -1316,121 +1733,133 @@ static long obj_segbase (long segment) { return segment; /* no special treatment */ } -static void obj_filename (char *inname, char *outname, efunc error) { +static void obj_filename (char *inname, char *outname, efunc error) +{ strcpy(obj_infile, inname); standard_extension (inname, outname, ".obj", error); } -static void obj_write_file (void) { - struct Segment *seg; +static void obj_write_file (int debuginfo) +{ + struct Segment *seg, *entry_seg_ptr = 0; + struct FileName *fn; + struct LineNumber *ln; struct Group *grp; - struct Public *pub; + struct Public *pub, *loc; struct External *ext; - struct ObjData *data; struct ImpDef *imp; struct ExpDef *export; static char boast[] = "The Netwide Assembler " NASM_VER; - int lname_idx, rectype; + int lname_idx; + ObjRecord *orp; /* * Write the THEADR module header. */ - recptr = record; - recptr = obj_write_name (recptr, obj_infile); - obj_record (THEADR, record, recptr); + orp = obj_new(); + orp->type = THEADR; + obj_name (orp, obj_infile); + obj_emit2 (orp); /* * Write the NASM boast comment. */ - recptr = record; - recptr = obj_write_rword (recptr, 0); /* comment type zero */ - recptr = obj_write_name (recptr, boast); - obj_record (COMENT, record, recptr); + orp->type = COMENT; + obj_rword (orp, 0); /* comment type zero */ + obj_name (orp, boast); + obj_emit2 (orp); + orp->type = COMENT; /* * Write the IMPDEF records, if any. */ for (imp = imphead; imp; imp = imp->next) { - recptr = record; - recptr = obj_write_rword (recptr, 0xA0); /* comment class A0 */ - recptr = obj_write_byte (recptr, 1); /* subfunction 1: IMPDEF */ + obj_rword (orp, 0xA0); /* comment class A0 */ + obj_byte (orp, 1); /* subfunction 1: IMPDEF */ if (imp->impname) - recptr = obj_write_byte (recptr, 0); /* import by name */ + obj_byte (orp, 0); /* import by name */ else - recptr = obj_write_byte (recptr, 1); /* import by ordinal */ - recptr = obj_write_name (recptr, imp->extname); - recptr = obj_write_name (recptr, imp->libname); + obj_byte (orp, 1); /* import by ordinal */ + obj_name (orp, imp->extname); + obj_name (orp, imp->libname); if (imp->impname) - recptr = obj_write_name (recptr, imp->impname); + obj_name (orp, imp->impname); else - recptr = obj_write_word (recptr, imp->impindex); - obj_record (COMENT, record, recptr); + obj_word (orp, imp->impindex); + obj_emit2 (orp); } /* * Write the EXPDEF records, if any. */ for (export = exphead; export; export = export->next) { - recptr = record; - recptr = obj_write_rword (recptr, 0xA0); /* comment class A0 */ - recptr = obj_write_byte (recptr, 2); /* subfunction 1: EXPDEF */ - recptr = obj_write_byte (recptr, export->flags); - recptr = obj_write_name (recptr, export->extname); - recptr = obj_write_name (recptr, export->intname); + obj_rword (orp, 0xA0); /* comment class A0 */ + obj_byte (orp, 2); /* subfunction 2: EXPDEF */ + obj_byte (orp, export->flags); + obj_name (orp, export->extname); + obj_name (orp, export->intname); if (export->flags & EXPDEF_FLAG_ORDINAL) - recptr = obj_write_word (recptr, export->ordinal); - obj_record (COMENT, record, recptr); + obj_word (orp, export->ordinal); + obj_emit2 (orp); + } + + /* we're using extended OMF if we put in debug info*/ + if (debuginfo) { + orp->type = COMENT; + obj_byte (orp, 0x40); + obj_byte (orp, dEXTENDED); + obj_emit2 (orp); } /* * Write the first LNAMES record, containing LNAME one, which * is null. Also initialise the LNAME counter. */ - recptr = record; - recptr = obj_write_name (recptr, ""); - obj_record (LNAMES, record, recptr); - lname_idx = 2; + orp->type = LNAMES; + obj_byte (orp, 0); + lname_idx = 1; + /* + * Write some LNAMES for the segment names + */ + for (seg = seghead; seg; seg = seg->next) { + orp = obj_name (orp, seg->name); + if (seg->segclass) + orp = obj_name (orp, seg->segclass); + if (seg->overlay) + orp = obj_name (orp, seg->overlay); + obj_commit (orp); + } + /* + * Write some LNAMES for the group names + */ + for (grp = grphead; grp; grp = grp->next) { + orp = obj_name (orp, grp->name); + obj_commit (orp); + } + obj_emit (orp); + /* - * Write the SEGDEF records. Each has an associated LNAMES - * record. + * Write the SEGDEF records. */ + orp->type = SEGDEF; for (seg = seghead; seg; seg = seg->next) { - int new_segdef; /* do we use the newer record type? */ int acbp; - int sn, cn, on; /* seg, class, overlay LNAME idx */ - - if (seg->use32 || seg->currentpos >= 0x10000L) - new_segdef = TRUE; - else - new_segdef = FALSE; - - recptr = record; - recptr = obj_write_name (recptr, seg->name); - sn = lname_idx++; - if (seg->segclass) { - recptr = obj_write_name (recptr, seg->segclass); - cn = lname_idx++; - } else - cn = 1; - if (seg->overlay) { - recptr = obj_write_name (recptr, seg->overlay); - on = lname_idx++; - } else - on = 1; - obj_record (LNAMES, record, recptr); + unsigned long seglen = seg->currentpos; acbp = (seg->combine << 2); /* C field */ - if (seg->currentpos >= 0x10000L && !new_segdef) - acbp |= 0x02; /* B bit */ - if (seg->use32) acbp |= 0x01; /* P bit is Use32 flag */ + else if (seglen == 0x10000L) { + seglen = 0; /* This special case may be needed for old linkers */ + acbp |= 0x02; /* B bit */ + } + /* A field */ if (seg->align >= SEG_ABS) - acbp |= 0x00; + /* acbp |= 0x00 */; else if (seg->align >= 4096) { if (seg->align > 4096) error(ERR_NONFATAL, "segment `%s' requires more alignment" @@ -1447,43 +1876,22 @@ static void obj_write_file (void) { } else acbp |= 0x20; - recptr = record; - recptr = obj_write_byte (recptr, acbp); + obj_byte (orp, acbp); if (seg->align & SEG_ABS) { - recptr = obj_write_word (recptr, seg->align - SEG_ABS); - recptr = obj_write_byte (recptr, 0); - } - if (new_segdef) - recptr = obj_write_dword (recptr, seg->currentpos); - else - recptr = obj_write_word (recptr, seg->currentpos & 0xFFFF); - recptr = obj_write_index (recptr, sn); - recptr = obj_write_index (recptr, cn); - recptr = obj_write_index (recptr, on); - if (new_segdef) - obj_record (SEGDEF+1, record, recptr); - else - obj_record (SEGDEF, record, recptr); - } - - /* - * Write some LNAMES for the group names. lname_idx is left - * alone here - it will catch up when we write the GRPDEFs. - */ - recptr = record; - for (grp = grphead; grp; grp = grp->next) { - if (recptr - record + strlen(grp->name)+2 > 1024) { - obj_record (LNAMES, record, recptr); - recptr = record; + obj_x (orp, seg->align - SEG_ABS); /* Frame */ + obj_byte (orp, 0); /* Offset */ } - recptr = obj_write_name (recptr, grp->name); + obj_x (orp, seglen); + obj_index (orp, ++lname_idx); + obj_index (orp, seg->segclass ? ++lname_idx : 1); + obj_index (orp, seg->overlay ? ++lname_idx : 1); + obj_emit2 (orp); } - if (recptr > record) - obj_record (LNAMES, record, recptr); /* * Write the GRPDEF records. */ + orp->type = GRPDEF; for (grp = grphead; grp; grp = grp->next) { int i; @@ -1495,96 +1903,76 @@ static void obj_write_file (void) { grp->segs[i].name = NULL; } } - recptr = record; - recptr = obj_write_index (recptr, lname_idx++); + obj_index (orp, ++lname_idx); for (i = 0; i < grp->nindices; i++) { - recptr = obj_write_byte (recptr, 0xFF); - recptr = obj_write_index (recptr, grp->segs[i].index); + obj_byte (orp, 0xFF); + obj_index (orp, grp->segs[i].index); } - obj_record (GRPDEF, record, recptr); + obj_emit2 (orp); } /* * Write the PUBDEF records: first the ones in the segments, * then the far-absolutes. */ + orp->type = PUBDEF; + orp->ori = ori_pubdef; for (seg = seghead; seg; seg = seg->next) { - int any; - - recptr = record; - recptr = obj_write_index (recptr, seg->grp ? seg->grp->obj_index : 0); - recptr = obj_write_index (recptr, seg->obj_index); - any = FALSE; - if (seg->use32) - rectype = PUBDEF+1; - else - rectype = PUBDEF; + orp->parm[0] = seg->grp ? seg->grp->obj_index : 0; + orp->parm[1] = seg->obj_index; for (pub = seg->pubhead; pub; pub = pub->next) { - if (recptr - record + strlen(pub->name) + 7 > 1024) { - if (any) - obj_record (rectype, record, recptr); - recptr = record; - recptr = obj_write_index (recptr, 0); - recptr = obj_write_index (recptr, seg->obj_index); - } - recptr = obj_write_name (recptr, pub->name); - if (seg->use32) - recptr = obj_write_dword (recptr, pub->offset); - else - recptr = obj_write_word (recptr, pub->offset); - recptr = obj_write_index (recptr, 0); - any = TRUE; + orp = obj_name (orp, pub->name); + orp = obj_x (orp, pub->offset); + orp = obj_byte (orp, 0); /* type index */ + obj_commit (orp); } - if (any) - obj_record (rectype, record, recptr); + obj_emit (orp); } + orp->parm[0] = 0; + orp->parm[1] = 0; for (pub = fpubhead; pub; pub = pub->next) { /* pub-crawl :-) */ - recptr = record; - recptr = obj_write_index (recptr, 0); /* no group */ - recptr = obj_write_index (recptr, 0); /* no segment either */ - recptr = obj_write_word (recptr, pub->segment); - recptr = obj_write_name (recptr, pub->name); - recptr = obj_write_word (recptr, pub->offset); - recptr = obj_write_index (recptr, 0); - obj_record (PUBDEF, record, recptr); + if (orp->parm[2] != pub->segment) { + obj_emit (orp); + orp->parm[2] = pub->segment; + } + orp = obj_name (orp, pub->name); + orp = obj_x (orp, pub->offset); + orp = obj_byte (orp, 0); /* type index */ + obj_commit (orp); } + obj_emit (orp); /* * Write the EXTDEF and COMDEF records, in order. */ - recptr = record; + orp->ori = ori_null; for (ext = exthead; ext; ext = ext->next) { if (ext->commonsize == 0) { - /* dj@delorie.com: check for buffer overrun before we overrun it */ - if (recptr - record + strlen(ext->name)+2 > RECORD_MAX) { - obj_record (EXTDEF, record, recptr); - recptr = record; + if (orp->type != EXTDEF) { + obj_emit (orp); + orp->type = EXTDEF; } - recptr = obj_write_name (recptr, ext->name); - recptr = obj_write_index (recptr, 0); + orp = obj_name (orp, ext->name); + orp = obj_index (orp, 0); } else { - if (recptr > record) - obj_record (EXTDEF, record, recptr); - recptr = record; - if (ext->commonsize) { - recptr = obj_write_name (recptr, ext->name); - recptr = obj_write_index (recptr, 0); - if (ext->commonelem) { - recptr = obj_write_byte (recptr, 0x61);/* far communal */ - recptr = obj_write_value (recptr, (ext->commonsize / - ext->commonelem)); - recptr = obj_write_value (recptr, ext->commonelem); - } else { - recptr = obj_write_byte (recptr, 0x62);/* near communal */ - recptr = obj_write_value (recptr, ext->commonsize); - } - obj_record (COMDEF, record, recptr); + if (orp->type != COMDEF) { + obj_emit (orp); + orp->type = COMDEF; + } + orp = obj_name (orp, ext->name); + orp = obj_index (orp, 0); + if (ext->commonelem) { + orp = obj_byte (orp, 0x61);/* far communal */ + orp = obj_value (orp, (ext->commonsize / ext->commonelem)); + orp = obj_value (orp, ext->commonelem); + } else { + orp = obj_byte (orp, 0x62);/* near communal */ + orp = obj_value (orp, ext->commonsize); } - recptr = record; } + obj_commit (orp); } - if (recptr > record) - obj_record (EXTDEF, record, recptr); + obj_emit (orp); /* * Write a COMENT record stating that the linker's first pass @@ -1592,150 +1980,251 @@ static void obj_write_file (void) { * MODEND record specifies a start point, in which case, * according to some variants of the documentation, this COMENT * should be omitted. So we'll omit it just in case. + * But, TASM puts it in all the time so if we are using + * TASM debug stuff we are putting it in */ - if (obj_entry_seg == NO_SEG) { - recptr = record; - recptr = obj_write_rword (recptr, 0x40A2); - recptr = obj_write_byte (recptr, 1); - obj_record (COMENT, record, recptr); - } + if (debuginfo || obj_entry_seg == NO_SEG) { + orp->type = COMENT; + obj_byte (orp, 0x40); + obj_byte (orp, dLINKPASS); + obj_byte (orp, 1); + obj_emit2 (orp); + } /* - * Write the LEDATA/FIXUPP pairs. + * 1) put out the compiler type + * 2) Put out the type info. The only type we are using is near label #19 + */ + if (debuginfo) { + int i; + struct Array *arrtmp = arrhead; + orp->type = COMENT; + obj_byte (orp, 0x40); + obj_byte (orp, dCOMPDEF); + obj_byte (orp, 4); + obj_byte (orp, 0); + obj_emit2 (orp); + + obj_byte (orp, 0x40); + obj_byte (orp, dTYPEDEF); + obj_word (orp, 0x18); /* type # for linking */ + obj_word (orp, 6); /* size of type */ + obj_byte (orp, 0x2a); /* absolute type for debugging */ + obj_emit2 (orp); + obj_byte (orp, 0x40); + obj_byte (orp, dTYPEDEF); + obj_word (orp, 0x19); /* type # for linking */ + obj_word (orp, 0); /* size of type */ + obj_byte (orp, 0x24); /* absolute type for debugging */ + obj_byte (orp, 0); /* near/far specifier */ + obj_emit2 (orp); + obj_byte (orp, 0x40); + obj_byte (orp, dTYPEDEF); + obj_word (orp, 0x1A); /* type # for linking */ + obj_word (orp, 0); /* size of type */ + obj_byte (orp, 0x24); /* absolute type for debugging */ + obj_byte (orp, 1); /* near/far specifier */ + obj_emit2 (orp); + obj_byte (orp, 0x40); + obj_byte (orp, dTYPEDEF); + obj_word (orp, 0x1b); /* type # for linking */ + obj_word (orp, 0); /* size of type */ + obj_byte (orp, 0x23); /* absolute type for debugging */ + obj_byte (orp, 0); + obj_byte (orp, 0); + obj_byte (orp, 0); + obj_emit2 (orp); + obj_byte (orp, 0x40); + obj_byte (orp, dTYPEDEF); + obj_word (orp, 0x1c); /* type # for linking */ + obj_word (orp, 0); /* size of type */ + obj_byte (orp, 0x23); /* absolute type for debugging */ + obj_byte (orp, 0); + obj_byte (orp, 4); + obj_byte (orp, 0); + obj_emit2 (orp); + obj_byte (orp, 0x40); + obj_byte (orp, dTYPEDEF); + obj_word (orp, 0x1d); /* type # for linking */ + obj_word (orp, 0); /* size of type */ + obj_byte (orp, 0x23); /* absolute type for debugging */ + obj_byte (orp, 0); + obj_byte (orp, 1); + obj_byte (orp, 0); + obj_emit2 (orp); + obj_byte (orp, 0x40); + obj_byte (orp, dTYPEDEF); + obj_word (orp, 0x1e); /* type # for linking */ + obj_word (orp, 0); /* size of type */ + obj_byte (orp, 0x23); /* absolute type for debugging */ + obj_byte (orp, 0); + obj_byte (orp, 5); + obj_byte (orp, 0); + obj_emit2 (orp); + + /* put out the array types */ + for (i= ARRAYBOT; i < arrindex; i++) { + obj_byte (orp, 0x40); + obj_byte (orp, dTYPEDEF); + obj_word (orp, i ); /* type # for linking */ + obj_word (orp, arrtmp->size); /* size of type */ + obj_byte (orp, 0x1A); /* absolute type for debugging (array)*/ + obj_byte (orp, arrtmp->basetype ); /* base type */ + obj_emit2 (orp); + arrtmp = arrtmp->next ; + } + } + /* + * write out line number info with a LINNUM record + * switch records when we switch segments, and output the + * file in a pseudo-TASM fashion. The record switch is naive; that + * is that one file may have many records for the same segment + * if there are lots of segment switches */ - for (data = datahead; data; data = data->next) { - if (data->nonempty) { - obj_record (data->letype, data->ledata, data->lptr); - if (data->fptr != data->fixupp) - obj_record (data->ftype, data->fixupp, data->fptr); + if (fnhead && debuginfo) { + seg = fnhead->lnhead->segment; + + for (fn = fnhead; fn; fn = fn->next) { + /* write out current file name */ + orp->type = COMENT; + orp->ori = ori_null; + obj_byte (orp, 0x40); + obj_byte (orp, dFILNAME); + obj_byte( orp,0); + obj_name( orp,fn->name); + obj_dword(orp, 0); + obj_emit2 (orp); + + /* write out line numbers this file */ + + orp->type = LINNUM; + orp->ori = ori_linnum; + for (ln = fn->lnhead; ln; ln = ln->next) { + if (seg != ln->segment) { + /* if we get here have to flush the buffer and start + * a new record for a new segment + */ + seg = ln->segment; + obj_emit ( orp ); + } + orp->parm[0] = seg->grp ? seg->grp->obj_index : 0; + orp->parm[1] = seg->obj_index; + orp = obj_word(orp, ln->lineno); + orp = obj_x(orp, ln->offset); + obj_commit (orp); + } + obj_emit (orp); } } - /* - * Write the MODEND module end marker. + * we are going to locate the entry point segment now + * rather than wait until the MODEND record, because, + * then we can output a special symbol to tell where the + * entry point is. + * */ - recptr = record; - rectype = MODEND; if (obj_entry_seg != NO_SEG) { - recptr = obj_write_byte (recptr, 0xC1); - /* - * Find the segment in the segment list. - */ for (seg = seghead; seg; seg = seg->next) { if (seg->index == obj_entry_seg) { - if (seg->grp) { - recptr = obj_write_byte (recptr, 0x10); - recptr = obj_write_index (recptr, seg->grp->obj_index); - } else { - recptr = obj_write_byte (recptr, 0x50); - } - recptr = obj_write_index (recptr, seg->obj_index); - if (seg->use32) { - rectype = MODEND+1; - recptr = obj_write_dword (recptr, obj_entry_ofs); - } else - recptr = obj_write_word (recptr, obj_entry_ofs); + entry_seg_ptr = seg; break; } } if (!seg) error(ERR_NONFATAL, "entry point is not in this module"); - } else - recptr = obj_write_byte (recptr, 0); - obj_record (rectype, record, recptr); -} - -static unsigned char *obj_write_data(unsigned char *ptr, - unsigned char *data, int len) { - while (len--) - *ptr++ = *data++; - return ptr; -} - -static unsigned char *obj_write_byte(unsigned char *ptr, int data) { - *ptr++ = data; - return ptr; -} - -static unsigned char *obj_write_word(unsigned char *ptr, int data) { - *ptr++ = data & 0xFF; - *ptr++ = (data >> 8) & 0xFF; - return ptr; -} - -static unsigned char *obj_write_dword(unsigned char *ptr, long data) { - *ptr++ = data & 0xFF; - *ptr++ = (data >> 8) & 0xFF; - *ptr++ = (data >> 16) & 0xFF; - *ptr++ = (data >> 24) & 0xFF; - return ptr; -} - -static unsigned char *obj_write_rword(unsigned char *ptr, int data) { - *ptr++ = (data >> 8) & 0xFF; - *ptr++ = data & 0xFF; - return ptr; -} - -static unsigned char *obj_write_name(unsigned char *ptr, char *data) { - *ptr++ = strlen(data); - if (obj_uppercase) { - while (*data) { - *ptr++ = (unsigned char) toupper(*data); - data++; - } - } else { - while (*data) - *ptr++ = (unsigned char) *data++; } - return ptr; -} -static unsigned char *obj_write_index(unsigned char *ptr, int data) { - if (data < 128) - *ptr++ = data; - else { - *ptr++ = 0x80 | ((data >> 8) & 0x7F); - *ptr++ = data & 0xFF; + /* + * get ready to put out symbol records + */ + orp->type = COMENT; + orp->ori = ori_local; + + /* + * put out a symbol for the entry point + * no dots in this symbol, because, borland does + * not (officially) support dots in label names + * and I don't know what various versions of TLINK will do + */ + if (debuginfo && obj_entry_seg != NO_SEG) { + orp = obj_name (orp,"start_of_program"); + orp = obj_word (orp,0x19); /* type: near label */ + orp = obj_index (orp, seg->grp ? seg->grp->obj_index : 0); + orp = obj_index (orp, seg->obj_index); + orp = obj_x (orp, obj_entry_ofs); + obj_commit (orp); + } + + /* + * put out the local labels + */ + for (seg = seghead; seg && debuginfo; seg = seg->next) { + /* labels this seg */ + for (loc = seg->lochead; loc; loc = loc->next) { + orp = obj_name (orp,loc->name); + orp = obj_word (orp, loc->type); + orp = obj_index (orp, seg->grp ? seg->grp->obj_index : 0); + orp = obj_index (orp, seg->obj_index); + orp = obj_x (orp,loc->offset); + obj_commit (orp); + } } - return ptr; -} + if (orp->used) + obj_emit (orp); -static unsigned char *obj_write_value(unsigned char *ptr, - unsigned long data) { - if (data <= 128) - *ptr++ = data; - else if (data <= 0xFFFF) { - *ptr++ = 129; - *ptr++ = data & 0xFF; - *ptr++ = (data >> 8) & 0xFF; - } else if (data <= 0xFFFFFFL) { - *ptr++ = 132; - *ptr++ = data & 0xFF; - *ptr++ = (data >> 8) & 0xFF; - *ptr++ = (data >> 16) & 0xFF; - } else { - *ptr++ = 136; - *ptr++ = data & 0xFF; - *ptr++ = (data >> 8) & 0xFF; - *ptr++ = (data >> 16) & 0xFF; - *ptr++ = (data >> 24) & 0xFF; + /* + * Write the LEDATA/FIXUPP pairs. + */ + for (seg = seghead; seg; seg = seg->next) { + obj_emit (seg->orp); + nasm_free (seg->orp); } - return ptr; + + /* + * Write the MODEND module end marker. + */ + orp->type = MODEND; + orp->ori = ori_null; + if (entry_seg_ptr) { + obj_byte (orp, 0xC1); + seg = entry_seg_ptr; + if (seg->grp) { + obj_byte (orp, 0x10); + obj_index (orp, seg->grp->obj_index); + } else { + /* + * the below changed to prevent TLINK crashing. + * Previous more efficient version read: + * + * obj_byte (orp, 0x50); + */ + obj_byte (orp, 0x00); + obj_index (orp, seg->obj_index); + } + obj_index (orp, seg->obj_index); + obj_x (orp, obj_entry_ofs); + } else + obj_byte (orp, 0); + obj_emit2 (orp); + nasm_free (orp); } -static void obj_record(int type, unsigned char *start, unsigned char *end) { - unsigned long cksum, len; +void obj_fwrite(ObjRecord *orp) +{ + unsigned int cksum, len; + unsigned char *ptr; - cksum = type; - fputc (type, ofp); - len = end-start+1; + cksum = orp->type; + if (orp->x_size == 32) + cksum |= 1; + fputc (cksum, ofp); + len = orp->committed+1; cksum += (len & 0xFF) + ((len>>8) & 0xFF); fwriteshort (len, ofp); - fwrite (start, 1, end-start, ofp); - while (start < end) - cksum += *start++; - fputc ( (-(long)cksum) & 0xFF, ofp); + fwrite (orp->buf, 1, len-1, ofp); + for (ptr=orp->buf; --len; ptr++) + cksum += *ptr; + fputc ( (-cksum) & 0xFF, ofp); } static char *obj_stdmac[] = { @@ -1743,7 +2232,7 @@ static char *obj_stdmac[] = { "%imacro group 1+.nolist", "[group %1]", "%endmacro", - "%imacro uppercase 1+.nolist", + "%imacro uppercase 0+.nolist", "[uppercase %1]", "%endmacro", "%imacro export 1+.nolist", @@ -1752,14 +2241,243 @@ static char *obj_stdmac[] = { "%imacro import 1+.nolist", "[import %1]", "%endmacro", + "%macro __NASM_CDecl__ 1", + "%endmacro", NULL }; +void dbgbi_init(struct ofmt * of, void * id, FILE * fp, efunc error) +{ + (void) of; + (void) id; + (void) fp; + (void) error; + + fnhead = NULL; + fntail = &fnhead; + arrindex = ARRAYBOT ; + arrhead = NULL; + arrtail = &arrhead; +} +static void dbgbi_cleanup(void) +{ + struct Segment *segtmp; + while (fnhead) { + struct FileName *fntemp = fnhead; + while (fnhead->lnhead) { + struct LineNumber *lntemp = fnhead->lnhead; + fnhead->lnhead = lntemp->next; + nasm_free( lntemp); + } + fnhead = fnhead->next; + nasm_free (fntemp->name); + nasm_free (fntemp); + } + for (segtmp=seghead; segtmp; segtmp=segtmp->next) { + while (segtmp->lochead) { + struct Public *loctmp = segtmp->lochead; + segtmp->lochead = loctmp->next; + nasm_free (loctmp->name); + nasm_free (loctmp); + } + } + while (arrhead) { + struct Array *arrtmp = arrhead; + arrhead = arrhead->next; + nasm_free (arrtmp); + } +} + +static void dbgbi_linnum (const char *lnfname, long lineno, long segto) +{ + struct FileName *fn; + struct LineNumber *ln; + struct Segment *seg; + + if (segto == NO_SEG) + return; + + /* + * If `any_segs' is still FALSE, we must define a default + * segment. + */ + if (!any_segs) { + int tempint; /* ignored */ + if (segto != obj_segment("__NASMDEFSEG", 2, &tempint)) + error (ERR_PANIC, "strange segment conditions in OBJ driver"); + } + + /* + * Find the segment we are targetting. + */ + for (seg = seghead; seg; seg = seg->next) + if (seg->index == segto) + break; + if (!seg) + error (ERR_PANIC, "lineno directed to nonexistent segment?"); + + for (fn = fnhead; fn; fn = fnhead->next) + if (!nasm_stricmp(lnfname,fn->name)) + break; + if (!fn) { + fn = nasm_malloc ( sizeof( *fn)); + fn->name = nasm_malloc ( strlen(lnfname) + 1) ; + strcpy (fn->name,lnfname); + fn->lnhead = NULL; + fn->lntail = & fn->lnhead; + fn->next = NULL; + *fntail = fn; + fntail = &fn->next; + } + ln = nasm_malloc ( sizeof( *ln)); + ln->segment = seg; + ln->offset = seg->currentpos; + ln->lineno = lineno; + ln->next = NULL; + *fn->lntail = ln; + fn->lntail = &ln->next; + +} +static void dbgbi_deflabel (char *name, long segment, + long offset, int is_global, char *special) +{ + struct Segment *seg; + + (void) special; + + /* + * If it's a special-retry from pass two, discard it. + */ + if (is_global == 3) + return; + + /* + * First check for the double-period, signifying something + * unusual. + */ + if (name[0] == '.' && name[1] == '.' && name[2] != '@') { + return; + } + + /* + * Case (i): + */ + if (obj_seg_needs_update) { + return; + } else if (obj_grp_needs_update) { + return; + } + if (segment < SEG_ABS && segment != NO_SEG && segment % 2) + return; + + if (segment >= SEG_ABS || segment == NO_SEG) { + return; + } + + /* + * If `any_segs' is still FALSE, we might need to define a + * default segment, if they're trying to declare a label in + * `first_seg'. But the label should exist due to a prior + * call to obj_deflabel so we can skip that. + */ + + for (seg = seghead; seg; seg = seg->next) + if (seg->index == segment) { + struct Public *loc = nasm_malloc (sizeof(*loc)); + /* + * Case (ii). Maybe MODPUB someday? + */ + last_defined = *seg->loctail = loc; + seg->loctail = &loc->next; + loc->next = NULL; + loc->name = nasm_strdup(name); + loc->offset = offset; + } +} +static void dbgbi_typevalue (long type) +{ + int vsize; + int elem = TYM_ELEMENTS(type); + type = TYM_TYPE(type); + + if (!last_defined) + return; + + switch (type) { + case TY_BYTE: + last_defined->type = 8; /* unsigned char */ + vsize = 1; + break; + case TY_WORD: + last_defined->type = 10; /* unsigned word */ + vsize = 2; + break; + case TY_DWORD: + last_defined->type = 12; /* unsigned dword */ + vsize = 4; + break; + case TY_FLOAT: + last_defined->type = 14; /* float */ + vsize = 4; + break; + case TY_QWORD: + last_defined->type = 15; /* qword */ + vsize = 8; + break; + case TY_TBYTE: + last_defined->type = 16; /* TBYTE */ + vsize = 10; + break; + default: + last_defined->type = 0x19; /*label */ + vsize = 0; + break; + } + + if (elem > 1) { + struct Array *arrtmp = nasm_malloc (sizeof(*arrtmp)); + int vtype = last_defined->type; + arrtmp->size = vsize * elem; + arrtmp->basetype = vtype; + arrtmp->next = NULL; + last_defined->type = arrindex++; + *arrtail = arrtmp; + arrtail = & (arrtmp->next); + } + last_defined = NULL; +} +static void dbgbi_output (int output_type, void *param) +{ + (void) output_type; + (void) param; +} +static struct dfmt borland_debug_form = { + "Borland Debug Records", + "borland", + dbgbi_init, + dbgbi_linnum, + dbgbi_deflabel, + null_debug_routine, + dbgbi_typevalue, + dbgbi_output, + dbgbi_cleanup, +}; + +static struct dfmt *borland_debug_arr[3] = { + &borland_debug_form, + &null_debug_form, + NULL +}; + struct ofmt of_obj = { - "Microsoft MS-DOS 16-bit OMF object files", + "MS-DOS 16-bit/32-bit OMF object files", "obj", + NULL, + borland_debug_arr, + &null_debug_form, obj_stdmac, obj_init, + obj_set_info, obj_out, obj_deflabel, obj_segment, diff --git a/outrdf.c b/outrdf.c index cde13277..d9989e52 100644 --- a/outrdf.c +++ b/outrdf.c @@ -316,6 +316,12 @@ static void rdf_out (long segto, void *data, unsigned long type, struct RelocRec rr; unsigned char databuf[4],*pd; + if (segto == NO_SEG) { + if ((type & OUT_TYPMASK) != OUT_RESERVE) + error (ERR_NONFATAL, "attempt to assemble code in ABSOLUTE space"); + return; + } + segto >>= 1; /* convert NASM segment no to RDF number */ if (segto != 0 && segto != 1 && segto != 2) { @@ -426,11 +432,13 @@ static void rdf_out (long segto, void *data, unsigned long type, } } -static void rdf_cleanup (void) { +static void rdf_cleanup (int debuginfo) { long l; unsigned char b[4],*d; struct BSSRec bs; + (void) debuginfo; + /* should write imported & exported symbol declarations to header here */ @@ -496,14 +504,29 @@ static char *rdf_stdmac[] = { "%imacro library 1+.nolist", "[library %1]", "%endmacro", + "%macro __NASM_CDecl__ 1", + "%endmacro", NULL }; +static int rdf_set_info(enum geninfo type, char **val) +{ + return 0; +} + struct ofmt of_rdf = { "Relocatable Dynamic Object File Format v1.1", +#ifdef OF_RDF2 + "oldrdf", +#else "rdf", +#endif + NULL, + null_debug_arr, + &null_debug_form, rdf_stdmac, rdf_init, + rdf_set_info, rdf_out, rdf_deflabel, rdf_section_names, diff --git a/outrdf2.c b/outrdf2.c new file mode 100644 index 00000000..4ae6799b --- /dev/null +++ b/outrdf2.c @@ -0,0 +1,690 @@ +/* outrdf2.c output routines for the Netwide Assembler to produce + * RDOFF version 2 format object files (which are intended + * mainly for use in proprietary projects, as the code to + * load and execute them is very simple). They will also be + * used for device drivers and possibly some executable files + * in the MOSCOW operating system. See Rdoff.txt for + * details. + * + * The Netwide Assembler is copyright (C) 1996-1998 Simon Tatham and + * Julian Hall. All rights reserved. The software is + * redistributable under the licence given in the file "Licence" + * distributed in the NASM archive. + */ + +#include +#include +#include +#include +#include + +#include "nasm.h" +#include "nasmlib.h" +#include "outform.h" + +/* VERBOSE_WARNINGS: define this to add some extra warnings... */ +#define VERBOSE_WARNINGS + +#ifdef OF_RDF2 + +#define RDF_MAXSEGS 64 /* maximum number of segments - user configurable */ + +typedef unsigned short int16; +typedef unsigned char byte; + +static const char *RDOFF2Id = "RDOFF2"; /* written to start of RDOFF files */ + + +/* the records that can be found in the RDOFF header */ + +/* Note that whenever a segment is referred to in the RDOFF file, its number + * is always half of the segment number that NASM uses to refer to it; this + * is because NASM only allocates even numbered segments, so as to not + * waste any of the 16 bits of segment number written to the file - this + * allows up to 65533 external labels to be defined; otherwise it would be + * 32764. */ + +struct RelocRec { + byte type; /* must be 1, or 6 for segment base ref */ + byte reclen; /* set to 8 */ + byte segment; /* only 0 for code, or 1 for data supported, + * but add 64 for relative refs (ie do not require + * reloc @ loadtime, only linkage) */ + long offset; /* from start of segment in which reference is loc'd */ + byte length; /* 1 2 or 4 bytes */ + int16 refseg; /* segment to which reference refers to */ +}; + +struct ImportRec { + byte type; /* must be 2, or 7 for FAR import */ + byte reclen; /* equals 3+label length */ + int16 segment; /* segment number allocated to the label for reloc + * records - label is assumed to be at offset zero + * in this segment, so linker must fix up with offset + * of segment and of offset within segment */ + char label[33]; /* zero terminated... should be written to file until + * the zero, but not after it - max len = 32 chars */ +}; + +struct ExportRec { + byte type; /* must be 3 */ + byte reclen; /* equals 6+label length */ + byte segment; /* segment referred to (0/1) */ + long offset; /* offset within segment */ + char label[33]; /* zero terminated as above. max len = 32 chars */ +}; + +struct DLLRec { + byte type; /* must be 4 */ + byte reclen; /* equals 1+library name */ + char libname[128]; /* name of library to link with at load time */ +}; + +struct BSSRec { + byte type; /* must be 5 */ + byte reclen; /* equeals 4 */ + long amount; /* number of bytes BSS to reserve */ +}; + +#define COUNT_SEGTYPES 9 + +static char * segmenttypes[COUNT_SEGTYPES] = { + "null", "text", "code", "data", "comment", "lcomment", "pcomment", + "symdebug", "linedebug" +}; + +static int segmenttypenumbers[COUNT_SEGTYPES] = { + 0, 1, 1, 2, 3, 4, 5, 6, 7 +}; + +/* code for managing buffers needed to seperate code and data into individual + * sections until they are ready to be written to the file. + * We'd better hope that it all fits in memory else we're buggered... */ + +#define BUF_BLOCK_LEN 4088 /* selected to match page size (4096) + * on 80x86 machines for efficiency */ + +/*********************************************************************** + * Actual code to deal with RDOFF2 ouput format begins here... + */ + +/* global variables set during the initialisation phase */ + +static struct SAA *seg[RDF_MAXSEGS]; /* seg 0 = code, seg 1 = data */ +static struct SAA *header; /* relocation/import/export records */ + +static FILE *ofile; + +static efunc error; + +static struct seginfo { + char *segname; + int segnumber; + int16 segtype; + int16 segreserved; + long seglength; +} segments[RDF_MAXSEGS]; + +static int nsegments; + +static long bsslength; +static long headerlength; + +static void rdf2_init(FILE *fp, efunc errfunc, ldfunc ldef, evalfunc eval) +{ + int segtext, segdata, segbss; + + /* set up the initial segments */ + segments[0].segname = ".text"; + segments[0].segnumber = 0; + segments[0].segtype = 1; + segments[0].segreserved = 0; + segments[0].seglength = 0; + + segments[1].segname = ".data"; + segments[1].segnumber = 1; + segments[1].segtype = 2; + segments[1].segreserved = 0; + segments[1].seglength = 0; + + segments[2].segname = ".bss"; + segments[2].segnumber = 2; + segments[2].segtype = 0xFFFF; /* reserved - should never be produced */ + segments[2].segreserved = 0; + segments[2].seglength = 0; + + nsegments = 3; + + ofile = fp; + error = errfunc; + + seg[0] = saa_init(1L); + seg[1] = saa_init(1L); + seg[2] = NULL; /* special case! */ + + header = saa_init(1L); + + segtext = seg_alloc(); + segdata = seg_alloc(); + segbss = seg_alloc(); + if (segtext != 0 || segdata != 2 || segbss != 4) + error(ERR_PANIC,"rdf segment numbers not allocated as expected (%d,%d,%d)", + segtext,segdata,segbss); + bsslength=0; + headerlength = 0; +} + +static long rdf2_section_names(char *name, int pass, int *bits) +{ + int i; + char * p, * q; + int code = -1; + int reserved = 0; + + /* + * Default is 32 bits, in the text segment. + */ + if (!name) { + *bits = 32; + return 0; + } + + /* look for segment type code following segment name */ + p = name; + while (*p && !isspace(*p)) p++; + if (*p) { /* we're now in whitespace */ + *p++ = '\0'; + while (*p && isspace(80)) *p++ = '\0'; + } + if (*p) { /* we're now in an attribute value */ + /* + * see if we have an optional ',number' following the type code + */ + if ((q = strchr(p, ','))) { + *q++ = '\0'; + + reserved = readnum(q, &i); + if (i) { + error(ERR_NONFATAL, "value following comma must be numeric"); + reserved = 0; + } + } + /* + * check it against the text strings in segmenttypes + */ + + for (i = 0; i < COUNT_SEGTYPES; i++) + if (!nasm_stricmp(p, segmenttypes[i])) { + code = segmenttypenumbers[i]; + break; + } + if (code == -1) { /* didn't find anything */ + code = readnum(p, &i); + if (i) { + error(ERR_NONFATAL, "unrecognised RDF segment type (%s)",p); + code = 3; + } + } + } + for (i = 0; i < nsegments; i++) { + if (!strcmp(name, segments[i].segname)) { + if (code != -1 || reserved != 0) + error(ERR_NONFATAL, "segment attributes specified on" + " redeclaration of segment"); + return segments[i].segnumber * 2; + } + } + + /* declaring a new segment! */ + + if (code == -1) { + error(ERR_NONFATAL, "new segment declared without type code"); + code = 3; + } + if (nsegments == RDF_MAXSEGS) { + error(ERR_FATAL, "reached compiled-in maximum segment limit (%d)", + RDF_MAXSEGS); + return NO_SEG; + } + + segments[nsegments].segname = nasm_strdup(name); + i = seg_alloc(); + if (i % 2 != 0) + error(ERR_PANIC, "seg_alloc() returned odd number"); + segments[nsegments].segnumber = i >> 1; + segments[nsegments].segtype = code; + segments[nsegments].segreserved = reserved; + segments[nsegments].seglength = 0; + + seg[nsegments] = saa_init(1L); + + return i; +} + +static void write_reloc_rec(struct RelocRec *r) +{ + char buf[4],*b; + + if (r->refseg != (int16)NO_SEG && (r->refseg & 1)) /* segment base ref */ + r->type = 6; + + r->refseg >>= 1; /* adjust segment nos to RDF rather than NASM */ + + saa_wbytes(header,&r->type,1); + saa_wbytes(header,&r->reclen,1); + saa_wbytes(header,&r->segment,1); + b = buf; WRITELONG(b,r->offset); + saa_wbytes(header,buf,4); + saa_wbytes(header,&r->length,1); + b = buf; WRITESHORT(b,r->refseg); + saa_wbytes(header,buf,2); + headerlength += r->reclen + 2; +} + +static void write_export_rec(struct ExportRec *r) +{ + char buf[4], *b; + + r->segment >>= 1; + + saa_wbytes(header,&r->type,1); + saa_wbytes(header,&r->reclen,1); + saa_wbytes(header,&r->segment,1); + b = buf; WRITELONG(b,r->offset); + saa_wbytes(header,buf,4); + saa_wbytes(header,r->label,strlen(r->label) + 1); + headerlength += r->reclen + 2; +} + +static void write_import_rec(struct ImportRec *r) +{ + char buf[4], *b; + + r->segment >>= 1; + + saa_wbytes(header,&r->type,1); + saa_wbytes(header,&r->reclen,1); + b = buf; WRITESHORT(b,r->segment); + saa_wbytes(header,buf,2); + saa_wbytes(header,r->label,strlen(r->label) + 1); + headerlength += r->reclen + 2; +} + +static void write_bss_rec(struct BSSRec *r) +{ + char buf[4], *b; + + saa_wbytes(header,&r->type,1); + saa_wbytes(header,&r->reclen,1); + b = buf; WRITELONG(b,r->amount); + saa_wbytes(header,buf,4); + headerlength += r->reclen + 2; +} + +static void write_dll_rec(struct DLLRec *r) +{ + saa_wbytes(header,&r->type,1); + saa_wbytes(header,&r->reclen,1); + saa_wbytes(header,r->libname,strlen(r->libname) + 1); + headerlength += r->reclen + 2; +} + +static void rdf2_deflabel(char *name, long segment, long offset, + int is_global, char *special) +{ + struct ExportRec r; + struct ImportRec ri; +#ifdef VERBOSE_WARNINGS + static int warned_common = 0; +#endif + static int farsym = 0; + static int i; + + if (special) { + while(*special == ' ' || *special == '\t') special++; + + if (!nasm_stricmp(special, "far")) { + farsym = 1; + } + else if (!nasm_stricmp(special, "near")) { + farsym = 0; + } + else + error(ERR_NONFATAL, "unrecognised symbol type `%s'", special); + } + + if (name[0] == '.' && name[1] == '.' && name[2] != '@') { + error (ERR_NONFATAL, "unrecognised special symbol `%s'", name); + return; + } + + if (is_global == 2) { +#ifdef VERBOSE_WARNINGS + if (!warned_common) { + error(ERR_WARNING,"common declarations not supported: using extern"); + warned_common = 1; + } +#endif + is_global = 1; + } + + for (i = 0; i < nsegments; i++) { + if (segments[i].segnumber == segment>>1) break; + } + if (i >= nsegments) { /* EXTERN declaration */ + if (farsym) + ri.type = 7; + else + ri.type = 2; + ri.segment = segment; + strncpy(ri.label,name,32); + ri.label[32] = 0; + ri.reclen = 3 + strlen(ri.label); + write_import_rec(&ri); + } else if (is_global) { + r.type = 3; + r.segment = segment; + r.offset = offset; + strncpy(r.label,name,32); + r.label[32] = 0; + r.reclen = 6 + strlen(r.label); + write_export_rec(&r); + } +} + +static void membufwrite(int segment, void * data, int bytes) +{ + int i; + char buf[4], * b; + + for (i = 0; i < nsegments; i++) { + if (segments[i].segnumber == segment) break; + } + if (i == nsegments) + error(ERR_PANIC, "can't find segment %d", segment); + + if (bytes < 0) { + b = buf; + if (bytes == -2) + WRITESHORT(b,*(short *)data); + else + WRITELONG(b,*(long *)data); + data = buf; + bytes = -bytes; + } + segments[i].seglength += bytes; + saa_wbytes(seg[i],data,bytes); +} + +static int getsegmentlength(int segment) +{ + int i; + for (i = 0; i < nsegments; i++) { + if (segments[i].segnumber == segment) break; + } + if (i == nsegments) + error(ERR_PANIC, "can't find segment %d", segment); + + return segments[i].seglength; +} + +static void rdf2_out (long segto, void *data, unsigned long type, + long segment, long wrt) +{ + long bytes = type & OUT_SIZMASK; + struct RelocRec rr; + unsigned char databuf[4],*pd; + int seg; + + if (segto == NO_SEG) { + if ((type & OUT_TYPMASK) != OUT_RESERVE) + error (ERR_NONFATAL, "attempt to assemble code in ABSOLUTE space"); + return; + } + + segto >>= 1; /* convert NASM segment no to RDF number */ + + for (seg = 0; seg < nsegments; seg++) { + if (segments[seg].segnumber == segto) break; + } + if (seg >= nsegments) { + error(ERR_NONFATAL,"specified segment not supported by rdf output format"); + return; + } + + if (wrt != NO_SEG) { + wrt = NO_SEG; /* continue to do _something_ */ + error (ERR_NONFATAL, "WRT not supported by rdf output format"); + } + + type &= OUT_TYPMASK; + + if (segto == 2 && type != OUT_RESERVE) + { + error(ERR_NONFATAL, "BSS segments may not be initialised"); + + /* just reserve the space for now... */ + + if (type == OUT_REL2ADR) + bytes = 2; + else + bytes = 4; + type = OUT_RESERVE; + } + + if (type == OUT_RESERVE) { + if (segto == 2) /* BSS segment space reserverd */ + bsslength += bytes; + else + while (bytes --) + membufwrite(segto,databuf,1); + } + else if (type == OUT_RAWDATA) { + if (segment != NO_SEG) + error(ERR_PANIC, "OUT_RAWDATA with other than NO_SEG"); + + membufwrite(segto,data,bytes); + } + else if (type == OUT_ADDRESS) { + + /* if segment == NO_SEG then we are writing an address of an + object within the same segment - do not produce reloc rec. */ + + /* FIXME - is this behaviour sane? at first glance it doesn't + appear to be. Must test this thoroughly...! */ + + if (segment != NO_SEG) + { + /* it's an address, so we must write a relocation record */ + + rr.type = 1; /* type signature */ + rr.reclen = 8; + rr.segment = segto; /* segment we're currently in */ + rr.offset = getsegmentlength(segto); /* current offset */ + rr.length = bytes; /* length of reference */ + rr.refseg = segment; /* segment referred to */ + write_reloc_rec(&rr); + } + + pd = databuf; /* convert address to little-endian */ + if (bytes == 2) + WRITESHORT (pd, *(long *)data); + else + WRITELONG (pd, *(long *)data); + + membufwrite(segto,databuf,bytes); + + } + else if (type == OUT_REL2ADR) + { + if (segment == segto) + error(ERR_PANIC, "intra-segment OUT_REL2ADR"); + + rr.reclen = 8; + rr.offset = getsegmentlength(segto); /* current offset */ + rr.length = 2; /* length of reference */ + rr.refseg = segment; /* segment referred to (will be >>1'd)*/ + + if (segment != NO_SEG && segment % 2) { + rr.type = 6; + rr.segment = segto; /* memory base refs *aren't ever* relative! */ + write_reloc_rec(&rr); + + /* what do we put in the code? Simply the data. This should almost + * always be zero, unless someone's doing segment arithmetic... + */ + rr.offset = *(long *) data; + } + else + { + rr.type = 1; /* type signature */ + rr.segment = segto+64; /* segment we're currently in + rel flag */ + write_reloc_rec(&rr); + + /* work out what to put in the code: offset of the end of this operand, + * subtracted from any data specified, so that loader can just add + * address of imported symbol onto it to get address relative to end of + * instruction: import_address + data(offset) - end_of_instrn */ + + rr.offset = *(long *)data -(rr.offset + bytes); + } + + membufwrite(segto,&rr.offset,-2); + } + else if (type == OUT_REL4ADR) + { + if (segment == segto) + error(ERR_PANIC, "intra-segment OUT_REL4ADR"); + if (segment != NO_SEG && segment % 2) { + error(ERR_PANIC, "erm... 4 byte segment base ref?"); + } + + rr.type = 1; /* type signature */ + rr.segment = segto+64; /* segment we're currently in + rel tag */ + rr.offset = getsegmentlength(segto); /* current offset */ + rr.length = 4; /* length of reference */ + rr.refseg = segment; /* segment referred to */ + rr.reclen = 8; + write_reloc_rec(&rr); + + rr.offset = *(long *)data -(rr.offset + bytes); + + membufwrite(segto,&rr.offset,-4); + } +} + +static void rdf2_cleanup (int debuginfo) { + long l; + struct BSSRec bs; + int i; + + (void) debuginfo; + + /* should write imported & exported symbol declarations to header here */ + + /* generate the output file... */ + fwrite(RDOFF2Id,6,1,ofile); /* file type magic number */ + + if (bsslength != 0) /* reserve BSS */ + { + bs.type = 5; + bs.amount = bsslength; + bs.reclen = 4; + write_bss_rec(&bs); + } + + /* + * calculate overall length of the output object + */ + l = headerlength + 4; + + for (i = 0; i < nsegments; i++) { + if (i == 2) continue; /* skip BSS segment */ + l += 10 + segments[i].seglength; + } + l += 10; /* null segment */ + + fwritelong(l, ofile); + + fwritelong(headerlength, ofile); + saa_fpwrite(header,ofile); /* dump header */ + saa_free(header); + + for (i = 0; i < nsegments; i++) { + if (i == 2) continue; + + fwriteshort(segments[i].segtype, ofile); + fwriteshort(segments[i].segnumber, ofile); + fwriteshort(segments[i].segreserved, ofile); + fwritelong(segments[i].seglength, ofile); + + saa_fpwrite(seg[i], ofile); + saa_free(seg[i]); + } + + /* null segment - write 10 bytes of zero */ + fwritelong(0,ofile); + fwritelong(0,ofile); + fwriteshort(0,ofile); + + fclose(ofile); +} + +static long rdf2_segbase (long segment) { + return segment; +} + +static int rdf2_directive (char *directive, char *value, int pass) { + struct DLLRec r; + + if (! strcmp(directive, "library")) { + if (pass == 1) { + r.type = 4; + strcpy(r.libname, value); + write_dll_rec(&r); + } + return 1; + } + + return 0; +} + +static void rdf2_filename (char *inname, char *outname, efunc error) { + standard_extension(inname,outname,".rdf",error); +} + +static char *rdf2_stdmac[] = { + "%define __SECT__ [section .text]", + "%imacro library 1+.nolist", + "[library %1]", + "%endmacro", + "%macro __NASM_CDecl__ 1", + "%endmacro", + NULL +}; + +static int rdf2_set_info(enum geninfo type, char **val) +{ + return 0; +} + + +struct ofmt of_rdf2 = { + "Relocatable Dynamic Object File Format v2.0", + "rdf", + NULL, + null_debug_arr, + &null_debug_form, + rdf2_stdmac, + rdf2_init, + rdf2_set_info, + rdf2_out, + rdf2_deflabel, + rdf2_section_names, + rdf2_segbase, + rdf2_directive, + rdf2_filename, + rdf2_cleanup +}; + +#endif /* OF_RDF2 */ diff --git a/parser.c b/parser.c index d7bbdb0c..704e2eb4 100644 --- a/parser.c +++ b/parser.c @@ -41,26 +41,34 @@ static int is_comma_next (void); static int i; static struct tokenval tokval; static efunc error; +static struct ofmt *outfmt; /* Structure of addresses of output routines */ +static loc_t *location; /* Pointer to current line's segment,offset */ + +void parser_global_info (struct ofmt *output, loc_t *locp) +{ + outfmt = output; + location = locp; +} insn *parse_line (int pass, char *buffer, insn *result, - efunc errfunc, evalfunc evaluate, evalinfofunc einfo) { + efunc errfunc, evalfunc evaluate, ldfunc ldef) +{ int operand; int critical; struct eval_hints hints; result->forw_ref = FALSE; error = errfunc; - einfo ("", 0L, 0L); stdscan_reset(); stdscan_bufptr = buffer; i = stdscan(NULL, &tokval); + result->label = NULL; /* Assume no label */ result->eops = NULL; /* must do this, whatever happens */ result->operands = 0; /* must initialise this */ if (i==0) { /* blank line - ignore */ - result->label = NULL; /* so, no label on it */ result->opcode = -1; /* and no instruction either */ return result; } @@ -68,23 +76,32 @@ insn *parse_line (int pass, char *buffer, insn *result, (i!=TOKEN_REG || (REG_SREG & ~reg_flags[tokval.t_integer]))) { error (ERR_NONFATAL, "label or instruction expected" " at start of line"); - result->label = NULL; result->opcode = -1; return result; } if (i == TOKEN_ID) { /* there's a label here */ result->label = tokval.t_charptr; - einfo (result->label, 0L, 0L); i = stdscan(NULL, &tokval); if (i == ':') { /* skip over the optional colon */ i = stdscan(NULL, &tokval); - } else if (i == 0 && pass == 1) { - error (ERR_WARNING|ERR_WARN_OL, + } else if (i == 0) { + error (ERR_WARNING|ERR_WARN_OL|ERR_PASS1, "label alone on a line without a colon might be in error"); } - } else /* no label; so, moving swiftly on */ - result->label = NULL; + if (i != TOKEN_INSN || tokval.t_integer != I_EQU) + { + /* + * FIXME: location->segment could be NO_SEG, in which case + * it is possible we should be passing 'abs_seg'. Look into this. + * Work out whether that is *really* what we should be doing. + * Generally fix things. I think this is right as it is, but + * am still not certain. + */ + ldef (result->label, location->segment, + location->offset, NULL, TRUE, FALSE, outfmt, errfunc); + } + } if (i==0) { result->opcode = -1; /* this line contains just a label */ @@ -95,7 +112,8 @@ insn *parse_line (int pass, char *buffer, insn *result, result->times = 1L; while (i == TOKEN_PREFIX || - (i==TOKEN_REG && !(REG_SREG & ~reg_flags[tokval.t_integer]))) { + (i==TOKEN_REG && !(REG_SREG & ~reg_flags[tokval.t_integer]))) + { /* * Handle special case: the TIMES prefix. */ @@ -115,9 +133,11 @@ insn *parse_line (int pass, char *buffer, insn *result, result->times = 1L; } else { result->times = value->value; - if (value->value < 0) + if (value->value < 0) { error(ERR_NONFATAL, "TIMES value %d is negative", value->value); + result->times = 0; + } } } else { if (result->nprefix == MAXPREFIX) @@ -169,7 +189,9 @@ insn *parse_line (int pass, char *buffer, insn *result, result->opcode == I_RESQ || result->opcode == I_REST || result->opcode == I_EQU) + { critical = pass; + } else critical = (pass==2 ? 2 : 0); @@ -178,12 +200,15 @@ insn *parse_line (int pass, char *buffer, insn *result, result->opcode == I_DD || result->opcode == I_DQ || result->opcode == I_DT || - result->opcode == I_INCBIN) { + result->opcode == I_INCBIN) + { extop *eop, **tail = &result->eops, **fixptr; int oper_num = 0; + result->eops_float = FALSE; + /* - * Begin to read the DB/DW/DD/DQ/DT operands. + * Begin to read the DB/DW/DD/DQ/DT/INCBIN operands. */ while (1) { i = stdscan(NULL, &tokval); @@ -204,14 +229,14 @@ insn *parse_line (int pass, char *buffer, insn *result, continue; } - if (i == TOKEN_FLOAT || i == '-') { + if ((i == TOKEN_FLOAT && is_comma_next()) || i == '-') { long sign = +1L; if (i == '-') { char *save = stdscan_bufptr; i = stdscan(NULL, &tokval); sign = -1L; - if (i != TOKEN_FLOAT) { + if (i != TOKEN_FLOAT || !is_comma_next()) { stdscan_bufptr = save; i = tokval.t_type = '-'; } @@ -219,23 +244,30 @@ insn *parse_line (int pass, char *buffer, insn *result, if (i == TOKEN_FLOAT) { eop->type = EOT_DB_STRING; + result->eops_float = TRUE; if (result->opcode == I_DD) eop->stringlen = 4; else if (result->opcode == I_DQ) eop->stringlen = 8; else if (result->opcode == I_DT) - eop->stringlen = 10; + eop->stringlen = 10; else { error(ERR_NONFATAL, "floating-point constant" " encountered in `D%c' instruction", result->opcode == I_DW ? 'W' : 'B'); - eop->type = EOT_NOTHING; + /* + * fix suggested by Pedro Gimeno... original line + * was: + * eop->type = EOT_NOTHING; + */ + eop->stringlen = 0; } eop = nasm_realloc(eop, sizeof(extop)+eop->stringlen); tail = &eop->next; *fixptr = eop; eop->stringval = (char *)eop + sizeof(extop); - if (!float_const (tokval.t_charptr, sign, + if (eop->stringlen < 4 || + !float_const (tokval.t_charptr, sign, (unsigned char *)eop->stringval, eop->stringlen, error)) eop->type = EOT_NOTHING; @@ -244,7 +276,8 @@ insn *parse_line (int pass, char *buffer, insn *result, } } - /* anything else */ { + /* anything else */ + { expr *value; value = evaluate (stdscan, NULL, &tokval, NULL, critical, error, NULL); @@ -312,7 +345,12 @@ insn *parse_line (int pass, char *buffer, insn *result, */ result->opcode = -1; return result; - } + } else /* DB ... */ + if (oper_num == 0) + error (ERR_WARNING|ERR_PASS1, + "no operand for data declaration"); + else + result->operands = oper_num; return result; } @@ -324,29 +362,42 @@ insn *parse_line (int pass, char *buffer, insn *result, expr *value; /* used most of the time */ int mref; /* is this going to be a memory ref? */ int bracket; /* is it a [] mref, or a & mref? */ + int setsize = 0; result->oprs[operand].addr_size = 0;/* have to zero this whatever */ result->oprs[operand].eaflags = 0; /* and this */ + result->oprs[operand].opflags = 0; + i = stdscan(NULL, &tokval); if (i == 0) break; /* end of operands: get out of here */ result->oprs[operand].type = 0; /* so far, no override */ while (i == TOKEN_SPECIAL) {/* size specifiers */ switch ((int)tokval.t_integer) { case S_BYTE: - result->oprs[operand].type |= BITS8; + if (!setsize) /* we want to use only the first */ + result->oprs[operand].type |= BITS8; + setsize = 1; break; case S_WORD: - result->oprs[operand].type |= BITS16; + if (!setsize) + result->oprs[operand].type |= BITS16; + setsize = 1; break; case S_DWORD: case S_LONG: - result->oprs[operand].type |= BITS32; + if (!setsize) + result->oprs[operand].type |= BITS32; + setsize = 1; break; case S_QWORD: - result->oprs[operand].type |= BITS64; + if (!setsize) + result->oprs[operand].type |= BITS64; + setsize = 1; break; case S_TWORD: - result->oprs[operand].type |= BITS80; + if (!setsize) + result->oprs[operand].type |= BITS80; + setsize = 1; break; case S_TO: result->oprs[operand].type |= TO; @@ -360,6 +411,8 @@ insn *parse_line (int pass, char *buffer, insn *result, case S_SHORT: result->oprs[operand].type |= SHORT; break; + default: + error (ERR_NONFATAL, "invalid operand size specification"); } i = stdscan(NULL, &tokval); } @@ -397,8 +450,12 @@ insn *parse_line (int pass, char *buffer, insn *result, } value = evaluate (stdscan, NULL, &tokval, - &result->forw_ref, critical, error, &hints); + &result->oprs[operand].opflags, + critical, error, &hints); i = tokval.t_type; + if (result->oprs[operand].opflags & OPFLAG_FORWARD) { + result->forw_ref = TRUE; + } if (!value) { /* error in evaluator */ result->opcode = -1; /* unrecoverable parse error: */ return result; /* ignore this instruction */ @@ -434,8 +491,12 @@ insn *parse_line (int pass, char *buffer, insn *result, i = stdscan(NULL, &tokval); } value = evaluate (stdscan, NULL, &tokval, - &result->forw_ref, critical, error, &hints); + &result->oprs[operand].opflags, + critical, error, &hints); i = tokval.t_type; + if (result->oprs[operand].opflags & OPFLAG_FORWARD) { + result->forw_ref = TRUE; + } /* and get the offset */ if (!value) { /* but, error in evaluator */ result->opcode = -1; /* unrecoverable parse error: */ @@ -480,34 +541,38 @@ insn *parse_line (int pass, char *buffer, insn *result, i = e->type, s = e->value; e++; } - if (e->type && e->type <= EXPR_REG_END) {/* it's a 2nd register */ - if (e->value != 1) { /* it has to be indexreg */ - if (i != -1) { /* but it can't be */ - error(ERR_NONFATAL, "invalid effective address"); - result->opcode = -1; - return result; - } else - i = e->type, s = e->value; - } else { /* it can be basereg */ - if (b != -1) /* or can it? */ - i = e->type, s = 1; - else - b = e->type; - } + if (e->type && e->type <= EXPR_REG_END) /* it's a 2nd register */ + { + if (b != -1) /* If the first was the base, ... */ + i = e->type, s = e->value; /* second has to be indexreg */ + + else if (e->value != 1) /* If both want to be index */ + { + error(ERR_NONFATAL, "invalid effective address"); + result->opcode = -1; + return result; + } + else + b = e->type; e++; } if (e->type != 0) { /* is there an offset? */ - if (e->type <= EXPR_REG_END) {/* in fact, is there an error? */ + if (e->type <= EXPR_REG_END) /* in fact, is there an error? */ + { error (ERR_NONFATAL, "invalid effective address"); result->opcode = -1; return result; - } else { + } + else + { if (e->type == EXPR_UNKNOWN) { - o = 0; /* doesn't matter what */ - result->oprs[operand].wrt = NO_SEG; /* nor this */ + o = 0; /* doesn't matter what */ + result->oprs[operand].wrt = NO_SEG; /* nor this */ result->oprs[operand].segment = NO_SEG; /* or this */ while (e->type) e++; /* go to the end of the line */ - } else { + } + else + { if (e->type == EXPR_SIMPLE) { o = e->value; e++; @@ -566,30 +631,63 @@ insn *parse_line (int pass, char *buffer, insn *result, result->oprs[operand].indexreg = i; result->oprs[operand].scale = s; result->oprs[operand].offset = o; - } else { /* it's not a memory reference */ + } + else /* it's not a memory reference */ + { if (is_just_unknown(value)) { /* it's immediate but unknown */ result->oprs[operand].type |= IMMEDIATE; result->oprs[operand].offset = 0; /* don't care */ result->oprs[operand].segment = NO_SEG; /* don't care again */ result->oprs[operand].wrt = NO_SEG;/* still don't care */ - } else if (is_reloc(value)) { /* it's immediate */ + } + else if (is_reloc(value)) /* it's immediate */ + { result->oprs[operand].type |= IMMEDIATE; result->oprs[operand].offset = reloc_value(value); result->oprs[operand].segment = reloc_seg(value); result->oprs[operand].wrt = reloc_wrt(value); if (is_simple(value) && reloc_value(value)==1) result->oprs[operand].type |= UNITY; - } else { /* it's a register */ + } + else /* it's a register */ + { + int i; + if (value->type>=EXPR_SIMPLE || value->value!=1) { error (ERR_NONFATAL, "invalid operand type"); result->opcode = -1; return result; } + + /* + * check that its only 1 register, not an expression... + */ + for (i = 1; value[i].type; i++) + if (value[i].value) { + error (ERR_NONFATAL, "invalid operand type"); + result->opcode = -1; + return result; + } + /* clear overrides, except TO which applies to FPU regs */ + if (result->oprs[operand].type & ~TO) { + /* + * we want to produce a warning iff the specified size + * is different from the register size + */ + i = result->oprs[operand].type & SIZE_MASK; + } + else + i = 0; + result->oprs[operand].type &= TO; result->oprs[operand].type |= REGISTER; result->oprs[operand].type |= reg_flags[value->type]; result->oprs[operand].basereg = value->type; + + if (i && (result->oprs[operand].type & SIZE_MASK) != i) + error (ERR_WARNING|ERR_PASS1, + "register size specification ignored"); } } } @@ -612,7 +710,8 @@ insn *parse_line (int pass, char *buffer, insn *result, return result; } -static int is_comma_next (void) { +static int is_comma_next (void) +{ char *p; int i; struct tokenval tv; @@ -623,7 +722,8 @@ static int is_comma_next (void) { return (i == ',' || i == ';' || !i); } -void cleanup_insn (insn *i) { +void cleanup_insn (insn *i) +{ extop *e; while (i->eops) { diff --git a/parser.h b/parser.h index 0681cd03..bc2135de 100644 --- a/parser.h +++ b/parser.h @@ -10,8 +10,9 @@ #ifndef NASM_PARSER_H #define NASM_PARSER_H +void parser_global_info (struct ofmt *output, loc_t *locp); insn *parse_line (int pass, char *buffer, insn *result, - efunc error, evalfunc evaluate, evalinfofunc einfo); + efunc error, evalfunc evaluate, ldfunc ldef); void cleanup_insn (insn *instruction); #endif diff --git a/preproc.c b/preproc.c index 032854e1..291b57ec 100644 --- a/preproc.c +++ b/preproc.c @@ -8,6 +8,11 @@ * initial version 18/iii/97 by Simon Tatham */ +#define br0 '{' +#define br1 "{" +#define br2 '}' +#define br3 "}" + #include #include #include @@ -64,12 +69,14 @@ struct MMacro { int plus; /* is the last parameter greedy? */ int nolist; /* is this macro listing-inhibited? */ int in_progress; - Token **defaults, *dlist; + Token *dlist; /* All defaults as one list */ + Token **defaults; /* Parameter default pointers */ int ndefs; /* number of default parameters */ Line *expansion; MMacro *next_active; - Token **params, *iline; + Token **params; /* actual parameters */ + Token *iline; /* invocation line */ int nparam, rotate, *paramlen; unsigned long unique; }; @@ -88,11 +95,6 @@ struct Context { * This is the internal form which we break input lines up into. * Typically stored in linked lists. * - * TOK_PS_OTHER is a token type used internally within - * expand_smacro(), to denote a token which has already been - * checked for being a potential macro, but may still be a context- - * local label. - * * Note that `type' serves a double meaning: TOK_SMAC_PARAM is not * necessarily used as-is, but is intended to denote the number of * the substituted parameter. So in the definition @@ -116,7 +118,7 @@ struct Token { }; enum { TOK_WHITESPACE = 1, TOK_COMMENT, TOK_ID, TOK_PREPROC_ID, TOK_STRING, - TOK_NUMBER, TOK_SMAC_END, TOK_OTHER, TOK_PS_OTHER, TOK_SMAC_PARAM, + TOK_NUMBER, TOK_SMAC_END, TOK_OTHER, TOK_SMAC_PARAM, TOK_INTERNAL_STRING }; @@ -271,14 +273,14 @@ static int pass; static unsigned long unique; /* unique identifier numbers */ -static char *linesync, *outline; - static Line *predef = NULL; static ListGen *list; /* * The number of hash values we use for the macro lookup tables. + * FIXME: We should *really* be able to configure this at run time, + * or even have the hash table automatically expanding when necessary. */ #define NHASH 31 @@ -321,7 +323,15 @@ int any_extrastdmac; * Forward declarations. */ static Token *expand_smacro (Token *tline); -static void update_fileline (int which); +static void make_tok_num(Token *tok, long val); + +/* + * Macros for safe checking of token pointers, avoid *(NULL) + */ +#define tok_type_(x,t) ((x) && (x)->type == (t)) +#define skip_white_(x) if (tok_type_((x), TOK_WHITESPACE)) (x)=(x)->next +#define tok_is_(x,v) (tok_type_((x), TOK_OTHER) && !strcmp((x)->text,(v))) +#define tok_isnt_(x,v) ((x) && ((x)->type!=TOK_OTHER || strcmp((x)->text,(v)))) /* * The pre-preprocessing stage... This function translates line @@ -329,7 +339,8 @@ static void update_fileline (int which); * flags') into NASM preprocessor line number indications (`%line * lineno file'). */ -static char *prepreproc(char *line) { +static char *prepreproc(char *line) +{ int lineno, fnlen; char *fname, *oldline; @@ -354,7 +365,10 @@ static char *prepreproc(char *line) { * invariant under case changes. We implement this by applying a * perfectly normal hash function to the uppercase of the string. */ -static int hash(char *s) { +static int hash(char *s) +{ + unsigned int h = 0; + int i = 0; /* * Powers of three, mod 31. */ @@ -362,8 +376,7 @@ static int hash(char *s) { 1, 3, 9, 27, 19, 26, 16, 17, 20, 29, 25, 13, 8, 24, 10, 30, 28, 22, 4, 12, 5, 15, 14, 11, 2, 6, 18, 23, 7, 21 }; - int h = 0; - int i = 0; + while (*s) { h += multipliers[i] * (unsigned char) (toupper(*s)); @@ -378,7 +391,8 @@ static int hash(char *s) { /* * Free a linked list of tokens. */ -static void free_tlist (Token *list) { +static void free_tlist (Token *list) +{ Token *t; while (list) { t = list; @@ -391,7 +405,8 @@ static void free_tlist (Token *list) { /* * Free a linked list of lines. */ -static void free_llist (Line *list) { +static void free_llist (Line *list) +{ Line *l; while (list) { l = list; @@ -401,10 +416,23 @@ static void free_llist (Line *list) { } } +/* + * Free an MMacro + */ +static void free_mmacro (MMacro *m) +{ + nasm_free (m->name); + free_tlist (m->dlist); + nasm_free (m->defaults); + free_llist (m->expansion); + nasm_free (m); +} + /* * Pop the context stack. */ -static void ctx_pop (void) { +static void ctx_pop (void) +{ Context *c = cstk; SMacro *smac, *s; @@ -421,19 +449,6 @@ static void ctx_pop (void) { nasm_free (c); } -/* - * Generate a line synchronisation comment, to ensure the assembler - * knows which source file the current output has really come from. - */ -static void line_sync (void) { - char text[30+FILENAME_MAX]; - sprintf(text, "%%line %d+%d %s", - (istk->expansion ? istk->lineno - istk->lineinc : istk->lineno), - (istk->expansion ? 0 : istk->lineinc), istk->fname); - nasm_free (linesync); - linesync = nasm_strdup(text); -} - #define BUF_DELTA 512 /* * Read a line from the top file in istk, handling multiple CR/LFs @@ -441,14 +456,16 @@ static void line_sync (void) { * return lines from the standard macro set if this has not already * been done. */ -static char *read_line (void) { +static char *read_line (void) +{ char *buffer, *p, *q; int bufsize; if (stdmacpos) { if (*stdmacpos) { char *ret = nasm_strdup(*stdmacpos++); - if (!*stdmacpos && any_extrastdmac) { + if (!*stdmacpos && any_extrastdmac) + { stdmacpos = extrastdmac; any_extrastdmac = FALSE; return ret; @@ -459,7 +476,8 @@ static char *read_line (void) { * most convenient way to implement the pre-include and * pre-define features. */ - if (!*stdmacpos) { + if (!*stdmacpos) + { Line *pd, *l; Token *head, **tail, *t, *tt; @@ -482,10 +500,9 @@ static char *read_line (void) { } } return ret; - } else { + } + else { stdmacpos = NULL; - line_sync(); - update_fileline(3); /* update __FILE__ and __LINE__ */ } } @@ -498,13 +515,13 @@ static char *read_line (void) { break; p += strlen(p); if (p > buffer && p[-1] == '\n') { - istk->lineno += istk->lineinc; - update_fileline(1); /* update __LINE__ only */ break; } if (p-buffer > bufsize-10) { + long offset = p-buffer; bufsize += BUF_DELTA; buffer = nasm_realloc(buffer, bufsize); + p = buffer+offset; /* prevent stale-pointer problems */ } } @@ -513,12 +530,14 @@ static char *read_line (void) { return NULL; } + src_set_linnum(src_get_linnum() + istk->lineinc); + /* * Play safe: remove CRs as well as LFs, if any of either are * present at the end of the line. */ - while (p > buffer && (p[-1] == '\n' || p[-1] == '\r')) - *--p = '\0'; + while (--p >= buffer && (*p == '\n' || *p == '\r')) + *p = '\0'; /* * Handle spurious ^Z, which may be inserted into source files @@ -536,7 +555,8 @@ static char *read_line (void) { * don't need to parse the value out of e.g. numeric tokens: we * simply split one string into many. */ -static Token *tokenise (char *line) { +static Token *tokenise (char *line) +{ char *p = line; int type; Token *list = NULL; @@ -544,31 +564,42 @@ static Token *tokenise (char *line) { while (*line) { p = line; - if (*p == '%' && - (p[1] == '{' || p[1] == '!' || (p[1] == '%' && isidchar(p[2])) || - p[1] == '$' || p[1] == '+' || p[1] == '-' || isidchar(p[1]))) { - type = TOK_PREPROC_ID; + if (*p == '%' && ( isdigit(p[1]) || + ((p[1] == '-' || p[1] == '+') && isdigit(p[2])))) + { p++; - if (*p == '{') { + do { + p++; + } while (isdigit(*p)); + type = TOK_PREPROC_ID; + } + else if (*p == '%' && p[1] == '{') { + p += 2; + while (*p && *p != '}') { + p[-1] = *p; p++; - while (*p && *p != '}') { - p[-1] = *p; - p++; - } - p[-1] = '\0'; - if (*p) p++; - } else { - if (*p == '!' || *p == '%' || *p == '$' || - *p == '+' || *p == '-') p++; - while (*p && isidchar(*p)) - p++; } - } else if (isidstart(*p) || (*p == '$' && isidstart(p[1]))) { + p[-1] = '\0'; + if (*p) p++; + type = TOK_PREPROC_ID; + } + else if (*p == '%' && (isidchar(p[1]) || + ((p[1] == '!' || p[1] == '%' || p[1] == '$') && + isidchar(p[2])))) + { + p++; + do { + p++; + } while (isidchar(*p)); + type = TOK_PREPROC_ID; + } + else if (isidstart(*p) || (*p == '$' && isidstart(p[1]))) { type = TOK_ID; p++; while (*p && isidchar(*p)) p++; - } else if (*p == '\'' || *p == '"') { + } + else if (*p == '\'' || *p == '"') { /* * A string token. */ @@ -578,7 +609,8 @@ static Token *tokenise (char *line) { while (*p && *p != c) p++; if (*p) p++; - } else if (isnumstart(*p)) { + } + else if (isnumstart(*p)) { /* * A number token. */ @@ -586,7 +618,8 @@ static Token *tokenise (char *line) { p++; while (*p && isnumchar(*p)) p++; - } else if (isspace(*p)) { + } + else if (isspace(*p)) { type = TOK_WHITESPACE; p++; while (*p && isspace(*p)) @@ -600,10 +633,12 @@ static Token *tokenise (char *line) { type = TOK_COMMENT; while (*p) p++; } - } else if (*p == ';') { + } + else if (*p == ';') { type = TOK_COMMENT; while (*p) p++; - } else { + } + else { /* * Anything else is an operator of some kind. We check * for all the double-character operators (>>, <<, //, @@ -623,7 +658,9 @@ static Token *tokenise (char *line) { (p[0] == '&' && p[1] == '&') || (p[0] == '|' && p[1] == '|') || (p[0] == '^' && p[1] == '^')) + { p++; + } p++; } if (type != TOK_COMMENT) { @@ -644,7 +681,8 @@ static Token *tokenise (char *line) { /* * Convert a line of tokens back into text. */ -static char *detoken (Token *tlist) { +char *detoken (Token *tlist) +{ Token *t; int len; char *line, *p; @@ -679,7 +717,8 @@ static char *detoken (Token *tlist) { * the first token in the line to be passed in as its private_data * field. */ -static int ppscan(void *private_data, struct tokenval *tokval) { +static int ppscan(void *private_data, struct tokenval *tokval) +{ Token **tlineptr = private_data; Token *tline; @@ -724,6 +763,25 @@ static int ppscan(void *private_data, struct tokenval *tokval) { return tokval->t_type = TOKEN_NUM; } + if (tline->type == TOK_STRING) { + int rn_warn; + char q, *r; + int l; + + r = tline->text; + q = *r++; + l = strlen(r); + + if (l == 0 || r[l-1] != q) + return tokval->t_type = TOKEN_ERRNUM; + tokval->t_integer = readstrnum(r, l-1, &rn_warn); + if (rn_warn) + error(ERR_WARNING|ERR_PASS1, + "character constant too long"); + tokval->t_charptr = NULL; + return tokval->t_type = TOKEN_NUM; + } + if (tline->type == TOK_OTHER) { if (!strcmp(tline->text, "<<")) return tokval->t_type = TOKEN_SHL; if (!strcmp(tline->text, ">>")) return tokval->t_type = TOKEN_SHR; @@ -752,12 +810,13 @@ static int ppscan(void *private_data, struct tokenval *tokval) { * context stack isn't deep enough for the supplied number of $ * signs. */ -static Context *get_ctx (char *name) { +static Context *get_ctx (char *name) +{ Context *ctx; int i; if (!cstk) { - error (ERR_NONFATAL|ERR_OFFBY1, "`%s': context stack is empty", name); + error (ERR_NONFATAL, "`%s': context stack is empty", name); return NULL; } @@ -767,7 +826,7 @@ static Context *get_ctx (char *name) { i++; ctx = ctx->next; if (!ctx) { - error (ERR_NONFATAL|ERR_OFFBY1, "`%s': context stack is only" + error (ERR_NONFATAL, "`%s': context stack is only" " %d level%s deep", name, i-1, (i==2 ? "" : "s")); return NULL; } @@ -780,7 +839,8 @@ static Context *get_ctx (char *name) { * simple wrapper which calls either strcmp or nasm_stricmp * depending on the value of the `casesense' parameter. */ -static int mstrcmp(char *p, char *q, int casesense) { +static int mstrcmp(char *p, char *q, int casesense) +{ return casesense ? strcmp(p,q) : nasm_stricmp(p,q); } @@ -791,26 +851,25 @@ static int mstrcmp(char *p, char *q, int casesense) { * the include path one by one until it finds the file or reaches * the end of the path. */ -static FILE *inc_fopen(char *file) { +static FILE *inc_fopen(char *file) +{ FILE *fp; char *prefix = "", *combine; IncPath *ip = ipath; - int len = strlen(file); - do { - combine = nasm_malloc(strlen(prefix)+len+1); - strcpy(combine, prefix); - strcat(combine, file); + while (1) { + combine = nasm_strcat(prefix,file); fp = fopen(combine, "r"); nasm_free (combine); if (fp) return fp; - prefix = ip ? ip->path : NULL; - if (ip) - ip = ip->next; - } while (prefix); + if (!ip) + break; + prefix = ip->path; + ip = ip->next; + } - error (ERR_FATAL|ERR_OFFBY1, + error (ERR_FATAL, "unable to open include file `%s'", file); return NULL; /* never reached - placate compilers */ } @@ -831,7 +890,8 @@ static FILE *inc_fopen(char *file) { * Note that this is also called with nparam zero to resolve * `ifdef'. */ -static int smacro_defined (char *name, int nparam, SMacro **defn) { +static int smacro_defined (char *name, int nparam, SMacro **defn, int nocase) +{ SMacro *m; Context *ctx; char *p; @@ -849,7 +909,7 @@ static int smacro_defined (char *name, int nparam, SMacro **defn) { } while (m) { - if (!mstrcmp(m->name, p, m->casesense) && + if (!mstrcmp(m->name, p, m->casesense & nocase) && (nparam == 0 || m->nparam == 0 || nparam == m->nparam)) { if (defn) { if (nparam == m->nparam) @@ -864,49 +924,14 @@ static int smacro_defined (char *name, int nparam, SMacro **defn) { return FALSE; } -/* - * Update the __FILE__ and __LINE__ macros. Specifically, update - * __FILE__ if bit 1 of our argument is set, and update __LINE__ if - * bit 0 is set. - * - * If the macros don't exist, a `%clear' must have happened, in - * which case we should exit quite happily and carry on going. It's - * not an error condition. - */ -static void update_fileline(int which) { - SMacro *sm; - char num[20]; - - if ((which & 3) && smacro_defined ("__FILE__", 0, &sm) && sm) { - free_tlist(sm->expansion); - sm->expansion = nasm_malloc(sizeof(Token)); - sm->expansion->next = NULL; - sm->expansion->mac = NULL; - sm->expansion->type = TOK_STRING; - sm->expansion->text = nasm_malloc(3+strlen(istk->fname)); - /* FIXME: throw an error if both sorts of quote are present */ - /* Better still, invent a way for us to cope with that case */ - sprintf(sm->expansion->text, "\"%s\"", istk->fname); - } - - if ((which & 1) && smacro_defined ("__LINE__", 0, &sm) && sm) { - free_tlist(sm->expansion); - sm->expansion = nasm_malloc(sizeof(Token)); - sm->expansion->next = NULL; - sm->expansion->mac = NULL; - sm->expansion->type = TOK_NUMBER; - sprintf(num, "%d", istk->lineno - istk->lineinc); - sm->expansion->text = nasm_strdup(num); - } -} - /* * Count and mark off the parameters in a multi-line macro call. * This is called both from within the multi-line macro expansion * code, and also to mark off the default parameters when provided * in a %macro definition line. */ -static void count_mmac_params (Token *t, int *nparam, Token ***params) { +static void count_mmac_params (Token *t, int *nparam, Token ***params) +{ int paramsize, brace; *nparam = paramsize = 0; @@ -916,14 +941,12 @@ static void count_mmac_params (Token *t, int *nparam, Token ***params) { paramsize += PARAM_DELTA; *params = nasm_realloc(*params, sizeof(**params) * paramsize); } - if (t && t->type == TOK_WHITESPACE) - t = t->next; + skip_white_(t); brace = FALSE; - if (t && t->type == TOK_OTHER && !strcmp(t->text, "{")) + if (tok_is_(t, "{")) brace = TRUE; (*params)[(*nparam)++] = t; - while (t && (t->type != TOK_OTHER || - strcmp(t->text, brace ? "}" : ","))) + while (tok_isnt_(t, brace ? "}" : ",")) t = t->next; if (t) { /* got a comma/brace */ t = t->next; @@ -932,21 +955,17 @@ static void count_mmac_params (Token *t, int *nparam, Token ***params) { * Now we've found the closing brace, look further * for the comma. */ - if (t && t->type == TOK_WHITESPACE) - t = t->next; - if (t && (t->type != TOK_OTHER || strcmp(t->text, ","))) { - error (ERR_NONFATAL|ERR_OFFBY1, + skip_white_(t); + if (tok_isnt_(t, ",")) { + error (ERR_NONFATAL, "braces do not enclose all of macro parameter"); - while (t && (t->type != TOK_OTHER || - strcmp(t->text, ","))) + while (tok_isnt_(t, ",")) t = t->next; } if (t) t = t->next; /* eat the comma */ } } - else /* got EOL */ - break; } } @@ -956,11 +975,12 @@ static void count_mmac_params (Token *t, int *nparam, Token ***params) { * * We must free the tline we get passed. */ -static int if_condition (Token *tline, int i) { - int j, casesense; - Token *t, *tt, **tptr, *origline; +static int if_condition (Token *tline, int i) +{ + int j, casesense; + Token * t, * tt, ** tptr, * origline; struct tokenval tokval; - expr *evalresult; + expr * evalresult; origline = tline; @@ -969,13 +989,12 @@ static int if_condition (Token *tline, int i) { case PP_IFNCTX: case PP_ELIFNCTX: j = FALSE; /* have we matched yet? */ if (!cstk) - error(ERR_FATAL|ERR_OFFBY1, + error(ERR_FATAL, "`%s': context stack is empty", directives[i]); else while (tline) { - if (tline->type == TOK_WHITESPACE) - tline = tline->next; + skip_white_(tline); if (!tline || tline->type != TOK_ID) { - error(ERR_NONFATAL|ERR_OFFBY1, + error(ERR_NONFATAL, "`%s' expects context identifiers", directives[i]); free_tlist (origline); return -1; @@ -993,18 +1012,17 @@ static int if_condition (Token *tline, int i) { case PP_IFNDEF: case PP_ELIFNDEF: j = FALSE; /* have we matched yet? */ while (tline) { - if (tline->type == TOK_WHITESPACE) - tline = tline->next; + skip_white_(tline); if (!tline || (tline->type != TOK_ID && (tline->type != TOK_PREPROC_ID || tline->text[1] != '$'))) { - error(ERR_NONFATAL|ERR_OFFBY1, + error(ERR_NONFATAL, "`%%if%sdef' expects macro identifiers", (i==PP_ELIFNDEF ? "n" : "")); free_tlist (origline); return -1; } - if (smacro_defined(tline->text, 0, NULL)) + if (smacro_defined(tline->text, 0, NULL, 1)) j = TRUE; tline = tline->next; } @@ -1017,7 +1035,7 @@ static int if_condition (Token *tline, int i) { case PP_IFIDNI: case PP_ELIFIDNI: case PP_IFNIDNI: case PP_ELIFNIDNI: tline = expand_smacro(tline); t = tt = tline; - while (tt && (tt->type != TOK_OTHER || strcmp(tt->text, ","))) + while (tok_isnt_(tt, ",")) tt = tt->next; if (!tt) { error(ERR_NONFATAL, "`%s' expects two comma-separated arguments"); @@ -1054,7 +1072,8 @@ static int if_condition (Token *tline, int i) { } if ((t->type != TOK_OTHER || strcmp(t->text, ",")) || tt) j = FALSE; /* trailing gunk on one end or other */ - if (i == PP_IFNIDN || i == PP_ELIFNIDN) + if (i == PP_IFNIDN || i == PP_ELIFNIDN || + i == PP_IFNIDNI || i == PP_ELIFNIDNI) j = !j; free_tlist (tline); return j; @@ -1064,10 +1083,10 @@ static int if_condition (Token *tline, int i) { case PP_IFSTR: case PP_ELIFSTR: case PP_IFNSTR: case PP_ELIFNSTR: tline = expand_smacro(tline); t = tline; - while (t && t->type == TOK_WHITESPACE) + while (tok_type_(t, TOK_WHITESPACE)) t = t->next; j = FALSE; /* placate optimiser */ - switch (i) { + if (t) switch (i) { case PP_IFID: case PP_ELIFID: case PP_IFNID: case PP_ELIFNID: j = (t->type == TOK_ID); break; @@ -1095,17 +1114,17 @@ static int if_condition (Token *tline, int i) { if (!evalresult) return -1; if (tokval.t_type) - error(ERR_WARNING|ERR_OFFBY1, + error(ERR_WARNING, "trailing garbage after expression ignored"); if (!is_simple(evalresult)) { - error(ERR_NONFATAL|ERR_OFFBY1, + error(ERR_NONFATAL, "non-constant value given to `%s'", directives[i]); return -1; } return reloc_value(evalresult) != 0; default: - error(ERR_FATAL|ERR_OFFBY1, + error(ERR_FATAL, "preprocessor directive `%s' not yet implemented", directives[i]); free_tlist (origline); @@ -1123,14 +1142,9 @@ static int if_condition (Token *tline, int i) { * Return values go like this: * * bit 0 is set if a directive was found (so the line gets freed) - * bit 1 is set if a blank line should be emitted - * bit 2 is set if a re-sync line number comment should be emitted - * - * (bits 1 and 2 are mutually exclusive in that the rest of the - * preprocessor doesn't guarantee to be able to handle the case in - * which both are set) */ -static int do_directive (Token *tline) { +static int do_directive (Token *tline) +{ int i, j, k, m, nparam, nolist; char *p, *mname; Include *inc; @@ -1145,9 +1159,8 @@ static int do_directive (Token *tline) { origline = tline; - if (tline && tline->type == TOK_WHITESPACE) - tline = tline->next; - if (!tline || tline->type != TOK_PREPROC_ID || + skip_white_(tline); + if (!tok_type_(tline, TOK_PREPROC_ID) || (tline->text[1]=='%' || tline->text[1]=='$' || tline->text[1]=='!')) return 0; @@ -1190,21 +1203,26 @@ static int do_directive (Token *tline) { i != PP_IFNUM && i != PP_ELIFNUM && i != PP_IFSTR && i != PP_ELIFSTR && i != PP_ELSE && i != PP_ENDIF) + { return 0; + } /* * If we're defining a macro or reading a %rep block, we should * ignore all directives except for %macro/%imacro (which * generate an error), %endm/%endmacro, and (only if we're in a - * %rep block) %endrep. + * %rep block) %endrep. If we're in a %rep block, another %rep + * causes an error, so should be let through. */ if (defining && i != PP_MACRO && i != PP_IMACRO && i != PP_ENDMACRO && i != PP_ENDM && - (defining->name || i != PP_ENDREP)) + (defining->name || (i != PP_ENDREP && i != PP_REP))) + { return 0; + } if (j != -2) { - error(ERR_NONFATAL|ERR_OFFBY1, "unknown preprocessor directive `%s'", + error(ERR_NONFATAL, "unknown preprocessor directive `%s'", tline->text); return 0; /* didn't get it */ } @@ -1213,16 +1231,13 @@ static int do_directive (Token *tline) { case PP_CLEAR: if (tline->next) - error(ERR_WARNING|ERR_OFFBY1, + error(ERR_WARNING, "trailing garbage after `%%clear' ignored"); for (j=0; jnext; - 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; iparamlen[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; itype-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, ¶ms); + 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, ¶ms); - 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, ¶ms); - if (m) { - last->next = NULL; - label = tline; - tline = t; - } - } - } + } + if (!tok_type_(t, TOK_ID) || (m = is_mmacro(t, ¶ms)) == 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; hnext; - nasm_free (m->name); - free_tlist (m->dlist); - nasm_free (m->defaults); - free_llist (m->expansion); - nasm_free (m); + free_mmacro(m); } while (smacros[h]) { SMacro *s = smacros[h]; @@ -2926,7 +2974,8 @@ static void pp_cleanup (void) { ctx_pop(); } -void pp_include_path (char *path) { +void pp_include_path (char *path) +{ IncPath *i; i = nasm_malloc(sizeof(IncPath)); @@ -2936,7 +2985,8 @@ void pp_include_path (char *path) { ipath = i; } -void pp_pre_include (char *fname) { +void pp_pre_include (char *fname) +{ Token *inc, *space, *name; Line *l; @@ -2961,8 +3011,9 @@ void pp_pre_include (char *fname) { predef = l; } -void pp_pre_define (char *definition) { - Token *def, *space, *name; +void pp_pre_define (char *definition) +{ + Token *def, *space; Line *l; char *equals; @@ -2972,7 +3023,7 @@ void pp_pre_define (char *definition) { def->next = space = nasm_malloc(sizeof(Token)); if (equals) *equals = ' '; - space->next = name = tokenise(definition); + space->next = tokenise(definition); if (equals) *equals = '='; @@ -2990,10 +3041,19 @@ void pp_pre_define (char *definition) { predef = l; } -void pp_extra_stdmac (char **macros) { +void pp_extra_stdmac (char **macros) +{ extrastdmac = macros; } +static void make_tok_num(Token *tok, long val) +{ + char numbuf[20]; + sprintf(numbuf, "%ld", val); + tok->text = nasm_strdup(numbuf); + tok->type = TOK_NUMBER; +} + Preproc nasmpp = { pp_reset, pp_getline, diff --git a/standard.mac b/standard.mac index 0be81088..5f862980 100644 --- a/standard.mac +++ b/standard.mac @@ -1,10 +1,10 @@ -; Standard macro set for NASM 0.97 -*- nasm -*- +; Standard macro set for NASM 0.98 -*- nasm -*- ; Note that although some user-level forms of directives are defined ; here, not all of them are: the user-level form of a format-specific ; directive should be defined in the module for that directive. %define __NASM_MAJOR__ 0 -%define __NASM_MINOR__ 97 +%define __NASM_MINOR__ 98 ; These two need to be defined, though the actual definitions will ; be constantly updated during preprocessing. diff --git a/sync.c b/sync.c index 7acba0ee..261afbca 100644 --- a/sync.c +++ b/sync.c @@ -25,7 +25,8 @@ static struct Sync { } *synx; static int nsynx; -void init_sync(void) { +void init_sync(void) +{ /* * I'd like to allocate an array of size SYNC_MAX, then write * `synx--' which would allow numbering the array from one @@ -48,7 +49,8 @@ void init_sync(void) { nsynx = 0; } -void add_sync(unsigned long pos, unsigned long length) { +void add_sync(unsigned long pos, unsigned long length) +{ int i; if (nsynx == SYNC_MAX) @@ -68,7 +70,8 @@ void add_sync(unsigned long pos, unsigned long length) { } } -unsigned long next_sync(unsigned long position, unsigned long *length) { +unsigned long next_sync(unsigned long position, unsigned long *length) +{ while (nsynx > 0 && synx[1].pos + synx[1].length <= position) { int i, j; struct Sync t; diff --git a/zoutieee.c b/zoutieee.c new file mode 100644 index 00000000..b36098a6 --- /dev/null +++ b/zoutieee.c @@ -0,0 +1,1457 @@ +/* outieee.c output routines for the Netwide Assembler to produce + * IEEE-std object files + * + * The Netwide Assembler is copyright (C) 1996 Simon Tatham and + * Julian Hall. All rights reserved. The software is + * redistributable under the licence given in the file "Licence" + * distributed in the NASM archive. + */ + +/* notes: I have tried to make this correspond to the IEEE version + * of the standard, specifically the primary ASCII version. It should + * be trivial to create the binary version given this source (which is + * one of MANY things that have to be done to make this correspond to + * the hp-microtek version of the standard). + * + * 16-bit support is assumed to use 24-bit addresses + * The linker can sort out segmentation-specific stuff + * if it keeps track of externals + * in terms of being relative to section bases + * + * A non-standard variable type, the 'Yn' variable, has been introduced. + * Basically it is a reference to extern 'n'- denoting the low limit + * (L-variable) of the section that extern 'n' is defined in. Like the + * x variable, there may be no explicit assignment to it, it is derived + * from the public definition corresponding to the extern name. This + * is required because the one thing the mufom guys forgot to do well was + * take into account segmented architectures. + * + * I use comment classes for various things and these are undefined by + * the standard. + * + * Debug info should be considered totally non-standard (local labels are + * standard but linenum records are not covered by the standard. + * Type defs have the standard format but absolute meanings for ordinal + * types are not covered by the standard.) + * + * David Lindauer, LADsoft + */ +#include +#include +#include +#include +#include /* Note: we need the ANSI version of stdarg.h */ +#include + +#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 */ -- cgit v1.2.1