diff options
-rw-r--r-- | AUTHORS | 90 | ||||
-rw-r--r-- | MODIFIED | 43 | ||||
-rw-r--r-- | Mkfiles/Makefile.dj | 2 | ||||
-rw-r--r-- | Mkfiles/Makefile.emx | 145 | ||||
-rw-r--r-- | Mkfiles/Makefile.vc | 2 | ||||
-rw-r--r-- | README.1st | 187 | ||||
-rw-r--r-- | Readme | 76 | ||||
-rw-r--r-- | assemble.c | 2 | ||||
-rw-r--r-- | doc/Makefile.in | 15 | ||||
-rw-r--r-- | doc/nasmdoc.src | 1032 | ||||
-rw-r--r-- | doc/rdsrc.pl | 37 | ||||
-rw-r--r-- | insns.dat | 287 | ||||
-rw-r--r-- | insns.h | 2 | ||||
-rw-r--r-- | labels.c | 110 | ||||
-rw-r--r-- | labels.h | 3 | ||||
-rw-r--r-- | listing.c | 6 | ||||
-rw-r--r-- | listing.h | 1 | ||||
-rw-r--r-- | macros.c | 9 | ||||
-rw-r--r-- | nasm.c | 285 | ||||
-rw-r--r-- | nasm.h | 32 | ||||
-rw-r--r-- | outaout.c | 2 | ||||
-rw-r--r-- | outelf.c | 6 | ||||
-rw-r--r-- | outobj.c | 44 | ||||
-rw-r--r-- | outrdf2.c | 58 | ||||
-rw-r--r-- | parser.c | 80 | ||||
-rw-r--r-- | preproc.c | 529 | ||||
-rw-r--r-- | proc32.ash | 441 | ||||
-rw-r--r-- | rdoff/Makefile.dj | 75 | ||||
-rw-r--r-- | rdoff/Makefile.emx | 76 | ||||
-rw-r--r-- | rdoff/Makefile.in | 12 | ||||
-rw-r--r-- | rdoff/Makefile.sc | 113 | ||||
-rw-r--r-- | rdoff/README | 12 | ||||
-rw-r--r-- | rdoff/ldrdf.c | 304 | ||||
-rw-r--r-- | rdoff/multboot.h | 27 | ||||
-rw-r--r-- | rdoff/rdf2bin.c | 17 | ||||
-rw-r--r-- | rdoff/rdf2ihx.c | 189 | ||||
-rw-r--r-- | rdoff/rdfdump.c | 29 | ||||
-rw-r--r-- | rdoff/rdfload.c | 7 | ||||
-rw-r--r-- | rdoff/rdoff.c | 26 | ||||
-rw-r--r-- | rdoff/rdoff.h | 33 | ||||
-rw-r--r-- | rdoff/symtab.c | 4 | ||||
-rw-r--r-- | scitech.txt | 213 | ||||
-rw-r--r-- | standard.mac | 10 | ||||
-rw-r--r-- | test/bintest.asm | 4 | ||||
-rw-r--r-- | test/test1.asm | 62 | ||||
-rw-r--r-- | test/test2.asm | 18 | ||||
-rw-r--r-- | test/test2a.asm | 22 | ||||
-rw-r--r-- | test/test3.asm | 45 | ||||
-rw-r--r-- | test/test4.asm | 16 | ||||
-rw-r--r-- | test/test4a.asm | 16 | ||||
-rw-r--r-- | test/test4b.asm | 17 | ||||
-rw-r--r-- | test/test4c.asm | 17 | ||||
-rw-r--r-- | test/test5.asm | 43 | ||||
-rw-r--r-- | test/test6.asm | 9 |
54 files changed, 4336 insertions, 606 deletions
@@ -0,0 +1,90 @@ +This is the AUTHORS file for the NASM project located at: +http://nasm.rm-f.net/ + +Names should be inserted as follows: + +N: Name Here +E: Email Here +D: Description Here +D: Additional Description Here.... and so on + +Such is life. +-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= + +N: Julian Hall +E: Jules@acris.co.uk +D: Original author and co-conspirator + +N: Simon Tatham +E: anakin@pobox.com +D: Original author and co-conspirator + +N: Nelson Rush +E: palisade@users.sourceforge.net +D: Some guy. + +N: Frank Kotler +E: fbkotler@nettaxi.com +D: Bug smashing. +D: Documentation - "KATMAI" and "3DNow!" instructions supported by 0.98 + +N: Stephen Silver +E: nasm@argentum.freeserve.co.uk +D: Documentation - "3dNow!" instructions and misc. +D: insns.dat fixes and new instructions. + +N: AMD Inc. (names of developers here?) +E: +D: 3DNow instructions +D: New Athlon instructions +D: Makefile.vc fix + +N: John Coffman +E: johninsd@users.sourceforge.net +D: added Jcc optimizations; CPU level checks +D: bug fixes, compilation fixes + +N: Yuri Zaporogets +E: yuriz@users.sourceforge.net +D: RDOFF support + +N: H. Peter Anvin +E: hpa@zytor.com +D: Organized 0.98 release and Linux binaries + +N: John Fine +E: johnfine@earthlink.net +D: Preprocessor and OBJ (OMF) output format driver +D: Organized DOS versions of 0.98 release + +N: Kendall Bennet +E: KendallB@scitechsoft.com +D: NASM enhancements +D: macros +D: Syntax modifications + +N: Gary Clark +E: +D: AMD 3DNow! instructions + +N: Andrew Crabtree +E: +D: Debugging support + +N: Rafael R. Sevilla +E: dido@pacific.net.ph +D: RDF2HEX utility + +N: Jaime Tejedor Gómez, aka Metalbrain +E: metalbrain_coder@gmx.net +D: jecxz bug fix + +N: James Seter +E: pharos@zsnes.com +D: --POSTFIX, --PREFIX switches +D: ? + +N: Edward J. Beroset +E: beroset@mindspring.com +D: added %substr and %strlen + @@ -1,3 +1,46 @@ +01/28/01 - fbk - added Stepane Denis' SSE2 instructions to a *working* + version of the code - some earlier versions were based on + broken code - sorry 'bout that. version "0.98.07" + +01/28/01 - fbk - cosmetic modifications to nasm.c, nasm.h, + AUTHORS, MODIFIED + +01/18/01 - fbk - "metalbrain"s jecxz bug fix in insns.dat + - alter nasmdoc.src to match - version "0.98.06f" + +01/09/01 - fbk - removed the "outforms.h" file - it appears to be + someone's old backup of "outform.h". version "0.98.06e" + +01/09/01 - fbk - finally added the fix for the "multiple %includes bug", + known since 7/27/99 - reported originally (?) and sent to + us by Austin Lunnen - he reports that John Fine had a fix + within the day. Here it is... + +---- Nelson Rush resigns from the group. Big thanks to Nelson for + his leadership and enthusiasm in getting these changes + incorporated into Nasm! + +---- fbk - [list +], [list -] directives - ineptly implemented, should + be re-written or removed, perhaps. + +---- Brian Raiter / fbk - "elfso bug" fix - applied to aoutb format + as well - testing might be desirable... + +08/07/00 - James Seter - -postfix, -prefix command line switches. + +---- Yuri Zaporogets - rdoff utility changes. + +John Coffman's changes: +For the JMP and other optimizations see the file README03.txt. + +Kendall Bennett's changes: +For changes since the 0.98 release see the file scitech.txt. Note + that you must define "TASM_COMPAT" at compile-time + to get the Tasm Ideal Mode compatibility. + +---------------------------------------------- +... this is the 0.98 "modified" file ... +-------------------------------------------------- This file details changes since NASM 0.98p3. All the releases in this file have been produced by H. Peter Anvin <hpa@zytor.com>. diff --git a/Mkfiles/Makefile.dj b/Mkfiles/Makefile.dj index fb33748..7cb2399 100644 --- a/Mkfiles/Makefile.dj +++ b/Mkfiles/Makefile.dj @@ -13,7 +13,7 @@ # You may need to adjust these values. -CC = gcc -s +CC = gcc CFLAGS = -O2 -I. # You _shouldn't_ need to adjust anything below this line. diff --git a/Mkfiles/Makefile.emx b/Mkfiles/Makefile.emx new file mode 100644 index 0000000..bb7ef0f --- /dev/null +++ b/Mkfiles/Makefile.emx @@ -0,0 +1,145 @@ +# Generated automatically from Makefile.in by configure. +# $Id$ +# +# Auto-configuring Makefile for 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. + +srcdir = . +prefix = /usr/local +exec_prefix = ${prefix} +bindir = ${exec_prefix}/bin +mandir = ${prefix}/man + +CC = gcc +CFLAGS = -s -Zomf -O2 -fomit-frame-pointer -Wall -pedantic \ + -I$(srcdir) -I. -DTASM_COMPAT +LDFLAGS = -s -Zomf -Zexe -Zcrtdll +LIBS = -lgcc + +INSTALL = ./install-sh -c +INSTALL_PROGRAM = ${INSTALL} +INSTALL_DATA = ${INSTALL} -m 644 + +NROFF = echo + +.SUFFIXES: .c .i .s .o .1 .man + +.PHONY: all doc rdf install clean distclean cleaner spotless install_rdf +.PHONY: install_doc everything install_everything + +.c.o: + $(CC) -c $(CFLAGS) -o $@ $< + +.c.s: + $(CC) -S $(CFLAGS) -o $@ $< + +.c.i: + $(CC) -E $(CFLAGS) -o $@ $< + +.1.man: + $(NROFF) -man $< > $@ + +NASM = nasm.o nasmlib.o float.o insnsa.o assemble.o labels.o \ + parser.o outform.o outbin.o outaout.o outcoff.o outelf.o \ + outobj.o outas86.o outrdf.o outrdf2.o outdbg.o zoutieee.o \ + preproc.o listing.o eval.o + +NDISASM = ndisasm.o disasm.o sync.o nasmlib.o insnsd.o + +all: nasm ndisasm nasm.man ndisasm.man + $(MAKE) -C rdoff -f Makefile.emx all + +nasm: $(NASM) + $(CC) $(LDFLAGS) -o nasm $(NASM) $(LIBS) + +ndisasm: $(NDISASM) + $(CC) $(LDFLAGS) -o ndisasm $(NDISASM) $(LIBS) + +assemble.o: assemble.c nasm.h insnsi.h nasmlib.h assemble.h insns.h +disasm.o: disasm.c nasm.h insnsi.h disasm.h sync.h insns.h names.c insnsn.c +eval.o: eval.c eval.h nasm.h insnsi.h nasmlib.h +float.o: float.c nasm.h insnsi.h +insnsa.o: insnsa.c nasm.h insnsi.h insns.h +insnsd.o: insnsd.c nasm.h insnsi.h insns.h +labels.o: labels.c nasm.h insnsi.h nasmlib.h +listing.o: listing.c nasm.h insnsi.h nasmlib.h listing.h +nasm.o: nasm.c nasm.h insnsi.h nasmlib.h preproc.h parser.h assemble.h labels.h \ + outform.h listing.h +nasmlib.o: nasmlib.c nasm.h insnsi.h nasmlib.h names.c insnsn.c +ndisasm.o: ndisasm.c nasm.h insnsi.h nasmlib.h sync.h disasm.h +outaout.o: outaout.c nasm.h insnsi.h nasmlib.h outform.h +outas86.o: outas86.c nasm.h insnsi.h nasmlib.h outform.h +outbin.o: outbin.c nasm.h insnsi.h nasmlib.h outform.h +outcoff.o: outcoff.c nasm.h insnsi.h nasmlib.h outform.h +outdbg.o: outdbg.c nasm.h insnsi.h nasmlib.h outform.h +outelf.o: outelf.c nasm.h insnsi.h nasmlib.h outform.h +outform.o: outform.c outform.h nasm.h insnsi.h +outobj.o: outobj.c nasm.h insnsi.h nasmlib.h outform.h +outrdf.o: outrdf.c nasm.h insnsi.h nasmlib.h outform.h +outrdf2.o: outrdf2.c nasm.h insnsi.h nasmlib.h outform.h +parser.o: parser.c nasm.h insnsi.h nasmlib.h parser.h float.h names.c insnsn.c +preproc.o: preproc.c nasm.h insnsi.h nasmlib.h macros.c +sync.o: sync.c sync.h +zoutieee.o: zoutieee.c nasm.h insnsi.h nasmlib.h outform.h + +# These source files are automagically generated from a single +# instruction-table file by a Perl script. They're distributed, +# though, so it isn't necessary to have Perl just to recompile NASM +# from the distribution. + +insnsa.c: insns.dat insns.pl + perl $(srcdir)/insns.pl -a $(srcdir)/insns.dat +insnsd.c: insns.dat insns.pl + perl $(srcdir)/insns.pl -d $(srcdir)/insns.dat +insnsi.h: insns.dat insns.pl + perl $(srcdir)/insns.pl -i $(srcdir)/insns.dat +insnsn.c: insns.dat insns.pl + perl $(srcdir)/insns.pl -n $(srcdir)/insns.dat + +# This source file is generated from the standard macros file +# `standard.mac' by another Perl script. Again, it's part of the +# standard distribution. + +macros.c: standard.mac macros.pl + perl $(srcdir)/macros.pl $(srcdir)/standard.mac + +install: nasm ndisasm + $(INSTALL_PROGRAM) nasm $(INSTALLROOT)$(bindir)/nasm + $(INSTALL_PROGRAM) ndisasm $(INSTALLROOT)$(bindir)/ndisasm + $(INSTALL_DATA) $(srcdir)/nasm.1 $(INSTALLROOT)$(mandir)/man1/nasm.1 + $(INSTALL_DATA) $(srcdir)/ndisasm.1 $(INSTALLROOT)$(mandir)/man1/ndisasm.1 + +clean: + rm -f *.o *.s *.i nasm ndisasm + cd rdoff && $(MAKE) clean + +distclean: clean + rm -f config.* Makefile *~ *.bak *.lst *.bin + cd rdoff && $(MAKE) distclean + +cleaner: clean + rm -f insnsa.c insnsd.c insnsi.h insnsn.c macros.c *.man + cd doc && $(MAKE) clean + +spotless: distclean cleaner + +rdf: + cd rdoff && $(MAKE) + +rdf_install install_rdf: + cd rdoff && $(MAKE) install + +doc: + cd doc && $(MAKE) all + +doc_install install_doc: + cd doc && $(MAKE) install + +everything: all doc rdf + +install_everything: everything install install_doc install_rdf + diff --git a/Mkfiles/Makefile.vc b/Mkfiles/Makefile.vc index 1e0ef1c..0bc4f68 100644 --- a/Mkfiles/Makefile.vc +++ b/Mkfiles/Makefile.vc @@ -34,7 +34,7 @@ all : nasm$(SUFFIX)$(EXE) ndisasm$(SUFFIX)$(EXE) # We have to have a horrible kludge here to get round the 128 character # limit, as usual... -LINKOBJS = a*.obj e*.obj f*.obj insnsa.obj l*.obj na*.obj o*.obj p*.obj +LINKOBJS = a*.obj e*.obj f*.obj insnsa.obj l*.obj na*.obj o*.obj p*.obj z*.obj nasm$(SUFFIX)$(EXE): $(NASMOBJS) cl /Fenasm$(SUFFIX).exe $(LINKOBJS) diff --git a/README.1st b/README.1st new file mode 100644 index 0000000..b1bf2da --- /dev/null +++ b/README.1st @@ -0,0 +1,187 @@ +This is a specially patched version of NASM. It can be used to supplement +building of Crystal Space, the Open Source 3D Engine project. You can find +Crystal Space at the following locations: + +http://crystal.linuxgames.com/ +http://crystal.sourceforge.net/ + +Details of changes in this version of NASM follow. + +-*- A new keyword %xdefine and its case-insensitive counterpart %ixdefine. + They work almost the same way as %define and %idefine but expand + the definition immediately, not on the invocation. Something like a cross + between %define and %assign. The "x" suffix stands for "eXpand", so + "xdefine" can be deciphered as "expand-and-define". Thus you can do + things like this: + + %assign ofs 0 + + %macro arg 1 + %xdefine %1 dword [esp+ofs] + %assign ofs ofs+4 + %endmacro + +-*- Changed the place where the expansion of %$name macros are expanded. + Now they are converted into ..@ctxnum.name form when detokenizing, so + there are no quirks as before when using %$name arguments to macros, + in macros etc. For example: + + %macro abc 1 + %define %1 hello + %endm + + abc %$here + %$here + + Now last line will be expanded to "hello" as expected. This also allows + for lots of goodies, a good example are extended "proc" macros included + in this archive. + +-*- Added a check for "cstk" in smacro_defined() before calling get_ctx() - + this allows for things like: + + %ifdef %$abc + %endif + + to work without warnings even in no context. + +-*- Added a check for "cstk" in %if*ctx and %elif*ctx directives - + this allows to use %ifctx without excessive warnings. If there is + no active context, %ifctx goes through "false" branch. + +-*- Removed "user error: " prefix with %error directive: it just clobbers the + output and has absolutely no functionality. Besides, this allows to write + macros that does not differ from build-in functions in any way. + +-*- Added expansion of string that is output by %error directive. Now you + can do things like: + + %define hello(x) Hello, x! + + %define %$name andy + %error "hello(%$name)" + + Same happened with %include directive. + +-*- Now all directives that expect an identifier will try to expand and + concatenate everything without whitespaces in between before usage. + For example, with "unfixed" nasm the commands + + %define %$abc hello + %define __%$abc goodbye + __%$abc + + would produce "incorrect" output: last line will expand to + + hello goodbyehello + + Not quite what you expected, eh? :-) The answer is that preprocessor + treats the %define construct as if it would be + + %define __ %$abc goodbye + + (note the white space between __ and %$abc). After my "fix" it + will "correctly" expand into + + goodbye + + as expected. Note that I use quotes around words "correct", "incorrect" + etc because this is rather a feature not a bug; however current behaviour + is more logical (and allows more advanced macro usage :-). + + Same change was applied to: + %push,%macro,%imacro,%define,%idefine,%xdefine,%ixdefine, + %assign,%iassign,%undef + +-*- A new directive [WARNING {+|-}warning-id] have been added. It works only + if the assembly phase is enabled (i.e. it doesn't work with nasm -e). + +-*- A new warning type: macro-selfref. By default this warning is disabled; + when enabled NASM warns when a macro self-references itself; for example + the following source: + + [WARNING macro-selfref] + + %macro push 1-* + %rep %0 + push %1 + %rotate 1 + %endrep + %endmacro + + push eax,ebx,ecx + + will produce a warning, but if we remove the first line we won't see it + anymore (which is The Right Thing To Do {tm} IMHO since C preprocessor + eats such constructs without warnings at all). + +-*- Added a "error" routine to preprocessor which always will set ERR_PASS1 + bit in severity_code. This removes annoying repeated errors on first + and second passes from preprocessor. + +-*- Added the %+ operator in single-line macros for concatenating two + identifiers. Usage example: + + %define _myfunc _otherfunc + %define cextern(x) _ %+ x + cextern (myfunc) + + After first expansion, third line will become "_myfunc". After this + expansion is performed again so it becomes "_otherunc". + +-*- Now if preprocessor is in a non-emmitting state, no warning or error + will be emmitted. Example: + + %if 1 + mov eax,ebx + %else + put anything you want between these two brackets, + even macro-parameter references %1 or local labels %$zz + or macro-local labels %%zz - no warning will be emmitted. + %endif + +-*- Context-local variables on expansion as a last resort are looked up + in outer contexts. For example, the following piece: + + %push outer + %define %$a [esp] + + %push inner + %$a + %pop + %pop + + will expand correctly the fourth line to [esp]; if we'll define another + %$a inside the "inner" context, it will take precedence over outer + definition. However, this modification has been applied only to + expand_smacro and not to smacro_define: as a consequence expansion + looks in outer contexts, but %ifdef won't look in outer contexts. + + This behaviour is needed because we don't want nested contexts to + act on already defined local macros. Example: + + %define %$arg1 [esp+4] + test eax,eax + if nz + mov eax,%$arg1 + endif + + In this example the "if" mmacro enters into the "if" context, so %$arg1 + is not valid anymore inside "if". Of course it could be worked around + by using explicitely %$$arg1 but this is ugly IMHO. + +-------------------------------// fixes for 0.98 //----------------------------- + +-*- Fixed memory leak in %undef. The origline wasn't freed before + exiting on success. + +-----------------------------// Fixes for 0.98.01 //---------------------------- + +-*- Fixed trap in preprocessor when line expanded to empty set of tokens. + This happens, for example, in the following case: + + #define SOMETHING + SOMETHING + + +Andrew Zabolotny <bit@eltech.ru> @@ -1,53 +1,49 @@ -This directory contains the necessary files to port the C compiler -``LCC'' (available by FTP from sunsite.doc.ic.ac.uk in the directory -/computing/programming/languages/c/lcc) to compile for Linux (a.out or -ELF) or other supported operating systems by using NASM as a back-end -code generator. -This patch has been tested on lcc version 4.0. + NetWide Assembler for the SciTech MGL + ------------------------------------- -To install: +This is a modified distribution of NASM, the Netwide Assembler. NASM +is a prototype general-purpose x86 assembler. It will currently output +flat-form binary files, a.out, COFF and ELF Unix object files, +Microsoft Win32 and 16-bit DOS object files, OS/2 object files, the +as86 object format, and a home-grown format called RDF. -- Copy `x86nasm.md' into the `src' directory of the lcc tree. +This version of NASM has been modified by SciTech Software such that it +can be used to assemble source code in the SciTech MGL graphics library, +and understands enough of TASM assembler syntax such that both NASM +and TASM can be used to generate assembler modules for the MGL graphics +library. A complete macro package is provided as part of the SciTech +MGL that provides macros to help in building modules that will work with +either assembler. -- Copy either `lin-elf.c' or `lin-aout.c' into the `etc' directory. +A pre-compiled binary of NASM is provided as part of the SciTech MGL +graphics library, however you may re-build the assembler from the sources +provided. To do so make sure you have the SciTech Makefile Utilties +correctly configured for your compiler, and then simly type: -- With previous versions, you had to modify x86-nasm.md if you weren't - using ELF. There is now inbuilt support within NASM in the shape - of the __CDECL__ macro, so this modification is no longer necessary. + unset DBG + dmake OPT=1 -- Make the following changes to `bind.c' in the `src' directory: +to build an optimised, non-debug version of the assembler. If you wish +to rebuild for a different OS other than DOS or Win32, you will need to +first compile the DMAKE make program for your OS. See the DMAKE source +code for more information. - - Near the top of the file, add a line that reads - extern Interface x86nasmIR; +Licensing issues: +----------------- - - In the `bindings' array, add the lines - "x86-nasm", &x86nasmIR, - "x86/nasm", &x86nasmIR, - (in sensible looking places...) +For information about how you can distribute and use NASM, see the +file Licence. - A sample `bind.c' has been provided to show what the result of - this might look like. You might be able to get away with using it - directly... +The NASM web page is at http://www.cryogen.com/Nasm/ -- Modify the lcc makefile to include rules for x86nasm.o: this will - have to be done in about three places. Just copy any line with - `x86' on it and modify it to read `x86nasm' everywhere. (Except - that in the list of object files that rcc is made up from, do - remember to ensure that every line but the last has a trailing - backslash...) +Bug reports specific to the SciTech MGL should be posted to SciTech +Software MGL newsgroups: -- You may have to modify the contents of `lin-elf.c' or `lin-aout.c' - to reflect the true locations of files such as crt0.o, crt1.o, - ld-linux.so and so forth. If you don't know where to find these, - compile a short C program with `gcc -v' and see what command line - gcc feeds to `ld'. + news://news.scitechsoft.com/scitech.mgl.developer -- You should now be able to build lcc, using `lin-elf.c' or - `lin-aout.c' as the system-dependent part of the `lcc' wrapper - program. +Bug reports (and patches if you can) for NASM itself that are not SciTech +MGL related should be sent to the authors at: -- Symlink x86nasm.c into the `src' directory before attempting the - triple test, or the compile will fail. - -- Now it should pass the triple test, on either ELF or a.out. Voila! + Julian Hall <jules@earthcorp.com> + Simon Tatham <anakin@pobox.com> @@ -152,7 +152,7 @@ static int jmp_match (long segment, long offset, int bits, if (c != 0370) return 0; - if (ins->oprs[0].opflags & OPFLAG_FORWARD) return 1; /* match a forward reference */ + if (ins->oprs[0].opflags & OPFLAG_FORWARD) return (! pass0); /*1;*/ /* match a forward reference */ isize = calcsize (segment, offset, bits, ins, code); if (ins->oprs[0].segment != segment) return 0; diff --git a/doc/Makefile.in b/doc/Makefile.in index 78fafa3..a7f2ab9 100644 --- a/doc/Makefile.in +++ b/doc/Makefile.in @@ -24,7 +24,9 @@ OUT = nasm.info all: $(OUT) -.SUFFIXES: .src .texi .info .ps .rtf .hpj .dvi .ps .txt .pl +os2: nasm.inf + +.SUFFIXES: .src .texi .info .ps .rtf .hpj .dvi .ps .txt .pl .ipf .inf # Consider html, txt and src output a side effect .src.texi: @@ -37,11 +39,18 @@ nasm.info: nasmdoc.texi $(MAKEINFO) $< mv -f *.info *.info-* info +# Rules for building an OS/2 book +.texi.ipf: + texi2ipf $< >$@ + +nasm.inf: nasmdoc.ipf + ipfc -i -s $< $@ + clean: - -rm -f *.rtf *.hpj *.texi *.ph *.gid + -rm -f *.rtf *.hpj *.texi *.ph *.gid *.ipf spotless: clean - -rm -rf html info *.hlp *.txt *.ps + -rm -rf html info *.hlp *.txt *.ps *.inf install: all $(INSTALL_DATA) info/* $(INSTALLROOT)$(infodir) diff --git a/doc/nasmdoc.src b/doc/nasmdoc.src index 2965707..c047f1f 100644 --- a/doc/nasmdoc.src +++ b/doc/nasmdoc.src @@ -1536,6 +1536,49 @@ The expression passed to \c{%assign} is a \i{critical expression} a relocatable reference such as a code or data address, or anything involving a register). +\H{strlen} \i{String Handling in Macros}: \i\c{%strlen} and \i\c{%substr} + +It's often useful to be able to handle strings in macros. NASM +supports two simple string handling macro operators from which +more complex operations can be constructed. + +\S{strlen} \i{String Length}: \i\c{%strlen} + +The \c{%strlen} macro is like \c{%assign} macro in that it creates +(or redefines) a numeric value to a macro. The difference is that +with \c{%strlen}, the numeric value is the length of a string. An +example of the use of this would be: + +\c %strlen charcnt 'my string' + +In this example, \c{charcnt} would receive the value 8, just as +if an \c{%assign} had been used. In this example, \c{'my string'} +was a literal string but it could also have been a single-line +macro that expands to a string, as in the following example: + +\c %define sometext 'my string' +\c %strlen charcnt sometext + +As in the first case, this would result in \c{charcnt} being +assigned the value of 8. + +\S{substr} \i{Sub-strings}: \i\c{%substr} + +Individual letters in strings can be extracted using \c{%substr}. +An example of its use is probably more useful than the description: + +\c %substr mychar 'xyz' 1 ; equivalent to %define mychar 'x' +\c %substr mychar 'xyz' 2 ; equivalent to %define mychar 'y' +\c %substr mychar 'xyz' 3 ; equivalent to %define mychar 'z' + +In this example, mychar gets the value of 'y'. As with \c{%strlen} +(see \k{strlen}), the first parameter is the single-line macro to +be created and the second is the string. The third parameter +specifies which character is to be selected. Note that the first +index is 1, not 0 and the last index is equal to the value that +\c{%strlen} would assign given the same string. Index values out +of range result in an empty string. + \H{mlmacro} \i{Multi-Line Macros}: \I\c{%imacro}\i\c{%macro} Multi-line macros are much more like the type of macro seen in MASM @@ -5620,6 +5663,19 @@ sign-extended to the length of the first operand. In these cases, the \c{BYTE} qualifier is necessary to force NASM to generate this form of the instruction. +\H{insADDPS} \i\c{ADDPS}: Packed Single FP ADD + +\c ADDPS xmmreg,mem128 ; 0f 58 /r [KATMAI,SSE] +\c ADDPS xmmreg,xmmreg ; 0f 58 /r [KATMAI,SSE] + +\c{ADDPS} performs addition on each of four packed SP FP +number items dst(0-31):=dst(0-31)+src(0-31), ..(63-32), etc. + +\H{insADDSS} \i\c{ADDSS}: Scalar Single FP ADD + +\c ADDSS xmmreg,mem128 ; f3 0f 58 /r [KATMAI,SSE] +\c ADDSS xmmreg,xmmreg ; f3 0f 58 /r [KATMAI,SSE] + \H{insAND} \i\c{AND}: Bitwise AND \c AND r/m8,reg8 ; 20 /r [8086] @@ -5655,6 +5711,18 @@ form of the instruction. The MMX instruction \c{PAND} (see \k{insPAND}) performs the same operation on the 64-bit MMX registers. +\H{insANDNPS} \i\c{ANDNPS}: Bitwise Logical AND NOT For Single FP + +\c ANDNPS xmmreg,mem128 ; 0f 55 /r [KATMAI,SSE] +\c ANDNPS xmmreg,xmmreg ; 0f 55 /r [KATMAI,SSE] + + +\H{insANDPS} \i\c{ANDPS}: Bitwise Logical AND For Single FP + +\c ANDPS xmmreg,mem128 ; 0f 54 /r [KATMAI,SSE] +\c ANDPS xmmreg,xmmreg ; 0f 54 /r [KATMAI,SSE] + + \H{insARPL} \i\c{ARPL}: Adjust RPL Field of Selector \c ARPL r/m16,reg16 ; 63 /r [286,PRIV] @@ -5872,6 +5940,102 @@ sign-extended to the length of the first operand. In these cases, the \c{BYTE} qualifier is necessary to force NASM to generate this form of the instruction. + +\H{insCMPEQPS} \i\c{CMPEQPS}: Packed Single FP Compare (CMPPS) + +\c CMPEQPS xmmreg,memory ; 0f c2 /r ib [KATMAI,SSE] +\c CMPEQPS xmmreg,xmmreg ; [KATMAI,SSE] + +\c{CMPPS} with condition set, re CMPPS. + +\H{insCMPEQSS} \i\c{CMPEQSS}: Scalar Single FP Compare (CMPSS) + +\c CMPEQSS xmmreg,memory ; ?? [KATMAI,SSE] +\c CMPEQSS xmmreg,xmmreg ; ?? [KATMAI,SSE] + +\c{CMPSS} with condition set, re CMPPS. + +\H{insCMPLEPS} \i\c{CMPLEPS}: Packed Single FP Compare (CMPPS) + +\c CMPLEPS xmmreg,memory ; ?? [KATMAI,SSE] +\c CMPLEPS xmmreg,xmmreg ; ?? [KATMAI,SSE] + + +\H{insCMPLESS} \i\c{CMPLESS}: Scalar Single FP Compare (CMPSS) + +\c CMPLESS xmmreg,memory ; ?? [KATMAI,SSE] +\c CMPLESS xmmreg,xmmreg ; ?? [KATMAI,SSE] + + +\H{insCMPLTPS} \i\c{CMPLTPS}: Packed Single FP Compare (CMPPS) + +\c CMPLTPS xmmreg,memory ; ?? [KATMAI,SSE] +\c CMPLTPS xmmreg,xmmreg ; ?? [KATMAI,SSE] + + +\H{insCMPLTSS} \i\c{CMPLTSS}: Scalar Single FP Compare (CMPSS) + +\c CMPLTSS xmmreg,memory ; ?? [KATMAI,SSE] +\c CMPLTSS xmmreg,xmmreg ; ?? [KATMAI,SSE] + + +\H{insCMPNEQPS} \i\c{CMPNEQPS}: Packed Single FP Compare (CMPPS) + +\c CMPNEQPS xmmreg,memory ; ?? [KATMAI,SSE] +\c CMPNEQPS xmmreg,xmmreg ; ?? [KATMAI,SSE] + + +\H{insCMPNEQSS} \i\c{CMPNEQSS}: Scalar Single FP Compare (CMPSS) + +\c CMPNEQSS xmmreg,memory ; ?? [KATMAI,SSE] +\c CMPNEQSS xmmreg,xmmreg ; ?? [KATMAI,SSE] + + +\H{insCMPNLEPS} \i\c{CMPNLEPS}: Packed Single FP Compare (CMPPS) + +\c CMPNLEPS xmmreg,memory ; ?? [KATMAI,SSE] +\c CMPNLEPS xmmreg,xmmreg ; ?? [KATMAI,SSE] + + +\H{insCMPNLESS} \i\c{CMPNLESS}: Scalar Single FP Compare (CMPSS) + +\c CMPNLESS xmmreg,memory ; ?? [KATMAI,SSE] +\c CMPNLESS xmmreg,xmmreg ; ?? [KATMAI,SSE] + + +\H{insCMPNLTPS} \i\c{CMPNLTPS}: Packed Single FP Compare (CMPPS) + +\c CMPNLTPS xmmreg,memory ; ?? [KATMAI,SSE] +\c CMPNLTPS xmmreg,xmmreg ; ?? [KATMAI,SSE] + + +\H{insCMPNLTSS} \i\c{CMPNLTSS}: Scalar Single FP Compare (CMPSS) + +\c CMPNLTSS xmmreg,memory ; ?? [KATMAI,SSE] +\c CMPNLTSS xmmreg,xmmreg ; ?? [KATMAI,SSE] + + +\H{insCMPORDPS} \i\c{CMPORDPS}: Packed Single FP Compare (CMPPS) + +\c CMPORDPS xmmreg,memory ; ?? [KATMAI,SSE] +\c CMPORDPS xmmreg,xmmreg ; ?? [KATMAI,SSE] + + +\H{insCMPORDSS} \i\c{CMPORDSS}: Scalar Single FP Compare (CMPSS) + +\c CMPORDSS xmmreg,memory ; ?? [KATMAI,SSE] +\c CMPORDSS xmmreg,xmmreg ; ?? [KATMAI,SSE] + + +\H{insCMPPS} \i\c{CMPPS}: Packed Single FP Compare + +\c CMPPS xmmreg,memory,immediate ; ?? [KATMAI,SSE,SB,AR2] +\c CMPPS xmmreg,xmmreg,immediate ; ?? [KATMAI,SSE,SB,AR2] + +\c{CMP(cc)PS} and \c{CMP(cc)SS} conditions (cc): +EQ, LT, LE, UNORD, NEQ, NLT, NLE, ORD + + \H{insCMPSB} \i\c{CMPSB}, \i\c{CMPSW}, \i\c{CMPSD}: Compare Strings \c CMPSB ; A6 [8086] @@ -5903,6 +6067,29 @@ The \c{REPE} and \c{REPNE} prefixes (equivalently, \c{REPZ} and \c{ECX} - again, the address size chooses which) times until the first unequal or equal byte is found. + + +\H{insCMPSS} \i\c{CMPSS}: Scalar Single FP Compare + +\c CMPSS xmmreg,memory,immediate ; ?? [KATMAI,SSE,SB,AR2] +\c CMPSS xmmreg,xmmreg,immediate ; ?? [KATMAI,SSE,SB,AR2] + +\c{CMP(cc)PS} and \c{CMP(cc)SS} conditions (cc): +EQ, LT, LE, UNORD, NEQ, NLT, NLE, ORD + + +\H{insCMPUNORDPS} \i\c{CMPUNORDPS}: Packed Single FP Compare (CMPPS) + +\c CMPUNORDPS xmmreg,memory ; ?? [KATMAI,SSE] +\c CMPUNORDPS xmmreg,xmmreg ; ?? [KATMAI,SSE] + + +\H{insCMPUNORDSS} \i\c{CMPUNORDSS}: Scalar Single FP Compare (CMPSS) + +\c CMPUNORDSS xmmreg,memory ; ?? [KATMAI,SSE] +\c CMPUNORDSS xmmreg,xmmreg ; ?? [KATMAI,SSE] + + \H{insCMPXCHG} \i\c{CMPXCHG}, \i\c{CMPXCHG486}: Compare and Exchange \c CMPXCHG r/m8,reg8 ; 0F B0 /r [PENT] @@ -5948,6 +6135,14 @@ value in \c{EDX:EAX}. If they are equal, it sets the zero flag and stores \c{ECX:EBX} into the memory area. If they are unequal, it clears the zero flag and leaves the memory area untouched. +\H{insCOMISS} \i\c{COMISS}: Scalar Ordered Single-FP Compare and Set EFLAGS + +\c COMISS xmmreg,memory ; ?? [KATMAI,SSE] +\c COMISS xmmreg,xmmreg ; ?? [KATMAI,SSE] + +Set Z, P, C according to comparison, clear O, S, A bits of EFLAGS. +Z=P=C=1 for "unordered" result (QNaN). + \H{insCPUID} \i\c{CPUID}: Get CPU Identification Code \c CPUID ; 0F A2 [PENT] @@ -5987,6 +6182,50 @@ Buffers). For more information on the data returned from \c{CPUID}, see the documentation on Intel's web site. + +\H{insCVTPI2PS} \i\c{CVTPI2PS}: +Packed Signed INT32 to Packed Single-FP Conversion + +\c CVTPI2PS xmmreg,mem64 ; ?? [KATMAI,SSE,MMX] +\c CVTPI2PS xmmreg,mmxreg ; ?? [KATMAI,SSE,MMX] + + +\H{insCVTPS2PI} \i\c{CVTPS2PI}: +Packed Single-FP to Packed INT32 Conversion + +\c CVTPS2PI mmxreg,mem64 ; ?? [KATMAI,SSE,MMX] +\c CVTPS2PI mmxreg,xmmreg ; ?? [KATMAI,SSE,MMX] + + +\H{insCVTSI2SS} \i\c{CVTSI2SS}: +Scalar Signed INT32 to Single-FP Conversion + +\c CVTSI2SS xmmreg,memory ; ?? [KATMAI,SSE,SD,AR1] +\c CVTSI2SS xmmreg,reg32 ; ?? [KATMAI,SSE] + + + +\H{insCVTSS2SI} \i\c{CVTSS2SI}: +Scalar Single-FP to Signed INT32 Conversion + +\c CVTSS2SI reg32,memory ; ?? [KATMAI,SSE] +\c CVTSS2SI reg32,xmmreg ; ?? [KATMAI,SSE] + + +\H{insCVTTPS2PI} \i\c{CVTTPS2PI}: +Packed Single-FP to Packed INT32 Conversion + +\c CVTTPS2PI mmxreg,memory ; ?? [KATMAI,SSE,MMX] +\c CVTTPS2PI mmxreg,xmmreg ; ?? [KATMAI,SSE,MMX] + + +\H{insCVTTSS2SI} \i\c{CVTTSS2SI}: +Scalr Single-FP to Signed INT32 Conversion + +\c CVTTSS2SI reg32,memory ; ?? [KATMAI,SSE] +\c CVTTSS2SI reg32,xmmreg ; ?? [KATMAI,SSE] + + \H{insDAA} \i\c{DAA}, \i\c{DAS}: Decimal Adjustments \c DAA ; 27 [8086] @@ -6043,6 +6282,24 @@ the quotient is stored in \c{EAX} and the remainder in \c{EDX}. Signed integer division is performed by the \c{IDIV} instruction: see \k{insIDIV}. +\H{insDIVPS} \i\c{DIVPS}: Packed Single-FP Divide + +\c DIVPS xmmreg,memory ; 0F,5E,/r [KATMAI,SSE] +\c DIVPS xmmreg,xmmreg ; ?? [KATMAI,SSE] + +\c{DIVPS}The DIVPS instruction divides the packed SP FP numbers +of both their operands. + + +\H{insDIVSS} \i\c{DIVSS}: Scalar Single-FP Divide + +\c DIVSS xmmreg,memory ; F3,0F,5E,/r [KATMAI,SSE] +\c DIVSS xmmreg,xmmreg ; ?? [KATMAI,SSE] + +c\{DIVSS}-The DIVSS instructions divide the lowest SP FP numbers +of both operands; the upper three fields are passed through from xmm1. + + \H{insEMMS} \i\c{EMMS}: Empty MMX State \c EMMS ; 0F 77 [PENT,MMX] @@ -6323,6 +6580,14 @@ operand. once it has finished. \c{FDIVRP} operates like \c{FDIVR TO}, but pops the register stack once it has finished. + +\H{insFEMMS} \i\c{FEMMS}: 3dnow instruction (duh!) + +\c FEMMS 0,0,0 ; ?? [PENT,3DNOW] + +3dnow instruction (duh!) + + \H{insFFREE} \i\c{FFREE}: Flag Floating-Point Register as Unused \c FFREE fpureg ; DD C0+r [8086,FPU] @@ -6754,6 +7019,35 @@ denormal. It also sets the C1 flag to the sign of the number. \c{FXCH} exchanges \c{ST0} with a given FPU register. The no-operand form exchanges \c{ST0} with \c{ST1}. +\H{insFXRSTOR} \i\c{FXRSTOR}: Restore FP and MMXTM State and +Streaming SIMD Extension State + +\c FXRSTOR memory ; 0F,AE,/1 [P6,SSE,FPU] + +\c{FXRSTOR}The FXRSTOR instruction reloads the FP and MMXTM technology +state, and the Streaming SIMD Extension state (environment and registers), +from the memory area defined by m512byte. This data should have been +written by a previous FXSAVE. + + +\H{insFXSAVE} \i\c{FXSAVE}: Store FP and MMXTM State + and Streaming SIMD + +\c FXSAVE memory ; 0F,AE,/0 [P6,SSE,FPU] + + +\c{FXSAVE}The FXSAVE instruction writes the current FP and + MMXTM technology state, and Streaming SIMD Extension state + (environment and registers), to the specified destination + defined by m512byte. It does this without checking for pending + unmasked floating-point exceptions (similar to the operation of + FNSAVE). Unlike the FSAVE/FNSAVE instructions, the processor +retains the contents of the FP and MMXTM technology state and + Streaming SIMD Extension state in the processor after the state + has been saved. This instruction has been optimized to maximize + floating-point save performance. + + \H{insFXTRACT} \i\c{FXTRACT}: Extract Exponent and Significand \c FXTRACT ; D9 F4 [8086,FPU] @@ -7007,8 +7301,8 @@ on the default \c{BITS} setting at the time. \H{insJCXZ} \i\c{JCXZ}, \i\c{JECXZ}: Jump if CX/ECX Zero -\c JCXZ imm ; o16 E3 rb [8086] -\c JECXZ imm ; o32 E3 rb [386] +\c JCXZ imm ; a16 E3 rb [8086] +\c JECXZ imm ; a32 E3 rb [386] \c{JCXZ} performs a short jump (with maximum range 128 bytes) if and only if the contents of the \c{CX} register is 0. \c{JECXZ} does the @@ -7118,6 +7412,17 @@ loads the \e{next} 16 bits from memory into \c{DS}. \c{LES}, \c{LFS}, \c{LGS} and \c{LSS} work in the same way but use the other segment registers. + +\H{insLDMXCSR} \i\c{LDMXCSR}: Load Streaming SIMD Extension + Control/Status + +\c LDMXCSR memory ; 0F,AE,/2 [KATMAI,SSE,SD] + +\c{LDMXCSR} The MXCSR control/status register is used to enable + masked/unmasked exception handling, to set rounding modes, to + set flush-to-zero mode, and to view exception status flags. + + \H{insLEA} \i\c{LEA}: Load Effective Address \c LEA reg16,mem ; o16 8D /r [8086] @@ -7260,6 +7565,73 @@ loaded into the destination (first) operand. descriptor specified by the segment selector given as its operand, and loads them into the Task Register. + +\H{insMASKMOVQ} \i\c{MASKMOVQ}: Byte Mask Write + +\c MASKMOVQ mmxreg,mmxreg ; 0F,F7,/r [KATMAI,MMX] + +\c{MASKMOVQ} Data is stored from the mm1 register to the location + specified by the di/edi register (using DS segment). The size + of the store depends on the address-size attribute. The most + significant bit in each byte of the mask register mm2 is used + to selectively write the data (0 = no write, 1 = write) on a + per-byte basis. + + +\H{insMAXPS} \i\c{MAXPS}: Packed Single-FP Maximum + +\c MAXPS xmmreg,memory ; 0F,5F,/r [KATMAI,SSE] +\c MAXPS xmmreg,xmmreg ; ?? [KATMAI,SSE] + +\c{MAXPS}The MAXPS instruction returns the maximum SP FP numbers + from XMM1 and XMM2/Mem.If the values being compared are both + zeroes, source2 (xmm2/m128) would be returned. If source2 + (xmm2/m128) is an sNaN, this sNaN is forwarded unchanged + to the destination (i.e., a quieted version of the sNaN + is not returned). + + +\H{insMAXSS} \i\c{MAXSS}: Scalar Single-FP Maximum + +\c MAXSS xmmreg,memory ; F3,0F,5F,/r [KATMAI,SSE] +\c MAXSS xmmreg,xmmreg ; ?? [KATMAI,SSE] + +\c{MAXSS}The MAXSS instruction returns the maximum SP FP number + from the lower SP FP numbers of XMM1 and XMM2/Mem; the upper + three fields are passed through from xmm1. If the values being + compared are both zeroes, source2 (xmm2/m128) will be returned. + If source2 (xmm2/m128) is an sNaN, this sNaN is forwarded + unchanged to the destination (i.e., a quieted version of the + sNaN is not returned). + + +\H{insMINPS} \i\c{MINPS}: Packed Single-FP Minimum + +\c MINPS xmmreg,memory ; 0F,5D,/r [KATMAI,SSE] +\c MINPS xmmreg,xmmreg ; ?? [KATMAI,SSE] + +\c{MINPS} The MINPS instruction returns the minimum SP FP + numbers from XMM1 and XMM2/Mem. If the values being compared + are both zeroes, source2 (xmm2/m128) would be returned. If + source2 (xmm2/m128) is an sNaN, this sNaN is forwarded unchanged + to the destination (i.e., a quieted version of the sNaN is + not returned). + + +\H{insMINSS} \i\c{MINSS}: Scalar Single-FP Minimum + +\c MINSS xmmreg,memory ; F3,0F,5D,/r [KATMAI,SSE] +\c MINSS xmmreg,xmmreg ; ?? [KATMAI,SSE] + +\c{MINSS} The MINSS instruction returns the minimum SP FP number + from the lower SP FP numbers from XMM1 and XMM2/Mem; the upper + three fields are passed through from xmm1. If the values being + compared are both zeroes, source2 (xmm2/m128) would be returned. + If source2 (xmm2/m128) is an sNaN, this sNaN is forwarded + unchanged to the destination (i.e., a quieted version of the + sNaN is not returned). + + \H{insMOV} \i\c{MOV}: Move Data \c MOV r/m8,reg8 ; 88 /r [8086] @@ -7311,6 +7683,21 @@ undefined. \c{CR4} is only a supported register on the Pentium and above. +\H{insMOVAPS} \i\c{MOVAPS}: Move Aligned Four Packed Single-FP + +\c MOVAPS xmmreg,memory ; 0F,28,/r [KATMAI,SSE] +\c MOVAPS memory,xmmreg ; 0F,29,/r [KATMAI,SSE] +\c MOVAPS xmmreg,xmmreg ; ?? [KATMAI,SSE] +\c MOVAPS xmmreg,xmmreg ; ?? [KATMAI,SSE] + +\c{MOVAPS} The linear address corresponds to the address of the + least-significant byte of the referenced memory data. When a + memory address is indicated, the 16 bytes of data at memory + location m128 are loaded or stored. When the register-register + form of this operation is used, the content of the 128-bit + source register is copied into the 128-bit destination register. + + \H{insMOVD} \i\c{MOVD}: Move Doubleword to/from MMX Register \c MOVD mmxreg,r/m32 ; 0F 6E /r [PENT,MMX] @@ -7320,6 +7707,57 @@ undefined. destination (first) operand. When the destination is a 64-bit MMX register, the top 32 bits are set to zero. + +\H{insMOVHLPS} \i\c{MOVHLPS}: High to Low Packed Single-FP + +\c MOVHLPS xmmreg,xmmreg ; OF,12,/r [KATMAI,SSE] + +\c{MOVHLPS} The upper 64-bits of the source register xmm2 are + loaded into the lower 64-bits of the 128-bit register xmm1, + and the upper 64-bits of xmm1 are left unchanged. + + +\H{insMOVHPS} \i\c{MOVHPS}: Move High Packed Single-FP + +\c MOVHPS xmmreg,memory ; 0F,16,/r [KATMAI,SSE] +\c MOVHPS memory,xmmreg ; 0F,17,/r [KATMAI,SSE] +\c MOVHPS xmmreg,xmmreg ; ?? [KATMAI,SSE,ND] + +\c{MOVHPS} The linear address corresponds to the address of the + least-significant byte of the referenced memory data. When the + load form of this operation is used, m64 is loaded into the + upper 64-bits of the 128-bit register xmm, and the lower 64-bits + are left unchanged. + + +\H{insMOVMSKPS} \i\c{MOVMSKPS}: Move Mask To Integer + +\c MOVMSKPS reg32,xmmreg ; 0F,50,/r [KATMAI,SSE] + +\c{MOVMSKPS} The MOVMSKPS instruction returns to the integer + register r32 a 4-bit mask formed of the most significant bits + of each SP FP number of its operand. + + +\H{insMOVNTPS} \i\c{MOVNTPS}: Move Aligned Four Packed Single-FP + Non Temporal + +\c MOVNTPS memory,xmmreg ; 0F,2B, /r [KATMAI,SSE] + +\c{MOVNTPS} The linear address corresponds to the address of the + least-significant byte of the referenced memory data. This store + instruction minimizes cache pollution. + + +\H{insMOVNTQ} \i\c{MOVNTQ}: Move 64 Bits Non Temporal + +\c MOVNTQ memory,mmxreg ; 0F,E7,/r [KATMAI,MMX,SM] + +\c{MOVNTQ} The linear address corresponds to the address of the + least-significant byte of the referenced memory data. This store + instruction minimizes cache pollution. + + \H{insMOVQ} \i\c{MOVQ}: Move Quadword to/from MMX Register \c MOVQ mmxreg,r/m64 ; 0F 6F /r [PENT,MMX] @@ -7328,6 +7766,8 @@ register, the top 32 bits are set to zero. \c{MOVQ} copies 64 bits from its source (second) operand into its destination (first) operand. + + \H{insMOVSB} \i\c{MOVSB}, \i\c{MOVSW}, \i\c{MOVSD}: Move String \c MOVSB ; A4 [8086] @@ -7356,6 +7796,22 @@ addressing registers by 2 or 4 instead of 1. The \c{REP} prefix may be used to repeat the instruction \c{CX} (or \c{ECX} - again, the address size chooses which) times. +\H{insMOVSS} \i\c{MOVSS}: Move Scalar Single-FP + +\c MOVSS xmmreg,memory ; F3,0F,10,/r [KATMAI,SSE] +\c MOVSS memory,xmmreg ; F3,0F,11,/r [KATMAI,SSE] +\c MOVSS xmmreg,xmmreg ; ?? [KATMAI,SSE] +\c MOVSS xmmreg,xmmreg ; ?? [KATMAI,SSE] + +\c{MOVSS} The linear address corresponds to the address of + the least-significant byte of the referenced memory data. + When a memory address is indicated, the four bytes of data + at memory location m32 are loaded or stored. When the load + form of this operation is used, the 32 bits from memory are + copied into the lower 32 bits of the 128-bit register xmm, + the 96 most significant bits being cleared. + + \H{insMOVSX} \i\c{MOVSX}, \i\c{MOVZX}: Move Data with Sign or Zero Extend \c MOVSX reg16,r/m8 ; o16 0F BE /r [386] @@ -7371,6 +7827,24 @@ its destination (first) operand, and copies the result into the destination operand. \c{MOVZX} does the same, but zero-extends rather than sign-extending. + +\H{insMOVUPS} \i\c{MOVUPS}: Move Unaligned Four Packed Single-FP + +\c MOVUPS xmmreg,memory ; 0F,10,/r [KATMAI,SSE] +\c MOVUPS memory,xmmreg ; 0F,11,/r [KATMAI,SSE] +\c MOVUPS xmmreg,xmmreg ; ?? [KATMAI,SSE] +\c MOVUPS xmmreg,xmmreg ; ?? [KATMAI,SSE] + +\c{MOVUPS} The linear address corresponds to the address of the + least-significant byte of the referenced memory data. When a + memory address is indicated, the 16 bytes of data at memory + location m128 are loaded to the 128-bit multimedia register + xmm or stored from the 128-bit multimedia register xmm. When + the register-register form of this operation is used, the content + of the 128-bit source register is copied into 128-bit register + xmm. No assumption is made about alignment. + + \H{insMUL} \i\c{MUL}: Unsigned Integer Multiply \c MUL r/m8 ; F6 /4 [8086] @@ -7393,6 +7867,27 @@ the product is stored in \c{EDX:EAX}. Signed integer multiplication is performed by the \c{IMUL} instruction: see \k{insIMUL}. +\H{insMULPS} \i\c{MULPS}: Packed Single-FP Multiply + +\c MULPS xmmreg,memory ; 0F,59,/r [KATMAI,SSE] +\c MULPS xmmreg,xmmreg ; ?? [KATMAI,SSE] + + +\c{MULPS} The MULPS instructions multiply the packed SP FP + numbers of both their operands. + + +\H{insMULSS} \i\c{MULSS}: Scalar Single-FP Multiply + + +\c MULSS xmmreg,memory ; F3,0F,59,/r [KATMAI,SSE] +\c MULSS xmmreg,xmmreg ; ?? [KATMAI,SSE] + +\c{MULSS}The MULSS instructions multiply the lowest SP FP + numbers of both their operands; the upper three fields + are passed through from xmm1. + + \H{insNEG} \i\c{NEG}, \i\c{NOT}: Two's and One's Complement \c NEG r/m8 ; F6 /3 [8086] @@ -7451,6 +7946,15 @@ form of the instruction. The MMX instruction \c{POR} (see \k{insPOR}) performs the same operation on the 64-bit MMX registers. +\H{insORPS} \i\c{ORPS}: Bit-wise Logical OR for Single-FP Data + +\c ORPS xmmreg,memory ; 0F,56,/r [KATMAI,SSE] +\c ORPS xmmreg,xmmreg ; ?? [KATMAI,SSE] + +\c{ORPS} The ORPS instructions return a bit-wise logical + OR between xmm1 and xmm2/mem. + + \H{insOUT} \i\c{OUT}: Output Data to I/O Port \c OUT imm8,AL ; E6 ib [8086] @@ -7580,6 +8084,38 @@ operands as vectors of eight unsigned bytes, and calculates the average of the corresponding bytes in the operands. The resulting vector of eight averages is stored in the first operand. + +\H{insPAVGB} \i\c{PAVGB}: Packed Average + +\c PAVGB mmxreg,mmxreg ; 0F,E0, /r [KATMAI,MMX] +\c PAVGB mmxreg,memory ; 0F,E3, /r [KATMAI,MMX,SM] + + +\H{insPAVGW} \i\c{PAVGW}: Packed Average + +\c PAVGW mmxreg,mmxreg ; ?? [KATMAI,MMX] +\c PAVGW mmxreg,memory ; ?? [KATMAI,MMX,SM] + +\c{PAVGB} The PAVG instructions add the unsigned data elements + of the source operand to the unsigned data elements of the + destination register, along with a carry-in. The results of + the add are then each independently right-shifted by one bit + position. The high order bits of each element are filled with + the carry bits of the corresponding sum. The destination operand + is an MMXTM technology register. The source operand can either + be an MMXTM technology register or a 64-bit memory operand. + The PAVGB instruction operates on packed unsigned bytes, and + the PAVGW instruction operates on packed unsigned words. + + +\H{insPAVGUSB} \i\c{PAVGUSB}: 3dnow instruction (duh!) + +\c PAVGUSB mmxreg,memory ; ?? [PENT,3DNOW,SM] +\c PAVGUSB mmxreg,mmxreg ; ?? [PENT,3DNOW] + +3dnow instruction (duh!) + + \H{insPCMPEQB} \i\c{PCMPxx}: MMX Packed Comparison \c PCMPEQB mmxreg,r/m64 ; 0F 74 /r [PENT,MMX] @@ -7609,7 +8145,7 @@ integer) than that of the second (source) operand. \H{insPDISTIB} \i\c{PDISTIB}: MMX Packed Distance and Accumulate with Implied Register -\c PDISTIB mmxreg,mem64 ; 0F 54 /r [CYRIX,MMX] +\c PDISTIB mmxreg,mem64 ; 0F 54 /r [CYRIX,MMX] \c{PDISTIB}, specific to the Cyrix MMX extensions, treats its two input operands as vectors of eight unsigned bytes. For each byte @@ -7624,6 +8160,167 @@ The implied output register is found in the same way as \c{PADDSIW} Note that \c{PDISTIB} cannot take a register as its second source operand. + +\H{insPEXTRW} \i\c{PEXTRW}: Extract Word + +\c PEXTRW reg32,mmxreg,immediate ; 0F,C5,/r,ib [KATMAI,MMX,SB,AR2] + +\c{PEXTRW}PEXTRW instruction moves the word in MM (selected by the + two least significant bits of imm8) to the lower half of a 32-bit + integer register. + + +\H{insPF2ID} \i\c{PF2ID}: 3dnow instruction (duh!) + +\c PF2ID mmxreg,memory ; ?? [PENT,3DNOW,SM] +\c PF2ID mmxreg,mmxreg ; ?? [PENT,3DNOW] + +3dnow instruction (duh!) + + +\H{insPFACC} \i\c{PFACC}: 3dnow instruction (duh!) + +\c PFACC mmxreg,memory ; ?? [PENT,3DNOW,SM] +\c PFACC mmxreg,mmxreg ; ?? [PENT,3DNOW] + +3dnow instruction (duh!) + + +\H{insPFADD} \i\c{PFADD}: 3dnow instruction (duh!) + +\c PFADD mmxreg,memory ; ?? [PENT,3DNOW,SM] +\c PFADD mmxreg,mmxreg ; ?? [PENT,3DNOW] + +3dnow instruction (duh!) + + +\H{insPFCMPEQ} \i\c{PFCMPEQ}: 3dnow instruction (duh!) + +\c PFCMPEQ mmxreg,memory ; ?? [PENT,3DNOW,SM] +\c PFCMPEQ mmxreg,mmxreg ; ?? [PENT,3DNOW] + +3dnow instruction (duh!) + + +\H{insPFCMPGE} \i\c{PFCMPGE}: 3dnow instruction (duh!) + +\c PFCMPGE mmxreg,memory ; ?? [PENT,3DNOW,SM] +\c PFCMPGE mmxreg,mmxreg ; ?? [PENT,3DNOW] + +3dnow instruction (duh!) + + +\H{insPFCMPGT} \i\c{PFCMPGT}: 3dnow instruction (duh!) + +\c PFCMPGT mmxreg,memory ; ?? [PENT,3DNOW,SM] +\c PFCMPGT mmxreg,mmxreg ; ?? [PENT,3DNOW] + +3dnow instruction (duh!) + + +\H{insPFMAX} \i\c{PFMAX}: 3dnow instruction (duh!) + +\c PFMAX mmxreg,memory ; ?? [PENT,3DNOW,SM] +\c PFMAX mmxreg,mmxreg ; ?? [PENT,3DNOW] + +3dnow instruction (duh!) + + +\H{insPFMIN} \i\c{PFMIN}: 3dnow instruction (duh!) + +\c PFMIN mmxreg,memory ; ?? [PENT,3DNOW,SM] +\c PFMIN mmxreg,mmxreg ; ?? [PENT,3DNOW] + +3dnow instruction (duh!) + + +\H{insPFMUL} \i\c{PFMUL}: 3dnow instruction (duh!) + +\c PFMUL mmxreg,memory ; ?? [PENT,3DNOW,SM] +\c PFMUL mmxreg,mmxreg ; ?? [PENT,3DNOW] + +3dnow instruction (duh!) + + +\H{insPFRCP} \i\c{PFRCP}: 3dnow instruction (duh!) + +\c PFRCP mmxreg,memory ; ?? [PENT,3DNOW,SM] +\c PFRCP mmxreg,mmxreg ; ?? [PENT,3DNOW] + +3dnow instruction (duh!) + + +\H{insPFRCPIT1} \i\c{PFRCPIT1}: 3dnow instruction (duh!) + +\c PFRCPIT1 mmxreg,memory ; ?? [PENT,3DNOW,SM] +\c PFRCPIT1 mmxreg,mmxreg ; ?? [PENT,3DNOW] + +3dnow instruction (duh!) + + +\H{insPFRCPIT2} \i\c{PFRCPIT2}: 3dnow instruction (duh!) + +\c PFRCPIT2 mmxreg,memory ; ?? [PENT,3DNOW,SM] +\c PFRCPIT2 mmxreg,mmxreg ; ?? [PENT,3DNOW] + +3dnow instruction (duh!) + + +\H{insPFRSQIT1} \i\c{PFRSQIT1}: 3dnow instruction (duh!) + +\c PFRSQIT1 mmxreg,memory ; ?? [PENT,3DNOW,SM] +\c PFRSQIT1 mmxreg,mmxreg ; ?? [PENT,3DNOW] + +3dnow instruction (duh!) + + +\H{insPFRSQRT} \i\c{PFRSQRT}: 3dnow instruction (duh!) + +\c PFRSQRT mmxreg,memory ; ?? [PENT,3DNOW,SM] +\c PFRSQRT mmxreg,mmxreg ; ?? [PENT,3DNOW] + +3dnow instruction (duh!) + + +\H{insPFSUB} \i\c{PFSUB}: 3dnow instruction (duh!) + +\c PFSUB mmxreg,memory ; ?? [PENT,3DNOW,SM] +\c PFSUB mmxreg,mmxreg ; ?? [PENT,3DNOW] + +3dnow instruction (duh!) + + +\H{insPFSUBR} \i\c{PFSUBR}: 3dnow instruction (duh!) + +\c PFSUBR mmxreg,memory ; ?? [PENT,3DNOW,SM] +\c PFSUBR mmxreg,mmxreg ; ?? [PENT,3DNOW] + +3dnow instruction (duh!) + + +\H{insPI2FD} \i\c{PI2FD}: 3dnow instruction (duh!) + +\c PI2FD mmxreg,memory ; ?? [PENT,3DNOW,SM] +\c PI2FD mmxreg,mmxreg ; ?? [PENT,3DNOW] + +3dnow instruction (duh!) + + +\H{insPINSRW} \i\c{PINSRW}: Insert Word + +\c PINSRW mmxreg,reg16,immediate ;0F,C4,/r,ib [KATMAI,MMX,SB,AR2] +\c PINSRW mmxreg,reg32,immediate ; ?? [KATMAI,MMX,SB,AR2,ND] +\c PINSRW mmxreg,memory,immediate ; ?? [KATMAI,MMX,SB,AR2] +\c PINSRW mmxreg,memory|bits16,immediate ; ?? [KATMAI,MMX,SB,AR2,ND] + +\c{PINSRW} The PINSRW instruction loads a word from the lower half + of a 32-bit integer register (or from memory) and inserts it in + the MM destination register, at a position defined by the two + least significant bits of the imm8 constant. The insertion is + done in such a way that the three other words from the + destination register are left untouched. + + \H{insPMACHRIW} \i\c{PMACHRIW}: MMX Packed Multiply and Accumulate with Rounding @@ -7658,6 +8355,51 @@ values of the words in corresponding positions, and sets each word of the destination (first) operand to whichever of the two words in that position had the larger absolute value. +\H{insPMAXSW} \i\c{PMAXSW}: Packed Signed Integer Word Maximum + +\c PMAXSW mmxreg,mmxreg ; 0F,EE, /r [KATMAI,MMX] +\c PMAXSW mmxreg,memory ; ?? [KATMAI,MMX,SM] + +\c{PMAXSW} The PMAXSW instruction returns the maximum between + the four signed words in MM1 and MM2/Mem. + + +\H{insPMAXUB} \i\c{PMAXUB}: Packed Unsigned Integer Byte Maximum + +\c PMAXUB mmxreg,mmxreg ; 0F,DE, /r [KATMAI,MMX] +\c PMAXUB mmxreg,memory ; ?? [KATMAI,MMX,SM] + +\c{PMAXUB} The PMAXUB instruction returns the maximum between + the eight unsigned words in MM1 and MM2/Mem. + + +\H{insPMINSW} \i\c{PMINSW}: Packed Signed Integer Word Minimum + +\c PMINSW mmxreg,mmxreg ; 0F,EA, /r [KATMAI,MMX] +\c PMINSW mmxreg,memory ; ?? [KATMAI,MMX,SM] + +\c{PMINSW} The PMINSW instruction returns the minimum between + the four signed words in MM1 and MM2/Mem. + + +\H{insPMINUB} \i\c{PMINUB}: Packed Unsigned Integer Byte Minimum + +\c PMINUB mmxreg,mmxreg ; 0F,DA, /r [KATMAI,MMX] +\c PMINUB mmxreg,memory ; ?? [KATMAI,MMX,SM] + +\c{PMINUB}The PMINUB instruction returns the minimum between + the eight unsigned words in MM1 and MM2/Mem. + + +\H{insPMOVMSKB} \i\c{PMOVMSKB}: Move Byte Mask To Integer + +\c PMOVMSKB reg32,mmxreg ; 0F,D7,/r [KATMAI,MMX] + +\c{PMOVMSKB} The PMOVMSKB instruction returns an 8-bit mask + formed of the most significant bits of each byte of its + source operand. + + \H{insPMULHRW} \i\c{PMULHRW}, \i\c{PMULHRIW}: MMX Packed Multiply High with Rounding @@ -7677,6 +8419,26 @@ For \c{PMULHRW}, the destination operand is the first operand; for \c{PMULHRIW} the destination operand is implied by the first operand in the manner of \c{PADDSIW} (\k{insPADDSIW}). + +\H{insPMULHRWA} \i\c{PMULHRWA}: 3dnow instruction (duh!) + +\c PMULHRWA mmxreg,memory ; ?? [PENT,3DNOW,SM] +\c PMULHRWA mmxreg,mmxreg ; ?? [PENT,3DNOW] + +3dnow instruction (duh!) + + +\H{insPMULHUW} \i\c{PMULHUW}: Packed Multiply High Unsigned + +\c PMULHUW mmxreg,mmxreg ; 0F,E4,/r [KATMAI,MMX] +\c PMULHUW mmxreg,memory ; ?? [KATMAI,MMX,SM] + +\c{PMULHUW} The PMULHUW instruction multiplies the four unsigned + words in the destination operand with the four unsigned words + in the source operand. The high-order 16 bits of the 32-bit + intermediate results are written to the destination operand. + + \H{insPMULHW} \i\c{PMULHW}, \i\c{PMULLW}: MMX Packed Multiply \c PMULHW mmxreg,r/m64 ; 0F E5 /r [PENT,MMX] @@ -7690,6 +8452,7 @@ signed doubleword results. destination (first) operand; \c{PMULLW} stores the bottom 16 bits of each doubleword in the destination operand. + \H{insPMVccZB} \i\c{PMVccZB}: MMX Packed Conditional Move \c PMVZB mmxreg,mem64 ; 0F 58 /r [CYRIX,MMX] @@ -7721,7 +8484,7 @@ source operand. \c POP r/m16 ; o16 8F /0 [8086] \c POP r/m32 ; o32 8F /0 [386] -\c POP CS ; 0F [8086,UNDOC] +\c POP CS ; 0F [8086,UNDOC] \c POP DS ; 1F [8086] \c POP ES ; 07 [8086] \c POP SS ; 17 [8086] @@ -7801,6 +8564,84 @@ See also \c{PUSHF} (\k{insPUSHF}). corresponding bits of the two inputs was 1), and stores the result in the destination (first) operand. + +\H{insPREFETCHNTA} \i\c{PREFETCHNTA}: Prefetch + +\c PREFETCHNTA memory ; 0F,18,/0 [KATMAI] + +\c{PREFETCHNTA} Move data specified by address closer to the + processor using the nta hint. + + +\H{insPREFETCHT0} \i\c{PREFETCHT0}: Prefetch + +\c PREFETCHT0 memory ; 0F,18,/1 [KATMAI] + +\c{PREFETCHT0} Move data specified by address closer to the + processor using the t0 hint. + + +\H{insPREFETCHT1} \i\c{PREFETCHT1}: Prefetch + +\c PREFETCHT1 memory ; 0F,18,/2 [KATMAI] + +\c{PREFETCHT1}Move data specified by address closer to the + processor using the t1 hint. + + +\H{insPREFETCHT2} \i\c{PREFETCHT2}: Prefetch + +\c PREFETCHT2 memory ; 0F,18,/3 [KATMAI] + +\c{PREFETCHT2} Move data specified by address closer to the + processor using the t2 hint. + + +\H{insPREFETCH} \i\c{PREFETCH}: 3dnow instruction (duh!) + +\c PREFETCH memory ; ?? [PENT,3DNOW,SM] + +3dnow instruction (duh!) + + +\H{insPREFETCHW} \i\c{PREFETCHW}: 3dnow instruction (duh!) + +\c PREFETCHW memory ; ?? [PENT,3DNOW,SM] + +3dnow instruction (duh!) + + + + + +\H{insPSADBW} \i\c{PSADBW}: Packed Sum of Absolute Differences + +\c PSADBW mmxreg,mmxreg ; 0F,F6, /r [KATMAI,MMX] +\c PSADBW mmxreg,memory ; ?? [KATMAI,MMX,SM] + +\c{PSADBW} The PSADBW instruction computes the absolute value of + the difference of unsigned bytes for mm1 and mm2/m64. These + differences are then summed to produce a word result in the lower + 16-bit field; the upper three words are cleared. The destination + operand is an MMXTM technology register. The source operand can + either be an MMXTM technology register or a 64-bit memory operand. + + +\H{insPSHUFW} \i\c{PSHUFW}: Packed Shuffle Word + +\c PSHUFW mmxreg,mmxreg,immediate ; 0F,70,/r,ib [KATMAI,MMX,SB,AR2] +\c PSHUFW mmxreg,memory,immediate ; ?? [KATMAI,MMX,SM2,SB,AR2] + +\c{PSHUFW} The PSHUF instruction uses the imm8 operand to select + which of the four words in MM2/Mem will be placed in each of the + words in MM1. Bits 1 and 0 of imm8 encode the source for + destination word 0 (MM1[15-0]), bits 3 and 2 encode for word 1, + bits 5 and 4 encode for word 2, and bits 7 and 6 encode for + word 3 (MM1[63-48]). Similarly, the two-bit encoding represents + which source word is to be used, e.g., a binary encoding of 10 + indicates that source word 2 (MM2/Mem[47-32]) will be used. + + \H{insPSLLD} \i\c{PSLLx}, \i\c{PSRLx}, \i\c{PSRAx}: MMX Bit Shifts \c PSLLW mmxreg,r/m64 ; 0F F1 /r [PENT,MMX] @@ -8061,6 +8902,28 @@ You can force the longer (286 and upwards, beginning with a \c{C1} byte) form of \c{RCL foo,1} by using a \c{BYTE} prefix: \c{RCL foo,BYTE 1}. Similarly with \c{RCR}. + +\H{insRCPPS} \i\c{RCPPS}: Packed Single-FP Reciprocal + +\c RCPPS xmmreg,memory ; 0F,53,/r [KATMAI,SSE] +\c RCPPS xmmreg,xmmreg ; ?? [KATMAI,SSE] + +\c{RCPPS}RCPPS returns an approximation of the reciprocal of the + SP FP numbers from xmm2/m128. The maximum error for this + approximation is: Error <=1.5x2-12 + + +\H{insRCPSS} \i\c{RCPSS}: Scalar Single-FP Reciprocal + +\c RCPSS xmmreg,memory ; F3,0F,53,/r [KATMAI,SSE] +\c RCPSS xmmreg,xmmreg ; ?? [KATMAI,SSE] + +\c{RCPSS}RCPSS returns an approximation of the reciprocal of the + lower SP FP number from xmm2/m32; the upper three fields are + passed through from xmm1. The maximum error for this + approximation is: |Error| <= 1.5x2-12 + + \H{insRDMSR} \i\c{RDMSR}: Read Model-Specific Registers \c RDMSR ; 0F 32 [PENT] @@ -8145,6 +9008,28 @@ foo,BYTE 1}. Similarly with \c{ROR}. \c{RSM} returns the processor to its normal operating mode when it was in System-Management Mode. + +\H{insRSQRTPS} \i\c{RSQRTPS}:Packed Single-FP Square Root Reciprocal + +\c RSQRTPS xmmreg,memory ; 0F,52,/r [KATMAI,SSE] +\c RSQRTPS xmmreg,xmmreg ; ?? [KATMAI,SSE] + +\c{RSQRTPS} RSQRTPS returns an approximation of the reciprocal + of the square root of the SP FP numbers rom xmm2/m128. The + maximum error for this approximation is: Error| <= 1.5x2-12 + + +\H{insRSQRTSS} \i\c{RSQRTSS}:Scalar Single-FP Square Root Reciprocal + +\c RSQRTSS xmmreg,memory ; F3,0F,52,/r [KATMAI,SSE] +\c RSQRTSS xmmreg,xmmreg ; ?? [KATMAI,SSE] + +\c{RSQRTSS} RSQRTSS returns an approximation of the reciprocal + of the square root of the lowest SP FP number from xmm2/m32; + the upper three fields are passed through from xmm1. The maximum + error for this approximation is: |Error| <= 1.5x2-12 + + \H{insSAHF} \i\c{SAHF}: Store AH to Flags \c SAHF ; 9E [8086] @@ -8193,7 +9078,7 @@ foo,BYTE 1}. Similarly with \c{SAR}. \H{insSALC} \i\c{SALC}: Set AL from Carry Flag -\c SALC ; D6 [8086,UNDOC] +\c SALC ; D6 [8086,UNDOC] \c{SALC} is an early undocumented instruction similar in concept to \c{SETcc} (\k{insSETcc}). Its function is to set \c{AL} to zero if @@ -8273,6 +9158,36 @@ first unequal or equal byte is found. \c{SETcc} sets the given 8-bit operand to zero if its condition is not satisfied, and to 1 if it is. + +\H{insSFENCE} \i\c{SFENCE}: Store Fence + +\c SFENCE 0,0,0 ; 0F AE /7 [KATMAI] + +\c{SFENCE} Weakly ordered memory types can enable higher + performance through such techniques as out-of-order issue, + write-combining, and write-collapsing. Memory ordering issues + can arise between a producer and a consumer of data and there + are a number of common usage models which may be affected by + weakly ordered stores: + 1. library functions, which use weakly ordered memory + to write results + 2. compiler-generated code, which also benefit from writing + weakly-ordered results + 3. hand-written code + The degree to which a consumer of data knows that the data is + weakly ordered can vary for these cases. As a result, the SFENCE + instruction provides a performance-efficient way of ensuring + ordering between routines that produce weakly-ordered results + and routines that consume this data. The SFENCE is ordered with + respect to stores and other SFENCE instructions. + SFENCE uses the following ModRM encoding: + Mod (7:6) = 11B + Reg/Opcode (5:3) = 111B + R/M (2:0) = 000B + All other ModRM encodings are defined to be reserved, and use + of these encodings risks incompatibility with future processors. + + \H{insSGDT} \i\c{SGDT}, \i\c{SIDT}, \i\c{SLDT}: Store Descriptor Table Pointers \c SGDT mem ; 0F 01 /0 [286,PRIV] @@ -8359,6 +9274,18 @@ EAX,EBX,4} would update \c{EAX} to hold \c{0xF0123456}. The number of bits to shift by is given by the third operand. Only the bottom 5 bits of the shift count are considered. + +\H{insSHUFPS} \i\c{SHUFPS}: Shuffle Single-FP + +\c SHUFPS xmmreg,memory,immediate ; 0F,C6,/r, ib [KATMAI,SSE,SB,AR2] +\c SHUFPS xmmreg,xmmreg,immediate ; ?? [KATMAI,SSE,SB,AR2] + +\c{SHUFPS} The SHUFPS instruction is able to shuffle any of the + four SP FP numbers from xmm1 to the lower two destination fields; + the upper two destination fields are generated from a shuffle of + any of the four SP FP numbers from xmm2/m128. + + \H{insSMI} \i\c{SMI}: System Management Interrupt \c SMI ; F1 [386,UNDOC] @@ -8375,6 +9302,25 @@ machine into system-management mode, a special debugging mode. the Machine Status Word, on 286 processors) into the destination operand. See also \c{LMSW} (\k{insLMSW}). + +\H{insSQRTPS} \i\c{SQRTPS}: Packed Single-FP Square Root + +\c SQRTPS xmmreg,memory ; 0F,51,/r [KATMAI,SSE] +\c SQRTPS xmmreg,xmmreg ; ?? [KATMAI,SSE] + +\c{SQRTPS} The SQRTPS instruction returns the square root of + the packed SP FP numbers from xmm2/m128. + + +\H{insSQRTSS} \i\c{SQRTSS}: Scalar Single-FP Square Root + +\c SQRTSS xmmreg,memory ; F3,0F,51,/r [KATMAI,SSE] +\c SQRTSS xmmreg,xmmreg ; ?? [KATMAI,SSE] + +\c{SQRTSS} The SQRTSS instructions return the square root of + the lowest SP FP numbers of their operand. + + \H{insSTC} \i\c{STC}, \i\c{STD}, \i\c{STI}: Set Flags \c STC ; F9 [8086] @@ -8389,6 +9335,21 @@ To clear the carry, direction, or interrupt flags, use the \c{CLC}, \c{CLD} and \c{CLI} instructions (\k{insCLC}). To invert the carry flag, use \c{CMC} (\k{insCMC}). + +\H{insSTMXCSR} \i\c{STMXCSR}: Store Streaming SIMD Extension + Control/Status + +\c STMXCSR memory ; 0F,AE,/3 [KATMAI,SSE,SD] + +\c{STMXCSR} The MXCSR control/status register is used to enable + masked/unmasked exception handling, to set rounding modes, + to set flush-to-zero mode, and to view exception status flags. + Refer to LDMXCSR for a description of the format of MXCSR. + The linear address corresponds to the address of the + least-significant byte of the referenced memory data. + The reserved bits in the MXCSR are stored as zeroes. + + \H{insSTOSB} \i\c{STOSB}, \i\c{STOSW}, \i\c{STOSD}: Store Byte to String \c STOSB ; AA [8086] @@ -8457,6 +9418,24 @@ sign-extended to the length of the first operand. In these cases, the \c{BYTE} qualifier is necessary to force NASM to generate this form of the instruction. +\H{insSUBPS} \i\c{SUBPS}: Packed Single-FP Subtract + +\c SUBPS xmmreg,memory ; 0F,5C,/r [KATMAI,SSE] +\c SUBPS xmmreg,xmmreg ; ?? [KATMAI,SSE] + +\c{SUBPS}T he SUBPS instruction subtracts the packed SP FP + numbers of both their operands. + + +\H{insSUBSS} \i\c{SUBSS}: Scalar Single-FP Subtract + +\c SUBSS xmmreg,memory ; F3,0F,5C, /r [KATMAI,SSE] +\c SUBSS xmmreg,xmmreg ; ?? [KATMAI,SSE] + +\c{SUBSS} The SUBSS instruction subtracts the lower SP FP + numbers of both their operands. + + \H{insTEST} \i\c{TEST}: Test Bits (notional bitwise AND) \c TEST r/m8,reg8 ; 84 /r [8086] @@ -8475,6 +9454,19 @@ form of the instruction. affects the flags as if the operation had taken place, but does not store the result of the operation anywhere. +\H{insUCOMISS} \i\c{UCOMISS}: Unordered Scalar Single-FP compare + and set EFLAGS + +\c UCOMISS xmmreg,memory ; 0F,2E,/r [KATMAI,SSE] +\c UCOMISS xmmreg,xmmreg ; ?? [KATMAI,SSE] + +\c{UCOMISS} The UCOMISS instructions compare the two lowest scalar + SP FP numbers, and set the ZF,PF,CF bits in the EFLAGS register + as described above. In addition, the OF, SF, and AF bits in the + EFLAGS register are zeroed out. The unordered predicate is + returned if either source operand is a NaN (qNaN or sNaN). + + \H{insUMOV} \i\c{UMOV}: User Move Data \c UMOV r/m8,reg8 ; 0F 10 /r [386,UNDOC] @@ -8490,6 +9482,27 @@ access user memory (as opposed to host memory). It is used just like an ordinary memory/register or register/register \c{MOV} instruction, but accesses user space. + +\H{insUNPCKHPS} \i\c{UNPCKHPS}: Unpack High Packed Single-FP Data + +\c UNPCKHPS xmmreg,memory ; 0F,15,/r [KATMAI,SSE] +\c UNPCKHPS xmmreg,xmmreg ; ?? [KATMAI,SSE] + +\c{UNPCKHPS} The UNPCKHPS instruction performs an interleaved + unpack of the high-order data elements of XMM1 and XMM2/Mem. + It ignores the lower half of the sources. + + +\H{insUNPCKLPS} \i\c{UNPCKLPS}: Unpack Low Packed Single-FP Data + +\c UNPCKLPS xmmreg,memory ; 0F,14,/r [KATMAI,SSE] +\c UNPCKLPS xmmreg,xmmreg ; ?? [KATMAI,SSE] + +\c{UNPCKLPS} The UNPCKLPS instruction performs an interleaved + unpack of the low-order data elements of XMM1 and XMM2/Mem. + It ignores the upper half part of the sources. + + \H{insVERR} \i\c{VERR}, \i\c{VERW}: Verify Segment Readability/Writability \c VERR r/m16 ; 0F 00 /4 [286,PRIV] @@ -8629,3 +9642,12 @@ form of the instruction. The MMX instruction \c{PXOR} (see \k{insPXOR}) performs the same operation on the 64-bit MMX registers. + + +\H{insXORPS} \i\c{XORPS}: Bit-wise Logical Xor for Single-FP Data + +\c XORPS xmmreg,memory ; 0F,57,/r [KATMAI,SSE] +\c XORPS xmmreg,xmmreg ; ?? [KATMAI,SSE] + +\c{XORPS} The XORPS instruction returns a bit-wise logical XOR + between XMM1 and XMM2/Mem. diff --git a/doc/rdsrc.pl b/doc/rdsrc.pl index 38044b1..b174dd2 100644 --- a/doc/rdsrc.pl +++ b/doc/rdsrc.pl @@ -5,11 +5,6 @@ # TODO: # -# PS output: -# - show page numbers in printed output -# - think about double-sided support (start all chapters on RHS, -# ie odd-numbered, pages). -# # Ellipsis support would be nice. # Source-form features: @@ -1091,6 +1086,7 @@ sub write_ps { # now) to the length of the current page. Also, _put_ this line on # the current page, and allocate it a y-coordinate. if ($ltypes[$i] =~ /^chap$/) { + $pnum += 1 - ($pnum & 1); # advance to odd numbered page if necessary $plen = 100; # ADJUSTABLE: space taken up by a chapter heading $ycoord[$i] = 0; # chapter heading: y-coord doesn't matter } else { @@ -1234,7 +1230,7 @@ sub write_ps { last PAGE if $i > $#psindex; } } - &ps_trailer; + &ps_trailer($page); close PS; select STDOUT; } @@ -1263,6 +1259,10 @@ sub ps_header { '/es /Helvetica-Oblique findfont 12 scalefont def', '/cs /Courier-Bold findfont 12 scalefont def', '/n 16#6E def /e 16#65 def /c 16#63 def', + '/pageodd {', + ' 550 50 moveto ns setfont dup stringwidth pop neg 0 rmoveto show', + '} def', + '/pageeven { 50 50 moveto ns setfont show } def', '/chapter {', ' 100 620 moveto', ' {', @@ -1383,14 +1383,18 @@ sub ps_header { } sub ps_trailer { - &ps_donepg; + my ($oldpg) = @_; + &ps_donepg($oldpg); print "%%Trailer\nrestore\n%%EOF\n"; } sub ps_throw_pg { my ($oldpg, $newpg) = @_; - &ps_donepg; - &ps_initpg($newpg); + while ($oldpg < $newpg) { + &ps_donepg($oldpg); + $oldpg++; + &ps_initpg($oldpg); + } } sub ps_initpg { @@ -1400,7 +1404,12 @@ sub ps_initpg { } sub ps_donepg { - print "%%PageTrailer\nrestore showpage\n"; + my ($pgnum) = @_; + if ($pgnum & 1) { + print "%%PageTrailer\n($pgnum)pageodd restore showpage\n"; + } else { + print "%%PageTrailer\n($pgnum)pageeven restore showpage\n"; + } } sub ps_out_line { @@ -1516,7 +1525,7 @@ sub write_texi { select TEXT; # Preamble. - print "\input texinfo \@c -*-texinfo-*-\n"; + print "\\input texinfo \@c -*-texinfo-*-\n"; print "\@c \%**start of header\n"; print "\@setfilename nasm.info\n"; print "\@dircategory Programming\n"; @@ -1550,7 +1559,7 @@ sub write_texi { print "\@end titlepage\n"; print "\n"; print "\@node Top, $tstruct_next{'Top'}, (dir), (dir)\n"; - print "\@top\n"; + print "\@top Netwide Assembler\n"; print "\n"; print "\@ifinfo\n"; print "This file documents NASM, the Netwide Assembler: an assembler\n"; @@ -1606,7 +1615,9 @@ sub write_texi { $title .= $ww unless $ww eq "\001"; } print "\@node $node, $tstruct_next{$node}, $tstruct_prev{$node},"; - print " $tstruct_up{$node}\n\@unnumbered $title\n"; + print " $tstruct_up{$node}\n"; + $hdr = ($ptype eq "subh" ? "\@unnumberedsubsec" : "\@unnumberedsec"); + print "$hdr $title\n"; } elsif ($ptype eq "code") { # Code paragraph. Surround with @example / @end example. print "\@example\n"; @@ -291,6 +291,7 @@ FDIVRP fpureg,fpu0 \1\xDE\10\xF0 8086,FPU FEMMS void \2\x0F\x0E PENT,3DNOW FENI void \3\x9B\xDB\xE0 8086,FPU FFREE fpureg \1\xDD\10\xC0 8086,FPU +FFREEP fpureg \1\xDF\10\xC0 P6,FPU,UNDOC FIADD mem32 \300\1\xDA\200 8086,FPU FIADD mem16 \300\1\xDE\200 8086,FPU FICOM mem32 \300\1\xDA\202 8086,FPU @@ -459,8 +460,8 @@ INVLPG mem \300\2\x0F\x01\207 486,PRIV IRET void \322\1\xCF 8086 IRETD void \321\1\xCF 386 IRETW void \320\1\xCF 8086 -JCXZ imm \320\1\xE3\50 8086 -JECXZ imm \321\1\xE3\50 386 +JCXZ imm \310\1\xE3\50 8086 +JECXZ imm \311\1\xE3\50 386 JMP imm|short \1\xEB\50 8086 JMP imm \370\1\xEB\50 8086,ND JMP imm \322\1\xE9\64 8086 @@ -887,9 +888,10 @@ 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 -RSDC reg_sreg,mem80 \301\2\x0F\x79\101 486,CYRIX,SMM +RSDC reg_sreg,mem80 \301\2\x0F\x79\110 486,CYRIX,SMM RSLDT mem80 \300\2\x0F\x7B\200 486,CYRIX,SMM RSM void \2\x0F\xAA PENT,SMM +RSTS mem80 \300\2\x0F\x7D\200 486,CYRIX,SMM SAHF void \1\x9E 8086 SAL rm8,unity \300\1\xD0\204 8086,ND SAL rm8,reg_cl \300\1\xD2\204 8086,ND @@ -1062,6 +1064,7 @@ VERW mem \300\1\x0F\17\205 286,PROT VERW mem16 \300\1\x0F\17\205 286,PROT VERW reg16 \300\1\x0F\17\205 286,PROT WAIT void \1\x9B 8086 +FWAIT void \1\x9B 8086 WBINVD void \2\x0F\x09 486,PRIV WRSHR void \2\x0F\x37 P6,CYRIX,SMM WRMSR void \2\x0F\x30 PENT,PRIV @@ -1143,7 +1146,7 @@ ANDPS xmmreg,mem \301\2\x0F\x54\110 KATMAI,S ANDPS xmmreg,xmmreg \2\x0F\x54\110 KATMAI,SSE CMPEQPS xmmreg,mem \301\331\2\x0F\xC2\110\1\x00 KATMAI,SSE CMPEQPS xmmreg,xmmreg \331\2\x0F\xC2\110\1\x00 KATMAI,SSE -CMPEQSS xmmreg,mem \301\333\2\x0F\xC2\110\1\0x00 KATMAI,SSE +CMPEQSS xmmreg,mem \301\333\2\x0F\xC2\110\1\x00 KATMAI,SSE CMPEQSS xmmreg,xmmreg \333\2\x0F\xC2\110\1\x00 KATMAI,SSE CMPLEPS xmmreg,mem \301\331\2\x0F\xC2\110\1\x02 KATMAI,SSE CMPLEPS xmmreg,xmmreg \331\2\x0F\xC2\110\1\x02 KATMAI,SSE @@ -1303,3 +1306,279 @@ PSADBW mmxreg,mmxreg \2\x0F\xF6\110 KATMAI,MMX PSADBW mmxreg,mem \301\2\x0F\xF6\110 KATMAI,MMX,SM PSHUFW mmxreg,mmxreg,imm \2\x0F\x70\110\22 KATMAI,MMX,SB,AR2 PSHUFW mmxreg,mem,imm \301\2\x0F\x70\110\22 KATMAI,MMX,SM2,SB,AR2 + +; The five new Athlon instructions +PF2IW mmxreg,mem \301\2\x0F\x0F\110\01\x1C PENT,3DNOW,SM +PF2IW mmxreg,mmxreg \2\x0F\x0F\110\01\x1C PENT,3DNOW +PFNACC mmxreg,mem \301\2\x0F\x0F\110\01\x8A PENT,3DNOW,SM +PFNACC mmxreg,mmxreg \2\x0F\x0F\110\01\x8A PENT,3DNOW +PFPNACC mmxreg,mem \301\2\x0F\x0F\110\01\x8E PENT,3DNOW,SM +PFPNACC mmxreg,mmxreg \2\x0F\x0F\110\01\x8E PENT,3DNOW +PI2FW mmxreg,mem \301\2\x0F\x0F\110\01\x0C PENT,3DNOW,SM +PI2FW mmxreg,mmxreg \2\x0F\x0F\110\01\x0C PENT,3DNOW +PSWAPD mmxreg,mem \301\2\x0F\x0F\110\01\xBB PENT,3DNOW,SM +PSWAPD mmxreg,mmxreg \2\x0F\x0F\110\01\xBB PENT,3DNOW + +; Introduced in Willamette +; opcode parameters assembly range +MASKMOVDQU xmmreg,xmmreg \3\x66\x0F\xF7 WILLAMETTE +CLFLUSH mem \2\x0F\xAE WILLAMETTE +MOVNTDQ xmmreg,mem \3\x66\x0F\xEF WILLAMETTE +MOVNTI reg32,mem \2\x0F\xC3 WILLAMETTE +PAUSE void \2\xF3\x90 WILLAMETTE +LFENCE void \3\x0F\xAE\xF8 WILLAMETTE +MFENCE void \3\x0F\xAE\xF8 WILLAMETTE + +; Willamette MMX instructions (SSE2) +MOVD xmmreg,reg32 \3\x66\x0F\x6E WILLAMETTE +MOVD reg32,xmmreg \3\x66\x0F\x7E WILLAMETTE +MOVD mem,xmmreg \3\x66\x0F\x7E WILLAMETTE +MOVD xmmreg,mem \3\x66\x0F\x6E WILLAMETTE +MOVDQA xmmreg,reg32 \3\x66\x0F\x6F WILLAMETTE +MOVDQA mem,xmmreg \3\x66\x0F\x7F WILLAMETTE +MOVDQA xmmreg,mem \3\x66\x0F\x6F WILLAMETTE +MOVDQA reg32,xmmreg \3\x66\x0F\x7F WILLAMETTE +MOVDQU xmmreg,reg32 \3\xF3\x0F\x6F WILLAMETTE +MOVDQU mem,xmmreg \3\xF3\x0F\x7F WILLAMETTE +MOVDQU xmmreg,mem \3\xF3\x0F\x6F WILLAMETTE +MOVDQU reg32,xmmreg \3\xF3\x0F\x7F WILLAMETTE +MOVQ2DQ mmxreg,xmmreg \3\xF2\x0F\xD6 WILLAMETTE +PACKSSWB xmmreg,xmmreg \3\x66\x0F\x63 WILLAMETTE +PACKSSWB xmmreg,mem \3\x66\x0F\x63 WILLAMETTE +PACKSSDW xmmreg,xmmreg \3\x66\x0F\x6B WILLAMETTE +PACKSSDW xmmreg,mem \3\x66\x0F\x6B WILLAMETTE +PACKUSWB xmmreg,xmmreg \3\x66\x0F\x67 WILLAMETTE +PACKUSWB xmmreg,mem \3\x66\x0F\x67 WILLAMETTE +PADDQ xmmreg,mmxreg \3\x66\x0F\xD4 WILLAMETTE +PADDQ xmmreg,mem \3\x66\x0F\xD4 WILLAMETTE +PADDD xmmreg,xmmreg \3\x66\x0F\xFE WILLAMETTE +PADDD xmmreg,mem \3\x66\x0F\xFE WILLAMETTE +PADDSB xmmreg,mem \3\x66\x0F\xEC WILLAMETTE +PADDSB xmmreg,xmmreg \3\x66\x0F\xEC WILLAMETTE +PADDSW xmmreg,mem \3\x66\x0F\xED WILLAMETTE +PADDSW xmmreg,xmmreg \3\x66\x0F\xED WILLAMETTE +PADDUSB xmmreg,mem \3\x66\x0F\xDC WILLAMETTE +PADDUSB xmmreg,xmmreg \3\x66\x0F\xDC WILLAMETTE +PADDUSW xmmreg,mem \3\x66\x0F\xDD WILLAMETTE +PADDUSW xmmreg,xmmreg \3\x66\x0F\xDD WILLAMETTE +PAND xmmreg,xmmreg \3\x66\x0F\xDB WILLAMETTE +PAND xmmreg,mem \3\x66\x0F\xDB WILLAMETTE +PANDN xmmreg,xmmreg \3\x66\x0F\xDF WILLAMETTE +PANDN xmmreg,mem \3\x66\x0F\xDF WILLAMETTE +PAVGB xmmreg,xmmreg \3\x66\x0F\xE0 WILLAMETTE +PAVGB xmmreg,mem \3\x66\x0F\xE0 WILLAMETTE +PAVGW xmmreg,xmmreg \3\x66\x0F\xE3 WILLAMETTE +PAVGW xmmreg,mem \3\x66\x0F\xE3 WILLAMETTE +PCMPEQB xmmreg,xmmreg \3\x66\x0F\x74 WILLAMETTE +PCMPEQB xmmreg,mem \3\x66\x0F\x74 WILLAMETTE +PCMPEQW xmmreg,xmmreg \3\x66\x0F\x75 WILLAMETTE +PCMPEQW xmmreg,mem \3\x66\x0F\x75 WILLAMETTE +PCMPEQD xmmreg,xmmreg \3\x66\x0F\x76 WILLAMETTE +PCMPEQD xmmreg,mem \3\x66\x0F\x76 WILLAMETTE +PCMPGTB xmmreg,xmmreg \3\x66\x0F\x64 WILLAMETTE +PCMPGTB xmmreg,mem \3\x66\x0F\x64 WILLAMETTE +PCMPGTW xmmreg,xmmreg \3\x66\x0F\x65 WILLAMETTE +PCMPGTW xmmreg,mem \3\x66\x0F\x65 WILLAMETTE +PCMPGTD xmmreg,xmmreg \3\x66\x0F\x66 WILLAMETTE +PCMPGTD xmmreg,mem \3\x66\x0F\x66 WILLAMETTE +PEXTRW reg32,xmmreg,imm8 \3\x66\x0F\xC5\110\22 WILLAMETTE +PINSRW xmmreg,reg16,imm \3\x66\x0F\xC4\110\22 WILLAMETTE,MMX,SB,AR2 +PINSRW xmmreg,reg32,imm \3\x66\x0F\xC4\110\22 WILLAMETTE,MMX,SB,AR2,ND +PINSRW xmmreg,mem,imm \301\3\x66\x0F\xC4\110\22 WILLAMETTE,MMX,SB,AR2 +PINSRW xmmreg,mem16,imm \301\3\x66\x0F\xC4\110\22 WILLAMETTE,MMX,SB,AR2,ND +PMAXSW xmmreg,xmmreg \3\x66\x0F\xEE\110 WILLAMETTE,MMX +PMAXSW xmmreg,mem \301\3\x66\x0F\xEE\110 WILLAMETTE,MMX,SM +PMAXUB xmmreg,xmmreg \3\x66\x0F\xDE\110 WILLAMETTE,MMX +PMAXUB xmmreg,mem \301\3\x66\x0F\xDE\110 WILLAMETTE,MMX,SM +PMINSW xmmreg,xmmreg \3\x66\x0F\xEA\110 WILLAMETTE,MMX +PMINSW xmmreg,mem \301\3\x66\x0F\xEA\110 WILLAMETTE,MMX,SM +PMINUB xmmreg,xmmreg \3\x66\x0F\xDA\110 WILLAMETTE,MMX +PMINUB xmmreg,mem \301\3\x66\x0F\xDA\110 WILLAMETTE,MMX,SM +PMOVMSKB reg32,xmmreg \3\x66\x0F\xD7\110 WILLAMETTE,MMX +PMULHUW xmmreg,xmmreg \3\x66\x0F\xE4\110 WILLAMETTE,MMX +PMULHUW xmmreg,mem \301\3\x66\x0F\xE4\110 WILLAMETTE,MMX,SM +PSADBW xmmreg,xmmreg \3\x66\x0F\xF6\110 WILLAMETTE,MMX +PSADBW xmmreg,mem \301\3\x66\x0F\xF6\110 WILLAMETTE,MMX,SM +PSHUFD xmmreg,xmmreg,imm \3\x66\x0F\x70\110\22 WILLAMETTE,MMX,SB,AR2 +PSHUFD xmmreg,mem,imm \301\3\x66\x0F\x70\110\22 WILLAMETTE,MMX,SM2,SB,AR2 +PMADDWD xmmreg,mem \301\3\x66\x0F\xF5\110 WILLAMETTE,MMX,SM +PMADDWD xmmreg,xmmreg \3\x66\x0F\xF5\110 WILLAMETTE,MMX +PMULLW xmmreg,mem \301\3\x66\x0F\xD5\110 WILLAMETTE,MMX,SM +PMULLW xmmreg,xmmreg \3\x66\x0F\xD5\110 WILLAMETTE,MMX +PMULUDQ mmxreg,mmxreg \2\x0F\xF4 WILLAMETTE +PMULUDQ mmxreg,mem \2\x0F\xF4 WILLAMETTE +PMULUDQ xmmreg,xmmreg \3\x66\x0F\xF4 WILLAMETTE +PMULUDQ xmmreg,mem \3\x66\x0F\xF4 WILLAMETTE +POR xmmreg,mem \301\3\x66\x0F\xEB\110 WILLAMETTE,MMX,SM +POR xmmreg,xmmreg \3\x66\x0F\xEB\110 WILLAMETTE,MMX +PSHUFLW xmmreg,xmmreg,imm8 \3\xF2\x0F\x70 WILLAMETTE +PSHUFLW xmmreg,mem,imm8 \3\xF2\x0F\x70 WILLAMETTE +PSHUFHW xmmreg,xmmreg,imm8 \3\xF3\x0F\x70 WILLAMETTE +PSHUFHW xmmreg,mem,imm8 \3\xF3\x0F\x70 WILLAMETTE +PSLLDQ xmmreg,imm8 \3\x66\x0F\x73 WILLAMETTE +PSLLD xmmreg,mem \301\3\x66\x0F\xF2\110 WILLAMETTE,MMX,SM +PSLLD xmmreg,xmmreg \3\x66\x0F\xF2\110 WILLAMETTE,MMX +PSLLD xmmreg,imm \3\x66\x0F\x72\206\25 WILLAMETTE,MMX +PSLLQ xmmreg,mem \301\3\x66\x0F\xF3\110 WILLAMETTE,MMX,SM +PSLLQ xmmreg,xmmreg \3\x66\x0F\xF3\110 WILLAMETTE,MMX +PSLLQ xmmreg,imm \3\x66\x0F\x73\206\25 WILLAMETTE,MMX +PSLLW xmmreg,mem \301\3\x66\x0F\xF1\110 WILLAMETTE,MMX,SM +PSLLW xmmreg,xmmreg \3\x66\x0F\xF1\110 WILLAMETTE,MMX +PSLLW xmmreg,imm \3\x66\x0F\x71\206\25 WILLAMETTE,MMX +PSRAD xmmreg,mem \301\3\x66\x0F\xE2\110 WILLAMETTE,MMX,SM +PSRAD xmmreg,xmmreg \3\x66\x0F\xE2\110 WILLAMETTE,MMX +PSRAD xmmreg,imm \3\x66\x0F\x72\204\25 WILLAMETTE,MMX +PSRAW xmmreg,mem \301\3\x66\x0F\xE1\110 WILLAMETTE,MMX,SM +PSRAW xmmreg,xmmreg \3\x66\x0F\xE1\110 WILLAMETTE,MMX +PSRAW xmmreg,imm \3\x66\x0F\x71\204\25 WILLAMETTE,MMX +PSRLW xmmreg,imm \3\x66\x0F\x73\202\25 WILLAMETTE,MMX +PSRLD xmmreg,mem \301\3\x66\x0F\xD2\110 WILLAMETTE,MMX,SM +PSRLD xmmreg,xmmreg \3\x66\x0F\xD2\110 WILLAMETTE,MMX +PSRLD xmmreg,imm \3\x66\x0F\x72\202\25 WILLAMETTE,MMX +PSRLQ xmmreg,mem \301\3\x66\x0F\xD3\110 WILLAMETTE,MMX,SM +PSRLQ xmmreg,xmmreg \3\x66\x0F\xD3\110 WILLAMETTE,MMX +PSRLQ xmmreg,imm \3\x66\x0F\x73\202\25 WILLAMETTE,MMX +PSRLW xmmreg,mem \301\3\x66\x0F\xD1\110 WILLAMETTE,MMX,SM +PSRLW xmmreg,xmmreg \3\x66\x0F\xD1\110 WILLAMETTE,MMX +PSRLW xmmreg,imm \3\x66\x0F\x71\202\25 WILLAMETTE,MMX +PSUBQ mmxreg,mmxreg \2\x0F\xFB WILLAMETTE +PSUBQ mmxreg,mem \2\x0F\xFB WILLAMETTE +PSUBQ xmmreg,xmmreg \3\x66\x0F\xFB WILLAMETTE +PSUBQ xmmreg,mem \3\x66\x0F\xFB WILLAMETTE +PSUBB xmmreg,mem \301\3\x66\x0F\xF8\110 WILLAMETTE,MMX,SM +PSUBB xmmreg,xmmreg \3\x66\x0F\xF8\110 WILLAMETTE,MMX +PSUBD xmmreg,mem \301\3\x66\x0F\xFA\110 WILLAMETTE,MMX,SM +PSUBD xmmreg,xmmreg \3\x66\x0F\xFA\110 WILLAMETTE,MMX +PSUBSB xmmreg,mem \301\3\x66\x0F\xE8\110 WILLAMETTE,MMX,SM +PSUBSB xmmreg,xmmreg \3\x66\x0F\xE8\110 WILLAMETTE,MMX +PSUBSW xmmreg,mem \301\3\x66\x0F\xE9\110 WILLAMETTE,MMX,SM +PSUBSW xmmreg,xmmreg \3\x66\x0F\xE9\110 WILLAMETTE,MMX +PSUBUSB xmmreg,mem \301\3\x66\x0F\xD8\110 WILLAMETTE,MMX,SM +PSUBUSB xmmreg,xmmreg \3\x66\x0F\xD8\110 WILLAMETTE,MMX +PSUBUSW xmmreg,mem \301\3\x66\x0F\xD9\110 WILLAMETTE,MMX,SM +PSUBUSW xmmreg,xmmreg \3\x66\x0F\xD9\110 WILLAMETTE,MMX +PSUBW xmmreg,mem \301\3\x66\x0F\xF9\110 WILLAMETTE,MMX,SM +PSUBW xmmreg,xmmreg \3\x66\x0F\xF9\110 WILLAMETTE,MMX +PUNPCKHBW xmmreg,mem \301\3\x66\x0F\x68\110 WILLAMETTE,MMX,SM +PUNPCKHBW xmmreg,xmmreg \3\x66\x0F\x68\110 WILLAMETTE,MMX +PUNPCKHDQ xmmreg,mem \301\3\x66\x0F\x6A\110 WILLAMETTE,MMX,SM +PUNPCKHDQ xmmreg,xmmreg \3\x66\x0F\x6A\110 WILLAMETTE,MMX +PUNPCKHWD xmmreg,mem \301\3\x66\x0F\x69\110 WILLAMETTE,MMX,SM +PUNPCKHWD xmmreg,xmmreg \3\x66\x0F\x69\110 WILLAMETTE,MMX +PUNPCKLBW xmmreg,mem \301\3\x66\x0F\x60\110 WILLAMETTE,MMX,SM +PUNPCKLBW xmmreg,xmmreg \3\x66\x0F\x60\110 WILLAMETTE,MMX +PUNPCKLDQ xmmreg,mem \301\3\x66\x0F\x62\110 WILLAMETTE,MMX,SM +PUNPCKLDQ xmmreg,xmmreg \3\x66\x0F\x62\110 WILLAMETTE,MMX +PUNPCKLWD xmmreg,mem \301\3\x66\x0F\x61\110 WILLAMETTE,MMX,SM +PUNPCKLWD xmmreg,xmmreg \3\x66\x0F\x61\110 WILLAMETTE,MMX +PUNPCKLQDQ xmmreg,xmmreg \3\x66\x0F\x6C\110 WILLAMETTE +PUNPCKLQDQ xmmreg,mem \301\3\x66\x0F\x6C\110 WILLAMETTE +PUNPCKHQDQ xmmreg,xmmreg \3\x66\x0F\x6D\110 WILLAMETTE +PUNPCKHQDQ xmmreg,mem \301\3\x66\x0F\x6D\110 WILLAMETTE +PXOR xmmreg,mem \301\3\x66\x0F\xEF\110 WILLAMETTE,MMX,SM +PXOR xmmreg,xmmreg \3\x66\x0F\xEF\110 WILLAMETTE,MMX +; Willamette Streaming SIMD instructions (SSE2) +; opcode parameters assembly range +ADDPD xmmreg,xmmreg \3\x66\x0F\x58 WILLAMETTE,SSE2 +ADDPD mem,xmmreg \3\x66\x0F\x58 WILLAMETTE,SSE2 +ADDSD xmmreg,xmmreg \3\xF2\x0F\x58 WILLAMETTE,SSE2 +ADDSD mem,xmmreg \3\xF2\x0F\x58 WILLAMETTE,SSE2 +ANDNPD xmmreg,xmmreg \3\x66\x0F\x54 WILLAMETTE,SSE2 +ANDNPD mem,xmmreg \3\x66\x0F\x54 WILLAMETTE,SSE2 +ANDDPD xmmreg,xmmreg \3\x66\x0F\x55 WILLAMETTE,SSE2 +ANDDPD mem,xmmreg \3\x66\x0F\x55 WILLAMETTE,SSE2 +CMPPD xmmreg,xmmreg,imm8 \3\x66\x0F\xC2 WILLAMETTE,SSE2 +CMPPD mem,xmmreg,imm8 \3\x66\x0F\xC2 WILLAMETTE,SSE2 +CMPSD xmmreg,xmmreg,imm8 \1\xA7 WILLAMETTE,SSE2 +CMPSD mem,xmmreg,imm8 \1\xA7 WILLAMETTE,SSE2 +COMISD xmmreg,xmmreg \3\x66\x0F\x2F WILLAMETTE,SSE2 +COMISD mem,xmmreg \3\x66\x0F\x2F WILLAMETTE,SSE2 +CVTPI2PD mmxreg,xmmreg \3\x66\x0F\x2A WILLAMETTE,SSE2 +CVTPI2PD mem,xmmreg \3\x66\x0F\x2A WILLAMETTE,SSE2 +CVTPD2PI xmmreg,mmxreg \3\x66\x0F\x2C WILLAMETTE,SSE2 +CVTPD2PI mem,mmxreg \3\x66\x0F\x2C WILLAMETTE,SSE2 +CVTSI2SD reg32,xmmreg \3\xF2\x0F\x2A WILLAMETTE,SSE2 +CVTSI2SD mem,xmmreg \3\xF2\x0F\x2A WILLAMETTE,SSE2 +CVTSD2SI xmmreg,reg32 \3\xF2\x0F\x2D WILLAMETTE,SSE2 +CVTSD2SI mem,reg32 \3\xF2\x0F\x2D WILLAMETTE,SSE2 +CVTPD2PS xmmreg,xmmreg \2\x0F\x2A WILLAMETTE,SSE2 +CVTPD2PS mem,xmmreg \2\x0F\x2A WILLAMETTE,SSE2 +CVTPS2PD xmmreg,xmmreg \2\x0F\x5A WILLAMETTE,SSE2 +CVTPS2PD mem,xmmreg \2\x0F\x5A WILLAMETTE,SSE2 +CVTSD2SS xmmreg,xmmreg \3\xF2\x0F\x5A WILLAMETTE,SSE2 +CVTSD2SS mem,xmmreg \3\xF2\x0F\x5A WILLAMETTE,SSE2 +CVTSS2SD xmmreg,xmmreg \3\xF3\x0F\x5A WILLAMETTE,SSE2 +CVTSS2SD mem,xmmreg \3\xF3\x0F\x5A WILLAMETTE,SSE2 +CVTPD2DQ xmmreg,xmmreg \3\xF2\x0F\xE6 WILLAMETTE,SSE2 +CVTPD2DQ mem,xmmreg \3\xF2\x0F\xE6 WILLAMETTE,SSE2 +CVTDQ2PD xmmreg,xmmreg \3\xF3\x0F\xE6 WILLAMETTE,SSE2 +CVTDQ2PD mem,xmmreg \3\xF3\x0F\xE6 WILLAMETTE,SSE2 +CVTDQ2PS xmmreg,xmmreg \2\x0F\x5B WILLAMETTE,SSE2 +CVTDQ2PS mem,xmmreg \2\x0F\x5B WILLAMETTE,SSE2 +CVTPS2DQ xmmreg,xmmreg \3\x66\x0F\x5B WILLAMETTE,SSE2 +CVTPS2DQ mem,xmmreg \3\x66\x0F\x5B WILLAMETTE,SSE2 +CVTTPD2PI mmxreg,xmmreg \3\x66\x0F\x2C WILLAMETTE,SSE2 +CVTTPD2PI mem,xmmreg \3\x66\x0F\x2C WILLAMETTE,SSE2 +CVTTPD2DQ mmxreg,xmmreg \3\x66\x0F\xE6 WILLAMETTE,SSE2 +CVTTPD2DQ mem,xmmreg \3\x66\x0F\xE6 WILLAMETTE,SSE2 +CVTTPS2DQ mmxreg,xmmreg \3\xF3\x0F\x5B WILLAMETTE,SSE2 +CVTTPS2DQ mem,xmmreg \3\xF3\x0F\x5B WILLAMETTE,SSE2 +CVTTPS2PI mmxreg,xmmreg \3\x0F\x2C WILLAMETTE,SSE2 +CVTTPS2PI mem,xmmreg \3\x0F\x2C WILLAMETTE,SSE2 +CVTTSD2SI mmxreg,xmmreg \3\xF2\x0F\x2C WILLAMETTE,SSE2 +CVTTSD2SI mem,xmmreg \3\xF2\x0F\x2C WILLAMETTE,SSE2 +CVTTSS2SI mmxreg,xmmreg \3\xF3\x0F\x2C WILLAMETTE,SSE2 +CVTTSS2SI mem,xmmreg \3\xF3\x0F\x2C WILLAMETTE,SSE2 +DIVPD xmmreg,xmmreg \3\x66\x0F\x5E WILLAMETTE,SSE2 +DIVPD mem,xmmreg \3\x66\x0F\x5E WILLAMETTE,SSE2 +DIVSD xmmreg,xmmreg \3\xF2\x0F\x5E WILLAMETTE,SSE2 +DIVSD mem,xmmreg \3\xF2\x0F\x5E WILLAMETTE,SSE2 +MAXPD xmmreg,xmmreg \3\x66\x0F\x5F WILLAMETTE,SSE2 +MAXPD mem,xmmreg \3\x66\x0F\x5F WILLAMETTE,SSE2 +MAXSD xmmreg,xmmreg \3\xF2\x0F\x5F WILLAMETTE,SSE2 +MAXSD mem,xmmreg \3\xF2\x0F\x5F WILLAMETTE,SSE2 +MINPD xmmreg,xmmreg \3\x66\x0F\x5D WILLAMETTE,SSE2 +MINPD mem,xmmreg \3\x66\x0F\x5D WILLAMETTE,SSE2 +MINSD xmmreg,xmmreg \3\xF2\x0F\x5D WILLAMETTE,SSE2 +MINSD mem,xmmreg \3\xF2\x0F\x5D WILLAMETTE,SSE2 +MOVAPD xmmreg,xmmreg \3\x66\x0F\x28 WILLAMETTE,SSE2 +MOVAPD xmmreg,xmmreg \3\x66\x0F\x29 WILLAMETTE,SSE2 +MOVAPD mem,xmmreg \3\x66\x0F\x29 WILLAMETTE,SSE2 +MOVAPD xmmreg,mem \3\x66\x0F\x28 WILLAMETTE,SSE2 +MOVHPD mem,xmmreg \3\x66\x0F\x17 WILLAMETTE,SSE2 +MOVHPD xmmreg,xmmreg \3\x66\x0F\x16 WILLAMETTE,SSE2 +MOVLPD mem,xmmreg \3\x66\x0F\x13 WILLAMETTE,SSE2 +MOVLPD xmmreg,xmmreg \3\x66\x0F\x12 WILLAMETTE,SSE2 +MOVMSKPD xmmreg,reg32 \3\x66\x0F\x50 WILLAMETTE,SSE2 +MOVSD xmmreg,xmmreg \3\xF2\x0F\x10 WILLAMETTE,SSE2 +MOVSD xmmreg,xmmreg \3\xF2\x0F\x11 WILLAMETTE,SSE2 +MOVSD mem,xmmreg \3\xF2\x0F\x11 WILLAMETTE,SSE2 +MOVSD xmmreg,mem \3\xF2\x0F\x10 WILLAMETTE,SSE2 +MOVUPD xmmreg,xmmreg \3\x66\x0F\x10 WILLAMETTE,SSE2 +MOVUPD xmmreg,xmmreg \3\x66\x0F\x11 WILLAMETTE,SSE2 +MOVUPD mem,xmmreg \3\x66\x0F\x11 WILLAMETTE,SSE2 +MOVUPD xmmreg,mem \3\x66\x0F\x10 WILLAMETTE,SSE2 +MULPD xmmreg,xmmreg \3\x66\x0F\x59 WILLAMETTE,SSE2 +MULPD mem,xmmreg \3\x66\x0F\x59 WILLAMETTE,SSE2 +MULSD xmmreg,xmmreg \3\xF2\x0F\x59 WILLAMETTE,SSE2 +MULSD mem,xmmreg \3\xF2\x0F\x59 WILLAMETTE,SSE2 +ORPD mem,xmmreg \3\x66\x0F\x56 WILLAMETTE,SSE2 +ORPD xmmreg,xmmreg,imm8 \3\x66\x0F\x56 WILLAMETTE,SSE2 +SHUFPD xmmreg,xmmreg,imm8 \3\x66\x0F\xC6 WILLAMETTE,SSE2 +SHUFPD mem,xmmreg \3\x66\x0F\xC6 WILLAMETTE,SSE2 +SQRTPD xmmreg,xmmreg \3\x66\x0F\x51 WILLAMETTE,SSE2 +SQRTPD mem,xmmreg \3\x66\x0F\x51 WILLAMETTE,SSE2 +SQRTSD xmmreg,xmmreg \3\xF2\x0F\x51 WILLAMETTE,SSE2 +SQRTSD mem,xmmreg \3\xF2\x0F\x51 WILLAMETTE,SSE2 +SUBPD xmmreg,xmmreg \3\x66\x0F\x5C WILLAMETTE,SSE2 +SUBPD mem,xmmreg \3\x66\x0F\x5C WILLAMETTE,SSE2 +SUBSD xmmreg,xmmreg \3\xF2\x0F\x5C WILLAMETTE,SSE2 +SUBSD mem,xmmreg \3\xF2\x0F\x5C WILLAMETTE,SSE2 +UCOMISD xmmreg,xmmreg \3\x66\x0F\x2E WILLAMETTE,SSE2 +UCOMISD mem,xmmreg \3\x66\x0F\x2E WILLAMETTE,SSE2 +UNPCKHPD xmmreg,xmmreg \3\x66\x0F\x15 WILLAMETTE,SSE2 +UNPCKHPD mem,xmmreg \3\x66\x0F\x15 WILLAMETTE,SSE2 +UNPCKLPD xmmreg,xmmreg \3\x66\x0F\x14 WILLAMETTE,SSE2 +UNPCKLPD mem,xmmreg \3\x66\x0F\x14 WILLAMETTE,SSE2 +XORPD xmmreg,xmmreg \3\x66\x0F\x57 WILLAMETTE,SSE2 +XORPD mem,xmmreg \3\x66\x0F\x57 WILLAMETTE,SSE2 @@ -62,6 +62,7 @@ struct itemplate { #define IF_MMX 0x00004000UL /* it's an MMX instruction */ #define IF_3DNOW 0x00008000UL /* it's a 3DNow! instruction */ #define IF_SSE 0x00010000UL /* it's a SSE (KNI, MMX2) instruction */ +#define IF_SSE2 0x00020000UL /* it's a SSE2 instruction */ #define IF_PMASK 0xFF000000UL /* the mask for processor types */ #define IF_PLEVEL 0x0F000000UL /* the mask for processor instr. level */ /* also the highest possible processor */ @@ -74,6 +75,7 @@ struct itemplate { #define IF_PENT 0x05000000UL /* Pentium instruction */ #define IF_P6 0x06000000UL /* P6 instruction */ #define IF_KATMAI 0x07000000UL /* Katmai instructions */ +#define IF_WILLAMETTE 0x08000000UL /* Willamette instructions */ #define IF_CYRIX 0x10000000UL /* Cyrix-specific instruction */ #define IF_AMD 0x20000000UL /* AMD-specific instruction */ @@ -15,8 +15,24 @@ /* * A local label is one that begins with exactly one period. Things * that begin with _two_ periods are NASM-specific things. + * + * If TASM compatibility is enabled, a local label can also begin with + * @@, so @@local is a TASM compatible local label. Note that we only + * check for the first @ symbol, although TASM requires both. */ +#ifdef TASM_COMPAT +#define islocal(l) \ + (tasm_compatible_mode ? \ + (((l)[0] == '.' || (l)[0] == '@') && (l)[1] != '.') : \ + ((l)[0] == '.' && (l)[1] != '.')) +#define islocalchar(c) \ + (tasm_compatible_mode ? \ + ((c) == '.' || (c) == '@') : \ + ((c) == '.')) +#else #define islocal(l) ((l)[0] == '.' && (l)[1] != '.') +#define islocalchar(c) ((c) == '.') +#endif #define LABEL_BLOCK 32 /* no. of labels/block */ #define LBLK_SIZE (LABEL_BLOCK*sizeof(union label)) @@ -71,6 +87,9 @@ static char *prevlabel; static int initialised = FALSE; +char lprefix[PREFIX_MAX] = {0}; +char lpostfix[PREFIX_MAX] = {0}; + /* * Internal routine: finds the `union label' corresponding to the * given label name. Creates a new one, if it isn't found, and if @@ -160,7 +179,8 @@ void redefine_label (char *label, long segment, long offset, char *special, int is_norm, int isextrn, struct ofmt *ofmt, efunc error) { union label *lptr; - + int exi; + /* 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 @@ -185,18 +205,50 @@ void redefine_label (char *label, long segment, long offset, char *special, error (ERR_PANIC, "can't find label `%s' on pass two", label); if (!islocal(label)) { - if (*label != '.' && lptr->defn.is_norm) + if (!islocalchar(*label) && lptr->defn.is_norm) prevlabel = lptr->defn.label; } global_offset_changed |= (lptr->defn.offset != offset); lptr->defn.offset = offset; + +if (pass0 == 1) { + exi = !!(lptr->defn.is_global & GLOBAL_BIT); + if (exi) + { + char *xsymbol; + int slen; + slen = strlen(lprefix); + slen += strlen(lptr->defn.label); + slen += strlen(lpostfix); + slen++; /* room for that null char */ + xsymbol = nasm_malloc(slen); + sprintf(xsymbol,"%s%s%s",lprefix,lptr->defn.label,lpostfix); + + ofmt->symdef (xsymbol, segment, offset, exi, + special ? special : lptr->defn.special); + ofmt->current_dfmt->debug_deflabel (xsymbol, segment, offset, exi, + special ? special : lptr->defn.special); +/** nasm_free(xsymbol); ! outobj.c stores the pointer; ouch!!! **/ + } + else + { + if ( (lptr->defn.is_global & (GLOBAL_BIT|EXTERN_BIT)) != EXTERN_BIT ) { + ofmt->symdef (lptr->defn.label, segment, offset, exi, + special ? special : lptr->defn.special); + ofmt->current_dfmt->debug_deflabel (label, segment, offset, exi, + special ? special : lptr->defn.special); + } + } +} /* if (pass0 == 1) */ + } void define_label (char *label, long segment, long offset, char *special, int is_norm, int isextrn, struct ofmt *ofmt, efunc error) { union label *lptr; + int exi; #ifdef DEBUG #if DEBUG<3 @@ -212,26 +264,48 @@ void define_label (char *label, long segment, long offset, char *special, } lptr->defn.is_global |= DEFINED_BIT; if (isextrn) - lptr->defn.is_global |= EXTERN_BIT; + lptr->defn.is_global |= EXTERN_BIT; - if (label[0] != '.' && is_norm) /* not local, but not special either */ - prevlabel = lptr->defn.label; - else if (label[0] == '.' && label[1] != '.' && !*prevlabel) - error(ERR_NONFATAL, "attempt to define a local label before any" - " non-local labels"); + if (!islocalchar(label[0]) && is_norm) /* not local, but not special either */ + prevlabel = lptr->defn.label; + else if (islocal(label) && !*prevlabel) { + error(ERR_NONFATAL, "attempt to define a local label before any" + " non-local labels"); + } lptr->defn.segment = segment; lptr->defn.offset = offset; - lptr->defn.is_norm = (label[0] != '.' && is_norm); - - if ( (lptr->defn.is_global & (GLOBAL_BIT|EXTERN_BIT)) != EXTERN_BIT ) { - ofmt->symdef (lptr->defn.label, segment, offset, - !!(lptr->defn.is_global & GLOBAL_BIT), - special ? special : lptr->defn.special); - ofmt->current_dfmt->debug_deflabel (label, segment, offset, - !!(lptr->defn.is_global & GLOBAL_BIT), - special ? special : lptr->defn.special); + lptr->defn.is_norm = (!islocalchar(label[0]) && is_norm); + +if (pass0 == 1 || (!is_norm && !isextrn && (segment&1))) { + exi = !!(lptr->defn.is_global & GLOBAL_BIT); + if (exi) + { + char *xsymbol; + int slen; + slen = strlen(lprefix); + slen += strlen(lptr->defn.label); + slen += strlen(lpostfix); + slen++; /* room for that null char */ + xsymbol = nasm_malloc(slen); + sprintf(xsymbol,"%s%s%s",lprefix,lptr->defn.label,lpostfix); + + ofmt->symdef (xsymbol, segment, offset, exi, + special ? special : lptr->defn.special); + ofmt->current_dfmt->debug_deflabel (xsymbol, segment, offset, exi, + special ? special : lptr->defn.special); +/** nasm_free(xsymbol); ! outobj.c stores the pointer; ouch!!! **/ + } + else + { + if ( (lptr->defn.is_global & (GLOBAL_BIT|EXTERN_BIT)) != EXTERN_BIT ) { + ofmt->symdef (lptr->defn.label, segment, offset, exi, + special ? special : lptr->defn.special); + ofmt->current_dfmt->debug_deflabel (label, segment, offset, exi, + special ? special : lptr->defn.special); + } } +} /* if (pass0 == 1) */ } void define_common (char *label, long segment, long size, char *special, @@ -246,7 +320,7 @@ void define_common (char *label, long segment, long size, char *special, } lptr->defn.is_global |= DEFINED_BIT; - if (label[0] != '.') /* not local, but not special either */ + if (!islocalchar(label[0])) /* not local, but not special either */ prevlabel = lptr->defn.label; else error(ERR_NONFATAL, "attempt to define a local label as a " @@ -6,6 +6,9 @@ * distributed in the NASM archive. */ +extern char lprefix[PREFIX_MAX]; +extern char lpostfix[PREFIX_MAX]; + 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, @@ -124,7 +124,7 @@ static void list_output (long offset, void *data, unsigned long type) { long typ, size; - if (!listp || suppress) + if (!listp || suppress || user_nolist) /* fbk - 9/2/00 */ return; typ = type & OUT_TYPMASK; @@ -201,6 +201,10 @@ static void list_line (int type, char *line) { if (!listp) return; + if (user_nolist){ /* fbk - 9/2/00 */ + listlineno++; + return; + } if (mistack && mistack->inhibiting) { @@ -10,5 +10,6 @@ #define NASM_LISTING_H extern ListGen nasmlist; +extern int user_nolist; /* fbk - 9/1/00 */ #endif @@ -57,12 +57,6 @@ static char *stdmac[] = { "%imacro bits 1+.nolist", "[bits %1]", "%endmacro", - "%imacro use16 0.nolist", - "[bits 16]", - "%endmacro", - "%imacro use32 0.nolist", - "[bits 32]", - "%endmacro", "%imacro global 1-*.nolist", "%rep %0", "[global %1]", @@ -75,8 +69,5 @@ static char *stdmac[] = { "%rotate 1", "%endrep", "%endmacro", - "%imacro cpu 1+.nolist", - "[cpu %1]", - "%endmacro", NULL }; @@ -38,18 +38,21 @@ static void register_output_formats(void); static void usage(void); static int using_debug_info; +#ifdef TASM_COMPAT +int tasm_compatible_mode = FALSE; +#endif static char inname[FILENAME_MAX]; static char outname[FILENAME_MAX]; static char listname[FILENAME_MAX]; static int globallineno; /* for forward-reference tracking */ -static int pass = 0; +/* static int pass = 0; */ static struct ofmt *ofmt = NULL; static FILE *error_file; /* Where to write error messages */ static FILE *ofile = NULL; -static int optimizing = 10; /* number of optimization passes to take */ +static int optimizing = 0; /* number of optimization passes to take */ static int sb, cmd_sb = 16; /* by default */ static unsigned long cmd_cpu = IF_PLEVEL; /* highest level by default */ static unsigned long cpu = IF_PLEVEL; /* passed to insn_size & assemble.c */ @@ -73,8 +76,6 @@ enum op_type { }; static enum op_type operating_mode; -/* used by error function to report location */ - /* * Which of the suppressible warnings are suppressed. Entry zero * doesn't do anything. Initial defaults are given here. @@ -128,6 +129,7 @@ static Preproc no_pp = { static int want_usage; static int terminate_after_phase; +int user_nolist = 0; /* fbk 9/2/00 */ static void nasm_fputs(char *line, FILE *ofile) { @@ -140,6 +142,7 @@ static void nasm_fputs(char *line, FILE *ofile) int main(int argc, char **argv) { + pass0 = 1; want_usage = terminate_after_phase = FALSE; nasm_set_malloc_error (report_error); @@ -184,7 +187,7 @@ int main(int argc, char **argv) if (outname[0] == '\0') ofmt->filename (inname, outname, report_error); ofile = NULL; - printf("%s: %s", outname, inname); + fprintf(stdout, "%s: %s", outname, inname); while ( (line = preproc->getline()) ) nasm_free (line); preproc->cleanup(); @@ -209,7 +212,7 @@ int main(int argc, char **argv) location.known = FALSE; - pass = 1; +/* pass = 1; */ preproc->reset (inname, 2, report_error, evaluate, &nasmlist); while ( (line = preproc->getline()) ) { /* @@ -326,6 +329,22 @@ static char *get_param (char *p, char *q, int *advance) return NULL; } +struct textargs +{ + char *label; + int value; +}; + +#define OPT_PREFIX 0 +#define OPT_POSTFIX 1 +struct textargs textopts[] = +{ + {"prefix",OPT_PREFIX}, + {"postfix",OPT_POSTFIX}, + {NULL,0} +}; + + int stopoptions = 0; static int process_arg (char *p, char *q) { @@ -338,9 +357,6 @@ static int process_arg (char *p, char *q) if (p[0]=='-' && ! stopoptions) { switch (p[1]) { - case '-': /* -- => stop processing options */ - stopoptions = 1; - break; case 's': error_file = stdout; break; @@ -370,7 +386,7 @@ static int process_arg (char *p, char *q) ofmt->current_dfmt = ofmt->debug_formats[0]; } else if (p[1]=='O') { /* Optimization level */ if (!isdigit(*param)) report_error(ERR_FATAL, - "command line optimization level must be 0..3"); + "command line optimization level must be 0..3 or <nn>"); optimizing = atoi(param); if (optimizing <= 0) optimizing = 0; else if (optimizing <= 3) optimizing *= 5; /* 5 passes for each level */ @@ -385,7 +401,7 @@ static int process_arg (char *p, char *q) } else if (p[1]=='l') { /* listing file */ strcpy (listname, param); } else if (p[1]=='E') { /* error messages file */ - error_file = fopen(param, "wt"); + error_file = fopen(param, "w"); if ( !error_file ) { error_file = stderr; /* Revert to default! */ report_error (ERR_FATAL | ERR_NOFILE | ERR_USAGE, @@ -410,6 +426,10 @@ static int process_arg (char *p, char *q) "[-l listfile]\n" " [options...] [--] filename\n" " or nasm -r for version info\n\n" +#ifdef TASM_COMPAT + " -t Assemble in SciTech TASM compatible mode\n" + " -g Generate debug information in selected format.\n" +#endif " -e preprocess only (writes output to stdout by default)\n" " -a don't preprocess (assemble only)\n" " -M generate Makefile dependencies on stdout\n\n" @@ -448,8 +468,17 @@ static int process_arg (char *p, char *q) dfmt_list(ofmt, stdout); exit(0); break; +#ifdef TASM_COMPAT + case 't': + tasm_compatible_mode = TRUE; + break; +#endif case 'r': +#ifdef TASM_COMPAT + printf("NASM version %s - SciTech TASM compatible additions\n", NASM_VER); +#else printf("NASM version %s\n", NASM_VER); +#endif #ifdef DEBUG printf("Compiled with -DDEBUG on " __DATE__ "\n"); #endif @@ -479,6 +508,66 @@ static int process_arg (char *p, char *q) case 'M': operating_mode = op_depend; break; + + case '-': + { + int s; + + if (p[2]==0) { /* -- => stop processing options */ + stopoptions = 1; + break; + } + for(s=0; textopts[s].label; s++) + { + if(!nasm_stricmp(p+2, textopts[s].label)) + { + break; + } + } + + switch(s) + { + + case OPT_PREFIX: + case OPT_POSTFIX: + { + if (!q) + { + report_error (ERR_NONFATAL | ERR_NOFILE | ERR_USAGE, + "option `--%s' requires an argument", + p+2); + break; + } + else + { + advance = 1, param = q; + } + + if(s == OPT_PREFIX) + { + strncpy(lprefix,param,PREFIX_MAX-1); + lprefix[PREFIX_MAX-1]=0; + break; + } + if(s == OPT_POSTFIX) + { + strncpy(lpostfix,param,POSTFIX_MAX-1); + lpostfix[POSTFIX_MAX-1]=0; + break; + } + break; + } + default: + { + report_error (ERR_NONFATAL | ERR_NOFILE | ERR_USAGE, + "unrecognised option `--%s'", + p+2); + break; + } + } + break; + } + default: if (!ofmt->setinfo(GI_SWITCH,&p)) report_error (ERR_NONFATAL | ERR_NOFILE | ERR_USAGE, @@ -562,11 +651,41 @@ static void process_respfile (FILE *rfile) } } +/* Function to process args from a string of args, rather than the + * argv array. Used by the environment variable and response file + * processing. + */ +#ifdef TASM_COMPAT +static void process_args (char *args) { + char *p, *q, *arg, *prevarg; + char separator = ' '; + + p = args; + if (*p && *p != '-') + separator = *p++; + arg = NULL; + while (*p) { + q = p; + while (*p && *p != separator) p++; + while (*p == separator) *p++ = '\0'; + prevarg = arg; + arg = q; + if (process_arg (prevarg, arg)) + arg = NULL; + } + if (arg) + process_arg (arg, NULL); +} +#endif + static void parse_cmdline(int argc, char **argv) { FILE *rfile; - char *envreal, *envcopy=NULL, *p, *q, *arg, *prevarg; + char *envreal, *envcopy=NULL, *p, *arg; +#ifndef TASM_COMPAT + char *q, *prevarg; char separator = ' '; +#endif *inname = *outname = *listname = '\0'; @@ -577,6 +696,9 @@ static void parse_cmdline(int argc, char **argv) arg = NULL; if (envreal) { envcopy = nasm_strdup(envreal); +#ifdef TASM_COMPAT + process_args(envcopy); +#else p = envcopy; if (*p && *p != '-') separator = *p++; @@ -591,6 +713,7 @@ static void parse_cmdline(int argc, char **argv) } if (arg) process_arg (arg, NULL); +#endif nasm_free (envcopy); } @@ -601,6 +724,31 @@ static void parse_cmdline(int argc, char **argv) { int i; argv++; +#ifdef TASM_COMPAT + if (argv[0][0] == '@') { + /* We have a response file, so process this as a set of + * arguments like the environment variable. This allows us + * to have multiple arguments on a single line, which is + * different to the -@resp file processing below for regular + * NASM. + */ + char *str = malloc(2048); + FILE *f = fopen(&argv[0][1],"r"); + if (!str) { + printf("out of memory"); + exit(-1); + } + if (f) { + while (fgets(str,2048,f)) { + process_args(str); + } + fclose(f); + } + free(str); + argc--; + argv++; + } +#endif 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"))) { @@ -629,7 +777,7 @@ static void assemble_file (char *fname) long seg, offs; struct tokenval tokval; expr * e; - int pass_max; + int pass, pass_max; int pass_cnt = 0; /* count actual passes */ if (cmd_sb == 32 && cmd_cpu < IF_386) @@ -637,18 +785,21 @@ static void assemble_file (char *fname) "32-bit segment size requires a higher cpu"); pass_max = optimizing + 2; /* passes 1, optimizing, then 2 */ - for (pass = 1; pass <= pass_max; pass++) { + pass0 = !optimizing; /* start at 1 if not optimizing */ + for (pass = 1; pass <= pass_max && pass0 <= 2; pass++) { int pass1, pass2; ldfunc def_label; pass1 = pass < pass_max ? 1 : 2; /* seq is 1, 1, 1,..., 1, 2 */ pass2 = pass > 1 ? 2 : 1; /* seq is 1, 2, 2,..., 2, 2 */ + /* pass0 seq is 0, 0, 0,..., 1, 2 */ + def_label = pass > 1 ? redefine_label : define_label; sb = cmd_sb; /* set 'bits' to command line default */ cpu = cmd_cpu; - if (pass == pass_max) { + if (pass0 == 2) { if (*listname) nasmlist.init(listname, report_error); } @@ -687,7 +838,8 @@ static void assemble_file (char *fname) } break; case 2: /* [EXTERN label:special] */ - if (pass == pass_max) { + if (*value == '$') value++; /* skip initial $ if present */ + if (pass0 == 2) { q = value; while (*q && *q != ':') q++; @@ -695,9 +847,7 @@ static void assemble_file (char *fname) *q++ = '\0'; ofmt->symdef(value, 0L, 0L, 3, q); } - } else if (pass == 1) { /* pass == 1 */ - if (*value == '$') - value++; /* skip initial $ if present */ + } else if (pass0 == 1) { /* pass == 1 */ q = value; validid = TRUE; if (!isidstart(*q)) @@ -722,13 +872,14 @@ static void assemble_file (char *fname) define_label (value, seg_alloc(), 0L, NULL, FALSE, TRUE, ofmt, report_error); } - } /* else pass == 1 */ + } /* else pass0 == 1 */ break; case 3: /* [BITS bits] */ sb = get_bits(value); break; case 4: /* [GLOBAL symbol:special] */ - if (pass == pass_max) { /* pass 2 */ + if (*value == '$') value++; /* skip initial $ if present */ + if (pass0 == 2) { /* pass 2 */ q = value; while (*q && *q != ':') q++; @@ -736,9 +887,7 @@ static void assemble_file (char *fname) *q++ = '\0'; ofmt->symdef(value, 0L, 0L, 3, q); } - } else if (pass == 1) { /* pass == 1 */ - if (*value == '$') - value++; /* skip initial $ if present */ + } else if (pass2 == 1) { /* pass == 1 */ q = value; validid = TRUE; if (!isidstart(*q)) @@ -762,7 +911,8 @@ static void assemble_file (char *fname) } /* pass == 1 */ break; case 5: /* [COMMON symbol size:special] */ - if (pass == 1) { + if (*value == '$') value++; /* skip initial $ if present */ + if (pass0 == 1) { p = value; validid = TRUE; if (!isidstart(*p)) @@ -800,7 +950,7 @@ static void assemble_file (char *fname) } else report_error (ERR_NONFATAL, "no size specified in" " COMMON declaration"); - } else if (pass == pass_max) { /* pass == 2 */ + } else if (pass0 == 2) { /* pass == 2 */ q = value; while (*q && *q != ':') { if (isspace(*q)) @@ -821,7 +971,7 @@ static void assemble_file (char *fname) NULL); if (e) { if (!is_reloc(e)) - report_error (pass==1 ? ERR_NONFATAL : ERR_PANIC, + report_error (pass0==1 ? ERR_NONFATAL : ERR_PANIC, "cannot use non-relocatable expression as " "ABSOLUTE address"); else { @@ -878,17 +1028,32 @@ static void assemble_file (char *fname) case 9: /* cpu */ cpu = get_cpu (value); break; + case 10: /* fbk 9/2/00 */ /* [LIST {+|-}] */ + while (*value && isspace(*value)) + value++; + + if (*value == '+') { + user_nolist = 0; + } + else { + if (*value == '-') { + user_nolist = 1; + } + else { + report_error (ERR_NONFATAL, "invalid parameter to \"list\" directive"); + } + } + break; default: - if (!ofmt->directive (line+1, value, pass1)) + if (!ofmt->directive (line+1, value, pass2)) report_error (pass1==1 ? ERR_NONFATAL : ERR_PANIC, "unrecognised directive [%s]", line+1); - break; } } else /* it isn't a directive */ { - parse_line (pass2, line, &output_ins, + parse_line (pass1, line, &output_ins, report_error, evaluate, def_label); @@ -1026,33 +1191,38 @@ static void assemble_file (char *fname) } else { /* instruction isn't an EQU */ if (pass1 == 1) { + long l = insn_size (location.segment, offs, sb, cpu, &output_ins, report_error); - if (using_debug_info && output_ins.opcode != -1) { + + /* if (using_debug_info) && output_ins.opcode != -1)*/ + if (using_debug_info); /* fbk 12/29/00 */ + + { /* 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; + 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; + 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; + 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; + 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; + 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; + typeinfo |= TY_WORD; + break; case I_DD: if (output_ins.eops_float) typeinfo |= TY_FLOAT; @@ -1062,13 +1232,16 @@ static void assemble_file (char *fname) case I_DQ: typeinfo |= TY_QWORD; break; - case I_DT: + case I_DT: typeinfo |= TY_TBYTE; break; default: typeinfo = TY_LABEL; + } + ofmt->current_dfmt->debug_typevalue(typeinfo); + } if (l != -1) { offs += l; @@ -1104,13 +1277,17 @@ static void assemble_file (char *fname) usage(); exit (1); } - pass_cnt++; - if (pass>1 && !global_offset_changed && pass<pass_max) pass = pass_max-1; + pass_cnt++; + if (pass>1 && !global_offset_changed) { + pass0++; + if (pass0==2) pass = pass_max - 1; + } else if (!optimizing) pass0++; + } /* for (pass=1; pass<=2; pass++) */ nasmlist.cleanup(); #if 1 - if (optimizing) + if (optimizing && using_debug_info) /* -On and -g switches */ fprintf(error_file, "info:: assembly required 1+%d+1 passes\n", pass_cnt-2); #endif @@ -1175,6 +1352,8 @@ static int getkw (char *buf, char **value) return 8; if (!nasm_stricmp(p, "cpu")) return 9; + if (!nasm_stricmp(p, "list")) /* fbk 9/2/00 */ + return 10; return -1; } @@ -1193,7 +1372,7 @@ static void report_error (int severity, char *fmt, ...) /* * See if it's a pass-one only warning and we're not in pass one. */ - if ((severity & ERR_PASS1) && pass != 1) + if ((severity & ERR_PASS1) && pass0 == 2) return; if (severity & ERR_NOFILE) @@ -1363,7 +1542,7 @@ static unsigned long get_cpu (char *value) if (!nasm_stricmp(value, "p3") || !nasm_stricmp(value, "katmai") ) return IF_KATMAI; - report_error (pass ? ERR_NONFATAL : ERR_FATAL, "unknown 'cpu' type"); + report_error (pass0<2 ? ERR_NONFATAL : ERR_FATAL, "unknown 'cpu' type"); return IF_PLEVEL; /* the maximum level */ } @@ -1381,7 +1560,7 @@ static int get_bits (char *value) i = 16; } } else { - report_error(pass ? ERR_NONFATAL : ERR_FATAL, + report_error(pass0<2 ? ERR_NONFATAL : ERR_FATAL, "`%s' is not a valid segment size; must be 16 or 32", value); i = 16; @@ -13,7 +13,7 @@ #define NASM_MAJOR_VER 0 #define NASM_MINOR_VER 98 -#define NASM_VER "0.98.03" +#define NASM_VER "0.98.08" #ifndef NULL #define NULL 0 @@ -33,6 +33,16 @@ #define FILENAME_MAX 256 #endif +#ifndef PREFIX_MAX +#define PREFIX_MAX 10 +#endif + +#ifndef POSTFIX_MAX +#define POSTFIX_MAX 10 +#endif + + + /* * Name pollution problems: <time.h> on Digital UNIX pulls in some * strange hardware header file which sees fit to define R_SP. We @@ -78,13 +88,15 @@ typedef void (*efunc) (int severity, char *fmt, ...); /* * These codes define specific types of suppressible warning. */ + +#define ERR_WARN_MASK 0x0000FF00 /* the mask for this feature */ +#define ERR_WARN_SHR 8 /* how far to shift right */ + #define ERR_WARN_MNP 0x00000100 /* macro-num-parameters warning */ #define ERR_WARN_MSR 0x00000200 /* macro self-reference */ #define ERR_WARN_OL 0x00000300 /* orphan label (no colon, and * alone on line) */ #define ERR_WARN_NOV 0x00000400 /* numeric overflow */ -#define ERR_WARN_MASK 0x0000FF00 /* the mask for this feature */ -#define ERR_WARN_SHR 8 /* how far to shift right */ #define ERR_WARN_MAX 4 /* the highest numbered one */ /* @@ -844,4 +856,18 @@ struct dfmt { #define elements(x) ( sizeof(x) / sizeof(*(x)) ) +#ifdef TASM_COMPAT +extern int tasm_compatible_mode; +#endif + +/* + * This declaration passes the "pass" number to all other modules + * "pass0" assumes the values: 0, 0, ..., 0, 1, 2 + * where 0 = optimizing pass + * 1 = pass 1 + * 2 = pass 2 + */ + +int pass0; /* this is globally known */ + #endif @@ -341,6 +341,7 @@ static void aout_deflabel (char *name, long segment, long offset, struct tokenval tokval; expr *e; int fwd = FALSE; + char *saveme=stdscan_bufptr; /* bugfix? fbk 8/10/00 */ if (!bsd) { error(ERR_NONFATAL, "Linux a.out does not support" @@ -369,6 +370,7 @@ static void aout_deflabel (char *name, long segment, long offset, sym->size = reloc_value(e); } } + stdscan_bufptr=saveme; /* bugfix? fbk 8/10/00 */ } special_used = TRUE; } @@ -346,6 +346,10 @@ static void elf_deflabel (char *name, long segment, long offset, struct Symbol *sym; int special_used = FALSE; +#if defined(DEBUG) && DEBUG>2 +fprintf(stderr, " elf_deflabel: %s, seg=%ld, off=%ld, is_global=%d, %s\n", + name, segment, offset, is_global, special); +#endif if (name[0] == '.' && name[1] == '.' && name[2] != '@') { /* * This is a NASM special symbol. We never allow it into @@ -496,6 +500,7 @@ static void elf_deflabel (char *name, long segment, long offset, struct tokenval tokval; expr *e; int fwd = FALSE; + char *saveme=stdscan_bufptr; /* bugfix? fbk 8/10/00 */ while (special[n] && isspace(special[n])) n++; @@ -518,6 +523,7 @@ static void elf_deflabel (char *name, long segment, long offset, else sym->size = reloc_value(e); } + stdscan_bufptr=saveme; /* bugfix? fbk 8/10/00 */ } special_used = TRUE; } @@ -105,7 +105,8 @@ enum RecordID { /* record ID codes */ FIXUPP = 0x9C, /* fixups (relocations) */ FIXU32 = 0x9D, /* 32-bit fixups (relocations) */ - MODEND = 0x8A /* module end */ + MODEND = 0x8A, /* module end */ + MODE32 = 0x8B /* module end for 32-bit objects */ }; enum ComentID { /* ID codes for comment records */ @@ -142,6 +143,7 @@ static void ori_null(ObjRecord *orp); static ObjRecord *obj_commit(ObjRecord *orp); static int obj_uppercase; /* Flag: all names in uppercase */ +static int obj_use32; /* Flag: at least one segment is 32-bit */ /* * Clear an ObjRecord structure. (Never reallocates). @@ -590,6 +592,9 @@ static long obj_entry_seg, obj_entry_ofs; struct ofmt of_obj; +/* The current segment */ +static struct Segment *current_seg; + static long obj_segment (char *, int, int *); static void obj_write_file(int debuginfo); static int obj_directive (char *, char *, int); @@ -620,7 +625,9 @@ static void obj_init (FILE *fp, efunc errfunc, ldfunc ldef, evalfunc eval) grptail = &grphead; obj_entry_seg = NO_SEG; obj_uppercase = FALSE; + obj_use32 = FALSE; passtwo = 0; + current_seg = NULL; of_obj.current_dfmt->init (&of_obj,NULL,fp,errfunc); } @@ -740,6 +747,11 @@ static void obj_deflabel (char *name, long segment, int i; int used_special = FALSE; /* have we used the special text? */ +#if defined(DEBUG) && DEBUG>2 +fprintf(stderr, " obj_deflabel: %s, seg=%ld, off=%ld, is_global=%d, %s\n", + name, segment, offset, is_global, special); +#endif + /* * If it's a special-retry from pass two, discard it. */ @@ -829,7 +841,17 @@ static void obj_deflabel (char *name, long segment, ext->next = NULL; exttail = &ext->next; ext->name = name; + /* Place by default all externs into the current segment */ ext->defwrt_type = DEFWRT_NONE; + if (current_seg) { + if (current_seg->grp) { + ext->defwrt_type = DEFWRT_GROUP; + ext->defwrt_ptr.grp = current_seg->grp; + } else { + ext->defwrt_type = DEFWRT_SEGMENT; + ext->defwrt_ptr.seg = current_seg; + } + } if (is_global == 2) { ext->commonsize = offset; ext->commonelem = 1; /* default FAR */ @@ -1088,7 +1110,7 @@ static void obj_write_fixup (ObjRecord *orp, int bytes, if (segto->use32) forp->type = FIXU32; else - forp->type = FIXUPP; + forp->type = FIXUPP; } if (seg % 2) { @@ -1224,8 +1246,13 @@ static long obj_segment (char *name, int pass, int *bits) * using the pointer it gets passed. That way we save memory, * by sponging off the label manager. */ +#if defined(DEBUG) && DEBUG>=3 +fprintf(stderr," obj_segment: < %s >, pass=%d, *bits=%d\n", + name, pass, *bits); +#endif if (!name) { *bits = 16; + current_seg = NULL; return first_seg; } else { struct Segment *seg; @@ -1271,6 +1298,7 @@ static long obj_segment (char *name, int pass, int *bits) *bits = 32; else *bits = 16; + current_seg = seg; return seg->index; } } @@ -1398,6 +1426,9 @@ static long obj_segment (char *name, int pass, int *bits) } } + /* We need to know whenever we have at least one 32-bit segment */ + obj_use32 |= seg->use32; + obj_seg_needs_update = seg; if (seg->align >= SEG_ABS) deflabel (name, NO_SEG, seg->align - SEG_ABS, @@ -1447,6 +1478,7 @@ static long obj_segment (char *name, int pass, int *bits) *bits = 32; else *bits = 16; + current_seg = seg; return seg->index; } } @@ -2178,7 +2210,7 @@ static void obj_write_file (int debuginfo) } } if (orp->used) - obj_emit (orp); + obj_emit (orp); /* * Write the LEDATA/FIXUPP pairs. @@ -2191,9 +2223,10 @@ static void obj_write_file (int debuginfo) /* * Write the MODEND module end marker. */ - orp->type = MODEND; + orp->type = obj_use32 ? MODE32 : MODEND; orp->ori = ori_null; if (entry_seg_ptr) { + orp->type = entry_seg_ptr->use32 ? MODE32 : MODEND; obj_byte (orp, 0xC1); seg = entry_seg_ptr; if (seg->grp) { @@ -2324,7 +2357,8 @@ static void dbgbi_linnum (const char *lnfname, long lineno, long segto) if (!seg) error (ERR_PANIC, "lineno directed to nonexistent segment?"); - for (fn = fnhead; fn; fn = fnhead->next) +/* for (fn = fnhead; fn; fn = fnhead->next) */ + for (fn = fnhead; fn; fn = fn->next) /* fbk - Austin Lunnen - John Fine*/ if (!nasm_stricmp(lnfname,fn->name)) break; if (!fn) { @@ -74,18 +74,18 @@ struct ExportRec { 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 */ + byte reclen; /* equals 4 */ long amount; /* number of bytes BSS to reserve */ }; +struct DLLModRec { + byte type; /* 4 for DLLRec, 8 for ModRec */ + byte reclen; /* 1+lib name length for DLLRec, 1+mod name length */ + char name[128]; /* library to link at load time or module name */ +}; + #define COUNT_SEGTYPES 9 static char * segmenttypes[COUNT_SEGTYPES] = { @@ -321,11 +321,14 @@ static void write_bss_rec(struct BSSRec *r) headerlength += r->reclen + 2; } -static void write_dll_rec(struct DLLRec *r) +/* + * Write library record. Also used for module name records. + */ +static void write_dllmod_rec(struct DLLModRec *r) { saa_wbytes(header,&r->type,1); saa_wbytes(header,&r->reclen,1); - saa_wbytes(header,r->libname,strlen(r->libname) + 1); + saa_wbytes(header,r->name,strlen(r->name) + 1); headerlength += r->reclen + 2; } @@ -334,12 +337,11 @@ static void rdf2_deflabel(char *name, long segment, long offset, { struct ExportRec r; struct ImportRec ri; -#ifdef VERBOSE_WARNINGS - static int warned_common = 0; -#endif static int farsym = 0; static int i; + if (is_global != 1) return; + if (special) { while(*special == ' ' || *special == '\t') special++; @@ -358,16 +360,6 @@ static void rdf2_deflabel(char *name, long segment, long offset, 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; } @@ -635,13 +627,24 @@ static long rdf2_segbase (long segment) { } static int rdf2_directive (char *directive, char *value, int pass) { - struct DLLRec r; - + struct DLLModRec r; + if (! strcmp(directive, "library")) { if (pass == 1) { r.type = 4; - strcpy(r.libname, value); - write_dll_rec(&r); + r.reclen=strlen(value)+1; + strcpy(r.name, value); + write_dllmod_rec(&r); + } + return 1; + } + + if (! strcmp(directive, "module")) { + if (pass == 1) { + r.type = 8; + r.reclen=strlen(value)+1; + strcpy(r.name, value); + write_dllmod_rec(&r); } return 1; } @@ -658,6 +661,9 @@ static char *rdf2_stdmac[] = { "%imacro library 1+.nolist", "[library %1]", "%endmacro", + "%imacro module 1+.nolist", + "[module %1]", + "%endmacro", "%macro __NASM_CDecl__ 1", "%endmacro", NULL @@ -421,28 +421,68 @@ insn *parse_line (int pass, char *buffer, insn *result, if (i == '[' || i == '&') { /* memory reference */ mref = TRUE; bracket = (i == '['); - i = stdscan(NULL, &tokval); + i = stdscan(NULL, &tokval); if (i == TOKEN_SPECIAL) { /* check for address size override */ - switch ((int)tokval.t_integer) { - case S_NOSPLIT: - result->oprs[operand].eaflags |= EAF_TIMESTWO; - break; - case S_BYTE: - result->oprs[operand].eaflags |= EAF_BYTEOFFS; - break; - case S_WORD: - result->oprs[operand].addr_size = 16; - result->oprs[operand].eaflags |= EAF_WORDOFFS; - break; - case S_DWORD: - case S_LONG: - result->oprs[operand].addr_size = 32; - result->oprs[operand].eaflags |= EAF_WORDOFFS; - break; - default: - error (ERR_NONFATAL, "invalid size specification in" - " effective address"); +#ifdef TASM_COMPAT + if (tasm_compatible_mode) { + switch ((int)tokval.t_integer) { + /* For TASM compatibility a size override inside the + * brackets changes the size of the operand, not the + * address type of the operand as it does in standard + * NASM syntax. Hence: + * + * mov eax,[DWORD val] + * + * is valid syntax in TASM compatibility mode. Note that + * you lose the ability to override the default address + * type for the instruction, but we never use anything + * but 32-bit flat model addressing in our code. + */ + case S_BYTE: + result->oprs[operand].type |= BITS8; + break; + case S_WORD: + result->oprs[operand].type |= BITS16; + break; + case S_DWORD: + case S_LONG: + result->oprs[operand].type |= BITS32; + break; + case S_QWORD: + result->oprs[operand].type |= BITS64; + break; + case S_TWORD: + result->oprs[operand].type |= BITS80; + break; + default: + error (ERR_NONFATAL, "invalid operand size specification"); + } + } else { +#endif + /* Standard NASM compatible syntax */ + switch ((int)tokval.t_integer) { + case S_NOSPLIT: + result->oprs[operand].eaflags |= EAF_TIMESTWO; + break; + case S_BYTE: + result->oprs[operand].eaflags |= EAF_BYTEOFFS; + break; + case S_WORD: + result->oprs[operand].addr_size = 16; + result->oprs[operand].eaflags |= EAF_WORDOFFS; + break; + case S_DWORD: + case S_LONG: + result->oprs[operand].addr_size = 32; + result->oprs[operand].eaflags |= EAF_WORDOFFS; + break; + default: + error (ERR_NONFATAL, "invalid size specification in" + " effective address"); + } +#ifdef TASM_COMPAT } +#endif i = stdscan(NULL, &tokval); } } else { /* immediate operand, or register */ @@ -262,6 +262,9 @@ static int inverse_ccs[] = { * Directive names. */ static char *directives[] = { +#ifdef TASM_COMPAT + "%arg", +#endif "%assign", "%clear", "%define", "%elif", "%elifctx", "%elifdef", "%elifid", "%elifidn", "%elifidni", "%elifnctx", "%elifndef", "%elifnid", "%elifnidn", "%elifnidni", "%elifnnum", "%elifnstr", @@ -269,11 +272,21 @@ static char *directives[] = { "%endrep", "%error", "%exitrep", "%iassign", "%idefine", "%if", "%ifctx", "%ifdef", "%ifid", "%ifidn", "%ifidni", "%ifnctx", "%ifndef", "%ifnid", "%ifnidn", "%ifnidni", "%ifnnum", - "%ifnstr", "%ifnum", "%ifstr", "%imacro", "%include", "%ixdefine", - "%line", "%macro", "%pop", "%push", "%rep", "%repl", "%rotate", - "%undef", "%xdefine" + "%ifnstr", "%ifnum", "%ifstr", "%imacro", "%include", + "%ixdefine", "%line", +#ifdef TASM_COMPAT + "%local", +#endif + "%macro", "%pop", "%push", "%rep", "%repl", "%rotate", +#ifdef TASM_COMPAT + "%stacksize", +#endif + "%strlen", "%substr", "%undef", "%xdefine" }; enum { +#ifdef TASM_COMPAT + PP_ARG, +#endif PP_ASSIGN, PP_CLEAR, PP_DEFINE, PP_ELIF, PP_ELIFCTX, PP_ELIFDEF, PP_ELIFID, PP_ELIFIDN, PP_ELIFIDNI, PP_ELIFNCTX, PP_ELIFNDEF, PP_ELIFNID, PP_ELIFNIDN, PP_ELIFNIDNI, PP_ELIFNNUM, PP_ELIFNSTR, @@ -281,11 +294,46 @@ enum { PP_ENDREP, PP_ERROR, PP_EXITREP, PP_IASSIGN, PP_IDEFINE, PP_IF, PP_IFCTX, PP_IFDEF, PP_IFID, PP_IFIDN, PP_IFIDNI, PP_IFNCTX, PP_IFNDEF, PP_IFNID, PP_IFNIDN, PP_IFNIDNI, PP_IFNNUM, - PP_IFNSTR, PP_IFNUM, PP_IFSTR, PP_IMACRO, PP_INCLUDE, PP_IXDEFINE, - PP_LINE, PP_MACRO, PP_POP, PP_PUSH, PP_REP, PP_REPL, PP_ROTATE, - PP_UNDEF, PP_XDEFINE + PP_IFNSTR, PP_IFNUM, PP_IFSTR, PP_IMACRO, PP_INCLUDE, + PP_IXDEFINE, PP_LINE, +#ifdef TASM_COMPAT + PP_LOCAL, +#endif + PP_MACRO, PP_POP, PP_PUSH, PP_REP, PP_REPL, PP_ROTATE, +#ifdef TASM_COMPAT + PP_STACKSIZE, +#endif + PP_STRLEN, PP_SUBSTR, PP_UNDEF, PP_XDEFINE }; +#ifdef TASM_COMPAT + +/* For TASM compatibility we need to be able to recognise TASM compatible + * conditional compilation directives. Using the NASM pre-processor does + * not work, so we look for them specifically from the following list and + * then jam in the equivalent NASM directive into the input stream. + */ + +#ifndef MAX +# define MAX(a,b) ( ((a) > (b)) ? (a) : (b)) +#endif + +enum { + TM_ARG, TM_ELIF, TM_ELSE, TM_ENDIF, TM_IF, TM_IFDEF, TM_IFDIFI, + TM_IFNDEF, TM_INCLUDE, TM_LOCAL +}; + +static char *tasm_directives[] = { + "arg", "elif", "else", "endif", "if", "ifdef", "ifdifi", + "ifndef", "include", "local" +}; + +static int StackSize = 4; +static char *StackPointer = "ebp"; +static int ArgOffset = 8; +static int LocalOffset = 4; + +#endif static Context *cstk; static Include *istk; @@ -351,7 +399,7 @@ static Token *expand_mmac_params (Token *tline); static Token *expand_smacro (Token *tline); static Token *expand_id (Token *tline); static Context *get_ctx (char *name, int all_contexts); -static void make_tok_num(Token *tok, long val); +static void make_tok_num(Token *tok, long val); static void error (int severity, char *fmt, ...); /* @@ -362,13 +410,72 @@ static void error (int severity, char *fmt, ...); #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)))) +#ifdef TASM_COMPAT +/* Handle TASM specific directives, which do not contain a % in + * front of them. We do it here because I could not find any other + * place to do it for the moment, and it is a hack (ideally it would + * be nice to be able to use the NASM pre-processor to do it). + */ +static char *check_tasm_directive(char *line) +{ + int i, j, k, m, len; + char *p = line, *oldline, oldchar; + + /* Skip whitespace */ + while (isspace(*p) && *p != 0) + p++; + + /* Binary search for the directive name */ + i = -1; + j = sizeof(tasm_directives) / sizeof(*tasm_directives); + len = 0; + while (!isspace(p [len]) && p [len] != 0) + len++; + if (len) { + oldchar = p [len]; + p [len] = 0; + while (j - i > 1) { + k = (j + i) / 2; + m = nasm_stricmp(p, tasm_directives [k]); + if (m == 0) { + /* We have found a directive, so jam a % in front of it + * so that NASM will then recognise it as one if it's own. + */ + p [len] = oldchar; + len = strlen(p); + oldline = line; + line = nasm_malloc(len + 2); + line [0] = '%'; + if (k == TM_IFDIFI) { + /* NASM does not recognise IFDIFI, so we convert it to + * %ifdef BOGUS. This is not used in NASM comaptible + * code, but does need to parse for the TASM macro + * package. + */ + strcpy(line + 1,"ifdef BOGUS"); + } else { + memcpy(line + 1, p, len + 1); + } + nasm_free(oldline); + return line; + } else if (m < 0) { + j = k; + } else + i = k; + } + p [len] = oldchar; + } + return line; +} +#endif + /* * The pre-preprocessing stage... This function translates line * number indications as they emerge from GNU cpp (`# lineno "file" * 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; @@ -385,6 +492,10 @@ static char *prepreproc(char *line) sprintf(line, "%%line %d %.*s", lineno, fnlen, fname); nasm_free (oldline); } +#ifdef TASM_COMPAT + if (tasm_compatible_mode) + return check_tasm_directive(line); +#endif return line; } @@ -639,7 +750,12 @@ static Token *tokenise (char *line) type = TOK_STRING; while (*p && *p != c) p++; - if (*p) p++; + if (*p) { + p++; + } + else { + error(ERR_WARNING, "unterminated string"); + } } else if (isnumstart(*p)) { /* @@ -914,6 +1030,20 @@ static Context *get_ctx (char *name, int all_contexts) return NULL; } +#ifdef TASM_COMPAT +/* Add a slash to the end of a path if it is missing. We use the + * forward slash to make it compatible with Unix systems. + */ +static void backslash(char *s) +{ + int pos = strlen(s); + if (s[pos-1] != '\\' && s[pos-1] != '/') { + s[pos] = '/'; + s[pos+1] = '\0'; + } +} +#endif + /* * Open an include file. This routine must always return a valid * file pointer if it returns - it's responsible for throwing an @@ -927,9 +1057,20 @@ static FILE *inc_fopen(char *file) char *prefix = "", *combine; IncPath *ip = ipath; static int namelen = 0; +#ifdef TASM_COMPAT + int len = strlen(file); +#endif while (1) { +#ifdef TASM_COMPAT + combine = nasm_malloc(strlen(prefix)+1+len+1); + strcpy(combine, prefix); + if (prefix[0] != 0) + backslash(combine); + strcat(combine, file); +#else combine = nasm_strcat(prefix,file); +#endif fp = fopen(combine, "r"); if (pass == 0 && fp) { @@ -1241,6 +1382,9 @@ void expand_macros_in_string (char **p) static int do_directive (Token *tline) { int i, j, k, m, nparam, nolist; +#ifdef TASM_COMPAT + int offset; +#endif char *p, *mname; Include *inc; Context *ctx; @@ -1324,6 +1468,201 @@ static int do_directive (Token *tline) } switch (i) { +#ifdef TASM_COMPAT + case PP_STACKSIZE: + /* Directive to tell NASM what the default stack size is. The + * default is for a 16-bit stack, and this can be overriden with + * %stacksize large. + * the following form: + * + * ARG arg1:WORD, arg2:DWORD, arg4:QWORD + */ + tline = tline->next; + if (tline && tline->type == TOK_WHITESPACE) + tline = tline->next; + if (!tline || tline->type != TOK_ID) { + error (ERR_NONFATAL,"`%%stacksize' missing size parameter"); + free_tlist (origline); + return 3; + } + if (nasm_stricmp(tline->text,"flat") == 0) { + /* All subsequent ARG directives are for a 32-bit stack */ + StackSize = 4; + StackPointer = "ebp"; + ArgOffset = 8; + LocalOffset = 4; + } else if (nasm_stricmp(tline->text,"large") == 0) { + /* All subsequent ARG directives are for a 16-bit stack, + * far function call. + */ + StackSize = 2; + StackPointer = "bp"; + ArgOffset = 4; + LocalOffset = 2; + } else if (nasm_stricmp(tline->text,"small") == 0) { + /* All subsequent ARG directives are for a 16-bit stack, + * far function call. We don't support near functions. + */ + StackSize = 2; + StackPointer = "bp"; + ArgOffset = 6; + LocalOffset = 2; + } else { + error (ERR_NONFATAL,"`%%stacksize' invalid size type"); + free_tlist (origline); + return 3; + } + free_tlist(origline); + return 3; + + case PP_ARG: + /* TASM like ARG directive to define arguments to functions, in + * the following form: + * + * ARG arg1:WORD, arg2:DWORD, arg4:QWORD + */ + offset = ArgOffset; + do { + char *arg,directive[256]; + int size = StackSize; + + /* Find the argument name */ + tline = tline->next; + if (tline && tline->type == TOK_WHITESPACE) + tline = tline->next; + if (!tline || tline->type != TOK_ID) { + error (ERR_NONFATAL,"`%%arg' missing argument parameter"); + free_tlist (origline); + return 3; + } + arg = tline->text; + + /* Find the argument size type */ + tline = tline->next; + if (!tline || tline->type != TOK_OTHER || tline->text[0] != ':') { + error (ERR_NONFATAL,"Syntax error processing `%%arg' directive"); + free_tlist (origline); + return 3; + } + tline = tline->next; + if (!tline || tline->type != TOK_ID) { + error (ERR_NONFATAL,"`%%arg' missing size type parameter"); + free_tlist (origline); + return 3; + } + + /* Allow macro expansion of type parameter */ + tt = tokenise(tline->text); + tt = expand_smacro(tt); + if (nasm_stricmp(tt->text,"byte") == 0) { + size = MAX(StackSize,1); + } else if (nasm_stricmp(tt->text,"word") == 0) { + size = MAX(StackSize,2); + } else if (nasm_stricmp(tt->text,"dword") == 0) { + size = MAX(StackSize,4); + } else if (nasm_stricmp(tt->text,"qword") == 0) { + size = MAX(StackSize,8); + } else if (nasm_stricmp(tt->text,"tword") == 0) { + size = MAX(StackSize,10); + } else { + error (ERR_NONFATAL,"Invalid size type for `%%arg' missing directive"); + free_tlist (tt); + free_tlist (origline); + return 3; + } + free_tlist (tt); + + /* Now define the macro for the argument */ + sprintf(directive,"%%define %s (%s+%d)", arg, StackPointer, offset); + do_directive(tokenise(directive)); + offset += size; + + /* Move to the next argument in the list */ + tline = tline->next; + if (tline && tline->type == TOK_WHITESPACE) + tline = tline->next; + } while (tline && tline->type == TOK_OTHER && tline->text[0] == ','); + free_tlist (origline); + return 3; + + case PP_LOCAL: + /* TASM like LOCAL directive to define local variables for a + * function, in the following form: + * + * LOCAL local1:WORD, local2:DWORD, local4:QWORD = LocalSize + * + * The '= LocalSize' at the end is ignored by NASM, but is + * required by TASM to define the local parameter size (and used + * by the TASM macro package). + */ + offset = LocalOffset; + do { + char *local,directive[256]; + int size = StackSize; + + /* Find the argument name */ + tline = tline->next; + if (tline && tline->type == TOK_WHITESPACE) + tline = tline->next; + if (!tline || tline->type != TOK_ID) { + error (ERR_NONFATAL,"`%%local' missing argument parameter"); + free_tlist (origline); + return 3; + } + local = tline->text; + + /* Find the argument size type */ + tline = tline->next; + if (!tline || tline->type != TOK_OTHER || tline->text[0] != ':') { + error (ERR_NONFATAL,"Syntax error processing `%%local' directive"); + free_tlist (origline); + return 3; + } + tline = tline->next; + if (!tline || tline->type != TOK_ID) { + error (ERR_NONFATAL,"`%%local' missing size type parameter"); + free_tlist (origline); + return 3; + } + + /* Allow macro expansion of type parameter */ + tt = tokenise(tline->text); + tt = expand_smacro(tt); + if (nasm_stricmp(tt->text,"byte") == 0) { + size = MAX(StackSize,1); + } else if (nasm_stricmp(tt->text,"word") == 0) { + size = MAX(StackSize,2); + } else if (nasm_stricmp(tt->text,"dword") == 0) { + size = MAX(StackSize,4); + } else if (nasm_stricmp(tt->text,"qword") == 0) { + size = MAX(StackSize,8); + } else if (nasm_stricmp(tt->text,"tword") == 0) { + size = MAX(StackSize,10); + } else { + error (ERR_NONFATAL,"Invalid size type for `%%local' missing directive"); + free_tlist (tt); + free_tlist (origline); + return 3; + } + free_tlist (tt); + + /* Now define the macro for the argument */ + sprintf(directive,"%%define %s (%s-%d)", local, StackPointer, offset); + do_directive(tokenise(directive)); + offset += size; + + /* Now define the assign to setup the enter_c macro correctly */ + sprintf(directive,"%%assign %%$localsize %%$localsize+%d", size); + do_directive(tokenise(directive)); + + /* Move to the next argument in the list */ + tline = tline->next; + if (tline && tline->type == TOK_WHITESPACE) + tline = tline->next; + } while (tline && tline->type == TOK_OTHER && tline->text[0] == ','); + free_tlist (origline); + return 3; +#endif case PP_CLEAR: if (tline->next) @@ -1940,6 +2279,178 @@ static int do_directive (Token *tline) free_tlist (origline); return 3; + case PP_STRLEN: + tline = tline->next; + skip_white_(tline); + tline = expand_id (tline); + if (!tline || (tline->type != TOK_ID && + (tline->type != TOK_PREPROC_ID || + tline->text[1] != '$'))) { + error (ERR_NONFATAL, + "`%%strlen' expects a macro identifier as first parameter"); + free_tlist (origline); + return 3; + } + ctx = get_ctx (tline->text, FALSE); + if (!ctx) + smhead = &smacros[hash(tline->text)]; + else + smhead = &ctx->localmac; + mname = tline->text; + last = tline; + tline = expand_smacro (tline->next); + last->next = NULL; + + t = tline; + while (tok_type_(t, TOK_WHITESPACE)) + t = t->next; + /* t should now point to the string */ + if (t->type != TOK_STRING) { + error(ERR_NONFATAL, + "`%%strlen` requires string as second parameter"); + free_tlist(tline); + free_tlist(origline); + return 3; + } + + macro_start = nasm_malloc(sizeof(*macro_start)); + macro_start->next = NULL; + make_tok_num(macro_start, strlen(t->text)-2); + macro_start->mac = NULL; + + /* + * 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 (ctx, mname, 0, &smac, i == PP_STRLEN)) { + if (!smac) + error (ERR_WARNING, + "single-line macro `%s' defined both with and" + " without parameters", mname); + else { + /* + * We're redefining, so we have to take over an + * existing SMacro structure. This means freeing + * what was already in it. + */ + nasm_free (smac->name); + free_tlist (smac->expansion); + } + } + else { + smac = nasm_malloc(sizeof(SMacro)); + smac->next = *smhead; + *smhead = smac; + } + smac->name = nasm_strdup(mname); + smac->casesense = (i == PP_STRLEN); + smac->nparam = 0; + smac->expansion = macro_start; + smac->in_progress = FALSE; + free_tlist (tline); + free_tlist (origline); + return 3; + + case PP_SUBSTR: + tline = tline->next; + skip_white_(tline); + tline = expand_id (tline); + if (!tline || (tline->type != TOK_ID && + (tline->type != TOK_PREPROC_ID || + tline->text[1] != '$'))) { + error (ERR_NONFATAL, + "`%%substr' expects a macro identifier as first parameter"); + free_tlist (origline); + return 3; + } + ctx = get_ctx (tline->text, FALSE); + if (!ctx) + smhead = &smacros[hash(tline->text)]; + else + smhead = &ctx->localmac; + mname = tline->text; + last = tline; + tline = expand_smacro (tline->next); + last->next = NULL; + + t = tline->next; + while (tok_type_(t, TOK_WHITESPACE)) + t = t->next; + + /* t should now point to the string */ + if (t->type != TOK_STRING) { + error(ERR_NONFATAL, + "`%%substr` requires string as second parameter"); + free_tlist(tline); + free_tlist(origline); + return 3; + } + + tt = t->next; + tptr = &tt; + tokval.t_type = TOKEN_INVALID; + evalresult = evaluate (ppscan, tptr, &tokval, NULL, pass, error, NULL); + if (!evalresult) { + free_tlist(tline); + free_tlist(origline); + return 3; + } + if (!is_simple(evalresult)) { + error(ERR_NONFATAL, + "non-constant value given to `%%substr`"); + free_tlist(tline); + free_tlist(origline); + return 3; + } + + macro_start = nasm_malloc(sizeof(*macro_start)); + macro_start->next = NULL; + macro_start->text = nasm_strdup("'''"); + if (evalresult->value > 0 && evalresult->value < strlen(t->text)-1) { + macro_start->text[1] = t->text[evalresult->value]; + } + else { + macro_start->text[2] = '\0'; + } + macro_start->type = TOK_STRING; + macro_start->mac = NULL; + + /* + * 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 (ctx, mname, 0, &smac, i == PP_SUBSTR)) { + if (!smac) + error (ERR_WARNING, + "single-line macro `%s' defined both with and" + " without parameters", mname); + else { + /* + * We're redefining, so we have to take over an + * existing SMacro structure. This means freeing + * what was already in it. + */ + nasm_free (smac->name); + free_tlist (smac->expansion); + } + } + else { + smac = nasm_malloc(sizeof(SMacro)); + smac->next = *smhead; + *smhead = smac; + } + smac->name = nasm_strdup(mname); + smac->casesense = (i == PP_SUBSTR); + smac->nparam = 0; + smac->expansion = macro_start; + smac->in_progress = FALSE; + free_tlist (tline); + free_tlist (origline); + return 3; + + case PP_ASSIGN: case PP_IASSIGN: tline = tline->next; diff --git a/proc32.ash b/proc32.ash new file mode 100644 index 0000000..f513b73 --- /dev/null +++ b/proc32.ash @@ -0,0 +1,441 @@ +;--------=========xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=========-------- +; +; Copyright (C) 1999 by Andrew Zabolotny +; Miscelaneous NASM macros that makes use of new preprocessor features +; +; This library is free software; you can redistribute it and/or +; modify it under the terms of the GNU Library General Public +; License as published by the Free Software Foundation; either +; version 2 of the License, or (at your option) any later version. +; +; This library is distributed in the hope that it will be useful, +; but WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +; Library General Public License for more details. +; +; You should have received a copy of the GNU Library General Public +; License along with this library; if not, write to the Free +; Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +; +;--------=========xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=========-------- + +; The macros in this file provides support for writing 32-bit C-callable +; NASM routines. For a short description of every macros see the +; corresponding comment before every one. Simple usage example: +; +; proc sin,1 +; targ %$angle +; fld %$angle +; fsin +; endproc sin + +%ifndef __PROC32_ASH__ +%define __PROC32_ASH__ + +[WARNING -macro-selfref] + +;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======----- +; Summary: +; Mangle a name to be compatible with the C compiler +; Arguments: +; The name +; Example: +; cname (my_func) +;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======----- +%ifdef EXTERNC_UNDERSCORE + %define cname(x) _ %+ x +%else + %define cname(x) x +%endif + +;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======----- +; Summary: +; Import an external C procedure definition +; Arguments: +; The name of external C procedure +; Example: +; cextern printf +;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======----- +%macro cextern 1 + %xdefine %1 cname(%1) + %ifidni __OUTPUT_FORMAT__,obj + extern %1:wrt FLAT + %else + extern %1 + %endif +%endmacro + +;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======----- +; Summary: +; Export an C procedure definition +; Arguments: +; The name of C procedure +; Example: +; cglobal my_printf +;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======----- +%macro cglobal 1 + %xdefine %1 cname(%1) + global %1 +%endmacro + +;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======----- +; Summary: +; Misc macros to deal with PIC shared libraries +; Comment: +; Note that we have a different syntax for working with and without +; PIC shared libraries. In a PIC environment we should load first +; the address of the variable into a register and then work through +; that address, i.e: mov eax,myvar; mov [eax],1 +; In a non-PIC environment we should directly write: mov myvar,1 +; Example: +; extvar myvar +; GetGOT +; %ifdef PIC +; mov ebx,myvar ; get offset of myvar into ebx +; %else +; lea ebx,myvar +; %endif +;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======----- +%ifdef PIC + cextern _GLOBAL_OFFSET_TABLE_ + %macro GetGOT 0 + %ifdef .$proc.stkofs + %assign .$proc.stkofs .$proc.stkofs+4 + %endif + call %$Get_GOT + %$Get_GOT: + pop ebx + add ebx,_GLOBAL_OFFSET_TABLE_ + $$ - %$Get_GOT wrt ..gotpc + %endmacro + %macro extvar 1 + cextern %1 + %xdefine %1 [ebx+%1 wrt ..got] + %endmacro +%else + %define GetGOT + %macro extvar 1 + cextern %1 + %endmacro +%endif + +;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======----- +; Summary: +; Begin a procedure definition +; For performance reasons we don't use stack frame pointer EBP, +; instead we're using the [esp+xx] addressing. Because of this +; you should be careful when you work with stack pointer. +; The push/pop instructions are macros that are defined to +; deal correctly with these issues. +; Arguments: +; First argument - the procedure name +; Second optional argument - the number of bytes for local variables +; The following arguments could specify the registers that should be +; pushed at beginning of procedure and popped before exiting +; Example: +; proc MyTestProc +; proc MyTestProc,4,ebx,esi,edi +;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======----- +%macro proc 1-3+ 0 + cglobal %1 + %push %1 + align 16 +%1: + %xdefine %$proc.name %1 + ; total size of local arguments + %assign %$proc.locsize (%2+3) & 0xFFFC + ; offset from esp to argument + %assign %$proc.argofs 4+%$proc.locsize + ; additional offset to args (tracks push/pops) + %assign .$proc.stkofs 0 + ; offset from esp to local arguments + %assign %$proc.locofs 0 + ; Now push the registers that we should save + %define %$proc.save %3 + %if %$proc.locsize != 0 + sub esp,%$proc.locsize + %endif + push %$proc.save +%endmacro + +;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======----- +; Summary: +; Declare an argument passed on stack +; This macro defines two additional macros: +; first (with the name given by first argument) - [esp+xx] +; second (with a underscore appended to first argument) - esp+xx +; Arguments: +; First argument defines the procedure argument name +; Second optional parameter defines the size of the argument +; Default value is 4 (a double word) +; Example: +; arg .my_float +; arg .my_double,8 +;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======----- +%macro arg 1-2 4 + %ifndef %$proc.argofs + %error "`arg' not in a proc context" + %else + ; Trick: temporary undefine .$proc.stkofs so that it won't be expanded + %assign %%. .$proc.stkofs + %undef .$proc.stkofs + %xdefine %{1}_ esp+%$proc.argofs+.$proc.stkofs + %xdefine %1 [esp+%$proc.argofs+.$proc.stkofs] + %assign .$proc.stkofs %%. + %assign %$proc.argofs %2+%$proc.argofs + %endif +%endmacro + +;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======----- +; Summary: +; Declare an local variable +; first (with the name given by first argument) - [esp+xx] +; second (with a slash prefixing the first argument) - esp+xx +; Arguments: +; First argument defines the procedure argument name +; Second optional parameter defines the size of the argument +; Default value is 4 (a double word) +; Example: +; loc .int_value +; loc .double_value,8 +;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======----- +%macro loc 1-2 4 + %ifndef %$proc.locofs + %error "`loc' not in a proc context" + %elif %$proc.locofs + %2 > %$proc.locsize + %error "local stack space exceeded" + %else + %assign %%. .$proc.stkofs + %undef .$proc.stkofs + %xdefine %{1}_ esp+%$proc.locofs+.$proc.stkofs + %xdefine %1 [esp+%$proc.locofs+.$proc.stkofs] + %assign .$proc.stkofs %%. + %assign %$proc.locofs %$proc.locofs+%2 + %endif +%endmacro + +;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======----- +; Summary: +; Get the type of given size into context-local variable %$type +; Arguments: +; Size of type we want (1,2,4,8 or 10) +; Example: +; type 4 ; gives "dword" +; type 10 ; gives "tword" +;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======----- +%macro type 1 + %if %1 = 1 + %define %$type byte + %elif %1 = 2 + %define %$type word + %elif %1 = 4 + %define %$type dword + %elif %1 = 8 + %define %$type qword + %elif %1 = 10 + %define %$type tword + %else + %define %$. %1 + %error "unknown type for argument size %$." + %endif +%endmacro + +;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======----- +; Summary: +; Same as `arg' but prepends "word", "dword" etc (typed arg) +; first (with the name given by first argument) - dword [esp+xx] +; second (with a slash prefixing the first argument) - esp+xx +; Arguments: +; Same as for `arg' +; Example: +; targ .my_float ; .my_float is now "dword [esp+xxx]" +; targ .my_double,8 ; .my_double is now "qword [esp+xxx]" +;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======----- +%macro targ 1-2 4 + %ifndef %$proc.argofs + %error "`targ' not in a proc context" + %else + arg %1,%2 + type %2 + %assign %%. .$proc.stkofs + %undef .$proc.stkofs + %xdefine %1 %$type %1 + %assign .$proc.stkofs %%. + %endif +%endmacro + +;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======----- +; Summary: +; Same as `loc' but prepends "word", "dword" etc (typed loc) +; first (with the name given by first argument) - dword [esp+xx] +; second (with a slash prefixing the first argument) - esp+xx +; Arguments: +; Same as for `loc' +; Example: +; tloc int_value +; tloc double_value,8 +;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======----- +%macro tloc 1-2 4 + %ifndef %$proc.locofs + %error "`tloc' not in a proc context" + %else + loc %1,%2 + type %2 + %assign %%. .$proc.stkofs + %undef .$proc.stkofs + %xdefine %1 %$type %1 + %assign .$proc.stkofs %%. + %endif +%endmacro + +;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======----- +; Summary: +; Finish a procedure +; Gives an error if proc/endproc pairs mismatch +; Defines an label called __end_(procedure name) +; which is useful for calculating function size +; Arguments: +; (optional) The name of procedure +; Example: +; endproc MyTestProc +;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======----- +%push tmp ; trick: define a dummy context to avoid error in next line +%macro endproc 0-1 %$proc.name + %ifndef %$proc.argofs + %error "`endproc' not in a proc context" + %elifnidn %$proc.name,%1 + %define %$. %1 + %error "endproc names mismatch: expected `%$proc.name'" + %error "but got `%$.' instead" + %elif %$proc.locofs < %$proc.locsize + %error "unused local space declared (used %$proc.locofs, requested %$proc.locsize)" + %else +%$exit: + ; Now pop the registers that we should restore on exit + pop %$proc.save + %if %$proc.locsize != 0 + add esp,%$proc.locsize + %endif + ret +__end_%1: + %pop + %endif +%endmacro +%pop + +;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======----- +; Summary: +; A replacement for "push" for use within procedures +; Arguments: +; any number of registers which will be push'ed successively +; Example: +; push eax,ebx,ecx,edx +;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======----- +%macro push 0-* +; dummy comment to avoid problems with "push" on the same line with a label + %rep %0 + push %1 + %rotate 1 + %assign .$proc.stkofs .$proc.stkofs+4 + %endrep +%endmacro + +;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======----- +; Summary: +; A replacement for "pop" for use within procedures +; Arguments: +; any number of registers which will be pop'ed in reverse order +; Example: +; pop eax,ebx,ecx,edx +;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======----- +%macro pop 0-* +; dummy comment to avoid problems with "pop" on the same line with a label + %rep %0 + %rotate -1 + pop %1 + %assign .$proc.stkofs .$proc.stkofs-4 + %endrep +%endmacro + +;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======----- +; Summary: +; Replacements for "pushfd" and "popfd" that takes care of esp +; Example: +; pushfd +; popfd +;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======----- +%macro pushfd 0 + pushfd + %assign .$proc.stkofs .$proc.stkofs+4 +%endmacro +%macro popfd 0 + popfd + %assign .$proc.stkofs .$proc.stkofs-4 +%endmacro + +;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======----- +; Summary: +; Exit from current procedure (optionally on given condition) +; Arguments: +; Either none or a condition code +; Example: +; exit +; exit nz +;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======----- +%macro exit 0-1 mp + j%1 near %$exit +%endmacro + +;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======----- +; Summary: +; start an conditional branch +; Arguments: +; A condition code +; second (optional) argument - "short" (by default - "near") +; Example: +; if nz +;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======----- +%macro if 1-2 near +; dummy comment to avoid problems with "if" on the same line with a label + %push if + j%-1 %2 %$elseif +%endmacro + +;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======----- +; Summary: +; define the "else" branch of a conditional statement +; Arguments: +; optionaly: "short" if jmp to endif is less than 128 bytes away +; Example: +; else +;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======----- +%macro else 0-1 + %ifnctx if + %error "`else' without matching `if'" + %else + jmp %1 %$endif +%$elseif: + %define %$elseif_defined + %endif +%endmacro + +;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======----- +; Summary: +; Finish am conditional statement +; Arguments: +; none +; Example: +; endif +;-----======xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx======----- +%macro endif 0 + %ifnctx if + %error "`endif' without matching `if'" + %else + %ifndef %$elseif_defined +%$elseif: + %endif +%$endif: + %pop + %endif +%endmacro + +%endif ; __PROC32_ASH__ diff --git a/rdoff/Makefile.dj b/rdoff/Makefile.dj new file mode 100644 index 0000000..2099739 --- /dev/null +++ b/rdoff/Makefile.dj @@ -0,0 +1,75 @@ +# Generated automatically from Makefile.in by configure. +# +# Auto-configuring Makefile for RDOFF object file utils; part of 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. + +# You may need to adjust these values. + +prefix = /djgpp +CC = gcc -s +CFLAGS = -O2 -I.. + +# You _shouldn't_ need to adjust anything below this line. + +exec_prefix = ${prefix} +bindir = ${exec_prefix}/bin +mandir = ${prefix}/man + +INSTALL = /usr/bin/install -c +INSTALL_PROGRAM = ${INSTALL} +INSTALL_DATA = ${INSTALL} -m 644 +LN_S = ln -s + +LDRDFLIBS = rdoff.o ../nasmlib.o symtab.o hash.o collectn.o rdlib.o segtab.o +RDXLIBS = rdoff.o rdfload.o symtab.o hash.o collectn.o + +.c.o: + $(CC) -c $(CFLAGS) $*.c + +all: rdfdump ldrdf rdx rdflib rdf2bin rdf2com + +rdfdump: rdfdump.o + $(CC) -o rdfdump rdfdump.o + +ldrdf: ldrdf.o $(LDRDFLIBS) + $(CC) -o ldrdf ldrdf.o $(LDRDFLIBS) +rdx: rdx.o $(RDXLIBS) + $(CC) -o rdx rdx.o $(RDXLIBS) +rdflib: rdflib.o + $(CC) -o rdflib rdflib.o +rdf2bin: rdf2bin.o $(RDXLIBS) nasmlib.o + $(CC) -o rdf2bin rdf2bin.o $(RDXLIBS) nasmlib.o +rdf2com: + $(LN_S) rdf2bin rdf2com + +rdf2bin.o: rdf2bin.c +rdfdump.o: rdfdump.c +rdoff.o: rdoff.c rdoff.h +ldrdf.o: ldrdf.c rdoff.h ../nasmlib.h symtab.h collectn.h rdlib.h +symtab.o: symtab.c symtab.h hash.h +collectn.o: collectn.c collectn.h +rdx.o: rdx.c rdoff.h rdfload.h symtab.h +rdfload.o: rdfload.c rdfload.h rdoff.h collectn.h symtab.h +rdlib.o: rdlib.c rdlib.h +rdflib.o: rdflib.c +hash.o: hash.c hash.h +segtab.o: segtab.c segtab.h + +nasmlib.o: ../nasmlib.c ../nasmlib.h ../names.c ../nasm.h + $(CC) -c $(CFLAGS) ../nasmlib.c + +clean: + rm -f *.o rdfdump ldrdf rdx rdflib rdf2bin rdf2com + +install: rdfdump ldrdf rdx rdflib rdf2bin rdf2com + $(INSTALL_PROGRAM) rdfdump $(bindir)/rdfdump + $(INSTALL_PROGRAM) ldrdf $(bindir)/ldrdf + $(INSTALL_PROGRAM) rdx $(bindir)/rdx + $(INSTALL_PROGRAM) rdflib $(bindir)/rdflib + $(INSTALL_PROGRAM) rdf2bin $(bindir)/rdf2bin + cd $(bindir); $(LN_S) rdf2bin rdf2com diff --git a/rdoff/Makefile.emx b/rdoff/Makefile.emx new file mode 100644 index 0000000..fbaa934 --- /dev/null +++ b/rdoff/Makefile.emx @@ -0,0 +1,76 @@ +# Generated automatically from Makefile.in by configure. +# $Id$ +# +# Auto-configuring Makefile for RDOFF object file utils; part of 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. + +top_srcdir = .. +srcdir = . +prefix = /usr/local +exec_prefix = ${prefix} +bindir = ${exec_prefix}/bin +mandir = ${prefix}/man + +CC = gcc +CFLAGS = -s -Zomf -O2 -fomit-frame-pointer -Wall -ansi -pedantic -I$(srcdir) -I$(top_srcdir) +LDFLAGS = -s -Zomf -Zexe -Zcrtdll +LIBS = -lgcc + +INSTALL = .././install-sh -c +INSTALL_PROGRAM = ${INSTALL} +INSTALL_DATA = ${INSTALL} -m 644 + +LDRDFLIBS = rdoff.o nasmlib.o symtab.o collectn.o rdlib.o segtab.o hash.o +RDXLIBS = rdoff.o rdfload.o symtab.o collectn.o hash.o + +.c.o: + $(CC) -c $(CFLAGS) -o $@ $< + +all: rdfdump ldrdf rdx rdflib rdf2bin + +rdfdump: rdfdump.o + $(CC) $(LDFLAGS) -o rdfdump rdfdump.o $(LIBS) +ldrdf: ldrdf.o $(LDRDFLIBS) + $(CC) $(LDFLAGS) -o ldrdf ldrdf.o $(LDRDFLIBS) $(LIBS) +rdx: rdx.o $(RDXLIBS) + $(CC) $(LDFLAGS) -o rdx rdx.o $(RDXLIBS) $(LIBS) +rdflib: rdflib.o + $(CC) $(LDFLAGS) -o rdflib rdflib.o $(LIBS) +rdf2bin: rdf2bin.o $(RDXLIBS) nasmlib.o + $(CC) $(LDFLAGS) -o rdf2bin rdf2bin.o $(RDXLIBS) nasmlib.o $(LIBS) + +rdf2bin.o: rdf2bin.c +rdfdump.o: rdfdump.c +rdoff.o: rdoff.c rdoff.h +ldrdf.o: ldrdf.c rdoff.h $(top_srcdir)/nasmlib.h symtab.h collectn.h rdlib.h +symtab.o: symtab.c symtab.h +collectn.o: collectn.c collectn.h +rdx.o: rdx.c rdoff.h rdfload.h symtab.h +rdfload.o: rdfload.c rdfload.h rdoff.h collectn.h symtab.h +rdlib.o: rdlib.c rdlib.h +rdflib.o: rdflib.c +segtab.o: segtab.c + +nasmlib.o: $(top_srcdir)/nasmlib.c + $(CC) -c $(CFLAGS) -o $@ $(top_srcdir)/nasmlib.c + +clean: + rm -f *.o rdfdump ldrdf rdx rdflib rdf2bin rdf2com + +spotless: clean + rm -f Makefile + +distclean: spotless + +install: rdfdump ldrdf rdx rdflib rdf2bin rdf2com + $(INSTALL_PROGRAM) rdfdump $(INSTALLROOT)$(bindir)/rdfdump + $(INSTALL_PROGRAM) ldrdf $(INSTALLROOT)$(bindir)/ldrdf + $(INSTALL_PROGRAM) rdx $(INSTALLROOT)$(bindir)/rdx + $(INSTALL_PROGRAM) rdflib $(INSTALLROOT)$(bindir)/rdflib + $(INSTALL_PROGRAM) rdf2bin $(INSTALLROOT)$(bindir)/rdf2bin + cd $(INSTALLROOT)$(bindir) && rm -f rdf2com && $(LN_S) rdf2bin rdf2com diff --git a/rdoff/Makefile.in b/rdoff/Makefile.in index 37cc111..46efc0a 100644 --- a/rdoff/Makefile.in +++ b/rdoff/Makefile.in @@ -29,9 +29,9 @@ LDRDFLIBS = rdoff.o nasmlib.o symtab.o collectn.o rdlib.o segtab.o hash.o RDXLIBS = rdoff.o rdfload.o symtab.o collectn.o hash.o .c.o: - $(CC) -c $(CFLAGS) -o $@ $< + $(CC) -c $(CFLAGS) $< -all: rdfdump ldrdf rdx rdflib rdf2bin rdf2com +all: rdfdump ldrdf rdx rdflib rdf2bin rdf2com rdf2ihx rdfdump: rdfdump.o $(CC) $(LDFLAGS) -o rdfdump rdfdump.o @@ -45,7 +45,10 @@ rdf2bin: rdf2bin.o $(RDXLIBS) nasmlib.o $(CC) $(LDFLAGS) -o rdf2bin rdf2bin.o $(RDXLIBS) nasmlib.o rdf2com: rm -f rdf2com && $(LN_S) rdf2bin rdf2com +rdf2ihx: rdf2ihx.o $(RDXLIBS) nasmlib.o + $(CC) $(LDFLAGS) -o rdf2ihx rdf2ihx.o $(RDXLIBS) nasmlib.o +rdf2ihx.o: rdf2ihx.c rdf2bin.o: rdf2bin.c rdfdump.o: rdfdump.c rdoff.o: rdoff.c rdoff.h @@ -62,17 +65,18 @@ nasmlib.o: $(top_srcdir)/nasmlib.c $(CC) -c $(CFLAGS) $(top_srcdir)/nasmlib.c clean: - rm -f *.o rdfdump ldrdf rdx rdflib rdf2bin rdf2com + rm -f *.o rdfdump ldrdf rdx rdflib rdf2bin rdf2com rdf2ihx spotless: clean rm -f Makefile distclean: spotless -install: rdfdump ldrdf rdx rdflib rdf2bin rdf2com +install: rdfdump ldrdf rdx rdflib rdf2bin rdf2com rdf2ihx $(INSTALL_PROGRAM) rdfdump $(INSTALLROOT)$(bindir)/rdfdump $(INSTALL_PROGRAM) ldrdf $(INSTALLROOT)$(bindir)/ldrdf $(INSTALL_PROGRAM) rdx $(INSTALLROOT)$(bindir)/rdx $(INSTALL_PROGRAM) rdflib $(INSTALLROOT)$(bindir)/rdflib $(INSTALL_PROGRAM) rdf2bin $(INSTALLROOT)$(bindir)/rdf2bin + $(INSTALL_PROGRAM) rdf2ihx $(INSTALLROOT)$(bindir)/rdf2ihx cd $(INSTALLROOT)$(bindir) && rm -f rdf2com && $(LN_S) rdf2bin rdf2com diff --git a/rdoff/Makefile.sc b/rdoff/Makefile.sc index fca911a..7b45fe7 100644 --- a/rdoff/Makefile.sc +++ b/rdoff/Makefile.sc @@ -1,57 +1,56 @@ -# Makefile for RDOFF object file utils; part of 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 Makefile is designed for use under Unix (probably fairly
-# portably).
-
-CC = sc
-CCFLAGS = -I..\ -c -a1 -mn -Nc -w2 -w7 -o+time -5
-LINK = link
-LINKFLAGS = /noi /exet:NT /su:console
-
-OBJ=obj
-EXE=.exe
-
-NASMLIB = ..\nasmlib.$(OBJ)
-NASMLIB_H = ..\nasmlib.h
-LDRDFLIBS = rdoff.$(OBJ) $(NASMLIB) symtab.$(OBJ) collectn.$(OBJ) rdlib.$(OBJ)
-RDXLIBS = rdoff.$(OBJ) rdfload.$(OBJ) symtab.$(OBJ) collectn.$(OBJ)
-
-.c.$(OBJ):
- $(CC) $(CCFLAGS) $*.c
-
-all : rdfdump$(EXE) ldrdf$(EXE) rdx$(EXE) rdflib$(EXE) rdf2bin$(EXE) rdf2com$(EXE)
-
-rdfdump$(EXE) : rdfdump.$(OBJ)
- $(LINK) $(LINKFLAGS) rdfdump.$(OBJ), rdfdump$(EXE);
-ldrdf$(EXE) : ldrdf.$(OBJ) $(LDRDFLIBS)
- $(LINK) $(LINKFLAGS) ldrdf.$(OBJ) $(LDRDFLIBS), ldrdf$(EXE);
-rdx$(EXE) : rdx.$(OBJ) $(RDXLIBS)
- $(LINK) $(LINKFLAGS) rdx.$(OBJ) $(RDXLIBS), rdx$(EXE);
-rdflib$(EXE) : rdflib.$(OBJ)
- $(LINK) $(LINKFLAGS) rdflib.$(OBJ), rdflib$(EXE);
-rdf2bin$(EXE) : rdf2bin.$(OBJ) $(RDXLIBS) $(NASMLIB)
- $(LINK) $(LINKFLAGS) rdf2bin.$(OBJ) $(RDXLIBS) $(NASMLIB), rdf2bin$(EXE);
-rdf2com$(EXE) : rdf2bin$(EXE)
- copy rdf2bin$(EXE) rdf2com$(EXE)
-
-rdf2bin.$(OBJ) : rdf2bin.c
-rdfdump.$(OBJ) : rdfdump.c
-rdoff.$(OBJ) : rdoff.c rdoff.h
-ldrdf.$(OBJ) : ldrdf.c rdoff.h $(NASMLIB_H) symtab.h collectn.h rdlib.h
-symtab.$(OBJ) : symtab.c symtab.h
-collectn.$(OBJ) : collectn.c collectn.h
-rdx.$(OBJ) : rdx.c rdoff.h rdfload.h symtab.h
-rdfload.$(OBJ) : rdfload.c rdfload.h rdoff.h collectn.h symtab.h
-rdlib.$(OBJ) : rdlib.c rdlib.h
-rdflib.$(OBJ) : rdflib.c
-
-clean :
- del *.$(OBJ) rdfdump$(EXE) ldrdf$(EXE) rdx$(EXE) rdflib$(EXE) rdf2bin$(EXE)
-
-
-
\ No newline at end of file +# Makefile for RDOFF object file utils; part of 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 Makefile is designed for use under Unix (probably fairly +# portably). + +CC = sc +CCFLAGS = -I..\ -c -a1 -mn -Nc -w2 -w7 -o+time -5 +LINK = link +LINKFLAGS = /noi /exet:NT /su:console + +OBJ=obj +EXE=.exe + +NASMLIB = ..\nasmlib.$(OBJ) +NASMLIB_H = ..\nasmlib.h +LDRDFLIBS = rdoff.$(OBJ) $(NASMLIB) symtab.$(OBJ) collectn.$(OBJ) rdlib.$(OBJ) +RDXLIBS = rdoff.$(OBJ) rdfload.$(OBJ) symtab.$(OBJ) collectn.$(OBJ) + +.c.$(OBJ): + $(CC) $(CCFLAGS) $*.c + +all : rdfdump$(EXE) ldrdf$(EXE) rdx$(EXE) rdflib$(EXE) rdf2bin$(EXE) rdf2com$(EXE) + +rdfdump$(EXE) : rdfdump.$(OBJ) + $(LINK) $(LINKFLAGS) rdfdump.$(OBJ), rdfdump$(EXE); +ldrdf$(EXE) : ldrdf.$(OBJ) $(LDRDFLIBS) + $(LINK) $(LINKFLAGS) ldrdf.$(OBJ) $(LDRDFLIBS), ldrdf$(EXE); +rdx$(EXE) : rdx.$(OBJ) $(RDXLIBS) + $(LINK) $(LINKFLAGS) rdx.$(OBJ) $(RDXLIBS), rdx$(EXE); +rdflib$(EXE) : rdflib.$(OBJ) + $(LINK) $(LINKFLAGS) rdflib.$(OBJ), rdflib$(EXE); +rdf2bin$(EXE) : rdf2bin.$(OBJ) $(RDXLIBS) $(NASMLIB) + $(LINK) $(LINKFLAGS) rdf2bin.$(OBJ) $(RDXLIBS) $(NASMLIB), rdf2bin$(EXE); +rdf2com$(EXE) : rdf2bin$(EXE) + copy rdf2bin$(EXE) rdf2com$(EXE) + +rdf2bin.$(OBJ) : rdf2bin.c +rdfdump.$(OBJ) : rdfdump.c +rdoff.$(OBJ) : rdoff.c rdoff.h +ldrdf.$(OBJ) : ldrdf.c rdoff.h $(NASMLIB_H) symtab.h collectn.h rdlib.h +symtab.$(OBJ) : symtab.c symtab.h +collectn.$(OBJ) : collectn.c collectn.h +rdx.$(OBJ) : rdx.c rdoff.h rdfload.h symtab.h +rdfload.$(OBJ) : rdfload.c rdfload.h rdoff.h collectn.h symtab.h +rdlib.$(OBJ) : rdlib.c rdlib.h +rdflib.$(OBJ) : rdflib.c + +clean : + del *.$(OBJ) rdfdump$(EXE) ldrdf$(EXE) rdx$(EXE) rdflib$(EXE) rdf2bin$(EXE) + + diff --git a/rdoff/README b/rdoff/README index 29f9aa0..66988d2 100644 --- a/rdoff/README +++ b/rdoff/README @@ -4,16 +4,8 @@ RDOFF Utils v0.3 The files contained in this directory are the C source code of a set of tools (and general purpose library files) for the manipulation of RDOFF version 2 object files. Note that these programs (with the -exception of 'rdfdump') will NOT work with version 1 object files. See -the subdirectory v1 for programs that perform that task. - -Note: If you do not have a v1 subdirectory, you may have unpacked the -ZIP file without specifying the 'restore directory structure' option - -delete these files, and run your ZIP extracter again with this option -turned on ('-d' for PKUNZIP). - -RDOFF version 1 is no longer really supported, you should be using -v2 instead now. +exception of 'rdfdump') will NOT work with version 1 object files. Version 1 +of RDOFF is no longer supported. You should be using v2 instead now. There is also a 'Changes' file, which documents the differences between RDOFF 1 and 2, and an 'rdoff2.txt' file, with complete documentation for the diff --git a/rdoff/ldrdf.c b/rdoff/ldrdf.c index 72f8725..3d9d749 100644 --- a/rdoff/ldrdf.c +++ b/rdoff/ldrdf.c @@ -29,13 +29,14 @@ #include <stdlib.h> #include <string.h> +#include "multboot.h" #include "rdoff.h" #include "symtab.h" #include "collectn.h" #include "rdlib.h" #include "segtab.h" -#define LDRDF_VERSION "1.00 alpha 1" +#define LDRDF_VERSION "1.02" #define RDF_MAXSEGS 64 /* #define STINGY_MEMORY */ @@ -91,6 +92,44 @@ struct librarynode * lastlib = NULL; /* the symbol table */ void * symtab = NULL; +/* objects search path */ +char * objpath = NULL; + +/* libraries search path */ +char * libpath = NULL; + +/* error file */ +static FILE * error_file; + +#ifdef _MULTBOOT_H + +/* loading address for multiboot header */ +unsigned MBHloadAddr; + +/* + * Tiny code that moves RDF loader to its working memory region: + * mov esi,SOURCE_ADDR ; BE xx xx xx xx + * mov edi,DEST_ADDR ; BF xx xx xx xx + * mov esp,edi ; 89 FC + * push edi ; 57 + * mov ecx,RDFLDR_LENGTH/4 ; B9 xx xx xx xx + * cld ; FC + * rep movsd ; F3 A5 + * ret ; C3 + */ + +#define RDFLDR_LENGTH 4096 /* Loader will be moved to unused */ +#define RDFLDR_DESTLOC 0xBF000 /* video page */ + +unsigned char RDFloaderMover[]={ + 0xBE, 0, 0, 0, 0, 0xBF, 0, 0xF0, 0xB, 0, + 0x89, 0xFC, 0x57, + 0xB9, 0, 4, 0, 0, + 0xFC, 0xF3, 0xA5, 0xC3 +}; + +#endif + /* the header of the output file, built up stage by stage */ rdf_headerbuf * newheader = NULL; @@ -107,7 +146,13 @@ struct ldrdfoptions { int verbose; int align; int warnUnresolved; + int errorUnresolved; int strip; + int respfile; + int stderr_redir; + int objpath; + int libpath; + int addMBheader; } options; int errorcount = 0; /* determines main program exit status */ @@ -305,11 +350,26 @@ void processmodule(const char * filename, struct modulenode * mod) break; case 3: /* exported symbol */ - if (mod->seginfo[(int)hr->e.segment].dest_seg == -1) - continue; - symtab_add(hr->e.label, mod->seginfo[(int)hr->e.segment].dest_seg, - mod->seginfo[(int)hr->e.segment].reloc + hr->e.offset); + { + int destseg; + long destreloc; + + if (hr->e.segment == 2) + { + destreloc = bss_length; + if (destreloc % options.align != 0) + destreloc += options.align - (destreloc % options.align); + destseg = 2; + } + else + { + if ((destseg = mod->seginfo[(int)hr->e.segment].dest_seg) == -1) + continue; + destreloc = mod->seginfo[(int)hr->e.segment].reloc; + } + symtab_add(hr->e.label, destseg, destreloc + hr->e.offset); break; + } case 5: /* BSS reservation */ /* @@ -353,6 +413,22 @@ void processmodule(const char * filename, struct modulenode * mod) } + +/* + * Look in list for module by its name. + */ +int lookformodule(const char *name) + { + struct modulenode *curr=modules; + + while(curr) { + if (!strcmp(name,curr->name)) return 1; + curr = curr->next; + } + return 0; + } + + /* * allocnewseg() * findsegment() @@ -415,7 +491,7 @@ void symtab_add(const char * symbol, int segment, long offset) * symbol previously defined */ if (segment < 0) return; - fprintf (stderr, "warning: `%s' redefined\n", symbol); + fprintf (error_file, "warning: `%s' redefined\n", symbol); return; } @@ -502,6 +578,7 @@ void add_library(const char * name) } lastlib = lastlib->next; } + lastlib->next = NULL; if (rdl_open(lastlib, name)) { rdl_perror("ldrdf", name); errorcount++; @@ -528,7 +605,7 @@ int search_libraries() void * header; int segment; long offset; - int doneanything = 0, keepfile; + int doneanything = 0, pass = 1, keepfile; rdfheaderrec * hr; cur = libraries; @@ -536,10 +613,12 @@ int search_libraries() while (cur) { if (options.verbose > 2) - printf("scanning library `%s'...\n", cur->name); + printf("scanning library `%s', pass %d...\n", cur->name, pass); for (i = 0; rdl_openmodule(cur, i, &f) == 0; i++) { + if (pass == 2 && lookformodule(f.name)) continue; + if (options.verbose > 3) printf(" looking in module `%s'\n", f.name); @@ -591,15 +670,25 @@ int search_libraries() lastmodule = lastmodule->next; memcpy(&lastmodule->f, &f, sizeof(f)); lastmodule->name = strdup(f.name); + lastmodule->next = NULL; processmodule(f.name, lastmodule); break; } if (!keepfile) - rdfclose(&f); + { + free(f.name); + f.name = NULL; + f.fp = NULL; + } } if (rdl_error != 0 && rdl_error != RDL_ENOTFOUND) rdl_perror("ldrdf", cur->name); + cur = cur->next; + if (cur == NULL && pass == 1) { + cur = libraries; + pass++; + } } return doneanything; @@ -614,8 +703,8 @@ int search_libraries() */ void write_output(const char * filename) { - FILE * f = fopen(filename, "wb"); - rdf_headerbuf * rdfheader = rdfnewheader(); + FILE * f; + rdf_headerbuf * rdfheader; struct modulenode * cur; int i, availableseg, seg, localseg, isrelative; void * header; @@ -625,18 +714,43 @@ void write_output(const char * filename) long offset; byte * data; - if (!f) { + if ((f = fopen(filename, "wb"))==NULL) { fprintf(stderr, "ldrdf: couldn't open %s for output\n", filename); exit(1); } - if (!rdfheader) { + if ((rdfheader=rdfnewheader())==NULL) { fprintf(stderr, "ldrdf: out of memory\n"); exit(1); } + + /* + * Add multiboot header if appropriate option is specified. + * Multiboot record *MUST* be the first record in output file. + */ + if (options.addMBheader) { + if (options.verbose) + puts("\nadding multiboot header record"); + + hr = (rdfheaderrec *) malloc(sizeof(struct MultiBootHdrRec)); + hr->mbh.type = 9; + hr->mbh.reclen = sizeof(struct tMultiBootHeader)+RDFLDRMOVER_SIZE; + + hr->mbh.mb.Magic = MB_MAGIC; + hr->mbh.mb.Flags = MB_FL_KLUDGE; + hr->mbh.mb.Checksum = ~(MB_MAGIC+MB_FL_KLUDGE-1); + hr->mbh.mb.HeaderAddr = MBHloadAddr+16; + hr->mbh.mb.LoadAddr = MBHloadAddr; + hr->mbh.mb.Entry = MBHloadAddr+16+sizeof(struct tMultiBootHeader); + + memcpy(hr->mbh.mover,RDFloaderMover,RDFLDRMOVER_SIZE); + + rdfaddheader(rdfheader,hr); + free(hr); + } if (options.verbose) printf ("\nbuilding output module (%d segments)\n", nsegs); - + /* * Allocate the memory for the segments. We may be better off * building the output module one segment at a time when running @@ -645,6 +759,8 @@ void write_output(const char * filename) */ for (i = 0; i < nsegs; i++) { + outputseg[i].data=NULL; + if(!outputseg[i].length) continue; outputseg[i].data = malloc(outputseg[i].length); if (!outputseg[i].data) { fprintf(stderr, "ldrdf: out of memory\n"); @@ -714,7 +830,7 @@ void write_output(const char * filename) * and the BSS segment (doh!) */ add_seglocation (&segs, 2, 2, cur->bss_reloc); - + while ((hr = rdfgetheaderrec(&cur->f))) { switch(hr->type) { @@ -786,7 +902,7 @@ void write_output(const char * filename) case 1: offset += *data; if (offset < -127 || offset > 128) - fprintf(stderr, "warning: relocation out of range " + fprintf(error_file, "warning: relocation out of range " "at %s(%02x:%08lx)\n", cur->name, (int)hr->r.segment, hr->r.offset); *data = (char) offset; @@ -794,7 +910,7 @@ void write_output(const char * filename) case 2: offset += * (short *)data; if (offset < -32767 || offset > 32768) - fprintf(stderr, "warning: relocation out of range " + fprintf(error_file, "warning: relocation out of range " "at %s(%02x:%08lx)\n", cur->name, (int)hr->r.segment, hr->r.offset); * (short *)data = (short) offset; @@ -832,8 +948,9 @@ void write_output(const char * filename) se = symtabFind(symtab, hr->i.label); if (!se || se->segment == -1) { if (options.warnUnresolved) { - fprintf(stderr, "warning: unresolved reference to `%s'" + fprintf(error_file, "warning: unresolved reference to `%s'" " in module `%s'\n", hr->i.label, cur->name); + if (options.errorUnresolved==1) errorcount++; } /* * we need to allocate a segment number for this @@ -900,6 +1017,16 @@ void write_output(const char * filename) rdfaddheader(rdfheader, hr); break; + case 8: /* module name */ + /* + * insert module name record if export symbols + * are not stripped. + */ + if (options.strip) break; + + rdfaddheader(rdfheader, hr); + break; + case 6: /* segment fixup */ /* * modify the segment numbers if necessary, and @@ -939,7 +1066,7 @@ void write_output(const char * filename) free(header); done_seglocations(&segs); - } + } /* * combined BSS reservation for the entire results @@ -957,6 +1084,18 @@ void write_output(const char * filename) if (i == 2) continue; rdfaddsegment (rdfheader, outputseg[i].length); } + + if (options.addMBheader) { + struct MultiBootHdrRec *mbhrec = (struct MultiBootHdrRec *)(rdfheader->buf->buffer); + unsigned l = membuflength(rdfheader->buf) + 14 + + 10*rdfheader->nsegments + rdfheader->seglength; + unsigned *ldraddr = (unsigned *)(mbhrec->mover+1); + + mbhrec->mb.LoadEndAddr = MBHloadAddr+l+10+RDFLDR_LENGTH; + mbhrec->mb.BSSendAddr = mbhrec->mb.LoadEndAddr; + *ldraddr = MBHloadAddr+l+10; + } + rdfwriteheader(f, rdfheader); rdfdoneheader(rdfheader); /* @@ -996,14 +1135,15 @@ void usage() printf(" ldrdf [options] object modules ... [-llibrary ...]\n"); printf(" ldrdf -r\n"); printf("options:\n"); - printf(" -v[=n] increases verbosity by 1, or sets it to n\n"); - printf(" -a nn sets segment alignment value (default 16)\n"); - printf(" -s strips exported symbols\n"); - printf(" -x warn about unresolved symbols\n"); - printf(" -o name write output in file 'name'\n"); - printf("\n"); - printf("Note: no library searching is performed. Please specify full\n"); - printf("paths to all files referenced.\n"); + printf(" -v[=n] increases verbosity by 1, or sets it to n\n"); + printf(" -a nn sets segment alignment value (default 16)\n"); + printf(" -s strips exported symbols\n"); + printf(" -x warn about unresolved symbols\n"); + printf(" -o name write output in file 'name'\n"); + printf(" -j path specify objects search path\n"); + printf(" -L path specify libraries search path\n"); + printf(" -mbh [address] add multiboot header to output file. Default\n"); + printf(" loading address is 0x110000\n"); exit(0); } @@ -1011,12 +1151,15 @@ int main(int argc, char ** argv) { char * outname = "aout.rdf"; int moduleloaded = 0; + char *respstrings[128] = {0, }; options.verbose = 0; options.align = 16; options.warnUnresolved = 0; options.strip = 0; - + + error_file = stderr; + argc --, argv ++; if (argc == 0) usage(); while (argc && **argv == '-' && argv[0][1] != 'l') @@ -1041,7 +1184,7 @@ int main(int argc, char ** argv) case 'a': options.align = atoi(argv[1]); if (options.align <= 0) { - fprintf(stderr, + fprintf(stderr, "ldrdf: -a expects a positive number argument\n"); exit(1); } @@ -1052,17 +1195,94 @@ int main(int argc, char ** argv) break; case 'x': options.warnUnresolved = 1; + if (argv[0][2]=='e') + options.errorUnresolved = 1; break; case 'o': outname = argv[1]; argv++, argc--; break; + case 'j': + if (!objpath) + { + options.objpath = 1; + objpath = argv[1]; + argv++, argc--; + break; + } + else + { + fprintf(stderr,"ldrdf: more than one objects search path specified\n"); + exit(1); + } + case 'L': + if (!libpath) + { + options.libpath = 1; + libpath = argv[1]; + argv++, argc--; + break; + } + else + { + fprintf(stderr,"ldrdf: more than one libraries search path specified\n"); + exit(1); + } + case '@': { + int i=0; + char buf[256]; + FILE *f; + + options.respfile = 1; + if (argv[1] != NULL) f = fopen(argv[1],"r"); + else + { + fprintf(stderr,"ldrdf: no response file name specified\n"); + exit(1); + } + + if (f == NULL) + { + fprintf(stderr,"ldrdf: unable to open response file\n"); + exit(1); + } + argc-=2; + while(fgets(buf,sizeof(buf)-1,f)!=NULL) + { + char *p; + if (buf[0]=='\n') continue; + if ((p = strchr(buf,'\n')) != 0) + *p=0; + if (i >= 128) + { + fprintf(stderr,"ldrdf: too many input files\n"); + exit(1); + } + *(respstrings+i) = newstr(buf); + argc++, i++; + } + goto done; + } + case '2': + options.stderr_redir = 1; + error_file = stdout; + break; + case 'm': + if (argv[0][2] == 'b' && argv[0][3] == 'h') { + if (argv[1][0] != '-') { + MBHloadAddr = atoi(argv[1]); + } else { + MBHloadAddr = MB_DEFAULTLOADADDR; + } + options.addMBheader = 1; + break; + } default: usage(); } argv++, argc--; } - +done: if (options.verbose > 4) { printf("ldrdf invoked with options:\n"); printf(" section alignment: %d bytes\n", options.align); @@ -1071,6 +1291,14 @@ int main(int argc, char ** argv) printf(" strip symbols\n"); if (options.warnUnresolved) printf(" warn about unresolved symbols\n"); + if (options.errorUnresolved) + printf(" error if unresolved symbols\n"); + if (options.objpath) + printf(" objects search path: %s\n",objpath); + if (options.libpath) + printf(" libraries search path: %s\n",libpath); + if (options.addMBheader) + printf(" loading address for multiboot header: 0x%X\n",MBHloadAddr); printf("\n"); } @@ -1082,12 +1310,17 @@ int main(int argc, char ** argv) exit(1); } + if (*respstrings) argv = respstrings; while (argc) { if (!strncmp(*argv, "-l", 2)) /* library */ - add_library(*argv + 2); + { + if(libpath) add_library(newstrcat(libpath,*argv + 2)); + else add_library(*argv + 2); + } else { - loadmodule(*argv); + if(objpath) loadmodule(newstrcat(objpath,*argv)); + else loadmodule(*argv); moduleloaded = 1; } argv++, argc--; @@ -1098,7 +1331,7 @@ int main(int argc, char ** argv) return 0; } - + search_libraries(); if (options.verbose > 2) @@ -1109,9 +1342,6 @@ int main(int argc, char ** argv) write_output(outname); - if (errorcount > 0) - exit(1); - + if (errorcount > 0) exit(1); return 0; } - diff --git a/rdoff/multboot.h b/rdoff/multboot.h new file mode 100644 index 0000000..9669e49 --- /dev/null +++ b/rdoff/multboot.h @@ -0,0 +1,27 @@ +/****************************************************************************** + multboot.h - MultiBoot header definitions. + ******************************************************************************/ + +#ifndef _MULTBOOT_H +#define _MULTBOOT_H + +#define MB_MAGIC 0x1BADB002 + +#define MB_FL_PGALIGN 1 /* Align boot modules on page */ +#define MB_FL_MEMINFO 2 /* Must pass memory info to OS */ +#define MB_FL_KLUDGE 0x10000 /* a.out kludge present */ + +struct tMultiBootHeader { + unsigned Magic; + unsigned Flags; + unsigned Checksum; + unsigned HeaderAddr; + unsigned LoadAddr; + unsigned LoadEndAddr; + unsigned BSSendAddr; + unsigned Entry; +}; + +#define MB_DEFAULTLOADADDR 0x110000 /* Default loading address */ + +#endif diff --git a/rdoff/rdf2bin.c b/rdoff/rdf2bin.c index 21ea97d..938b4a9 100644 --- a/rdoff/rdf2bin.c +++ b/rdoff/rdf2bin.c @@ -29,7 +29,7 @@ int main(int argc, char **argv) int tmp; FILE *of; char * padding; - int codepad, datapad; + int codepad, datapad, bsspad=0; if (argc < 2) { puts("Usage: rdf2bin [-o relocation-origin] [-p segment-alignment] " @@ -58,6 +58,13 @@ int main(int argc, char **argv) fprintf(stderr,"rdf2bin: invalid parameter: %s\n",*argv); return 1; } + } else if (! strcmp(*argv,"-b")) { + argv++, argc--; + bsspad = readnum(*argv, &tmp); + if (tmp) { + fprintf(stderr,"rdf2bin: invalid parameter: %s\n",*argv); + return 1; + } } else break; @@ -69,8 +76,7 @@ int main(int argc, char **argv) } m = rdfload(*argv); - if (! m) - { + if (! m) { rdfperror("rdf2bin",*argv); return 1; } @@ -119,6 +125,11 @@ int main(int argc, char **argv) fprintf(stderr,"rdf2bin: error writing to %s\n", *argv); return 1; } + + if (bsspad) { + void *p = calloc(bsspad-=(m->bssrel - origin),1); + fwrite(p,1,bsspad,of); + } fclose(of); return 0; diff --git a/rdoff/rdf2ihx.c b/rdoff/rdf2ihx.c new file mode 100644 index 0000000..c6dd8e3 --- /dev/null +++ b/rdoff/rdf2ihx.c @@ -0,0 +1,189 @@ +/* rdf2ihx: convert an RDOFF object file to Intel Hex format. This is based + on rdf2bin. Note that this program only writes 16-bit HEX. */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "rdfload.h" +#include "rdoff.h" +#include "nasmlib.h" +#include "symtab.h" + +long origin = 0; +int align = 16; + +/* This function writes a single n-byte data record to of. Maximum value + for n is 255. */ +static int write_data_record(FILE *of, int ofs, int nbytes, + unsigned char *data) +{ + int i, iofs; + unsigned int checksum; + + iofs = ofs; + fprintf(of, ":%02X%04X00", nbytes, ofs); + checksum = 0; + for (i=0; i<nbytes; i++) { + fprintf(of, "%02X", data[i]); + ofs++; + checksum += data[i]; + } + checksum = checksum + /* current checksum */ + nbytes + /* RECLEN (one byte) */ + ((iofs >> 8) & 0xff) + /* high byte of load offset */ + (iofs & 0xff); /* low byte of load offset */ + checksum = ~checksum + 1; + fprintf(of, "%02X\n", checksum&0xff); + return(ofs); +} + +int main(int argc, char **argv) +{ + rdfmodule *m; + int tmp; + FILE *of; + char *padding; + unsigned char *segbin[2]; + int pad[2], segn, ofs, i; + long segaddr; + unsigned int checksum; + symtabEnt *s; + + if (argc < 2) { + puts("Usage: rdf2ihx [-o relocation-origin] [-p segment-alignment] " + "input-file output-file"); + return(1); + } + + argv++, argc--; + + while (argc > 2) { + if (strcmp(*argv,"-o") == 0) { + argv++, argc--; + origin = readnum(*argv, &tmp); + if (tmp) { + fprintf(stderr,"rdf2ihx: invalid parameter: %s\n",*argv); + return 1; + } + } else if (strcmp(*argv,"-p") == 0) { + argv++, argc--; + align = readnum(*argv, &tmp); + if (tmp) { + fprintf(stderr,"rdf2ihx: invalid parameter: %s\n",*argv); + return 1; + } + } else + break; + argv++, argc--; + } + if (argc < 2) { + puts("rdf2bin: required parameter missing"); + return -1; + } + m = rdfload(*argv); + + if (!m) { + rdfperror("rdf2bin",*argv); + return 1; + } + printf("relocating %s: origin=%lx, align=%d\n",*argv, origin, align); + + m->textrel = origin; + m->datarel = origin + m->f.seg[0].length; + if (m->datarel % align != 0) { + pad[0] = align - (m->datarel % align); + m->datarel += pad[0]; + } else { + pad[0] = 0; + } + + m->bssrel = m->datarel + m->f.seg[1].length; + if (m->bssrel % align != 0) { + pad[1] = align - (m->bssrel % align); + m->bssrel += pad[1]; + } else { + pad[1] = 0; + } + + printf("code: %08lx\ndata: %08lx\nbss: %08lx\n", + m->textrel, m->datarel, m->bssrel); + + rdf_relocate(m); + + argv++; + + of = fopen(*argv,"w"); + if (!of) { + fprintf(stderr,"rdf2ihx: could not open output file %s\n",*argv); + return(1); + } + + padding = malloc(align); + if (!padding) { + fprintf(stderr,"rdf2ihx: out of memory\n"); + return(1); + } + + /* write extended segment address record */ + fprintf(of, ":02000002"); /* Record mark, reclen, load offset & rectyp + fields for ext. seg. address record */ + segaddr = ((origin >> 16) & 0xffff); /* segment address */ + fprintf(of, "%04X", (unsigned int)(segaddr & 0xffff)); + checksum = 0x02 + /* reclen */ + 0x0000 + /* Load Offset */ + 0x02 + /* Rectyp */ + (segaddr & 0xff) + /* USBA low */ + ((segaddr >> 8) & 0xff); /* USBA high */ + checksum = ~checksum + 1; /* two's-complement the checksum */ + fprintf(of, "%02X\n", checksum & 0xff); + + /* See if there's a '_main' symbol in the symbol table */ + if ((s=symtabFind(m->symtab, "_main")) == NULL) { + printf("No _main symbol found, no start segment address record added\n"); + } else { + printf("_main symbol found at %04x:%04x\n", s->segment, + (unsigned int)(s->offset & 0xffff)); + /* Create a start segment address record for the _main symbol. */ + segaddr = ((s->segment & 0xffff) << 16) + ((s->offset) & 0xffff); + fprintf(of, ":04000003"); /* Record mark, reclen, load offset & rectyp + fields for start seg. addr. record */ + fprintf(of, "%08lX", segaddr); /* CS/IP field */ + checksum = 0x04 + /* reclen */ + 0x0000 + /* load offset */ + 0x03 + /* Rectyp */ + (segaddr & 0xff) + /* low-low byte of segaddr */ + ((segaddr >> 8) & 0xff) + /* low-high byte of segaddr */ + ((segaddr >> 16) & 0xff) + /* high-low byte of segaddr */ + ((segaddr >> 24) & 0xff); /* high-high byte of segaddr */ + checksum = ~checksum + 1; /* two's complement */ + fprintf(of, "%02X\n", checksum & 0xff); + } + + /* Now it's time to write data records from the code and data segments in. + This current version doesn't check for segment overflow; proper behavior + should be to output a segment address record for the code and data + segments. Something to do. */ + ofs = 0; + segbin[0] = m->t; + segbin[1] = m->d; + for (segn=0; segn<2; segn++) { + int mod, adr; + + if (m->f.seg[segn].length == 0) + continue; + for (i=0; i+15<m->f.seg[segn].length; i+=16) { + ofs = write_data_record(of, ofs, 16, &segbin[segn][i]); + } + if ((mod=m->f.seg[segn].length & 0x000f) != 0) { + adr = m->f.seg[segn].length & 0xfff0; + ofs = write_data_record(of, ofs, mod, &segbin[segn][adr]); + } + } + /* output an end of file record */ + fprintf(of, ":00000001FF\n"); + + fclose(of); + return 0; +} + diff --git a/rdoff/rdfdump.c b/rdoff/rdfdump.c index cb79a64..347fdb1 100644 --- a/rdoff/rdfdump.c +++ b/rdoff/rdfdump.c @@ -2,6 +2,8 @@ #include <stdlib.h> #include <string.h> +#include "multboot.h" + FILE *infile; typedef unsigned short int16; @@ -35,6 +37,7 @@ void print_header(long length, int rdf_version) { unsigned char reclen; long o,ll; int16 rs; + struct tMultiBootHeader *mb; while (length > 0) { fread(&t,1,1,infile); @@ -47,7 +50,7 @@ void print_header(long length, int rdf_version) { fread(&s,1,1,infile); fread(&o,4,1,infile); fread(&l,1,1,infile); - fread(&rs,2,1,infile); + fread(&rs,2,1,infile); printf(" %s: location (%04x:%08lx), length %d, " "referred seg %04x\n", t == 1 ? "relocation" : "seg relocation", (int)s,translatelong(o),(int)l, @@ -98,7 +101,8 @@ void print_header(long length, int rdf_version) { printf(" export: (%04x:%08lx) = %s\n",(int)s,translatelong(o),buf); if (rdf_version == 1) length -= ll + 6; break; - case 4: /* DLL record */ + case 4: /* DLL and Module records */ + case 8: ll = 0; if (rdf_version == 1) { @@ -108,10 +112,11 @@ void print_header(long length, int rdf_version) { } else { - for (; ll < reclen - 1; ll++) + for (; ll < reclen; ll++) fread(&buf[ll],1,1,infile); } - printf(" dll: %s\n",buf); + if (t==4) printf(" dll: %s\n",buf); + else printf(" module: %s\n",buf); if (rdf_version == 1) length -= ll + 1; break; case 5: /* BSS reservation */ @@ -121,9 +126,19 @@ void print_header(long length, int rdf_version) { if (rdf_version > 1 && reclen != 4) printf(" warning: reclen != 4\n"); break; + + case 9: /* MultiBoot header record */ + fread(buf,reclen,1,infile); + mb = (struct tMultiBootHeader *)buf; + printf(" multiboot header: load address=0x%X, size=0x%X, entry=0x%X\n", + mb->LoadAddr, mb->LoadEndAddr - mb->LoadAddr, mb->Entry); + break; default: printf(" unrecognised record (type %d",(int)t); - if (rdf_version > 1) printf(", length %d",(int)reclen); + if (rdf_version > 1) { + printf(", length %d",(int)reclen); + fseek(infile,reclen,SEEK_CUR); + } printf(")\n"); if (rdf_version == 1) length --; } @@ -158,7 +173,7 @@ int main(int argc,char **argv) { long headerlength = 0; long objectlength = 0; - puts("RDOFF Dump utility v2.0 (C) Copyright 1996 Julian R Hall"); + puts("RDOFF Dump utility v2.1\n(c) Copyright 1996,99,2000 Julian R Hall, Yuri M Zaporogets"); if (argc < 2) { fputs("Usage: rdfdump [-v] <filename>\n",stderr); @@ -178,7 +193,7 @@ int main(int argc,char **argv) { infile = fopen(argv[1],"rb"); if (! infile) { - fprintf(stderr,"rdfdump: Could not open %s",argv[1]); + fprintf(stderr,"rdfdump: Could not open %s\n",argv[1]); exit(1); } diff --git a/rdoff/rdfload.c b/rdoff/rdfload.c index 5b98103..4737282 100644 --- a/rdoff/rdfload.c +++ b/rdoff/rdfload.c @@ -29,12 +29,13 @@ extern int rdf_errno; rdfmodule * rdfload(const char *filename) { - rdfmodule * f = malloc(sizeof(rdfmodule)); + rdfmodule * f; long bsslength = 0; char * hdr; rdfheaderrec *r; - if (f == NULL) + f = malloc(sizeof(rdfmodule)); + if (f == NULL) { rdf_errno = 6; /* out of memory */ return NULL; @@ -92,7 +93,7 @@ rdfmodule * rdfload(const char *filename) } f->b = malloc ( bsslength ); - if (! f->b ) + if (bsslength && (!f->b)) { free(f->t); free(f->d); diff --git a/rdoff/rdoff.c b/rdoff/rdoff.c index 7f4937a..e7d8b76 100644 --- a/rdoff/rdoff.c +++ b/rdoff/rdoff.c @@ -24,6 +24,7 @@ #include <string.h> #include <errno.h> +#include "multboot.h" #include "rdoff.h" #define newstr(str) strcpy(malloc(strlen(str) + 1),str) @@ -49,13 +50,14 @@ memorybuffer * newmembuf() memorybuffer * t; t = malloc(sizeof(memorybuffer)); + if (!t) return NULL; t->length = 0; t->next = NULL; return t; } -void membufwrite(memorybuffer *b, void *data, int bytes) +void membufwrite(memorybuffer *const b, void *data, int bytes) { int16 w; long l; @@ -276,7 +278,10 @@ int rdfopenhere(rdffile *f, FILE *fp, int *refcount, const char *name) int rdfclose(rdffile *f) { if (! f->refcount || ! --(*f->refcount)) - fclose(f->fp); + { + fclose(f->fp); + f->fp = NULL; + } free(f->name); return 0; @@ -400,6 +405,10 @@ rdfheaderrec *rdfgetheaderrec(rdffile *f) RI32(r.b.amount); break; + case 8: /* Module name record */ + RS(r.m.modname,127); + break; + default: #ifdef STRICT_ERRORS rdf_errno = 8; /* unknown header record */ @@ -420,7 +429,7 @@ void rdfheaderrewind(rdffile *f) rdf_headerbuf * rdfnewheader(void) { - rdf_headerbuf * hb = malloc(sizeof(hb)); + rdf_headerbuf * hb = malloc(sizeof(rdf_headerbuf)); if (hb == NULL) return NULL; hb->buf = newmembuf(); @@ -468,6 +477,16 @@ int rdfaddheader(rdf_headerbuf * h, rdfheaderrec * r) membufwrite(h->buf,&r->b.amount,-4); break ; + case 8: /* Module name */ + membufwrite(h->buf,&r->m.modname,strlen(r->m.modname) + 1); + break ; + +#ifdef _MULTBOOT_H + case 9: /* MultiBoot header */ + membufwrite(h->buf,&r->mbh.mb,sizeof(struct tMultiBootHeader)+RDFLDRMOVER_SIZE); + break ; +#endif + default: #ifdef STRICT_ERRORS return (rdf_errno = 8); @@ -509,3 +528,4 @@ void rdfdoneheader(rdf_headerbuf * h) freemembuf(h->buf); free(h); } + diff --git a/rdoff/rdoff.h b/rdoff/rdoff.h index e23ffa4..0c57231 100644 --- a/rdoff/rdoff.h +++ b/rdoff/rdoff.h @@ -9,7 +9,7 @@ * as acknowledgement is given in an appropriate manner to its authors, * with instructions of how to obtain a copy via ftp. */ - + #ifndef _RDOFF_H #define _RDOFF_H "RDOFF2 support routines v0.3" @@ -48,7 +48,7 @@ struct ImportRec { struct ExportRec { byte type; /* must be 3 */ byte reclen; /* content length */ - byte segment; /* segment referred to (0/1) */ + byte segment; /* segment referred to (0/1/2) */ long offset; /* offset within segment */ char label[33]; /* zero terminated as above. max len = 32 chars */ }; @@ -65,6 +65,28 @@ struct BSSRec { long amount; /* number of bytes BSS to reserve */ }; +struct ModRec { + byte type; /* must be 8 */ + byte reclen; /* content length */ + char modname[128]; /* module name */ +}; + +#ifdef _MULTBOOT_H + +#define RDFLDRMOVER_SIZE 22 + +struct MultiBootHdrRec { + byte type; /* must be 9 */ + byte reclen; /* content length */ +#ifdef __GNUC__ + struct tMultiBootHeader mb __attribute__ ((packed)); /* MultiBoot header */ +#else + struct tMultiBootHeader mb; +#endif + byte mover[RDFLDRMOVER_SIZE]; /* Mover of RDF loader */ +}; +#endif + /* GenericRec - contains the type and length field, plus a 128 byte char array 'data', which will probably never be used! */ @@ -82,6 +104,10 @@ typedef union RDFHeaderRec { struct ExportRec e; /* type == 3 */ struct DLLRec d; /* type == 4 */ struct BSSRec b; /* type == 5 */ + struct ModRec m; /* type == 8 */ +#ifdef _MULTBOOT_H + struct MultiBootHdrRec mbh; /* type == 9 */ +#endif } rdfheaderrec; struct SegmentHeaderRec { @@ -167,4 +193,7 @@ int rdfaddsegment(rdf_headerbuf *h, long seglength); int rdfwriteheader(FILE *fp,rdf_headerbuf *h); void rdfdoneheader(rdf_headerbuf *h); +/* This is needed by linker to write multiboot header record */ +int membuflength(memorybuffer *b); + #endif /* _RDOFF_H */ diff --git a/rdoff/symtab.c b/rdoff/symtab.c index 4959a5d..8570f98 100644 --- a/rdoff/symtab.c +++ b/rdoff/symtab.c @@ -9,6 +9,7 @@ */ #include <stdio.h> #include <stdlib.h> +#include <string.h> #include <malloc.h> #include "symtab.h" @@ -106,6 +107,7 @@ symtabDump(void *stab, FILE* of) { symtab mytab = (symtab)stab; int i; + char *SegNames[3]={"code","data","bss"}; fprintf(of, "Symbol table is ...\n"); for (i=0; i < SYMTABSIZE; ++i) { @@ -116,7 +118,7 @@ symtabDump(void *stab, FILE* of) } while(l) { fprintf(of, "%-32s %s:%08lx (%ld)\n",l->ent.name, - l->ent.segment ? "data" : "code" , + SegNames[l->ent.segment], l->ent.offset, l->ent.flags); l = l->next; } diff --git a/scitech.txt b/scitech.txt new file mode 100644 index 0000000..049694f --- /dev/null +++ b/scitech.txt @@ -0,0 +1,213 @@ + + The Netwide Assembler: NASM + =========================== + +-------------------------------------------------------------------------------- + SciTech MGL Modifications +-------------------------------------------------------------------------------- + +All changes can be compiled in and out using the TASM_COMPAT macros, +and when compiled without TASM_COMPAT defined we get the exact same +binary as the unmodified 0.98 sources. + +standard.mac: +macros.c: + . Added macros to ignore TASM directives before first include + +nasm.h: + . Added extern declaration for tasm_compatible_mode + +nasm.c: + . Added global variable tasm_compatible_mode + . Added command line switch for TASM compatible mode (-t) + . Changed version command line to reflect when compiled with TASM additions + . Added response file processing to allow all arguments on a single + line (response file is @resp rather than -@resp for NASM format). + +labels.c: + . Changes islocal() macro to support TASM style @@local labels. + . Added islocalchar() macro to support TASM style @@local labels. + +parser.c: + . Added support for TASM style memory references (ie: mov [DWORD eax],10 + rather than the NASM style mov DWORD [eax],10). + +preproc.c: + . Added new directives, %arg, %local, %stacksize to directives table + . Added support for TASM style directives without a leading % symbol. + +-------------------------------------------------------------------------------- + Integrated a block of changes from Andrew Zabolotny <bit@eltech.ru>: +-------------------------------------------------------------------------------- + +-*- A new keyword %xdefine and its case-insensitive counterpart %ixdefine. + They work almost the same way as %define and %idefine but expand + the definition immediately, not on the invocation. Something like a cross + between %define and %assign. The "x" suffix stands for "eXpand", so + "xdefine" can be deciphered as "expand-and-define". Thus you can do + things like this: + + %assign ofs 0 + + %macro arg 1 + %xdefine %1 dword [esp+ofs] + %assign ofs ofs+4 + %endmacro + +-*- Changed the place where the expansion of %$name macros are expanded. + Now they are converted into ..@ctxnum.name form when detokenizing, so + there are no quirks as before when using %$name arguments to macros, + in macros etc. For example: + + %macro abc 1 + %define %1 hello + %endm + + abc %$here + %$here + + Now last line will be expanded into "hello" as expected. This also allows + for lots of goodies, a good example are extended "proc" macros included + in this archive. + +-*- Added a check for "cstk" in smacro_defined() before calling get_ctx() - + this allows for things like: + + %ifdef %$abc + %endif + + to work without warnings even in no context. + +-*- Added a check for "cstk" in %if*ctx and %elif*ctx directives - + this allows to use %ifctx without excessive warnings. If there is + no active context, %ifctx goes through "false" branch. + +-*- Removed "user error: " prefix with %error directive: it just clobbers the + output and has absolutely no functionality. Besides, this allows to write + macros that does not differ from built-in functions in any way. + +-*- Added expansion of string that is output by %error directive. Now you + can do things like: + + %define hello(x) Hello, x! + + %define %$name andy + %error "hello(%$name)" + + Same happened with %include directive. + +-*- Now all directives that expect an identifier will try to expand and + concatenate everything without whitespaces in between before usage. + For example, with "unfixed" nasm the commands + + %define %$abc hello + %define __%$abc goodbye + __%$abc + + would produce "incorrect" output: last line will expand to + + hello goodbyehello + + Not quite what you expected, eh? :-) The answer is that preprocessor + treats the %define construct as if it would be + + %define __ %$abc goodbye + + (note the white space between __ and %$abc). After my "fix" it + will "correctly" expand into + + goodbye + + as expected. Note that I use quotes around words "correct", "incorrect" + etc because this is rather a feature not a bug; however current behaviour + is more logical (and allows more advanced macro usage :-). + + Same change was applied to: + %push,%macro,%imacro,%define,%idefine,%xdefine,%ixdefine, + %assign,%iassign,%undef + +-*- A new directive [WARNING {+|-}warning-id] have been added. It works only + if the assembly phase is enabled (i.e. it doesn't work with nasm -e). + +-*- A new warning type: macro-selfref. By default this warning is disabled; + when enabled NASM warns when a macro self-references itself; for example + the following source: + + [WARNING macro-selfref] + + %macro push 1-* + %rep %0 + push %1 + %rotate 1 + %endrep + %endmacro + + push eax,ebx,ecx + + will produce a warning, but if we remove the first line we won't see it + anymore (which is The Right Thing To Do {tm} IMHO since C preprocessor + eats such constructs without warnings at all). + +-*- Added a "error" routine to preprocessor which always will set ERR_PASS1 + bit in severity_code. This removes annoying repeated errors on first + and second passes from preprocessor. + +-*- Added the %+ operator in single-line macros for concatenating two + identifiers. Usage example: + + %define _myfunc _otherfunc + %define cextern(x) _ %+ x + cextern (myfunc) + + After first expansion, third line will become "_myfunc". After this + expansion is performed again so it becomes "_otherunc". + +-*- Now if preprocessor is in a non-emmitting state, no warning or error + will be emmitted. Example: + + %if 1 + mov eax,ebx + %else + put anything you want between these two brackets, + even macro-parameter references %1 or local labels %$zz + or macro-local labels %%zz - no warning will be emmitted. + %endif + +-*- Context-local variables on expansion as a last resort are looked up + in outer contexts. For example, the following piece: + + %push outer + %define %$a [esp] + + %push inner + %$a + %pop + %pop + + will expand correctly the fourth line to [esp]; if we'll define another + %$a inside the "inner" context, it will take precedence over outer + definition. However, this modification has been applied only to + expand_smacro and not to smacro_define: as a consequence expansion + looks in outer contexts, but %ifdef won't look in outer contexts. + + This behaviour is needed because we don't want nested contexts to + act on already defined local macros. Example: + + %define %$arg1 [esp+4] + test eax,eax + if nz + mov eax,%$arg1 + endif + + In this example the "if" mmacro enters into the "if" context, so %$arg1 + is not valid anymore inside "if". Of course it could be worked around + by using explicitely %$$arg1 but this is ugly IMHO. + +-*- Fixed memory leak in %undef. The origline wasn't freed before + exiting on success. + +-*- Fixed trap in preprocessor when line expanded to empty set of tokens. + This happens, for example, in the following case: + + #define SOMETHING + SOMETHING diff --git a/standard.mac b/standard.mac index 05905d6..58e65df 100644 --- a/standard.mac +++ b/standard.mac @@ -96,3 +96,13 @@ __SECT__ [cpu %1] %endmacro + +; Macros to make NASM ignore some TASM directives before the first include +; directive. + +%idefine IDEAL +%idefine JUMPS +%idefine P386 +%idefine P486 +%idefine P586 +%idefine END diff --git a/test/bintest.asm b/test/bintest.asm index 6799b38..94d2bf7 100644 --- a/test/bintest.asm +++ b/test/bintest.asm @@ -26,7 +26,7 @@ jmp start ; [6] -end mov ax,0x4c00 ; [1] +endX mov ax,0x4c00 ; [1] int 0x21 start mov byte [bss_sym],',' ; [1] [8] @@ -49,7 +49,7 @@ start mov byte [bss_sym],',' ; [1] [8] datasym db 'hello world', 13, 10, '$' ; [2] bssptr dw bss_sym ; [2] [11] dataptr dw datasym+5 ; [2] [10] -textptr dw end ; [2] [9] +textptr dw endX ; [2] [9] SECTION .bss diff --git a/test/test1.asm b/test/test1.asm deleted file mode 100644 index ce24ca1..0000000 --- a/test/test1.asm +++ /dev/null @@ -1,62 +0,0 @@ - segment text - bits 16 - - imul edx,[addr],10 - imul eax,20 - imul edx,eax,130 - - push 0x40 - push word 0x40 - push word 4095 - push byte 0x40 - push dword 0x40 - push dword 4095 - - add ax,1 - add bx,1 - cmp cx,0 - sub dx,3 - sbb si,-1 - xor ax,0xffff - xor ax,-1 - xor bx,0xffff - xor bx,-1 - - - adc bx,add1 - adc bx,-7 - adc bx,-128 - adc bx,-129 - adc bx,addr - adc bx,byte -7 -add1: adc bx,word -7 - adc bx,add1 - resb 256 -addr: nop - adc bx,addr - adc eax,5 - adc eax,500 - adc eax,byte 5 - adc ax,4 - adc ebx,7 - adc ebx,700 - adc ebx,byte 7 - adc ecx,1 - adc eax,1 - - shr edx,mmm - shr edx,one - adc ebx,byte mmm -m1: adc ebx,mmm -mmm equ 9 -m2: adc ebx,mmm -one equ 1 - shr edx,mmm - shr edx,one - shr edx,1 -tend dw tend - - segment data - db 'abc' - db '', 12, 13, 0 - diff --git a/test/test2.asm b/test/test2.asm deleted file mode 100644 index 5bbb034..0000000 --- a/test/test2.asm +++ /dev/null @@ -1,18 +0,0 @@ - USE16 - CPU 386 - -debugdump001: -goo: jmp foo - jc near foo - mov ax,[si+5] - mov ax,[si-7] - mov ax,[si+n] - nop - resb 10 -foo: jmp goo - jc goo - jmp short goo -debugdump002: push 0 -n equ 3 - - diff --git a/test/test2a.asm b/test/test2a.asm deleted file mode 100644 index 2ed09a7..0000000 --- a/test/test2a.asm +++ /dev/null @@ -1,22 +0,0 @@ - use32 - cpu P3 - -debugdump001: -goo: jmp foo -; cpu 386 - jc near foo - mov ax,[si+5] - mov ax,[si-7] - mov ax,[si+n] - align 16 -; cpu 486 - bswap edx -; cpu 186 - resb 10 -foo: jmp goo - jc goo - jmp short goo -debugdump002: push 0 -n equ 3 - - diff --git a/test/test3.asm b/test/test3.asm deleted file mode 100644 index 457ed44..0000000 --- a/test/test3.asm +++ /dev/null @@ -1,45 +0,0 @@ -debugdump001: - jc baker - jmp able - 20 - jmp able -baker: nop - times 125 nop -able: jmp baker - jmp baker + 20 - times 122 nop - jmp able -loc: nop - jc able+20 - - jmp able1 - 20 - jmp able1 -baker1: nop - times 126 nop -able1: jmp near baker1 - jmp baker1 + 20 - times 122 nop - jmp able1 -loc1: nop - -able2: jmp baker2 - times 124 nop - jmp able2 - nop -baker2: nop - - - -able3: jmp baker3 - times 124 nop - jmp able3 - nop - nop -baker3: nop -debugdump099: nop - - - - - - - diff --git a/test/test4.asm b/test/test4.asm deleted file mode 100644 index 357553e..0000000 --- a/test/test4.asm +++ /dev/null @@ -1,16 +0,0 @@ - cpu 186 - -start: jmp able - xor ax,ax - jc start - jnc able - jc charlie - times 100 nop -able: jc start - times 100 nop -baker: jc start - times 100 nop -charlie: jc baker - jnc able - jmp start -end: db 0 diff --git a/test/test4a.asm b/test/test4a.asm deleted file mode 100644 index bbf85a3..0000000 --- a/test/test4a.asm +++ /dev/null @@ -1,16 +0,0 @@ - cpu 386 - -start: jmp able - xor ax,ax - jc start - jnc able - jc charlie - times 100 nop -able: jc start - times 100 nop -baker: jc start - times 100 nop -charlie: jc baker - jnc able - jmp start -end: db 0 diff --git a/test/test4b.asm b/test/test4b.asm deleted file mode 100644 index 6344881..0000000 --- a/test/test4b.asm +++ /dev/null @@ -1,17 +0,0 @@ - use32 - cpu 186 - -start: jmp able - xor ax,ax - jc start - jnc able - jc charlie - times 100 nop -able: jc start - times 100 nop -baker: jc start - times 100 nop -charlie: jc baker - jnc able - jmp start -end: db 0 diff --git a/test/test4c.asm b/test/test4c.asm deleted file mode 100644 index 5d87349..0000000 --- a/test/test4c.asm +++ /dev/null @@ -1,17 +0,0 @@ - use32 - cpu 386 - -start: jmp able - xor ax,ax - jc start - jnc able - jc charlie - times 100 nop -able: jc start - times 100 nop -baker: jc start - times 100 nop -charlie: jc baker - jnc able - jmp start -end: db 0 diff --git a/test/test5.asm b/test/test5.asm deleted file mode 100644 index 12b0ee4..0000000 --- a/test/test5.asm +++ /dev/null @@ -1,43 +0,0 @@ -%macro pushm 1-* -%rep %0 -%rotate -1 -push %1 -%endrep -%endmacro - -%macro popm 1-* -%rep %0 -pop %1 -%rotate 1 -%endrep -%endmacro - -%macro pusha 0 -push ax -push cx -push dx -push bx -push bp -mov bp,sp -lea bp,[bp+10] -xchg bp,[bp-10] -push bp -push si -push di -%endmacro - -%macro popa 0 -pop di -pop si -pop bp -pop bx -pop bx -pop dx -pop cx -pop ax -%endmacro - - pushm ax,bx,cx,dx - popm ax,bx,cx,dx - pusha - popa diff --git a/test/test6.asm b/test/test6.asm deleted file mode 100644 index cf6dca0..0000000 --- a/test/test6.asm +++ /dev/null @@ -1,9 +0,0 @@ -; test6.asm -; assemble with; nasm -O2 ... -; -%rep 20000 - jmp forward -%endrep -forward: dd forward - -
\ No newline at end of file |