0
0
mirror of https://github.com/netwide-assembler/nasm.git synced 2025-08-23 10:33:50 -04:00

NASM 0.95

This commit is contained in:
H. Peter Anvin 2002-04-30 20:52:26 +00:00
parent d7ed89eac9
commit 6768eb71d8
44 changed files with 2278 additions and 428 deletions

120
Changes
View File

@ -82,8 +82,8 @@ seg-fault under Linux.
Included a new Borland C makefile, Makefile.bc2, donated by Fox Included a new Borland C makefile, Makefile.bc2, donated by Fox
Cutter <lmb@comtch.iea.com>. Cutter <lmb@comtch.iea.com>.
0.94 not released yet 0.94 released April 1997
--------------------- ------------------------
Major item: added the macro processor. Major item: added the macro processor.
@ -124,4 +124,120 @@ Due to the advent of the preprocessor, the [INCLUDE] and [INC]
directives have become obsolete. They are still supported in this directives have become obsolete. They are still supported in this
version, with a warning, but won't be in the next. version, with a warning, but won't be in the next.
Fixed a bug in OBJ format, which caused incorrect object records to
be output when absolute labels were made global.
Updates to RDOFF subdirectory, and changes to outrdf.c. Updates to RDOFF subdirectory, and changes to outrdf.c.
0.95 released July 1997
-----------------------
Fixed yet another ELF bug. This one manifested if the user relied on
the default segment, and attempted to define global symbols without
first explicitly declaring the target segment.
Added makefiles (for NASM and the RDF tools) to build Win32 console
apps under Symantec C++. Donated by Mark Junker.
Added `macros.bas' and `insns.bas', QBasic versions of the Perl
scripts that convert `standard.mac' to `macros.c' and convert
`insns.dat' to `insnsa.c' and `insnsd.c'. Also thanks to Mark
Junker.
Changed the diassembled forms of the conditional instructions so
that JB is now emitted as JC, and other similar changes. Suggested
list by Ulrich Doewich.
Added `@' to the list of valid characters to begin an identifier
with.
Documentary changes, notably the addition of the `Common Problems'
section in nasm.doc.
Fixed a bug relating to 32-bit PC-relative fixups in OBJ.
Fixed a bug in perm_copy() in labels.c which was causing exceptions
in cleanup_labels() on some systems.
Positivity sanity check in TIMES argument changed from a warning to
an error following a further complaint.
Changed the acceptable limits on byte and word operands to allow
things like `~10111001b' to work.
Fixed a major problem in the preprocessor which caused seg-faults if
macro definitions contained blank lines or comment-only lines.
Fixed inadequate error checking on the commas separating the
arguments to `db', `dw' etc.
Fixed a crippling bug in the handling of macros with operand counts
defined with a `+' modifier.
Fixed a bug whereby object file formats which stored the input file
name in the output file (such as OBJ and COFF) weren't doing so
correctly when the output file name was specified on the command
line.
Removed [INC] and [INCLUDE] support for good, since they were
obsolete anyway.
Fixed a bug in OBJ which caused all fixups to be output in 16-bit
(old-format) FIXUPP records, rather than putting the 32-bit ones in
FIXUPP32 (new-format) records.
Added, tentatively, OS/2 object file support (as a minor variant on
OBJ).
Updates to Fox Cutter's Borland C makefile, Makefile.bc2.
Removed a spurious second fclose() on the output file.
Added the `-s' command line option to redirect all messages which
would go to stderr (errors, help text) to stdout instead.
Added the `-w' command line option to selectively suppress some
classes of assembly warning messages.
Added the `-p' pre-include and `-d' pre-define command-line options.
Added an include file search path: the `-i' command line option.
Fixed a silly little preprocessor bug whereby starting a line with a
`%!' environment-variable reference caused an `unknown directive'
error.
Added the long-awaited listing file support: the `-l' command line
option.
Fixed a problem with OBJ format whereby, in the absence of any
explicit segment definition, non-global symbols declared in the
implicit default segment generated spurious EXTDEF records in the
output.
Added the NASM environment variable.
From this version forward, Win32 console-mode binaries will be
included in the DOS distribution in addition to the 16-bit binaries.
Added Makefile.vc for this purpose.
Added `return 0;' to test/objlink.c to prevent compiler warnings.
Added the __NASM_MAJOR__ and __NASM_MINOR__ standard defines.
Added an alternative memory-reference syntax in which prefixing an
operand with `&' is equivalent to enclosing it in square brackets,
at the request of Fox Cutter.
Errors in pass two now cause the program to return a non-zero error
code, which they didn't before.
Fixed the single-line macro cycle detection, which didn't work at
all on macros with no parameters (caused an infinite loop). Also
changed the behaviour of single-line macro cycle detection to work
like cpp, so that macros like `extrn' as given in the documentation
can be implemented.
Fixed the implementation of WRT, which was too restrictive in that
you couldn't do `mov ax,[di+abc wrt dgroup]' because (di+abc) wasn't
a relocatable reference.

View File

@ -32,7 +32,7 @@ NASMOBJS = nasm.$(OBJ) nasmlib.$(OBJ) float.$(OBJ) insnsa.$(OBJ) \
assemble.$(OBJ) labels.$(OBJ) parser.$(OBJ) outform.$(OBJ) \ assemble.$(OBJ) labels.$(OBJ) parser.$(OBJ) outform.$(OBJ) \
outbin.$(OBJ) outaout.$(OBJ) outcoff.$(OBJ) outelf.$(OBJ) \ outbin.$(OBJ) outaout.$(OBJ) outcoff.$(OBJ) outelf.$(OBJ) \
outobj.$(OBJ) outas86.$(OBJ) outrdf.$(OBJ) outdbg.$(OBJ) \ outobj.$(OBJ) outas86.$(OBJ) outrdf.$(OBJ) outdbg.$(OBJ) \
preproc.$(OBJ) preproc.$(OBJ) listing.$(OBJ)
NDISASMOBJS = ndisasm.$(OBJ) disasm.$(OBJ) sync.$(OBJ) nasmlib.$(OBJ) \ NDISASMOBJS = ndisasm.$(OBJ) disasm.$(OBJ) sync.$(OBJ) nasmlib.$(OBJ) \
insnsd.$(OBJ) insnsd.$(OBJ)
@ -45,26 +45,30 @@ nasm$(EXE): $(NASMOBJS)
ndisasm$(EXE): $(NDISASMOBJS) ndisasm$(EXE): $(NDISASMOBJS)
$(LINK) $(DLINKFLAGS) $(NDISASMOBJS) $(LIBRARIES) $(LINK) $(DLINKFLAGS) $(NDISASMOBJS) $(LIBRARIES)
assemble.$(OBJ): assemble.c nasm.h assemble.h insns.h assemble.$(OBJ): assemble.c nasm.h nasmlib.h assemble.h insns.h
disasm.$(OBJ): disasm.c nasm.h disasm.h sync.h insns.h names.c disasm.$(OBJ): disasm.c nasm.h disasm.h sync.h insns.h names.c
float.$(OBJ): float.c nasm.h float.$(OBJ): float.c nasm.h
insnsa.$(OBJ): insnsa.c nasm.h insns.h insnsa.$(OBJ): insnsa.c nasm.h insns.h
insnsd.$(OBJ): insnsd.c nasm.h insns.h insnsd.$(OBJ): insnsd.c nasm.h insns.h
labels.$(OBJ): labels.c nasm.h nasmlib.h labels.$(OBJ): labels.c nasm.h nasmlib.h
nasm.$(OBJ): nasm.c nasm.h nasmlib.h parser.h assemble.h labels.h outform.h listing.$(OBJ): listing.c nasm.h nasmlib.h listing.h
macros.$(OBJ): macros.c
names.$(OBJ): names.c
nasm.$(OBJ): nasm.c nasm.h nasmlib.h preproc.h parser.h assemble.h labels.h \
outform.h listing.h
nasmlib.$(OBJ): nasmlib.c nasm.h nasmlib.h nasmlib.$(OBJ): nasmlib.c nasm.h nasmlib.h
ndisasm.$(OBJ): ndisasm.c nasm.h sync.h disasm.h ndisasm.$(OBJ): ndisasm.c nasm.h nasmlib.h sync.h disasm.h
outas86.$(OBJ): outas86.c nasm.h nasmlib.h outaout.$(OBJ): outaout.c nasm.h nasmlib.h outform.h
outaout.$(OBJ): outaout.c nasm.h nasmlib.h outas86.$(OBJ): outas86.c nasm.h nasmlib.h outform.h
outbin.$(OBJ): outbin.c nasm.h nasmlib.h outbin.$(OBJ): outbin.c nasm.h nasmlib.h outform.h
outcoff.$(OBJ): outcoff.c nasm.h nasmlib.h outcoff.$(OBJ): outcoff.c nasm.h nasmlib.h outform.h
outdbg.$(OBJ): outdbg.c nasm.h nasmlib.h outdbg.$(OBJ): outdbg.c nasm.h nasmlib.h outform.h
outelf.$(OBJ): outelf.c nasm.h nasmlib.h outelf.$(OBJ): outelf.c nasm.h nasmlib.h outform.h
outobj.$(OBJ): outobj.c nasm.h nasmlib.h
outrdf.$(OBJ): outrdf.c nasm.h nasmlib.h
outform.$(OBJ): outform.c outform.h nasm.h outform.$(OBJ): outform.c outform.h nasm.h
outobj.$(OBJ): outobj.c nasm.h nasmlib.h outform.h
outrdf.$(OBJ): outrdf.c nasm.h nasmlib.h outform.h
parser.$(OBJ): parser.c nasm.h nasmlib.h parser.h float.h names.c parser.$(OBJ): parser.c nasm.h nasmlib.h parser.h float.h names.c
preproc.$(OBJ): preproc.c macros.c preproc.h nasm.h nasmlib.h preproc.$(OBJ): preproc.c nasm.h nasmlib.h macros.c
sync.$(OBJ): sync.c sync.h sync.$(OBJ): sync.c sync.h
# These two source files are automagically generated from a single # These two source files are automagically generated from a single
@ -94,7 +98,6 @@ clean :
# unless you're using the Makefile under Linux, running bash, with # unless you're using the Makefile under Linux, running bash, with
# gzip, GNU tar and a sensible version of zip readily available. # gzip, GNU tar and a sensible version of zip readily available.
DOSEXES = nasm.exe ndisasm.exe
MANPAGES = nasm.man ndisasm.man MANPAGES = nasm.man ndisasm.man
.SUFFIXES: .man .1 .SUFFIXES: .man .1
@ -102,5 +105,5 @@ MANPAGES = nasm.man ndisasm.man
.1.man: .1.man:
-man ./$< | ul > $@ -man ./$< | ul > $@
dist: $(AUTOSRCS) $(MANPAGES) $(DOSEXES) clean dist: $(AUTOSRCS) $(MANPAGES) clean
makedist.sh makedist.sh

View File

@ -27,20 +27,43 @@
# Libaries, if not you'll get some errors. Make sure to keep the trailing # Libaries, if not you'll get some errors. Make sure to keep the trailing
# backslash, as it's needed, and remeber to use \\ not \ as that will cause # backslash, as it's needed, and remeber to use \\ not \ as that will cause
# some errors. # some errors.
#
# Also inportant, if you get a DGROUP error when you compile NASM, remove
# or comment out the 'NASMSize=l' line, and uncoment (remove the #) from the
# NASMSize=h line. Then run 'make Clean' to delete the object files. Then run
# make again to re-build NASM as huge.
#
# History:
# 06/13/97: * Added the EXED varable for the location to put the EXE files.
# * Because different versions of Borland and Turbo C have
# different GROUPings for the DGROUP, some version, when you
# compile NASM, you will get a DGROUP overflow error, making it
# so NASM has to be compiled as huge. As this isn't a constant
# through systems (and apperently some version of Borland,
# compileing as huge causes some errors) the NASMSize verable
# has been added to spicify what size of code you want to
# compile as and defaults to large.
# 06/16/97: * Added 'merge dupicate strings' to the options for compiles.
NASMSize=l #Compile Nasm as Large
#NASMSize=h #Compile Nasm as Huge
LIB =c:\\tc\\lib\\ #location standard libaries LIB =c:\\tc\\lib\\ #location standard libaries
OBJD=obj\\ #directory to put OBJ files in OBJD=obj\\ #directory to put OBJ files in
EXED=.\ #directory to put the EXE files.
CC = tcc #compiler CC = tcc #compiler
LINK = tlink #linker LINK = tlink #linker
CCFLAGS = /c /O /A /ml /n$(OBJD) #compiler flags for NASM CCFLAGS = /d /c /O /A /m$(NASMSize) /n$(OBJD) #compiler flags for NASM
#/d=merge dupicate strings
#/c=compile only #/c=compile only
#/O=Optimise jumps #/O=Optimise jumps
#/A=ANSI standard C #/A=ANSI standard C
#/ml=Model Large #/m$(NASMSize>=the model to use
#/n$(OBJD)= put the OBJ files in the diectory given. #/n$(OBJD)= put the OBJ files in the diectory given.
DCCFLAGS = /c /O /A /mh /n$(OBJD) #compiler flags for NDISASM DCCFLAGS = /d /c /O /A /mh /n$(OBJD) #compiler flags for NDISASM
#/d=merge dupicate strings
#/c=compile only #/c=compile only
#/O=Optimise jumps #/O=Optimise jumps
#/A=ANSI standard C #/A=ANSI standard C
@ -71,7 +94,8 @@ DASM_ASM=$(CC) $(DCCFLAGS) $&.c #command line for NDISASM
NASMOBJS = $(OBJD)nasm.$(OBJ) $(OBJD)nasmlib.$(OBJ) $(OBJD)float.$(OBJ) \ NASMOBJS = $(OBJD)nasm.$(OBJ) $(OBJD)nasmlib.$(OBJ) $(OBJD)float.$(OBJ) \
$(OBJD)insnsa.$(OBJ) $(OBJD)assemble.$(OBJ) $(OBJD)labels.$(OBJ) \ $(OBJD)insnsa.$(OBJ) $(OBJD)assemble.$(OBJ) $(OBJD)labels.$(OBJ) \
$(OBJD)parser.$(OBJ) $(OBJD)outform.$(OBJ) $(OBJD)preproc.$(OBJ) $(OBJD)parser.$(OBJ) $(OBJD)outform.$(OBJ) $(OBJD)preproc.$(OBJ) \
$(OBJD)listing.$(OBJ)
################################################################ ################################################################
#The OBJ files that NDISASM is dependent on #The OBJ files that NDISASM is dependent on
@ -96,17 +120,17 @@ all : nasm$(EXE) ndisasm$(EXE)
#NASM, NDISASM compile, I hope it's self explanitorie #NASM, NDISASM compile, I hope it's self explanitorie
nasm$(EXE): $(NASMOBJS) $(OUTOBJ) nasm$(EXE): $(NASMOBJS) $(OUTOBJ)
$(LINK) $(LINKFLAGS) @&&^ #command for the linker $(LINK) $(LINKFLAGS) @&&^ #command for the linker
$(LIB)c0l.obj $(NASMOBJS) $(OUTOBJ) #OBJ file list, $(LIB)c0$(NASMSize).obj $(NASMOBJS) $(OUTOBJ) #OBJ file list
nasm$(EXE) #EXE file name $(EXED)nasm$(EXE) #EXE file name
# No need of a map file # No need of a map file
$(LIB)cl.lib $(LIBRARIES) #Libaries needed $(LIB)c$(NASMSize).lib $(LIBRARIES) #Libaries needed
^ ^
ndisasm$(EXE): $(NDISASMOBJS) ndisasm$(EXE): $(NDISASMOBJS)
$(LINK) $(LINKFLAGS) @&&^ #command for the linker $(LINK) $(LINKFLAGS) @&&^ #command for the linker
$(LIB)c0h.obj $(NDISASMOBJS) #OBJ file list $(LIB)c0h.obj $(NDISASMOBJS) #OBJ file list
ndisasm$(EXE) #EXE file name $(EXED)ndisasm$(EXE) #EXE file name
# No need of a map file # No need of a map file
$(LIB)ch.lib $(LIBRARIES) #Libaries needed $(LIB)ch.lib $(LIBRARIES) #Libaries needed
^ ^
@ -123,8 +147,11 @@ $(OBJD)float.$(OBJ): float.c nasm.h
$(OBJD)labels.$(OBJ): labels.c nasm.h nasmlib.h $(OBJD)labels.$(OBJ): labels.c nasm.h nasmlib.h
$(NASM_ASM) $(NASM_ASM)
$(OBJD)nasm.$(OBJ): nasm.c nasm.h nasmlib.h parser.h assemble.h labels.h $(OBJD)listing.$(OBJ): listing.c nasm.h nasmlib.h listing.h
outform.h $(NASM_ASM)
$(OBJD)nasm.$(OBJ): nasm.c nasm.h nasmlib.h parser.h assemble.h labels.h \
listing.h outform.h
$(NASM_ASM) $(NASM_ASM)
$(OBJD)nasmlib.$(OBJ): nasmlib.c nasm.h nasmlib.h $(OBJD)nasmlib.$(OBJ): nasmlib.c nasm.h nasmlib.h
@ -155,10 +182,10 @@ $(OBJD)insnsd.$(OBJ): insnsd.c nasm.h insns.h
$(DASM_ASM) $(DASM_ASM)
# This is a kludge from the word go, as we can't use the nasmlib.obj compiled # This is a kludge from the word go, as we can't use the nasmlib.obj compiled
# for NASM, as it's the wrong model size, so we have to compile it again, # for NASM, as it's could be the wrong model size, so we have to compile it
# but in huge. # again as huge to make sure.
# #
# So as not to overwrite the nasmlib.obj for NASM (if I did, that # So as not to overwrite the nasmlib.obj for NASM (if it did, that
# could cause all kinds of problems) it compiles it into nasmlibd.obj. # could cause all kinds of problems) it compiles it into nasmlibd.obj.
# #
# the -o... switch tells it the name to compile the obj file to, right here # the -o... switch tells it the name to compile the obj file to, right here
@ -205,4 +232,4 @@ clean :
del nasm$(EXE) del nasm$(EXE)
del ndisasm$(EXE) del ndisasm$(EXE)
# Makefile created by Fox Cutter <lmb@comtch.iea.com> --01/21/97 # Makefile created by Fox Cutter <lmb@comtch.iea.com> --01/27/97

View File

@ -27,7 +27,7 @@ NASMOBJS1 = nasm.$(OBJ) nasmlib.$(OBJ) float.$(OBJ) insnsa.$(OBJ)
NASMOBJS2 = assemble.$(OBJ) labels.$(OBJ) parser.$(OBJ) outform.$(OBJ) NASMOBJS2 = assemble.$(OBJ) labels.$(OBJ) parser.$(OBJ) outform.$(OBJ)
NASMOBJS3 = outbin.$(OBJ) outaout.$(OBJ) outcoff.$(OBJ) outelf.$(OBJ) NASMOBJS3 = outbin.$(OBJ) outaout.$(OBJ) outcoff.$(OBJ) outelf.$(OBJ)
NASMOBJS4 = outobj.$(OBJ) outas86.$(OBJ) outdbg.$(OBJ) outrdf.$(OBJ) NASMOBJS4 = outobj.$(OBJ) outas86.$(OBJ) outdbg.$(OBJ) outrdf.$(OBJ)
NASMOBJS5 = preproc.$(OBJ) NASMOBJS5 = preproc.$(OBJ) listing.$(OBJ)
NASMOBJS = $(NASMOBJS1) $(NASMOBJS2) $(NASMOBJS3) $(NASMOBJS4) $(NASMOBJS5) NASMOBJS = $(NASMOBJS1) $(NASMOBJS2) $(NASMOBJS3) $(NASMOBJS4) $(NASMOBJS5)
@ -57,7 +57,9 @@ float.$(OBJ): float.c nasm.h
insnsa.$(OBJ): insnsa.c nasm.h insns.h insnsa.$(OBJ): insnsa.c nasm.h insns.h
insnsd.$(OBJ): insnsd.c nasm.h insns.h insnsd.$(OBJ): insnsd.c nasm.h insns.h
labels.$(OBJ): labels.c nasm.h nasmlib.h labels.$(OBJ): labels.c nasm.h nasmlib.h
nasm.$(OBJ): nasm.c nasm.h nasmlib.h parser.h assemble.h labels.h outform.h listing.$(OBJ): listing.c nasm.h nasmlib.h listing.h
nasm.$(OBJ): nasm.c nasm.h nasmlib.h parser.h assemble.h labels.h \
listing.h outform.h
nasmlib.$(OBJ): nasmlib.c nasm.h nasmlib.h nasmlib.$(OBJ): nasmlib.c nasm.h nasmlib.h
ndisasm.$(OBJ): ndisasm.c nasm.h sync.h disasm.h ndisasm.$(OBJ): ndisasm.c nasm.h sync.h disasm.h
outas86.$(OBJ): outas86.c nasm.h nasmlib.h outas86.$(OBJ): outas86.c nasm.h nasmlib.h

View File

@ -10,8 +10,8 @@
# It's been tested with Microsoft C 5.x plus Borland Make. (Yes, I # It's been tested with Microsoft C 5.x plus Borland Make. (Yes, I
# know it's silly, but...) # know it's silly, but...)
CC = cl CC = cl /c /O /AL
CCFLAGS = /c /O /AL QCL = qcl /c /AL
LINK = cl LINK = cl
LINKFLAGS = LINKFLAGS =
LIBRARIES = LIBRARIES =
@ -19,13 +19,13 @@ EXE = .exe#
OBJ = obj# OBJ = obj#
.c.$(OBJ): .c.$(OBJ):
$(CC) $(CCFLAGS) $*.c $(CC) $*.c
NASMOBJS = nasm.$(OBJ) nasmlib.$(OBJ) float.$(OBJ) insnsa.$(OBJ) \ NASMOBJS = nasm.$(OBJ) nasmlib.$(OBJ) float.$(OBJ) insnsa.$(OBJ) \
assemble.$(OBJ) labels.$(OBJ) parser.$(OBJ) outform.$(OBJ) \ assemble.$(OBJ) labels.$(OBJ) parser.$(OBJ) outform.$(OBJ) \
outbin.$(OBJ) outaout.$(OBJ) outcoff.$(OBJ) outelf.$(OBJ) \ outbin.$(OBJ) outaout.$(OBJ) outcoff.$(OBJ) outelf.$(OBJ) \
outobj.$(OBJ) outas86.$(OBJ) outrdf.$(OBJ) outdbg.$(OBJ) \ outobj.$(OBJ) outas86.$(OBJ) outrdf.$(OBJ) outdbg.$(OBJ) \
preproc.$(OBJ) preproc.$(OBJ) listing.$(OBJ)
NDISASMOBJS = ndisasm.$(OBJ) disasm.$(OBJ) sync.$(OBJ) nasmlib.$(OBJ) \ NDISASMOBJS = ndisasm.$(OBJ) disasm.$(OBJ) sync.$(OBJ) nasmlib.$(OBJ) \
insnsd.$(OBJ) insnsd.$(OBJ)
@ -45,7 +45,9 @@ assemble.$(OBJ): assemble.c nasm.h assemble.h insns.h
disasm.$(OBJ): disasm.c nasm.h disasm.h sync.h insns.h names.c disasm.$(OBJ): disasm.c nasm.h disasm.h sync.h insns.h names.c
float.$(OBJ): float.c nasm.h float.$(OBJ): float.c nasm.h
labels.$(OBJ): labels.c nasm.h nasmlib.h labels.$(OBJ): labels.c nasm.h nasmlib.h
nasm.$(OBJ): nasm.c nasm.h nasmlib.h parser.h assemble.h labels.h outform.h listing.$(OBJ): listing.c nasm.h nasmlib.h listing.h
nasm.$(OBJ): nasm.c nasm.h nasmlib.h parser.h assemble.h labels.h \
listing.h outform.h
nasmlib.$(OBJ): nasmlib.c nasm.h nasmlib.h nasmlib.$(OBJ): nasmlib.c nasm.h nasmlib.h
ndisasm.$(OBJ): ndisasm.c nasm.h sync.h disasm.h ndisasm.$(OBJ): ndisasm.c nasm.h sync.h disasm.h
outas86.$(OBJ): outas86.c nasm.h nasmlib.h outas86.$(OBJ): outas86.c nasm.h nasmlib.h
@ -65,9 +67,9 @@ sync.$(OBJ): sync.c sync.h
# CL proper; and we don't need any optimisation in these modules # CL proper; and we don't need any optimisation in these modules
# since they're just data. # since they're just data.
insnsa.$(OBJ): insnsa.c nasm.h insns.h insnsa.$(OBJ): insnsa.c nasm.h insns.h
qcl /c /AL insnsa.c $(QCL) insnsa.c
insnsd.$(OBJ): insnsd.c nasm.h insns.h insnsd.$(OBJ): insnsd.c nasm.h insns.h
qcl /c /AL insnsd.c $(QCL) insnsd.c
clean : clean :
del *.obj del *.obj

222
Makefile.sc Normal file
View File

@ -0,0 +1,222 @@
# Makefile for the Netwide Assembler under 32-bit Windows(tm)
#
# 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 to build NASM using the 32-bit WIN32 C
# compiler Symantec(tm) C++ 7.5, provided you have a MAKE-utility
# that's compatible to SMAKE.
CC = sc
CCFLAGS = -c -a1 -mn -Nc -w2 -w7 -o+time -5
# -5 optimize for pentium (tm)
# -c compile only
# -o-all no optimizations (to avoid problems in disasm.c)
# -o+time optimize for speed
# -o+space optimize for size
# -A1 byte alignment for structures
# -mn compile for Win32 executable
# -Nc create COMDAT records
# -w2 possible unattended assignment: off
# -w7 for loops with empty instruction-body
LINK = link
LINKFLAGS = /noi /exet:NT /su:console
# /noignorecase all symbols are case-sensitive
# /exet:NT Exetype: NT (Win32)
# /su:console Subsystem: Console (Console-App)
LIBRARIES =
EXE = .exe
OBJ = obj
.c.$(OBJ):
$(CC) $(CCFLAGS) $*.c
#
# modules needed for different programs
#
NASMOBJS = nasm.$(OBJ) nasmlib.$(OBJ) float.$(OBJ) insnsa.$(OBJ) \
assemble.$(OBJ) labels.$(OBJ) parser.$(OBJ) outform.$(OBJ) \
outbin.$(OBJ) outaout.$(OBJ) outcoff.$(OBJ) outelf.$(OBJ) \
outobj.$(OBJ) outas86.$(OBJ) outrdf.$(OBJ) outdbg.$(OBJ) \
preproc.$(OBJ) listing.$(OBJ)
NDISASMOBJS = ndisasm.$(OBJ) disasm.$(OBJ) sync.$(OBJ) nasmlib.$(OBJ) \
insnsd.$(OBJ)
#
# programs to create
#
all : nasm$(EXE) ndisasm$(EXE)
#
# We have to have a horrible kludge here to get round the 128 character
# limit, as usual... we'll simply use LNK-files :)
#
nasm$(EXE): $(NASMOBJS)
$(LINK) $(LINKFLAGS) @<<
$(NASMOBJS)
nasm.exe;
<<
ndisasm$(EXE): $(NDISASMOBJS)
$(LINK) $(LINKFLAGS) @<<
$(NDISASMOBJS)
ndisasm.exe;
<<
#
# modules for programs
#
disasm.$(OBJ): disasm.c nasm.h disasm.h sync.h insns.h names.c
assemble.$(OBJ): assemble.c nasm.h assemble.h insns.h
float.$(OBJ): float.c nasm.h
labels.$(OBJ): labels.c nasm.h nasmlib.h
listing.$(OBJ): listing.c nasm.h nasmlib.h listing.h
nasm.$(OBJ): nasm.c nasm.h nasmlib.h parser.h assemble.h labels.h \
listing.h outform.h
nasmlib.$(OBJ): nasmlib.c nasm.h nasmlib.h
ndisasm.$(OBJ): ndisasm.c nasm.h sync.h disasm.h
outas86.$(OBJ): outas86.c nasm.h nasmlib.h
outaout.$(OBJ): outaout.c nasm.h nasmlib.h
outbin.$(OBJ): outbin.c nasm.h nasmlib.h
outcoff.$(OBJ): outcoff.c nasm.h nasmlib.h
outdbg.$(OBJ): outdbg.c nasm.h nasmlib.h
outelf.$(OBJ): outelf.c nasm.h nasmlib.h
outobj.$(OBJ): outobj.c nasm.h nasmlib.h
outrdf.$(OBJ): outrdf.c nasm.h nasmlib.h
outform.$(OBJ): outform.c outform.h nasm.h
parser.$(OBJ): parser.c nasm.h nasmlib.h parser.h float.h names.c
preproc.$(OBJ): preproc.c macros.c preproc.h nasm.h nasmlib.h
sync.$(OBJ): sync.c sync.h
insnsa.$(OBJ): insnsa.c nasm.h insns.h
insnsd.$(OBJ): insnsd.c nasm.h insns.h
clean :
del *.obj
del nasm$(EXE)
del ndisasm$(EXE)

76
Makefile.vc Normal file
View File

@ -0,0 +1,76 @@
# Makefile for the Netwide Assembler under Win32
#
# 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 to build NASM as a Win32 command-
# line executable. It's been tested with Visual C++ 1.10.
CC = cl /c /O
QCL = cl /c
LINK = cl
LINKFLAGS =
LIBRARIES =
EXE = .exe#
OBJ = obj#
SUFFIX = w# # by default, this makefile produces nasmw.exe and ndisasmw.exe
.c.$(OBJ):
$(CC) $*.c
NASMOBJS = nasm.$(OBJ) nasmlib.$(OBJ) float.$(OBJ) insnsa.$(OBJ) \
assemble.$(OBJ) labels.$(OBJ) parser.$(OBJ) outform.$(OBJ) \
outbin.$(OBJ) outaout.$(OBJ) outcoff.$(OBJ) outelf.$(OBJ) \
outobj.$(OBJ) outas86.$(OBJ) outrdf.$(OBJ) outdbg.$(OBJ) \
preproc.$(OBJ) listing.$(OBJ)
NDISASMOBJS = ndisasm.$(OBJ) disasm.$(OBJ) sync.$(OBJ) nasmlib.$(OBJ) \
insnsd.$(OBJ)
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 f*.obj insnsa.obj l*.obj na*.obj o*.obj p*.obj
nasm$(SUFFIX)$(EXE): $(NASMOBJS)
cl /Fenasm$(SUFFIX).exe $(LINKOBJS)
ndisasm$(SUFFIX)$(EXE): $(NDISASMOBJS)
cl /Fendisasm$(SUFFIX).exe $(NDISASMOBJS)
assemble.$(OBJ): assemble.c nasm.h assemble.h insns.h
disasm.$(OBJ): disasm.c nasm.h disasm.h sync.h insns.h names.c
float.$(OBJ): float.c nasm.h
labels.$(OBJ): labels.c nasm.h nasmlib.h
listing.$(OBJ): listing.c nasm.h nasmlib.h listing.h
nasm.$(OBJ): nasm.c nasm.h nasmlib.h parser.h assemble.h labels.h \
listing.h outform.h
nasmlib.$(OBJ): nasmlib.c nasm.h nasmlib.h
ndisasm.$(OBJ): ndisasm.c nasm.h sync.h disasm.h
outas86.$(OBJ): outas86.c nasm.h nasmlib.h
outaout.$(OBJ): outaout.c nasm.h nasmlib.h
outbin.$(OBJ): outbin.c nasm.h nasmlib.h
outcoff.$(OBJ): outcoff.c nasm.h nasmlib.h
outdbg.$(OBJ): outdbg.c nasm.h nasmlib.h
outelf.$(OBJ): outelf.c nasm.h nasmlib.h
outobj.$(OBJ): outobj.c nasm.h nasmlib.h
outrdf.$(OBJ): outrdf.c nasm.h nasmlib.h
outform.$(OBJ): outform.c outform.h nasm.h
parser.$(OBJ): parser.c nasm.h nasmlib.h parser.h float.h names.c
preproc.$(OBJ): preproc.c macros.c preproc.h nasm.h nasmlib.h
sync.$(OBJ): sync.c sync.h
# Another grotty hack: QC is less likely to run out of memory than
# CL proper; and we don't need any optimisation in these modules
# since they're just data.
insnsa.$(OBJ): insnsa.c nasm.h insns.h
$(QCL) insnsa.c
insnsd.$(OBJ): insnsd.c nasm.h insns.h
$(QCL) insnsd.c
clean :
del *.obj
del nasm$(SUFFIX)$(EXE)
del ndisasm$(SUFFIX)$(EXE)

View File

@ -42,7 +42,7 @@ NASMOBJS = nasm.$(OBJ) nasmlib.$(OBJ) float.$(OBJ) insnsa.$(OBJ) \
assemble.$(OBJ) labels.$(OBJ) parser.$(OBJ) outform.$(OBJ) \ assemble.$(OBJ) labels.$(OBJ) parser.$(OBJ) outform.$(OBJ) \
outbin.$(OBJ) outaout.$(OBJ) outcoff.$(OBJ) outelf.$(OBJ) \ outbin.$(OBJ) outaout.$(OBJ) outcoff.$(OBJ) outelf.$(OBJ) \
outobj.$(OBJ) outas86.$(OBJ) outrdf.$(OBJ) outdbg.$(OBJ) \ outobj.$(OBJ) outas86.$(OBJ) outrdf.$(OBJ) outdbg.$(OBJ) \
preproc.$(OBJ) preproc.$(OBJ) listing.$(OBJ)
NDISASMOBJS = ndisasm.$(OBJ) disasm.$(OBJ) sync.$(OBJ) nasmlib.$(OBJ) \ NDISASMOBJS = ndisasm.$(OBJ) disasm.$(OBJ) sync.$(OBJ) nasmlib.$(OBJ) \
insnsd.$(OBJ) insnsd.$(OBJ)
@ -92,7 +92,9 @@ float.$(OBJ): float.c nasm.h
insnsa.$(OBJ): insnsa.c nasm.h insns.h insnsa.$(OBJ): insnsa.c nasm.h insns.h
insnsd.$(OBJ): insnsd.c nasm.h insns.h insnsd.$(OBJ): insnsd.c nasm.h insns.h
labels.$(OBJ): labels.c nasm.h nasmlib.h labels.$(OBJ): labels.c nasm.h nasmlib.h
nasm.$(OBJ): nasm.c nasm.h nasmlib.h parser.h assemble.h labels.h outform.h listing.$(OBJ): listing.c nasm.h nasmlib.h listing.h
nasm.$(OBJ): nasm.c nasm.h nasmlib.h parser.h assemble.h labels.h \
listing.h outform.h
nasmlib.$(OBJ): nasmlib.c nasm.h nasmlib.h nasmlib.$(OBJ): nasmlib.c nasm.h nasmlib.h
ndisasm.$(OBJ): ndisasm.c nasm.h sync.h disasm.h ndisasm.$(OBJ): ndisasm.c nasm.h sync.h disasm.h
outas86.$(OBJ): outas86.c nasm.h nasmlib.h outas86.$(OBJ): outas86.c nasm.h nasmlib.h

View File

@ -42,7 +42,7 @@ NASMOBJS = nasm.$(OBJ) nasmlib.$(OBJ) float.$(OBJ) insnsa.$(OBJ) \
assemble.$(OBJ) labels.$(OBJ) parser.$(OBJ) outform.$(OBJ) \ assemble.$(OBJ) labels.$(OBJ) parser.$(OBJ) outform.$(OBJ) \
outbin.$(OBJ) outaout.$(OBJ) outcoff.$(OBJ) outelf.$(OBJ) \ outbin.$(OBJ) outaout.$(OBJ) outcoff.$(OBJ) outelf.$(OBJ) \
outobj.$(OBJ) outas86.$(OBJ) outrdf.$(OBJ) outdbg.$(OBJ) \ outobj.$(OBJ) outas86.$(OBJ) outrdf.$(OBJ) outdbg.$(OBJ) \
preproc.$(OBJ) preproc.$(OBJ) listing.$(OBJ)
NDISASMOBJS = ndisasm.$(OBJ) disasm.$(OBJ) sync.$(OBJ) nasmlib.$(OBJ) \ NDISASMOBJS = ndisasm.$(OBJ) disasm.$(OBJ) sync.$(OBJ) nasmlib.$(OBJ) \
insnsd.$(OBJ) insnsd.$(OBJ)
@ -92,7 +92,9 @@ float.$(OBJ): float.c nasm.h
insnsa.$(OBJ): insnsa.c nasm.h insns.h insnsa.$(OBJ): insnsa.c nasm.h insns.h
insnsd.$(OBJ): insnsd.c nasm.h insns.h insnsd.$(OBJ): insnsd.c nasm.h insns.h
labels.$(OBJ): labels.c nasm.h nasmlib.h labels.$(OBJ): labels.c nasm.h nasmlib.h
nasm.$(OBJ): nasm.c nasm.h nasmlib.h parser.h assemble.h labels.h outform.h listing.$(OBJ): listing.c nasm.h nasmlib.h listing.h
nasm.$(OBJ): nasm.c nasm.h nasmlib.h parser.h assemble.h labels.h \
listing.h outform.h
nasmlib.$(OBJ): nasmlib.c nasm.h nasmlib.h nasmlib.$(OBJ): nasmlib.c nasm.h nasmlib.h
ndisasm.$(OBJ): ndisasm.c nasm.h sync.h disasm.h ndisasm.$(OBJ): ndisasm.c nasm.h sync.h disasm.h
outas86.$(OBJ): outas86.c nasm.h nasmlib.h outas86.$(OBJ): outas86.c nasm.h nasmlib.h

48
Readme
View File

@ -1,8 +1,8 @@
This is a distribution of NASM, the Netwide Assembler. NASM is a This is a distribution of NASM, the Netwide Assembler. NASM is a
prototype general-purpose x86 assembler. It will currently output prototype general-purpose x86 assembler. It will currently output
flat-form binary files, a.out, COFF and ELF Unix object files, flat-form binary files, a.out, COFF and ELF Unix object files,
Microsoft 16-bit DOS and Win32 object files, the as86 object format, Microsoft Win32 and 16-bit DOS object files, OS/2 object files, the
and a home-grown format called RDF. as86 object format, and a home-grown format called RDF.
Also included is NDISASM, a prototype x86 binary-file disassembler Also included is NDISASM, a prototype x86 binary-file disassembler
which uses the same instruction table as NASM. which uses the same instruction table as NASM.
@ -14,24 +14,38 @@ access). You may also want to copy the man page `nasm.1' (and maybe
`ndisasm.1') to somewhere sensible. `ndisasm.1') to somewhere sensible.
To rebuild the DOS sources, various makefiles are provided: To rebuild the DOS sources, various makefiles are provided:
- Makefile.dos, the one I build the standard releases from, designed
for a hybrid system using Microsoft C and Borland Make (don't ask - Makefile.dos, the one I build the standard 16-bit releases from,
why :-) designed for a hybrid system using Microsoft C and Borland Make
- Makefile.bor (for Borland C) (don't ask why :-)
- Makefile.bc2 (also for Borland C, contributed by Fox Cutter - Makefile.vc, for Microsoft Visual C++ compiling to a Win32
<lmb@comtch.iea.com>, may work better than Makefile.bor in some command-line application. This is the one I build the standard
cases). Win32 release binaries from.
- Makefile.bor, for Borland C.
- Makefile.bc2, also for Borland C, contributed by Fox Cutter.
Reported to work better than Makefile.bor on some systems.
- Makefile.sc, for Symantec C++. Contributed by Mark Junker.
- Makefile.wc, for Watcom C, compiling to a 32-bit extended DOS - Makefile.wc, for Watcom C, compiling to a 32-bit extended DOS
executable. Contributed by Dominik Behr. executable. Contributed by Dominik Behr.
- Makefile.wcw, also for Watcom C, compiling to a Win32 command- - Makefile.wcw, also for Watcom C, compiling to a Win32 command-
line application. Also contributed by Dominik Behr. line application. Also contributed by Dominik Behr.
I don't guarantee that any of those, other than Makefile.dos, work, I can't guarantee that all of those makefiles work, because I don't
since I don't have the compilers to test them myself. Also be have all of those compilers. However, Makefile.dos and Makefile.vc
warned: I have had various conflicting reports regarding building work on my system, and so do Makefile.bor and Makefile.bc2.
NASM using Borland C. Several people have informed me that it
doesn't work except under Huge model, and one or two have said that Be careful with Borland C: there have been various conflicting
it doesn't work under Huge model either. reports about how reliable the Huge memory model is. If you try to
compile NASM in Large model, you may get DGROUP overflows due to the
vast quantity of data in the instruction tables. I've had reports
from some people that Huge model doesn't work at all (and also
reports from others that it works fine), so if you don't want to try
moving to Huge, you could try adding the option `-dc' to the
compiler command line instead, which causes string literals to be
moved from DGROUP to the code segments and might make Large model
start working. (Either solution works for me.)
Dominik Behr has also contributed the file misc/pmw.bat, which is a Dominik Behr has also contributed the file misc/pmw.bat, which is a
batch file to turn the output from Makefile.wc (NASM.EXE and batch file to turn the output from Makefile.wc (NASM.EXE and
@ -85,5 +99,7 @@ information about the internal structure of NASM, see
`internal.doc'. (In particular, _please_ read `internal.doc' before `internal.doc'. (In particular, _please_ read `internal.doc' before
writing any code for us...) writing any code for us...)
The NASM web page is at http://www.cryogen.com/Nasm/
Bug reports (and patches if you can) should be sent to Bug reports (and patches if you can) should be sent to
<jules@dcs.warwick.ac.uk> or <anakin@pobox.com>. <jules@earthcorp.com> or <anakin@pobox.com>.

View File

@ -53,6 +53,7 @@
#include <string.h> #include <string.h>
#include "nasm.h" #include "nasm.h"
#include "nasmlib.h"
#include "assemble.h" #include "assemble.h"
#include "insns.h" #include "insns.h"
@ -67,6 +68,7 @@ typedef struct {
static efunc errfunc; static efunc errfunc;
static struct ofmt *outfmt; static struct ofmt *outfmt;
static ListGen *list;
static long calcsize (long, long, int, insn *, char *); static long calcsize (long, long, int, insn *, char *);
static void gencode (long, long, int, insn *, char *, long); static void gencode (long, long, int, insn *, char *, long);
@ -75,8 +77,49 @@ static int matches (struct itemplate *, insn *);
static ea *process_ea (operand *, ea *, int, int, int); static ea *process_ea (operand *, ea *, int, int, int);
static int chsize (operand *, int); static int chsize (operand *, int);
/*
* This routine wrappers the real output format's output routine,
* in order to pass a copy of the data off to the listing file
* generator at the same time.
*/
static void out (long offset, long segto, void *data, unsigned long type,
long segment, long wrt) {
if ((type & OUT_TYPMASK) == OUT_ADDRESS) {
if (segment != NO_SEG || wrt != NO_SEG) {
/*
* This address is relocated. We must write it as
* OUT_ADDRESS, so there's no work to be done here.
*/
list->output (offset, data, type);
} else {
unsigned char p[4], *q = p;
/*
* This is a non-relocated address, and we're going to
* convert it into RAWDATA format.
*/
if ((type & OUT_SIZMASK) == 4) {
WRITELONG (q, * (long *) data);
list->output (offset, p, OUT_RAWDATA+4);
} else {
WRITESHORT (q, * (long *) data);
list->output (offset, p, OUT_RAWDATA+2);
}
}
} else if ((type & OUT_TYPMASK) == OUT_RAWDATA) {
list->output (offset, data, type);
} else if ((type & OUT_TYPMASK) == OUT_RESERVE) {
list->output (offset, NULL, type);
} else if ((type & OUT_TYPMASK) == OUT_REL2ADR ||
(type & OUT_TYPMASK) == OUT_REL4ADR) {
list->output (offset, data, type);
}
outfmt->output (segto, data, type, segment, wrt);
}
long assemble (long segment, long offset, int bits, long assemble (long segment, long offset, int bits,
insn *instruction, struct ofmt *output, efunc error) { insn *instruction, struct ofmt *output, efunc error,
ListGen *listgen) {
int j, size_prob; int j, size_prob;
long insn_end, itimes; long insn_end, itimes;
long start = offset; long start = offset;
@ -84,6 +127,7 @@ long assemble (long segment, long offset, int bits,
errfunc = error; /* to pass to other functions */ errfunc = error; /* to pass to other functions */
outfmt = output; /* likewise */ outfmt = output; /* likewise */
list = listgen; /* and again */
if (instruction->opcode == -1) if (instruction->opcode == -1)
return 0; return 0;
@ -114,16 +158,16 @@ long assemble (long segment, long offset, int bits,
"one-byte relocation attempted"); "one-byte relocation attempted");
else { else {
unsigned char c = e->offset; unsigned char c = e->offset;
outfmt->output (segment, &c, OUT_RAWDATA+1, out (offset, segment, &c, OUT_RAWDATA+1,
NO_SEG, NO_SEG); NO_SEG, NO_SEG);
} }
} else if (wsize > 5) { } else if (wsize > 5) {
errfunc (ERR_NONFATAL, "integer supplied to a D%c" errfunc (ERR_NONFATAL, "integer supplied to a D%c"
" instruction", wsize==8 ? 'Q' : 'T'); " instruction", wsize==8 ? 'Q' : 'T');
} else } else
outfmt->output (segment, &e->offset, out (offset, segment, &e->offset,
OUT_ADDRESS+wsize, e->segment, OUT_ADDRESS+wsize, e->segment,
e->wrt); e->wrt);
offset += wsize; offset += wsize;
} else if (e->type == EOT_DB_STRING) { } else if (e->type == EOT_DB_STRING) {
int align; int align;
@ -131,15 +175,25 @@ long assemble (long segment, long offset, int bits,
align = (-e->stringlen) % wsize; align = (-e->stringlen) % wsize;
if (align < 0) if (align < 0)
align += wsize; align += wsize;
outfmt->output (segment, e->stringval, out (offset, segment, e->stringval,
OUT_RAWDATA+e->stringlen, NO_SEG, NO_SEG); OUT_RAWDATA+e->stringlen, NO_SEG, NO_SEG);
if (align) if (align)
outfmt->output (segment, "\0\0\0\0", out (offset, segment, "\0\0\0\0",
OUT_RAWDATA+align, NO_SEG, NO_SEG); OUT_RAWDATA+align, NO_SEG, NO_SEG);
offset += e->stringlen + align; offset += e->stringlen + align;
} }
} }
if (t > 0 && t == instruction->times-1) {
/*
* Dummy call to list->output to give the offset to the
* listing module.
*/
list->output (offset, NULL, OUT_RAWDATA);
list->uplevel (LIST_TIMES);
}
} }
if (instruction->times > 1)
list->downlevel (LIST_TIMES);
return offset - start; return offset - start;
} }
@ -170,6 +224,12 @@ long assemble (long segment, long offset, int bits,
len > instruction->eops->next->next->offset) len > instruction->eops->next->next->offset)
len = instruction->eops->next->next->offset; len = instruction->eops->next->next->offset;
} }
/*
* Dummy call to list->output to give the offset to the
* listing module.
*/
list->output (offset, NULL, OUT_RAWDATA);
list->uplevel(LIST_INCBIN);
while (t--) { while (t--) {
fseek (fp, fseek (fp,
(instruction->eops->next ? (instruction->eops->next ?
@ -189,11 +249,21 @@ long assemble (long segment, long offset, int bits,
" reading file `%s'", fname); " reading file `%s'", fname);
return 0; /* it doesn't much matter... */ return 0; /* it doesn't much matter... */
} }
outfmt->output (segment, buf, OUT_RAWDATA+m, out (offset, segment, buf, OUT_RAWDATA+m,
NO_SEG, NO_SEG); NO_SEG, NO_SEG);
l -= m; l -= m;
} }
} }
list->downlevel(LIST_INCBIN);
if (instruction->times > 1) {
/*
* Dummy call to list->output to give the offset to the
* listing module.
*/
list->output (offset, NULL, OUT_RAWDATA);
list->uplevel(LIST_TIMES);
list->downlevel(LIST_TIMES);
}
fclose (fp); fclose (fp);
return instruction->times * len; return instruction->times * len;
} }
@ -257,13 +327,23 @@ long assemble (long segment, long offset, int bits,
"invalid instruction prefix"); "invalid instruction prefix");
} }
if (c != 0) if (c != 0)
outfmt->output (segment, &c, OUT_RAWDATA+1, out (offset, segment, &c, OUT_RAWDATA+1,
NO_SEG, NO_SEG); NO_SEG, NO_SEG);
offset++; offset++;
} }
gencode (segment, offset, bits, instruction, codes, insn_end); gencode (segment, offset, bits, instruction, codes, insn_end);
offset += insn_size; offset += insn_size;
if (itimes > 0 && itimes == instruction->times-1) {
/*
* Dummy call to list->output to give the offset to the
* listing module.
*/
list->output (offset, NULL, OUT_RAWDATA);
list->uplevel (LIST_TIMES);
}
} }
if (instruction->times > 1)
list->downlevel (LIST_TIMES);
return offset - start; return offset - start;
} else if (m > 0) { } else if (m > 0) {
size_prob = m; size_prob = m;
@ -473,7 +553,7 @@ static void gencode (long segment, long offset, int bits,
while (*codes) switch (c = *codes++) { while (*codes) switch (c = *codes++) {
case 01: case 02: case 03: case 01: case 02: case 03:
outfmt->output (segment, codes, OUT_RAWDATA+c, NO_SEG, NO_SEG); out (offset, segment, codes, OUT_RAWDATA+c, NO_SEG, NO_SEG);
codes += c; codes += c;
offset += c; offset += c;
break; break;
@ -486,7 +566,7 @@ static void gencode (long segment, long offset, int bits,
default: default:
errfunc (ERR_PANIC, "bizarre 8086 segment register received"); errfunc (ERR_PANIC, "bizarre 8086 segment register received");
} }
outfmt->output (segment, bytes, OUT_RAWDATA+1, NO_SEG, NO_SEG); out (offset, segment, bytes, OUT_RAWDATA+1, NO_SEG, NO_SEG);
offset++; offset++;
break; break;
case 05: case 07: case 05: case 07:
@ -496,48 +576,48 @@ static void gencode (long segment, long offset, int bits,
default: default:
errfunc (ERR_PANIC, "bizarre 386 segment register received"); errfunc (ERR_PANIC, "bizarre 386 segment register received");
} }
outfmt->output (segment, bytes, OUT_RAWDATA+1, NO_SEG, NO_SEG); out (offset, segment, bytes, OUT_RAWDATA+1, NO_SEG, NO_SEG);
offset++; offset++;
break; break;
case 010: case 011: case 012: case 010: case 011: case 012:
bytes[0] = *codes++ + regval(&ins->oprs[c-010]); bytes[0] = *codes++ + regval(&ins->oprs[c-010]);
outfmt->output (segment, bytes, OUT_RAWDATA+1, NO_SEG, NO_SEG); out (offset, segment, bytes, OUT_RAWDATA+1, NO_SEG, NO_SEG);
offset += 1; offset += 1;
break; break;
case 017: case 017:
bytes[0] = 0; bytes[0] = 0;
outfmt->output (segment, bytes, OUT_RAWDATA+1, NO_SEG, NO_SEG); out (offset, segment, bytes, OUT_RAWDATA+1, NO_SEG, NO_SEG);
offset += 1; offset += 1;
break; break;
case 014: case 015: case 016: case 014: case 015: case 016:
if (ins->oprs[c-014].offset < -128 || ins->oprs[c-014].offset > 127) if (ins->oprs[c-014].offset < -128 || ins->oprs[c-014].offset > 127)
errfunc (ERR_WARNING, "signed byte value exceeds bounds"); errfunc (ERR_WARNING, "signed byte value exceeds bounds");
bytes[0] = ins->oprs[c-014].offset; bytes[0] = ins->oprs[c-014].offset;
outfmt->output (segment, bytes, OUT_RAWDATA+1, NO_SEG, NO_SEG); out (offset, segment, bytes, OUT_RAWDATA+1, NO_SEG, NO_SEG);
offset += 1; offset += 1;
break; break;
case 020: case 021: case 022: case 020: case 021: case 022:
if (ins->oprs[c-020].offset < -128 || ins->oprs[c-020].offset > 255) if (ins->oprs[c-020].offset < -256 || ins->oprs[c-020].offset > 255)
errfunc (ERR_WARNING, "byte value exceeds bounds"); errfunc (ERR_WARNING, "byte value exceeds bounds");
bytes[0] = ins->oprs[c-020].offset; bytes[0] = ins->oprs[c-020].offset;
outfmt->output (segment, bytes, OUT_RAWDATA+1, NO_SEG, NO_SEG); out (offset, segment, bytes, OUT_RAWDATA+1, NO_SEG, NO_SEG);
offset += 1; offset += 1;
break; break;
case 024: case 025: case 026: case 024: case 025: case 026:
if (ins->oprs[c-024].offset < 0 || ins->oprs[c-024].offset > 255) if (ins->oprs[c-024].offset < 0 || ins->oprs[c-024].offset > 255)
errfunc (ERR_WARNING, "unsigned byte value exceeds bounds"); errfunc (ERR_WARNING, "unsigned byte value exceeds bounds");
bytes[0] = ins->oprs[c-024].offset; bytes[0] = ins->oprs[c-024].offset;
outfmt->output (segment, bytes, OUT_RAWDATA+1, NO_SEG, NO_SEG); out (offset, segment, bytes, OUT_RAWDATA+1, NO_SEG, NO_SEG);
offset += 1; offset += 1;
break; break;
case 030: case 031: case 032: case 030: case 031: case 032:
if (ins->oprs[c-030].segment == NO_SEG && if (ins->oprs[c-030].segment == NO_SEG &&
ins->oprs[c-030].wrt == NO_SEG && ins->oprs[c-030].wrt == NO_SEG &&
(ins->oprs[c-030].offset < -32768L || (ins->oprs[c-030].offset < -65536L ||
ins->oprs[c-030].offset > 65535L)) ins->oprs[c-030].offset > 65535L))
errfunc (ERR_WARNING, "word value exceeds bounds"); errfunc (ERR_WARNING, "word value exceeds bounds");
data = ins->oprs[c-030].offset; data = ins->oprs[c-030].offset;
outfmt->output (segment, &data, OUT_ADDRESS+2, out (offset, segment, &data, OUT_ADDRESS+2,
ins->oprs[c-030].segment, ins->oprs[c-030].wrt); ins->oprs[c-030].segment, ins->oprs[c-030].wrt);
offset += 2; offset += 2;
break; break;
@ -545,10 +625,10 @@ static void gencode (long segment, long offset, int bits,
data = ins->oprs[c-034].offset; data = ins->oprs[c-034].offset;
size = ((ins->oprs[c-034].addr_size ? size = ((ins->oprs[c-034].addr_size ?
ins->oprs[c-034].addr_size : bits) == 16 ? 2 : 4); ins->oprs[c-034].addr_size : bits) == 16 ? 2 : 4);
if (size==16 && (data < -32768L || data > 65535L)) if (size==16 && (data < -65536L || data > 65535L))
errfunc (ERR_WARNING, "word value exceeds bounds"); errfunc (ERR_WARNING, "word value exceeds bounds");
outfmt->output (segment, &data, OUT_ADDRESS+size, out (offset, segment, &data, OUT_ADDRESS+size,
ins->oprs[c-034].segment, ins->oprs[c-034].wrt); ins->oprs[c-034].segment, ins->oprs[c-034].wrt);
offset += size; offset += size;
break; break;
case 037: case 037:
@ -556,15 +636,15 @@ static void gencode (long segment, long offset, int bits,
errfunc (ERR_NONFATAL, "value referenced by FAR is not" errfunc (ERR_NONFATAL, "value referenced by FAR is not"
" relocatable"); " relocatable");
data = 0L; data = 0L;
outfmt->output (segment, &data, OUT_ADDRESS+2, out (offset, segment, &data, OUT_ADDRESS+2,
outfmt->segbase(1+ins->oprs[0].segment), outfmt->segbase(1+ins->oprs[0].segment),
ins->oprs[0].wrt); ins->oprs[0].wrt);
offset += 2; offset += 2;
break; break;
case 040: case 041: case 042: case 040: case 041: case 042:
data = ins->oprs[c-040].offset; data = ins->oprs[c-040].offset;
outfmt->output (segment, &data, OUT_ADDRESS+4, out (offset, segment, &data, OUT_ADDRESS+4,
ins->oprs[c-040].segment, ins->oprs[c-040].wrt); ins->oprs[c-040].segment, ins->oprs[c-040].wrt);
offset += 4; offset += 4;
break; break;
case 050: case 051: case 052: case 050: case 051: case 052:
@ -574,17 +654,18 @@ static void gencode (long segment, long offset, int bits,
if (data > 127 || data < -128) if (data > 127 || data < -128)
errfunc (ERR_NONFATAL, "short jump is out of range"); errfunc (ERR_NONFATAL, "short jump is out of range");
bytes[0] = data; bytes[0] = data;
outfmt->output (segment, bytes, OUT_RAWDATA+1, NO_SEG, NO_SEG); out (offset, segment, bytes, OUT_RAWDATA+1, NO_SEG, NO_SEG);
offset += 1; offset += 1;
break; break;
case 060: case 061: case 062: case 060: case 061: case 062:
if (ins->oprs[c-060].segment != segment) { if (ins->oprs[c-060].segment != segment) {
data = ins->oprs[c-060].offset; data = ins->oprs[c-060].offset;
outfmt->output (segment, &data, OUT_REL2ADR+insn_end-offset, out (offset, segment, &data, OUT_REL2ADR+insn_end-offset,
ins->oprs[c-060].segment, ins->oprs[c-060].wrt); ins->oprs[c-060].segment, ins->oprs[c-060].wrt);
} else { } else {
data = ins->oprs[c-060].offset - insn_end; data = ins->oprs[c-060].offset - insn_end;
outfmt->output (segment, &data, OUT_ADDRESS+2, NO_SEG, NO_SEG); out (offset, segment, &data,
OUT_ADDRESS+2, NO_SEG, NO_SEG);
} }
offset += 2; offset += 2;
break; break;
@ -594,30 +675,33 @@ static void gencode (long segment, long offset, int bits,
if (ins->oprs[c-064].segment != segment) { if (ins->oprs[c-064].segment != segment) {
data = ins->oprs[c-064].offset; data = ins->oprs[c-064].offset;
size = (bits == 16 ? OUT_REL2ADR : OUT_REL4ADR); size = (bits == 16 ? OUT_REL2ADR : OUT_REL4ADR);
outfmt->output (segment, &data, size+insn_end-offset, out (offset, segment, &data, size+insn_end-offset,
ins->oprs[c-064].segment, ins->oprs[c-064].wrt); ins->oprs[c-064].segment, ins->oprs[c-064].wrt);
size = (bits == 16 ? 2 : 4); size = (bits == 16 ? 2 : 4);
} else { } else {
data = ins->oprs[c-064].offset - insn_end; data = ins->oprs[c-064].offset - insn_end;
outfmt->output (segment, &data, OUT_ADDRESS+size, NO_SEG, NO_SEG); out (offset, segment, &data,
OUT_ADDRESS+size, NO_SEG, NO_SEG);
} }
offset += size; offset += size;
break; break;
case 070: case 071: case 072: case 070: case 071: case 072:
if (ins->oprs[c-070].segment != segment) { if (ins->oprs[c-070].segment != segment) {
data = ins->oprs[c-070].offset; data = ins->oprs[c-070].offset;
outfmt->output (segment, &data, OUT_REL4ADR+insn_end-offset, out (offset, segment, &data, OUT_REL4ADR+insn_end-offset,
ins->oprs[c-070].segment, ins->oprs[c-070].wrt); ins->oprs[c-070].segment, ins->oprs[c-070].wrt);
} else { } else {
data = ins->oprs[c-070].offset - insn_end; data = ins->oprs[c-070].offset - insn_end;
outfmt->output (segment, &data, OUT_ADDRESS+4, NO_SEG, NO_SEG); out (offset, segment, &data,
OUT_ADDRESS+4, NO_SEG, NO_SEG);
} }
offset += 4; offset += 4;
break; break;
case 0300: case 0301: case 0302: case 0300: case 0301: case 0302:
if (chsize (&ins->oprs[c-0300], bits)) { if (chsize (&ins->oprs[c-0300], bits)) {
*bytes = 0x67; *bytes = 0x67;
outfmt->output (segment, bytes, OUT_RAWDATA+1, NO_SEG, NO_SEG); out (offset, segment, bytes,
OUT_RAWDATA+1, NO_SEG, NO_SEG);
offset += 1; offset += 1;
} else } else
offset += 0; offset += 0;
@ -625,7 +709,8 @@ static void gencode (long segment, long offset, int bits,
case 0310: case 0310:
if (bits==32) { if (bits==32) {
*bytes = 0x67; *bytes = 0x67;
outfmt->output (segment, bytes, OUT_RAWDATA+1, NO_SEG, NO_SEG); out (offset, segment, bytes,
OUT_RAWDATA+1, NO_SEG, NO_SEG);
offset += 1; offset += 1;
} else } else
offset += 0; offset += 0;
@ -633,7 +718,8 @@ static void gencode (long segment, long offset, int bits,
case 0311: case 0311:
if (bits==16) { if (bits==16) {
*bytes = 0x67; *bytes = 0x67;
outfmt->output (segment, bytes, OUT_RAWDATA+1, NO_SEG, NO_SEG); out (offset, segment, bytes,
OUT_RAWDATA+1, NO_SEG, NO_SEG);
offset += 1; offset += 1;
} else } else
offset += 0; offset += 0;
@ -643,7 +729,8 @@ static void gencode (long segment, long offset, int bits,
case 0320: case 0320:
if (bits==32) { if (bits==32) {
*bytes = 0x66; *bytes = 0x66;
outfmt->output (segment, bytes, OUT_RAWDATA+1, NO_SEG, NO_SEG); out (offset, segment, bytes,
OUT_RAWDATA+1, NO_SEG, NO_SEG);
offset += 1; offset += 1;
} else } else
offset += 0; offset += 0;
@ -651,7 +738,8 @@ static void gencode (long segment, long offset, int bits,
case 0321: case 0321:
if (bits==16) { if (bits==16) {
*bytes = 0x66; *bytes = 0x66;
outfmt->output (segment, bytes, OUT_RAWDATA+1, NO_SEG, NO_SEG); out (offset, segment, bytes,
OUT_RAWDATA+1, NO_SEG, NO_SEG);
offset += 1; offset += 1;
} else } else
offset += 0; offset += 0;
@ -660,7 +748,8 @@ static void gencode (long segment, long offset, int bits,
break; break;
case 0330: case 0330:
*bytes = *codes++ + condval[ins->condition]; *bytes = *codes++ + condval[ins->condition];
outfmt->output (segment, bytes, OUT_RAWDATA+1, NO_SEG, NO_SEG); out (offset, segment, bytes,
OUT_RAWDATA+1, NO_SEG, NO_SEG);
offset += 1; offset += 1;
break; break;
case 0340: case 0341: case 0342: case 0340: case 0341: case 0342:
@ -668,7 +757,8 @@ static void gencode (long segment, long offset, int bits,
errfunc (ERR_PANIC, "non-constant BSS size in pass two"); errfunc (ERR_PANIC, "non-constant BSS size in pass two");
else { else {
long size = ins->oprs[0].offset << (c-0340); long size = ins->oprs[0].offset << (c-0340);
outfmt->output (segment, NULL, OUT_RESERVE+size, NO_SEG, NO_SEG); out (offset, segment, NULL,
OUT_RESERVE+size, NO_SEG, NO_SEG);
offset += size; offset += size;
} }
break; break;
@ -694,8 +784,8 @@ static void gencode (long segment, long offset, int bits,
/* /*
* the cast in the next line is to placate MS C... * the cast in the next line is to placate MS C...
*/ */
outfmt->output (segment, bytes, OUT_RAWDATA+(long)(p-bytes), out (offset, segment, bytes, OUT_RAWDATA+(long)(p-bytes),
NO_SEG, NO_SEG); NO_SEG, NO_SEG);
s = p-bytes; s = p-bytes;
switch (ea_data.bytes) { switch (ea_data.bytes) {
@ -703,16 +793,16 @@ static void gencode (long segment, long offset, int bits,
break; break;
case 1: case 1:
*bytes = ins->oprs[(c>>3)&7].offset; *bytes = ins->oprs[(c>>3)&7].offset;
outfmt->output (segment, bytes, OUT_RAWDATA+1, out (offset, segment, bytes, OUT_RAWDATA+1,
NO_SEG, NO_SEG); NO_SEG, NO_SEG);
s++; s++;
break; break;
case 2: case 2:
case 4: case 4:
data = ins->oprs[(c>>3)&7].offset; data = ins->oprs[(c>>3)&7].offset;
outfmt->output (segment, &data, OUT_ADDRESS+ea_data.bytes, out (offset, segment, &data,
ins->oprs[(c>>3)&7].segment, OUT_ADDRESS+ea_data.bytes,
ins->oprs[(c>>3)&7].wrt); ins->oprs[(c>>3)&7].segment, ins->oprs[(c>>3)&7].wrt);
s += ea_data.bytes; s += ea_data.bytes;
break; break;
} }

View File

@ -12,6 +12,7 @@
long insn_size (long segment, long offset, int bits, long insn_size (long segment, long offset, int bits,
insn *instruction, efunc error); insn *instruction, efunc error);
long assemble (long segment, long offset, int bits, long assemble (long segment, long offset, int bits,
insn *instruction, struct ofmt *output, efunc error); insn *instruction, struct ofmt *output, efunc error,
ListGen *listgen);
#endif #endif

View File

@ -96,8 +96,8 @@ static int whichreg(long regflags, int regval) {
static char *whichcond(int condval) { static char *whichcond(int condval) {
static int conds[] = { static int conds[] = {
C_O, C_NO, C_B, C_AE, C_E, C_NE, C_BE, C_A, C_O, C_NO, C_C, C_NC, C_Z, C_NZ, C_NA, C_A,
C_S, C_NS, C_PE, C_PO, C_L, C_GE, C_LE, C_G C_S, C_NS, C_PE, C_PO, C_L, C_NL, C_NG, C_G
}; };
return conditions[conds[condval]]; return conditions[conds[condval]];
} }

16
float.c
View File

@ -55,7 +55,8 @@ static int multiply(unsigned short *to, unsigned short *from) {
} }
} }
static void flconvert(char *string, unsigned short *mant, long *exponent) { static void flconvert(char *string, unsigned short *mant, long *exponent,
efunc error) {
char digits[MANT_DIGITS], *p, *q, *r; char digits[MANT_DIGITS], *p, *q, *r;
unsigned short mult[MANT_WORDS], *m, bit; unsigned short mult[MANT_WORDS], *m, bit;
long tenpwr, twopwr; long tenpwr, twopwr;
@ -69,7 +70,8 @@ static void flconvert(char *string, unsigned short *mant, long *exponent) {
if (!seendot) if (!seendot)
seendot = TRUE; seendot = TRUE;
else { else {
fprintf(stderr, "too many periods!\n"); error (ERR_NONFATAL,
"too many periods in floating-point constant");
return; return;
} }
} else if (*string >= '0' && *string <= '9') { } else if (*string >= '0' && *string <= '9') {
@ -84,7 +86,9 @@ static void flconvert(char *string, unsigned short *mant, long *exponent) {
tenpwr++; tenpwr++;
} }
} else { } else {
fprintf(stderr, "`%c' is invalid char\n", *string); error (ERR_NONFATAL,
"floating-point constant: `%c' is invalid character",
*string);
return; return;
} }
string++; string++;
@ -209,7 +213,7 @@ static int to_double(char *str, long sign, unsigned char *result,
sign = (sign < 0 ? 0x8000L : 0L); sign = (sign < 0 ? 0x8000L : 0L);
flconvert (str, mant, &exponent); flconvert (str, mant, &exponent, error);
if (mant[0] & 0x8000) { if (mant[0] & 0x8000) {
/* /*
* Non-zero. * Non-zero.
@ -269,7 +273,7 @@ static int to_float(char *str, long sign, unsigned char *result,
sign = (sign < 0 ? 0x8000L : 0L); sign = (sign < 0 ? 0x8000L : 0L);
flconvert (str, mant, &exponent); flconvert (str, mant, &exponent, error);
if (mant[0] & 0x8000) { if (mant[0] & 0x8000) {
/* /*
* Non-zero. * Non-zero.
@ -322,7 +326,7 @@ static int to_ldoub(char *str, long sign, unsigned char *result,
sign = (sign < 0 ? 0x8000L : 0L); sign = (sign < 0 ? 0x8000L : 0L);
flconvert (str, mant, &exponent); flconvert (str, mant, &exponent, error);
if (mant[0] & 0x8000) { if (mant[0] & 0x8000) {
/* /*
* Non-zero. * Non-zero.

View File

@ -138,7 +138,7 @@ sub format {
# \17 means byte zero # \17 means byte zero
# \330 means byte plus condition code # \330 means byte plus condition code
# \0 or \340 mean give up and return empty set # \0 or \340 mean give up and return empty set
sub startbyte { # FIXME we cheat, for now :-) sub startbyte {
local ($codes) = @_; local ($codes) = @_;
local $word, @range; local $word, @range;

View File

@ -15,8 +15,10 @@ look like:
| float.c | | float.c |
| | | |
+--- assemble.c ---+ +--- assemble.c ---+
nasm.c ---+ | +--- nasmlib.c | | |
| insnsa.c | nasm.c ---+ insnsa.c +--- nasmlib.c
| |
+--- listing.c ----+
| | | |
+---- labels.c ----+ +---- labels.c ----+
| | | |
@ -25,9 +27,9 @@ look like:
+----- *out.c -----+ +----- *out.c -----+
In other words, each of `preproc.c', `parser.c', `assemble.c', In other words, each of `preproc.c', `parser.c', `assemble.c',
`labels.c', `outform.c' and each of the output format modules `labels.c', `listing.c', `outform.c' and each of the output format
`*out.c' are independent modules, which do not inter-communicate modules `*out.c' are independent modules, which do not directly
except through the main program. inter-communicate except through the main program.
The Netwide *Disassembler* is not intended to be particularly The Netwide *Disassembler* is not intended to be particularly
portable or reusable or anything, however. So I won't bother portable or reusable or anything, however. So I won't bother
@ -167,6 +169,15 @@ The label manager module is (theoretically :) restartable: after
calling `cleanup_labels', you can call `init_labels' again, and calling `cleanup_labels', you can call `init_labels' again, and
start a new assembly with a new set of symbols. start a new assembly with a new set of symbols.
listing.c
---------
This file contains the listing file generator. The interface to the
module is through the one symbol it exports, `nasmlist', which is a
structure containing six function pointers. The calling semantics of
these functions isn't terribly well thought out, as yet, but it
works (just about) so it's going to get left alone for now...
outform.c outform.c
--------- ---------

View File

@ -133,7 +133,8 @@ void define_label_stub (char *label, efunc error) {
lptr = find_label (label, 1); lptr = find_label (label, 1);
if (!lptr) if (!lptr)
error (ERR_PANIC, "can't find label `%s' on pass two", label); error (ERR_PANIC, "can't find label `%s' on pass two", label);
prevlabel = lptr->defn.label; if (*label != '.')
prevlabel = lptr->defn.label;
} }
} }
@ -156,7 +157,7 @@ void define_label (char *label, long segment, long offset,
if (label[0] != '.') /* not local, but not special either */ if (label[0] != '.') /* not local, but not special either */
prevlabel = lptr->defn.label; prevlabel = lptr->defn.label;
else if (!*prevlabel) else if (label[1] != '.' && !*prevlabel)
error(ERR_NONFATAL, "attempt to define a local label before any" error(ERR_NONFATAL, "attempt to define a local label before any"
" non-local labels"); " non-local labels");
@ -282,6 +283,7 @@ static char *perm_copy (char *string1, char *string2) {
if (perm_tail->size - perm_tail->usage < len) { if (perm_tail->size - perm_tail->usage < len) {
perm_tail->next = (struct permts *)nasm_malloc(sizeof(struct permts)); perm_tail->next = (struct permts *)nasm_malloc(sizeof(struct permts));
perm_tail = perm_tail->next; perm_tail = perm_tail->next;
perm_tail->next = NULL;
perm_tail->size = PERMTS_SIZE; perm_tail->size = PERMTS_SIZE;
perm_tail->usage = 0; perm_tail->usage = 0;
} }

240
listing.c Normal file
View File

@ -0,0 +1,240 @@
/* listing.c listing file generator 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.
*
* initial version 2/vii/97 by Simon Tatham
*/
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <ctype.h>
#include "nasm.h"
#include "nasmlib.h"
#include "listing.h"
#define LIST_MAX_LEN 216 /* something sensible */
#define LIST_INDENT 40
#define LIST_HEXBIT 18
typedef struct MacroInhibit MacroInhibit;
static struct MacroInhibit {
MacroInhibit *next;
int level;
int inhibiting;
} *mistack;
static char xdigit[] = "0123456789ABCDEF";
#define HEX(a,b) (*(a)=xdigit[((b)>>4)&15],(a)[1]=xdigit[(b)&15]);
static char listline[LIST_MAX_LEN];
static int listlinep;
static char listdata[2*LIST_INDENT]; /* we need less than that actually */
static long listoffset;
static long listlineno;
static long listp;
static int suppress; /* for INCBIN & TIMES special cases */
static int listlevel, listlevel_e;
static FILE *listfp;
static void list_emit (void) {
if (!listlinep && !listdata[0])
return;
fprintf(listfp, "%6ld ", ++listlineno);
if (listdata[0])
fprintf(listfp, "%08lX %-*s", listoffset, LIST_HEXBIT+1, listdata);
else
fprintf(listfp, "%*s", LIST_HEXBIT+10, "");
if (listlevel_e)
fprintf(listfp, "%s<%d>", (listlevel < 10 ? " " : ""), listlevel_e);
else if (listlinep)
fprintf(listfp, " ");
if (listlinep)
fprintf(listfp, " %s", listline);
fputc('\n', listfp);
listlinep = FALSE;
listdata[0] = '\0';
}
static void list_init (char *fname, efunc error) {
listfp = fopen (fname, "w");
if (!listfp) {
error (ERR_NONFATAL, "unable to open listing file `%s'", fname);
return;
}
*listline = '\0';
listlineno = 0;
listp = TRUE;
listlevel = 0;
suppress = 0;
mistack = nasm_malloc(sizeof(MacroInhibit));
mistack->next = NULL;
mistack->level = 0;
mistack->inhibiting = TRUE;
}
static void list_cleanup (void) {
if (!listp)
return;
while (mistack) {
MacroInhibit *temp = mistack;
mistack = temp->next;
nasm_free (temp);
}
list_emit();
fclose (listfp);
}
static void list_out (long offset, char *str) {
if (strlen(listdata) + strlen(str) > LIST_HEXBIT) {
strcat(listdata, "-");
list_emit();
}
if (!listdata[0])
listoffset = offset;
strcat(listdata, str);
}
static void list_output (long offset, void *data, unsigned long type) {
long typ, size;
if (!listp || suppress)
return;
typ = type & OUT_TYPMASK;
size = type & OUT_SIZMASK;
if (typ == OUT_RAWDATA) {
unsigned char *p = data;
char q[3];
while (size--) {
HEX (q, *p);
q[2] = '\0';
list_out (offset++, q);
p++;
}
} else if (typ == OUT_ADDRESS) {
unsigned long d = *(long *)data;
char q[11];
unsigned char p[4], *r = p;
if (size == 4) {
q[0] = '['; q[9] = ']'; q[10] = '\0';
WRITELONG (r, d);
HEX (q+1, p[0]);
HEX (q+3, p[1]);
HEX (q+5, p[2]);
HEX (q+7, p[3]);
list_out (offset, q);
} else {
q[0] = '['; q[5] = ']'; q[6] = '\0';
WRITESHORT (r, d);
HEX (q+1, p[0]);
HEX (q+3, p[1]);
list_out (offset, q);
}
} else if (typ == OUT_REL2ADR) {
unsigned long d = *(long *)data;
char q[11];
unsigned char p[4], *r = p;
q[0] = '('; q[5] = ')'; q[6] = '\0';
WRITESHORT (r, d);
HEX (q+1, p[0]);
HEX (q+3, p[1]);
list_out (offset, q);
} else if (typ == OUT_REL4ADR) {
unsigned long d = *(long *)data;
char q[11];
unsigned char p[4], *r = p;
q[0] = '('; q[9] = ')'; q[10] = '\0';
WRITELONG (r, d);
HEX (q+1, p[0]);
HEX (q+3, p[1]);
HEX (q+5, p[2]);
HEX (q+7, p[3]);
list_out (offset, q);
} else if (typ == OUT_RESERVE) {
char q[20];
sprintf(q, "<res %08lX>", size);
list_out (offset, q);
}
}
static void list_line (int type, char *line) {
if (!listp)
return;
if (mistack && mistack->inhibiting) {
if (type == LIST_MACRO)
return;
else { /* pop the m i stack */
MacroInhibit *temp = mistack;
mistack = temp->next;
nasm_free (temp);
}
}
list_emit();
listlinep = TRUE;
strncpy (listline, line, LIST_MAX_LEN-1);
listline[LIST_MAX_LEN-1] = '\0';
listlevel_e = listlevel;
}
static void list_uplevel (int type) {
if (!listp)
return;
if (type == LIST_INCBIN || type == LIST_TIMES) {
suppress |= (type == LIST_INCBIN ? 1 : 2);
list_out (listoffset, type == LIST_INCBIN ? "<incbin>" : "<rept>");
return;
}
listlevel++;
if (mistack && mistack->inhibiting && type == LIST_INCLUDE) {
MacroInhibit *temp = nasm_malloc(sizeof(MacroInhibit));
temp->next = mistack;
temp->level = listlevel;
temp->inhibiting = FALSE;
mistack = temp;
} else if (type == LIST_MACRO_NOLIST) {
MacroInhibit *temp = nasm_malloc(sizeof(MacroInhibit));
temp->next = mistack;
temp->level = listlevel;
temp->inhibiting = TRUE;
mistack = temp;
}
}
static void list_downlevel (int type) {
if (!listp)
return;
if (type == LIST_INCBIN || type == LIST_TIMES) {
suppress &= ~(type == LIST_INCBIN ? 1 : 2);
return;
}
listlevel--;
while (mistack && mistack->level > listlevel) {
MacroInhibit *temp = mistack;
mistack = temp->next;
nasm_free (temp);
}
}
ListGen nasmlist = {
list_init,
list_cleanup,
list_output,
list_line,
list_uplevel,
list_downlevel
};

14
listing.h Normal file
View File

@ -0,0 +1,14 @@
/* listing.h header file for listing.c
*
* 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.
*/
#ifndef NASM_LISTING_H
#define NASM_LISTING_H
extern ListGen nasmlist;
#endif

View File

@ -1,51 +1,66 @@
/* This file auto-generated from standard.mac by macros.pl - don't edit it */ /* This file auto-generated from standard.mac by macros.pl - don't edit it */
static char *stdmac[] = { static char *stdmac[] = {
"%define __NASM_MAJOR__ 0",
"%define __NASM_MINOR__ 95",
"%define __SECT__", "%define __SECT__",
"%imacro section 1+", "%imacro section 1+.nolist",
"%define __SECT__ [section %1]", "%define __SECT__ [section %1]",
"__SECT__", "__SECT__",
"%endmacro", "%endmacro",
"%imacro segment 1+", "%imacro segment 1+.nolist",
"%define __SECT__ [segment %1]", "%define __SECT__ [segment %1]",
"__SECT__", "__SECT__",
"%endmacro", "%endmacro",
"%imacro absolute 1+", "%imacro absolute 1+.nolist",
"%define __SECT__ [absolute %1]", "%define __SECT__ [absolute %1]",
"__SECT__", "__SECT__",
"%endmacro", "%endmacro",
"%imacro struc 1", "%imacro struc 1.nolist",
"%push struc", "%push struc",
"%define %$strucname %1", "%define %$strucname %1",
"[absolute 0]", "[absolute 0]",
"%endmacro", "%endmacro",
"%imacro endstruc 0", "%imacro endstruc 0.nolist",
"%{$strucname}_size:", "%{$strucname}_size:",
"%pop", "%pop",
"__SECT__", "__SECT__",
"%endmacro", "%endmacro",
"%imacro extern 1+", "%imacro istruc 1.nolist",
"%push istruc",
"%define %$strucname %1",
"%$strucstart:",
"%endmacro",
"%imacro at 1-2+.nolist",
"times %1-($-%$strucstart) db 0",
"%2",
"%endmacro",
"%imacro iend 0.nolist",
"times %{$strucname}_size-($-%$strucstart) db 0",
"%pop",
"%endmacro",
"%imacro extern 1+.nolist",
"[extern %1]", "[extern %1]",
"%endmacro", "%endmacro",
"%imacro bits 1+", "%imacro bits 1+.nolist",
"[bits %1]", "[bits %1]",
"%endmacro", "%endmacro",
"%imacro global 1+", "%imacro global 1+.nolist",
"[global %1]", "[global %1]",
"%endmacro", "%endmacro",
"%imacro common 1+", "%imacro common 1+.nolist",
"[common %1]", "[common %1]",
"%endmacro", "%endmacro",
"%imacro org 1+", "%imacro org 1+.nolist",
"[org %1]", "[org %1]",
"%endmacro", "%endmacro",
"%imacro group 1+", "%imacro group 1+.nolist",
"[group %1]", "[group %1]",
"%endmacro", "%endmacro",
"%imacro uppercase 1+", "%imacro uppercase 1+.nolist",
"[uppercase %1]", "[uppercase %1]",
"%endmacro", "%endmacro",
"%imacro library 1+", "%imacro library 1+.nolist",
"[library %1]", "[library %1]",
"%endmacro", "%endmacro",
NULL NULL

27
macros.pl Normal file
View File

@ -0,0 +1,27 @@
#!/usr/bin/perl
#
# macros.pl produce macros.c from standard.mac
#
# 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.
open INPUT,"standard.mac" || die "unable to open standard.mac\n";
open OUTPUT,">macros.c" || die "unable to open macros.c\n";
print OUTPUT "/* This file auto-generated from standard.mac by macros.pl" .
" - don't edit it */\n\nstatic char *stdmac[] = {\n";
while (<INPUT>) {
chomp;
# this regexp ought to match anything at all, so why bother with
# a sensible error message ;-)
die "swirly thing alert" unless /^\s*((\s*([^"';\s]+|"[^"]*"|'[^']*'))*)/;
$_ = $1;
s/\\/\\\\/g;
s/"/\\"/g;
print OUTPUT " \"$_\",\n" if length > 0;
}
print OUTPUT " NULL\n};\n"

View File

@ -52,10 +52,10 @@ variable nasm_kw_6 = strncat("cmovaecmovbecmovgecmovlecmovnacmovnbcmovnc",
"cmovpecmovpofcmovbfcmovefcmovufcomipfcompp", "cmovpecmovpofcmovbfcmovefcmovufcomipfcompp",
"fdivrpficompfidivrfisubrfldenvfldl2efldl2t", "fdivrpficompfidivrfisubrfldenvfldl2efldl2t",
"fldlg2fldln2fpatanfprem1frstorfscalefsetpm", "fldlg2fldln2fpatanfprem1frstorfscalefsetpm",
"fstenvfsubrpfucomifucompinvlpgloopneloopnz", "fstenvfsubrpfucomifucompincbininvlpgloopne",
"paddsbpaddswpmulhwpmullwpsubsbpsubswpushad", "loopnzpaddsbpaddswpmulhwpmullwpsubsbpsubsw",
"pushawpushfdpushfwsetnaesetnbesetngesetnle", "pushadpushawpushfdpushfwsetnaesetnbesetnge",
"wbinvd", 9); "setnlewbinvd", 9);
variable nasm_kw_7 = strncat("cmovnaecmovnbecmovngecmovnlecmpxchgfcmovbe", variable nasm_kw_7 = strncat("cmovnaecmovnbecmovngecmovnlecmpxchgfcmovbe",
"fcmovnbfcmovnefcmovnufdecstpfincstpfrndint", "fcmovnbfcmovnefcmovnufdecstpfincstpfrndint",
"fsincosfucomipfucomppfxtractfyl2xp1loadall", "fsincosfucomipfucomppfxtractfyl2xp1loadall",

350
nasm.c
View File

@ -19,6 +19,7 @@
#include "assemble.h" #include "assemble.h"
#include "labels.h" #include "labels.h"
#include "outform.h" #include "outform.h"
#include "listing.h"
static void report_error (int, char *, ...); static void report_error (int, char *, ...);
static void parse_cmdline (int, char **); static void parse_cmdline (int, char **);
@ -30,6 +31,7 @@ static void usage(void);
static char *obuf; static char *obuf;
static char inname[FILENAME_MAX]; static char inname[FILENAME_MAX];
static char outname[FILENAME_MAX]; static char outname[FILENAME_MAX];
static char listname[FILENAME_MAX];
static char realout[FILENAME_MAX]; static char realout[FILENAME_MAX];
static int lineno; /* for error reporting */ static int lineno; /* for error reporting */
static int lineinc; /* set by [LINE] or [ONELINE] */ static int lineinc; /* set by [LINE] or [ONELINE] */
@ -40,6 +42,8 @@ static struct ofmt *ofmt = NULL;
static FILE *ofile = NULL; static FILE *ofile = NULL;
static int sb = 16; /* by default */ static int sb = 16; /* by default */
static int use_stdout = FALSE; /* by default, errors to stderr */
static long current_seg; static long current_seg;
static struct RAA *offsets; static struct RAA *offsets;
static long abs_offset; static long abs_offset;
@ -53,13 +57,38 @@ static int preprocess_only;
/* used by error function to report location */ /* used by error function to report location */
static char currentfile[FILENAME_MAX]; static char currentfile[FILENAME_MAX];
/*
* Which of the suppressible warnings are suppressed. Entry zero
* doesn't do anything. Initial defaults are given here.
*/
static char suppressed[1+ERR_WARN_MAX] = {
0, FALSE, TRUE
};
/*
* The option names for the suppressible warnings. As before, entry
* zero does nothing.
*/
static char *suppressed_names[1+ERR_WARN_MAX] = {
NULL, "macro-params", "orphan-labels"
};
/*
* The explanations for the suppressible warnings. As before, entry
* zero does nothing.
*/
static char *suppressed_what[1+ERR_WARN_MAX] = {
NULL, "macro calls with wrong no. of params",
"labels alone on lines without trailing `:'"
};
/* /*
* This is a null preprocessor which just copies lines from input * This is a null preprocessor which just copies lines from input
* to output. It's used when someone explicitly requests that NASM * to output. It's used when someone explicitly requests that NASM
* not preprocess their source file. * not preprocess their source file.
*/ */
static void no_pp_reset (char *, efunc); static void no_pp_reset (char *, efunc, ListGen *);
static char *no_pp_getline (void); static char *no_pp_getline (void);
static void no_pp_cleanup (void); static void no_pp_cleanup (void);
static Preproc no_pp = { static Preproc no_pp = {
@ -111,7 +140,7 @@ int main(int argc, char **argv) {
"unable to open output file `%s'", outname); "unable to open output file `%s'", outname);
} else } else
ofile = NULL; ofile = NULL;
preproc->reset (inname, report_error); preproc->reset (inname, report_error, &nasmlist);
strcpy(currentfile,inname); strcpy(currentfile,inname);
lineno = 0; lineno = 0;
lineinc = 1; lineinc = 1;
@ -130,8 +159,15 @@ int main(int argc, char **argv) {
if (ofile && terminate_after_phase) if (ofile && terminate_after_phase)
remove(outname); remove(outname);
} else { } else {
/*
* We must call ofmt->filename _anyway_, even if the user
* has specified their own output file, because some
* formats (eg OBJ and COFF) use ofmt->filename to find out
* the name of the input file and then put that inside the
* file.
*/
ofmt->filename (inname, realout, report_error);
if (!*outname) { if (!*outname) {
ofmt->filename (inname, realout, report_error);
strcpy(outname, realout); strcpy(outname, realout);
} }
@ -140,15 +176,29 @@ int main(int argc, char **argv) {
report_error (ERR_FATAL | ERR_NOFILE, report_error (ERR_FATAL | ERR_NOFILE,
"unable to open output file `%s'", outname); "unable to open output file `%s'", outname);
} }
/*
* We must call init_labels() before ofmt->init() since
* some object formats will want to define labels in their
* init routines. (eg OS/2 defines the FLAT group)
*/
init_labels ();
ofmt->init (ofile, report_error, define_label); ofmt->init (ofile, report_error, define_label);
assemble_file (inname); assemble_file (inname);
if (!terminate_after_phase) { if (!terminate_after_phase) {
ofmt->cleanup (); ofmt->cleanup ();
cleanup_labels (); cleanup_labels ();
} }
fclose (ofile); /*
if (terminate_after_phase) * We had an fclose on the output file here, but we
* actually do that in all the object file drivers as well,
* so we're leaving out the one here.
* fclose (ofile);
*/
if (terminate_after_phase) {
remove(outname); remove(outname);
if (listname[0])
remove(listname);
}
} }
if (want_usage) if (want_usage)
@ -156,78 +206,171 @@ int main(int argc, char **argv) {
raa_free (offsets); raa_free (offsets);
saa_free (forwrefs); saa_free (forwrefs);
return 0; if (terminate_after_phase)
return 1;
else
return 0;
}
static int process_arg (char *p, char *q) {
char *param;
int i;
int advance = 0;
if (!p || !p[0])
return 0;
if (p[0]=='-') {
switch (p[1]) {
case 's':
use_stdout = TRUE;
break;
case 'o': /* these parameters take values */
case 'f':
case 'p':
case 'd':
case 'i':
case 'l':
if (p[2]) /* the parameter's in the option */
param = p+2;
else if (!q) {
report_error (ERR_NONFATAL | ERR_NOFILE | ERR_USAGE,
"option `-%c' requires an argument",
p[1]);
break;
} else
advance = 1, param = q;
if (p[1]=='o') { /* output file */
strcpy (outname, param);
} else if (p[1]=='f') { /* output format */
ofmt = ofmt_find(param);
if (!ofmt) {
report_error (ERR_FATAL | ERR_NOFILE | ERR_USAGE,
"unrecognised output format `%s'",
param);
}
} else if (p[1]=='p') { /* pre-include */
pp_pre_include (param);
} else if (p[1]=='d') { /* pre-define */
pp_pre_define (param);
} else if (p[1]=='i') { /* include search path */
pp_include_path (param);
} else if (p[1]=='l') { /* listing file */
strcpy (listname, param);
}
break;
case 'h':
fprintf(use_stdout ? stdout : stderr,
"usage: nasm [-o outfile] [-f format] [-l listfile]"
" [options...] filename\n");
fprintf(use_stdout ? stdout : stderr,
" or nasm -r for version info\n\n");
fprintf(use_stdout ? stdout : stderr,
" -e means preprocess only; "
"-a means don't preprocess\n");
fprintf(use_stdout ? stdout : stderr,
" -s means send errors to stdout not stderr\n");
fprintf(use_stdout ? stdout : stderr,
" -i<path> adds a pathname to the include file"
" path\n -p<file> pre-includes a file;"
" -d<macro>[=<value] pre-defines a macro\n");
fprintf(use_stdout ? stdout : stderr,
" -w+foo enables warnings about foo; "
"-w-foo disables them\n where foo can be:\n");
for (i=1; i<=ERR_WARN_MAX; i++)
fprintf(use_stdout ? stdout : stderr,
" %-16s%s (default %s)\n",
suppressed_names[i], suppressed_what[i],
suppressed[i] ? "off" : "on");
fprintf(use_stdout ? stdout : stderr,
"\nvalid output formats for -f are"
" (`*' denotes default):\n");
ofmt_list(ofmt, use_stdout ? stdout : stderr);
exit (0); /* never need usage message here */
break;
case 'r':
fprintf(use_stdout ? stdout : stderr,
"NASM version %s\n", NASM_VER);
exit (0); /* never need usage message here */
break;
case 'e': /* preprocess only */
preprocess_only = TRUE;
break;
case 'a': /* assemble only - don't preprocess */
preproc = &no_pp;
break;
case 'w':
if (p[2] != '+' && p[2] != '-') {
report_error (ERR_NONFATAL | ERR_NOFILE | ERR_USAGE,
"invalid option to `-w'");
} else {
for (i=1; i<=ERR_WARN_MAX; i++)
if (!nasm_stricmp(p+3, suppressed_names[i]))
break;
if (i <= ERR_WARN_MAX)
suppressed[i] = (p[2] == '-');
else
report_error (ERR_NONFATAL | ERR_NOFILE | ERR_USAGE,
"invalid option to `-w'");
}
break;
default:
report_error (ERR_NONFATAL | ERR_NOFILE | ERR_USAGE,
"unrecognised option `-%c'",
p[1]);
break;
}
} else {
if (*inname) {
report_error (ERR_NONFATAL | ERR_NOFILE | ERR_USAGE,
"more than one input file specified");
} else
strcpy(inname, p);
}
return advance;
} }
static void parse_cmdline(int argc, char **argv) { static void parse_cmdline(int argc, char **argv) {
char *param; char *envreal, *envcopy, *p, *q, *arg, *prevarg;
char separator = ' ';
*inname = *outname = '\0'; *inname = *outname = *listname = '\0';
while (--argc) {
char *p = *++argv; /*
if (p[0]=='-') { * First, process the NASM environment variable.
switch (p[1]) { */
case 'o': /* these parameters take values */ envreal = getenv("NASM");
case 'f': arg = NULL;
if (p[2]) /* the parameter's in the option */ if (envreal) {
param = p+2; envcopy = nasm_strdup(envreal);
else if (!argv[1]) { p = envcopy;
report_error (ERR_NONFATAL | ERR_NOFILE | ERR_USAGE, if (*p && *p != '-')
"option `-%c' requires an argument", separator = *p++;
p[1]); while (*p) {
break; q = p;
} else while (*p && *p != separator) p++;
--argc, param = *++argv; while (*p == separator) *p++ = '\0';
if (p[1]=='o') { /* output file */ prevarg = arg;
strcpy (outname, param); arg = q;
} else if (p[1]=='f') { /* output format */ if (process_arg (prevarg, arg))
ofmt = ofmt_find(param); arg = NULL;
if (!ofmt) {
report_error (ERR_FATAL | ERR_NOFILE | ERR_USAGE,
"unrecognised output format `%s'",
param);
}
}
break;
case 'h':
fprintf(stderr,
"usage: nasm [-o outfile] [-f format]"
" [-a] [-e] filename\n");
fprintf(stderr,
" or nasm -r for version info\n\n");
fprintf(stderr,
" -e means preprocess only; "
"-a means don't preprocess\n\n");
fprintf(stderr,
"valid output formats for -f are"
" (`*' denotes default):\n");
ofmt_list(ofmt);
exit (0); /* never need usage message here */
break;
case 'r':
fprintf(stderr, "NASM version %s\n", NASM_VER);
exit (0); /* never need usage message here */
break;
case 'e': /* preprocess only */
preprocess_only = TRUE;
break;
case 'a': /* assemble only - don't preprocess */
preproc = &no_pp;
break;
default:
report_error (ERR_NONFATAL | ERR_NOFILE | ERR_USAGE,
"unrecognised option `-%c'",
p[1]);
break;
}
} else {
if (*inname) {
report_error (ERR_NONFATAL | ERR_NOFILE | ERR_USAGE,
"more than one input file specified");
} else
strcpy(inname, p);
} }
nasm_free (envcopy);
} }
if (arg)
process_arg (arg, NULL);
/*
* Now process the actual command line.
*/
while (--argc) {
int i;
argv++;
i = process_arg (argv[0], argc > 1 ? argv[1] : NULL);
argv += i, argc -= i;
}
if (!*inname) if (!*inname)
report_error (ERR_NONFATAL | ERR_NOFILE | ERR_USAGE, report_error (ERR_NONFATAL | ERR_NOFILE | ERR_USAGE,
"no input file specified"); "no input file specified");
@ -239,12 +382,10 @@ static void assemble_file (char *fname) {
int i, rn_error; int i, rn_error;
long seg; long seg;
init_labels ();
/* pass one */ /* pass one */
pass = 1; pass = 1;
current_seg = ofmt->section(NULL, pass, &sb); current_seg = ofmt->section(NULL, pass, &sb);
preproc->reset(fname, report_error); preproc->reset(fname, report_error, &nasmlist);
strcpy(currentfile,fname); strcpy(currentfile,fname);
lineno = 0; lineno = 0;
lineinc = 1; lineinc = 1;
@ -378,15 +519,19 @@ static void assemble_file (char *fname) {
if (output_ins.opcode == I_EQU) { if (output_ins.opcode == I_EQU) {
/* /*
* Special `..' EQUs get processed in pass two. * Special `..' EQUs get processed in pass two,
* except `..@' macro-processor EQUs which are done
* in the normal place.
*/ */
if (!output_ins.label) if (!output_ins.label)
report_error (ERR_NONFATAL, report_error (ERR_NONFATAL,
"EQU not preceded by label"); "EQU not preceded by label");
else if (output_ins.label[0] != '.' || else if (output_ins.label[0] != '.' ||
output_ins.label[1] != '.') { output_ins.label[1] != '.' ||
output_ins.label[2] == '@') {
if (output_ins.operands == 1 && if (output_ins.operands == 1 &&
(output_ins.oprs[0].type & IMMEDIATE)) { (output_ins.oprs[0].type & IMMEDIATE) &&
output_ins.oprs[0].wrt == NO_SEG) {
define_label (output_ins.label, define_label (output_ins.label,
output_ins.oprs[0].segment, output_ins.oprs[0].segment,
output_ins.oprs[0].offset, output_ins.oprs[0].offset,
@ -395,8 +540,10 @@ static void assemble_file (char *fname) {
(output_ins.oprs[0].type & IMMEDIATE) && (output_ins.oprs[0].type & IMMEDIATE) &&
(output_ins.oprs[0].type & COLON) && (output_ins.oprs[0].type & COLON) &&
output_ins.oprs[0].segment == NO_SEG && output_ins.oprs[0].segment == NO_SEG &&
output_ins.oprs[0].wrt == NO_SEG &&
(output_ins.oprs[1].type & IMMEDIATE) && (output_ins.oprs[1].type & IMMEDIATE) &&
output_ins.oprs[1].segment == NO_SEG) { output_ins.oprs[1].segment == NO_SEG &&
output_ins.oprs[1].wrt == NO_SEG) {
define_label (output_ins.label, define_label (output_ins.label,
output_ins.oprs[0].offset | SEG_ABS, output_ins.oprs[0].offset | SEG_ABS,
output_ins.oprs[1].offset, output_ins.oprs[1].offset,
@ -430,6 +577,8 @@ static void assemble_file (char *fname) {
/* pass two */ /* pass two */
pass = 2; pass = 2;
saa_rewind (forwrefs); saa_rewind (forwrefs);
if (*listname)
nasmlist.init(listname, report_error);
{ {
int *p = saa_rstruct (forwrefs); int *p = saa_rstruct (forwrefs);
if (p) if (p)
@ -440,7 +589,7 @@ static void assemble_file (char *fname) {
current_seg = ofmt->section(NULL, pass, &sb); current_seg = ofmt->section(NULL, pass, &sb);
raa_free (offsets); raa_free (offsets);
offsets = raa_init(); offsets = raa_init();
preproc->reset(fname, report_error); preproc->reset(fname, report_error, &nasmlist);
strcpy(currentfile,fname); strcpy(currentfile,fname);
lineno = 0; lineno = 0;
lineinc = 1; lineinc = 1;
@ -542,10 +691,12 @@ static void assemble_file (char *fname) {
define_label_stub (output_ins.label, report_error); define_label_stub (output_ins.label, report_error);
if (output_ins.opcode == I_EQU) { if (output_ins.opcode == I_EQU) {
/* /*
* Special `..' EQUs get processed here. * Special `..' EQUs get processed here, except
* `..@' macro processor EQUs which are done above.
*/ */
if (output_ins.label[0] == '.' && if (output_ins.label[0] == '.' &&
output_ins.label[1] == '.') { output_ins.label[1] == '.' &&
output_ins.label[2] != '@') {
if (output_ins.operands == 1 && if (output_ins.operands == 1 &&
(output_ins.oprs[0].type & IMMEDIATE)) { (output_ins.oprs[0].type & IMMEDIATE)) {
define_label (output_ins.label, define_label (output_ins.label,
@ -567,13 +718,14 @@ static void assemble_file (char *fname) {
} }
} }
offs += assemble (current_seg, offs, sb, offs += assemble (current_seg, offs, sb,
&output_ins, ofmt, report_error); &output_ins, ofmt, report_error, &nasmlist);
cleanup_insn (&output_ins); cleanup_insn (&output_ins);
set_curr_ofs (offs); set_curr_ofs (offs);
} }
nasm_free (line); nasm_free (line);
} }
preproc->cleanup(); preproc->cleanup();
nasmlist.cleanup();
} }
static int getkw (char *buf, char **value) { static int getkw (char *buf, char **value) {
@ -601,6 +753,7 @@ static int getkw (char *buf, char **value) {
*value = buf; *value = buf;
} else { } else {
*buf++ = '\0'; *buf++ = '\0';
while (isspace(*buf)) buf++; /* beppu - skip leading whitespace */
*value = buf; *value = buf;
while (*buf!=']') buf++; while (*buf!=']') buf++;
*buf++ = '\0'; *buf++ = '\0';
@ -625,20 +778,28 @@ static int getkw (char *buf, char **value) {
static void report_error (int severity, char *fmt, ...) { static void report_error (int severity, char *fmt, ...) {
va_list ap; va_list ap;
/*
* See if it's a suppressed warning.
*/
if ((severity & ERR_MASK) == ERR_WARNING &&
(severity & ERR_WARN_MASK) != 0 &&
suppressed[ (severity & ERR_WARN_MASK) >> ERR_WARN_SHR ])
return; /* and bail out if so */
if (severity & ERR_NOFILE) if (severity & ERR_NOFILE)
fputs ("nasm: ", stderr); fputs ("nasm: ", use_stdout ? stdout : stderr);
else else
fprintf (stderr, "%s:%d: ", currentfile, fprintf (use_stdout ? stdout : stderr, "%s:%d: ", currentfile,
lineno + (severity & ERR_OFFBY1 ? lineinc : 0)); lineno + (severity & ERR_OFFBY1 ? lineinc : 0));
if ( (severity & ERR_MASK) == ERR_WARNING) if ( (severity & ERR_MASK) == ERR_WARNING)
fputs ("warning: ", stderr); fputs ("warning: ", use_stdout ? stdout : stderr);
else if ( (severity & ERR_MASK) == ERR_PANIC) else if ( (severity & ERR_MASK) == ERR_PANIC)
fputs ("panic: ", stderr); fputs ("panic: ", use_stdout ? stdout : stderr);
va_start (ap, fmt); va_start (ap, fmt);
vfprintf (stderr, fmt, ap); vfprintf (use_stdout ? stdout : stderr, fmt, ap);
fputc ('\n', stderr); fputc ('\n', use_stdout ? stdout : stderr);
if (severity & ERR_USAGE) if (severity & ERR_USAGE)
want_usage = TRUE; want_usage = TRUE;
@ -666,7 +827,7 @@ static void report_error (int severity, char *fmt, ...) {
} }
static void usage(void) { static void usage(void) {
fputs("type `nasm -h' for help\n", stderr); fputs("type `nasm -h' for help\n", use_stdout ? stdout : stderr);
} }
static void register_output_formats(void) { static void register_output_formats(void) {
@ -688,13 +849,16 @@ static void register_output_formats(void) {
#ifdef OF_AS86 #ifdef OF_AS86
extern struct ofmt of_as86; extern struct ofmt of_as86;
#endif #endif
/* DOS formats: OBJ, Win32 */ /* DOS and DOS-ish formats: OBJ, OS/2, Win32 */
#ifdef OF_OBJ #ifdef OF_OBJ
extern struct ofmt of_obj; extern struct ofmt of_obj;
#endif #endif
#ifdef OF_WIN32 #ifdef OF_WIN32
extern struct ofmt of_win32; extern struct ofmt of_win32;
#endif #endif
#ifdef OF_OS2
extern struct ofmt of_os2;
#endif
#ifdef OF_RDF #ifdef OF_RDF
extern struct ofmt of_rdf; extern struct ofmt of_rdf;
#endif #endif
@ -723,6 +887,9 @@ static void register_output_formats(void) {
#ifdef OF_WIN32 #ifdef OF_WIN32
ofmt_register (&of_win32); ofmt_register (&of_win32);
#endif #endif
#ifdef OF_OS2
ofmt_register (&of_os2);
#endif
#ifdef OF_RDF #ifdef OF_RDF
ofmt_register (&of_rdf); ofmt_register (&of_rdf);
#endif #endif
@ -740,12 +907,13 @@ static void register_output_formats(void) {
static FILE *no_pp_fp; static FILE *no_pp_fp;
static efunc no_pp_err; static efunc no_pp_err;
static void no_pp_reset (char *file, efunc error) { static void no_pp_reset (char *file, efunc error, ListGen *listgen) {
no_pp_err = error; no_pp_err = error;
no_pp_fp = fopen(file, "r"); no_pp_fp = fopen(file, "r");
if (!no_pp_fp) if (!no_pp_fp)
no_pp_err (ERR_FATAL | ERR_NOFILE, no_pp_err (ERR_FATAL | ERR_NOFILE,
"unable to open input file `%s'", file); "unable to open input file `%s'", file);
(void) listgen; /* placate compilers */
} }
static char *no_pp_getline (void) { static char *no_pp_getline (void) {

382
nasm.doc
View File

@ -74,8 +74,15 @@ will assemble `myfile.asm' into an ELF object file `myfile.o'. And
will assemble `myfile.asm' into a raw binary program `myfile.com'. will assemble `myfile.asm' into a raw binary program `myfile.com'.
To get usage instructions from NASM, try typing `nasm -h'. This will To produce a listing file, with the hex codes output from NASM
also list the available output file formats, and what they are. displayed on the left of the original sources, use `-l' to give a
listing file name, for example:
nasm -f coff myfile.asm -l myfile.lst
To get further usage instructions from NASM, try typing `nasm -h'.
This will also list the available output file formats, and what they
are.
If you use Linux but aren't sure whether your system is a.out or If you use Linux but aren't sure whether your system is a.out or
ELF, type `file /usr/bin/nasm' or wherever you put the NASM binary. ELF, type `file /usr/bin/nasm' or wherever you put the NASM binary.
@ -95,6 +102,92 @@ Like Unix compilers and assemblers, NASM is silent unless it goes
wrong: you won't see any output at all, unless it gives error wrong: you won't see any output at all, unless it gives error
messages. messages.
If you define an environment variable called NASM, the program will
interpret it as a list of extra command-line options, processed
before the real command line. This is probably most useful for
defining an include-file search path by putting a lot of `-i'
options in the NASM variable.
The variable's value will be considered to be a space-separated list
of options unless it begins with something other than a minus sign,
in which case the first character will be taken as the separator.
For example, if you want to define a macro whose value has a space
in it, then setting the NASM variable to `-dNAME="my name"' won't
work because the string will be split at the space into `-dNAME="my'
and `name"', but setting it to `|-dNAME="my name"' will be fine
because all further operands will be considered to be separated by
vertical bars and so the space has no special meaning.
Quick Start for MASM Users
==========================
If you're used to writing programs with MASM, or with TASM in
MASM-compatible (non-Ideal) mode, or with A86, this section attempts
to outline the major differences between MASM's syntax and NASM's.
If you're not already used to MASM, it's probably worth skipping
this section.
One simple difference is that NASM is case-sensitive. It makes a
difference whether you call your label `foo', `Foo' or `FOO'. If
you're assembling to the `obj' MS-DOS output format (or `os2'), you
can invoke the `UPPERCASE' directive (documented below, in the
Output Formats section) and ensure that all symbols exported to
other code modules are forced to uppercase; but even then, _within_
a single module, NASM will distinguish between labels differing only
in case.
There are also differences in some of the instructions and register
names: for example, NASM calls the floating-point stack registers
`st0', `st1' and so on, rather than MASM's `ST(0)' notation or A86's
simple numeric `0'. And NASM doesn't support LODS, MOVS, STOS, SCAS,
CMPS, INS, or OUTS, but only supports the size-specified versions
LODSB, MOVSW, SCASD and so on.
The _major_ difference, though, is the absence in NASM of variable
typing. MASM will notice when you declare a variable as `var dw 0',
and will remember that `var' is a WORD-type variable, so that
instructions such as `mov var,2' can be unambiguously given the WORD
size rather than BYTE or DWORD. NASM doesn't and won't do this. The
statement `var dw 0' merely defines `var' to be a label marking a
point in memory: no more and no less. It so happens that there are
two bytes of data following that point in memory before the next
line of code, but NASM doesn't remember or care. If you want to
store the number 2 in such a variable, you must specify the size of
the operation _always_: `mov word [var],2'. This is a deliberate
design decision, _not_ a bug, so please could people not send us
mail asking us to `fix' it...
The above example also illustrates another important difference
between MASM and NASM syntax: the use of OFFSET and of square
brackets. In MASM, declaring `var dw 0' entitles you to code `mov
ax,var' to get at the _contents_ of the variable, and you must write
`mov ax,offset var' to get the _address_ of the variable. In NASM,
`mov ax,var' gives you the address, and to get at the contents you
must code `mov ax,[var]'. Again, this is a deliberate design
decision, since it brings consistency to the syntax: `mov ax,[var]'
and `mov ax,[bx]' both refer to the contents of memory and both have
square brackets, whereas neither `mov ax,bx' nor `mov ax,var' refers
to memory contents and so neither one has square brackets.
This is even more confusing in A86, where declaring a label with a
trailing colon defines it to be a `label' as opposed to a `variable'
and causes A86 to adopt NASM-style semantics; so in A86, `mov
ax,var' has different behaviour depending on whether `var' was
declared as `var: dw 0' or `var dw 0'. NASM is very simple by
comparison: _everything_ is a label. The OFFSET keyword is not
required, and in fact constitutes a syntax error (though you can
code `%define offset' to suppress the error messages if you want),
and `var' always refers to the _address_ of the label whereas
`[var]' refers to the _contents_.
As an addendum to this point of syntax, it's also worth noting that
the hybrid-style syntaxes supported by MASM and its clones, such as
`mov ax,table[bx]', where a memory reference is denoted by one
portion outside square brackets and another portion inside, are also
not supported by NASM. The correct syntax for the above is `mov
ax,[table+bx]'. Likewise, `mov ax,es:[di]' is wrong and `mov
ax,[es:di]' is right.
Writing Programs with NASM Writing Programs with NASM
========================== ==========================
@ -106,7 +199,11 @@ LABEL: INSTRUCTION OPERANDS ; COMMENT
`LABEL' defines a label pointing to that point in the source. There `LABEL' defines a label pointing to that point in the source. There
are no restrictions on white space: labels may have white space are no restrictions on white space: labels may have white space
before them, or not, as you please. The colon after the label is before them, or not, as you please. The colon after the label is
also optional. also optional. (Note that NASM can be made to give a warning when it
sees a label which is the only thing on a line with no trailing
colon, on the grounds that such a label might easily be a mistyped
instruction name. The command line option `-w+orphan-labels' will
enable this feature.)
Valid characters in labels are letters, numbers, `_', `$', `#', `@', Valid characters in labels are letters, numbers, `_', `$', `#', `@',
`~', `?', and `.'. The only characters which may be used as the `~', `?', and `.'. The only characters which may be used as the
@ -271,6 +368,11 @@ Note that there is no effective difference between `times 100 resb
1' and `resb 100', except that the latter will be assembled about 1' and `resb 100', except that the latter will be assembled about
100 times faster due to the internal structure of the assembler. 100 times faster due to the internal structure of the assembler.
Note also that TIMES can't be applied to macros: the reason for this
is that TIMES is processed after the macro phase, which allows the
argument to TIMES to contain expressions such as `64-$+buffer' as
above.
Effective Addresses Effective Addresses
=================== ===================
@ -334,6 +436,12 @@ for both of the above instructions, in an effort to save space.
There is not, currently, any means for forcing NASM to generate the There is not, currently, any means for forcing NASM to generate the
larger form of the instruction. larger form of the instruction.
An alternative syntax is supported, in which prefixing an operand
with `&' is synonymous with enclosing it in square brackets. The
square bracket syntax is the recommended one, however, and is the
syntax generated by NDISASM. But, for example, `mov eax,&ebx+ecx' is
equivalent to `mov eax,[ebx+ecx]'.
Mixing 16 and 32 Bit Code: Unusual Instruction Sizes Mixing 16 and 32 Bit Code: Unusual Instruction Sizes
==================================================== ====================================================
@ -349,13 +457,13 @@ difficult instructions are things like far jumps.
Suppose you are in a 16-bit segment, in protected mode, and you want Suppose you are in a 16-bit segment, in protected mode, and you want
to execute a far jump to a point in a 32-bit segment. You need to to execute a far jump to a point in a 32-bit segment. You need to
code a 32-bit far jump in a 16-bit segment; not many assemblers I code a 32-bit far jump in a 16-bit segment; not all assemblers will
know of will easily support this. NASM can, by means of the `word' easily support this. NASM can, by means of the `word' and `dword'
and `dword' specifiers. So you can code specifiers. So you can code
call 1234h:5678h ; this uses the default segment size jmp 1234h:5678h ; this uses the default segment size
call word 1234h:5678h ; this is guaranteed to be 16-bit jmp word 1234h:5678h ; this is guaranteed to be 16-bit
call dword 1234h:56789ABCh ; and this is guaranteed 32-bit jmp dword 1234h:56789ABCh ; and this is guaranteed 32-bit
and NASM will generate correct code for them. and NASM will generate correct code for them.
@ -512,6 +620,11 @@ unary + and -, ~, SEG highest
As usual, operators within a precedence level associate to the left As usual, operators within a precedence level associate to the left
(i.e. `2-3-4' evaluates the same way as `(2-3)-4'). (i.e. `2-3-4' evaluates the same way as `(2-3)-4').
Note that since the `%' character is used by the preprocessor, it's
worth making sure that the `%' and `%%' operators are followed by a
space, to prevent the preprocessor trying to interpret them as
macro-related things.
A form of algebra is done by NASM when evaluating expressions: I A form of algebra is done by NASM when evaluating expressions: I
have already stated that an effective address expression such as have already stated that an effective address expression such as
`[EAX*6-EAX]' will be recognised by NASM as algebraically equivalent `[EAX*6-EAX]' will be recognised by NASM as algebraically equivalent
@ -537,24 +650,26 @@ to the beginning of the _segment_; if you can't guarantee that the
segment itself begins on a four-byte boundary, this alignment is segment itself begins on a four-byte boundary, this alignment is
useless or worse. Be sure you know what kind of alignment you can useless or worse. Be sure you know what kind of alignment you can
guarantee to get out of your linker before you start trying to use guarantee to get out of your linker before you start trying to use
TIMES to align to page boundaries. (Of course, the OBJ file format TIMES to align to page boundaries. (Of course, the `obj' and `os2'
can happily cope with page alignment, provided you specify that file formats can happily cope with page alignment, provided you
segment attribute.) specify that segment attribute.)
SEG and WRT SEG and WRT
=========== ===========
NASM contains the capability for its object file formats (currently, NASM contains the capability for its object file formats (currently,
only `obj' makes use of this) to permit programs to directly refer only `obj' and its variant `os2' make use of this) to permit
to the segment-base values of their segments. This is achieved programs to directly refer to the segment-base values of their
either by the object format defining the segment names as symbols segments. This is achieved either by the object format defining the
(`obj' does this), or by the use of the SEG operator. segment names as symbols (`obj' and `os2' do this), or by the use of
the SEG operator.
SEG is a unary prefix operator which, when applied to a symbol SEG is a unary prefix operator which, when applied to a symbol
defined in a segment, will yield the segment base value of that defined in a segment, will yield the segment base value of that
segment. (In `obj' format, symbols defined in segments which are segment. (In `obj' and `os2' format, symbols defined in segments
grouped are considered to be primarily a member of the _group_, not which are grouped are considered to be primarily a member of the
the segment, and the return value of SEG reflects this.) _group_, not the segment, and the return value of SEG reflects
this.)
SEG may be used for far pointers: it is guaranteed that for any SEG may be used for far pointers: it is guaranteed that for any
symbol `sym', using the offset `sym' from the segment base `SEG sym' symbol `sym', using the offset `sym' from the segment base `SEG sym'
@ -708,8 +823,8 @@ below.
In 32-bit mode, instructions are prefixed with 0x66 or 0x67 prefixes In 32-bit mode, instructions are prefixed with 0x66 or 0x67 prefixes
when they use 16-bit data or addresses; in 16-bit mode, the reverse when they use 16-bit data or addresses; in 16-bit mode, the reverse
happens. NASM's default depends on the object format; the defaults happens. NASM's default depends on the object format; the defaults
are documented with the formats. (See `obj', in particular, for some are documented with the formats. (See `obj' and `os2', in
unusual behaviour.) particular, for some unusual behaviour.)
`SECTION name' or `SEGMENT name' changes which section the code you `SECTION name' or `SEGMENT name' changes which section the code you
write will be assembled into. Acceptable section names vary between write will be assembled into. Acceptable section names vary between
@ -756,8 +871,8 @@ it refers to.
`COMMON symbol size' defines a symbol as being common: it is `COMMON symbol size' defines a symbol as being common: it is
declared to have the given size, and it is merged at link time with declared to have the given size, and it is merged at link time with
any declarations of the same symbol in other modules. This is not any declarations of the same symbol in other modules. This is not
_fully_ supported in the `obj' file format: see the section on `obj' _fully_ supported in the `obj' or `os2' file format: see the section
for details. on `obj' for details.
`STRUC structure' begins the definition of a data structure, and `STRUC structure' begins the definition of a data structure, and
`ENDSTRUC' ends it. The structure shown above may be defined, `ENDSTRUC' ends it. The structure shown above may be defined,
@ -766,8 +881,8 @@ exactly equivalently, using STRUC as follows:
struc st struc st
stLong resd 1 stLong resd 1
stWord resw 1 stWord resw 1
stByte1 resb 1 stByte resb 1
stByte2 resb 1 stStr resb 32
endstruc endstruc
Notice that this code still defines the symbol `st_size' to be the Notice that this code still defines the symbol `st_size' to be the
@ -777,6 +892,36 @@ remembering which section you were assembling in (whereas in the
version using `ABSOLUTE' it was up to the programmer to sort that version using `ABSOLUTE' it was up to the programmer to sort that
out). out).
`ISTRUC structure' begins the declaration of an initialised instance
of a data structure. You can then use the `AT' macro to assign
values to the structure members, and `IEND' to finish. So, for
example, given the structure `st' above:
istruc st
at stLong, dd 0x1234
at stWord, dw 23
at stByte, db 'q'
at stStr, db 'hello, world', 13, 10, 0
iend
Note that there's nothing stopping the instruction after `at' from
overflowing on to the next line if you want. So the above example
could just as well have contained
at stStr, db 'hello, world'
db 13, 10, 0
or even (if you prefer this style)
at stStr
db 'hello, world'
db 13, 10, 0
Note also that the `ISTRUC' mechanism is implemented as a set of
macros, and uses TIMES internally to achieve its effect; so the
structure fields must be initialised in the same order as they were
defined in.
This is where user-level directives differ from primitives: the This is where user-level directives differ from primitives: the
`SECTION' (and `SEGMENT') user-level directives don't just call the `SECTION' (and `SEGMENT') user-level directives don't just call the
primitive versions, but they also `%define' the special preprocessor primitive versions, but they also `%define' the special preprocessor
@ -788,14 +933,9 @@ ENDSTRUC - they are implemented in terms of ABSOLUTE and SECTION.
This also means that if you use STRUC before explicitly announcing a This also means that if you use STRUC before explicitly announcing a
target section, you should explicitly announce one after ENDSTRUC. target section, you should explicitly announce one after ENDSTRUC.
The primitive directive [INCLUDE filename] (or the equivalent form
[INC filename]) is supported as a synonym for the preprocessor-
oriented `%include' form, but only temporarily: this usage will be
phased out in the next version of NASM.
Directives may also be specific to the output file format. At Directives may also be specific to the output file format. At
present, the `bin' and `obj' formats define extra directives, which present, the `bin', `obj' and `os2' formats define extra directives,
are specified below. which are specified below.
The Preprocessor The Preprocessor
================ ================
@ -841,7 +981,30 @@ all to expand to `bar'.
There is a mechanism which detects when a macro call has occurred as There is a mechanism which detects when a macro call has occurred as
a result of a previous expansion of the same macro, to guard against a result of a previous expansion of the same macro, to guard against
circular references and infinite loops. If this happens, the circular references and infinite loops. If this happens, the
preprocessor will report an error. preprocessor will only expand the first occurrence of the macro.
Hence:
%define a(x) 1+a(x)
mov ax,a(3) ; becomes 1+a(3) and expands no further
This can be useful for doing things like this:
%macro extrn 1 ; see next section for explanation of `%macro'
extern _%1
%define %1 _%1
%endmacro
which would avoid having to put leading underscores on external
variables, because you could just code
extrn foo
mov ax,foo
and it would expand as
extern foo
%define foo _foo
mov ax,foo ; becomes mov ax,_foo as required
Single-line macros with parameters can be overloaded: it is possible Single-line macros with parameters can be overloaded: it is possible
to define two or more single-line macros with the same name, each to define two or more single-line macros with the same name, each
@ -852,6 +1015,19 @@ name _with_ parameters, and vice versa (though single-line macros
may be redefined, keeping the same number of parameters, without may be redefined, keeping the same number of parameters, without
error). error).
You can pre-define single-line macros using the `-d' option on the
NASM command line, such as
nasm filename -dDEBUG
(and then you might have various conditional-assembly bits under
`%ifdef DEBUG'), or possibly
nasm filename -dTYPE=4
(which might allow you to re-assemble your code to do several
different things depending on the value of TYPE).
Multiple-line macros Multiple-line macros
-------------------- --------------------
@ -875,6 +1051,16 @@ expects no parameters. Macros can be overloaded: if two macros are
defined with the same name but different numbers of parameters, they defined with the same name but different numbers of parameters, they
will be treated as separate. Multi-line macros may not be redefined. will be treated as separate. Multi-line macros may not be redefined.
The assembler will usually generate a warning if you code a line
which looks like a macro call but involves a number of parameters
which the macro in question isn't ready to support. (For example, if
you code a macro `%macro foo 1' and also `%macro foo 3', then you
write `foo a,b', a warning will be generated.) This feature can be
disabled by the use of the command line option `-w-macro-params',
since sometimes it's intentional (for example, you might define
`%macro push 2' to allow you to push two registers at once; but
`push ax' shouldn't then generate a warning).
Macros taking parameters can be written using `%1', `%2' and so on Macros taking parameters can be written using `%1', `%2' and so on
to reference the parameters. So this code to reference the parameters. So this code
@ -902,7 +1088,7 @@ with `%%'. So:
This defines a different label in place of `%%skip' every time it's This defines a different label in place of `%%skip' every time it's
called. (Of course the above code could have easily been coded using called. (Of course the above code could have easily been coded using
`jnz $+3', but not in more complex cases...) The actual label `jnz $+3', but not in more complex cases...) The actual label
defined would be `macro.2345.skip', where 2345 is replaced by some defined would be `..@2345.skip', where 2345 is replaced by some
number that changes with each macro call. Users are warned to avoid number that changes with each macro call. Users are warned to avoid
defining labels of this shape themselves. defining labels of this shape themselves.
@ -923,7 +1109,7 @@ modifier on the `%macro' line:
%endmacro %endmacro
fputs [filehandle], "hi there", 13, 10 fputs [filehandle], "hi there", 13, 10
This declares `pstring' to be a macro that accepts _at least two_ This declares `fputs' to be a macro that accepts _at least two_
parameters, and all parameters after the first one are lumped parameters, and all parameters after the first one are lumped
together as part of the last specified one (in this case %2). So in together as part of the last specified one (in this case %2). So in
the macro call, `%1' expands to `[filehandle]' while `%2' expands to the macro call, `%1' expands to `[filehandle]' while `%2' expands to
@ -1002,9 +1188,9 @@ defined:
which will expand to something like which will expand to something like
jnae macro.1234.skip jnae ..@1234.skip
mov ax,bx mov ax,bx
macro.1234.skip: ..@1234.skip:
Note that `%+1' will allow CXZ or ECXZ to be passed as condition Note that `%+1' will allow CXZ or ECXZ to be passed as condition
codes, but `%-1' will of course be unable to invert them. codes, but `%-1' will of course be unable to invert them.
@ -1034,6 +1220,28 @@ Defaults may be omitted, in which case they are taken to be blank.
`%endm' is a valid synonym for `%endmacro'. `%endm' is a valid synonym for `%endmacro'.
The specification for the number of macro parameters can be suffixed
with `.nolist' if you don't want the macro to be explicitly expanded
in listing files:
%macro ping 1-2+.nolist
; some stuff
%endmacro
Standard Macros and `%clear'
----------------------------
NASM defines a set of standard macros, before the input file gets
processed; these are primarily there in order to provide standard
language features (such as structure support). However, it's
conceivable that a user might want to write code that doesn't have
the standard macros defined; you can achieve this by using the
preprocessor directive `%clear' at the top of your program, which
will undefine _everything_ that's defined by the preprocessor.
In particular, NASM defines the symbols `__NASM_MAJOR__' and
`__NASM_MINOR__' to be the major and minor version numbers of NASM.
Conditional Assembly Conditional Assembly
-------------------- --------------------
@ -1054,9 +1262,12 @@ File Inclusion
-------------- --------------
You can include a file using the `%include' directive. Included You can include a file using the `%include' directive. Included
files are only searched for in the current directory: there isn't files are searched for in the current directory, and then in all
(yet - if there's demand for it it could be arranged) any default directories specified on the command line with the `-i' option.
search path for standard include files. (Note that the directories specified on the command line are
directly prepended to the filename, so they must include the
necessary trailing slash under DOS or Unix, or the equivalent on
other systems.)
This, again, works like C: `%include' is used to include a file. Of This, again, works like C: `%include' is used to include a file. Of
course it's quite likely you'd want to do the normal sort of thing course it's quite likely you'd want to do the normal sort of thing
@ -1075,6 +1286,10 @@ and then elsewhere
so that it doesn't matter if the file accidentally gets included so that it doesn't matter if the file accidentally gets included
more than once. more than once.
You can force an include file to be included without using a
`%include' command, by specifying it as a pre-include file on the
command line using the `-p' option.
The Context Stack The Context Stack
----------------- -----------------
@ -1159,8 +1374,8 @@ Output Formats
============== ==============
The current output formats supported are `bin', `aout', `coff', The current output formats supported are `bin', `aout', `coff',
`elf', `as86', `obj', `win32', `rdf', and the debug pseudo-format `elf', `as86', `obj', `os2', `win32', `rdf', and the debug
`dbg'. pseudo-format `dbg'.
`bin': flat-form binary `bin': flat-form binary
----------------------- -----------------------
@ -1181,17 +1396,18 @@ NASM does not support the use of ORG to jump around inside an object
file, like MASM does (see the `Bugs' section for a demonstration of file, like MASM does (see the `Bugs' section for a demonstration of
the use of MASM's form of ORG to do something that NASM's won't do.) the use of MASM's form of ORG to do something that NASM's won't do.)
Like almost all formats (not `obj'), the `bin' format defines the Like almost all formats (but not `obj' or `os2'), the `bin' format
section names `.text', `.data' and `.bss'. The layout is that defines the section names `.text', `.data' and `.bss'. The layout is
`.text' comes first in the output file, followed by `.data', and that `.text' comes first in the output file, followed by `.data',
notionally followed by `.bss'. So if you declare a BSS section in a and notionally followed by `.bss'. So if you declare a BSS section
flat binary file, references to the BSS section will refer to space in a flat binary file, references to the BSS section will refer to
past the end of the actual file. The `.data' and `.bss' sections are space past the end of the actual file. The `.data' and `.bss'
considered to be aligned on four-byte boundaries: this is achieved sections are considered to be aligned on four-byte boundaries: this
by inserting padding zero bytes between the end of the text section is achieved by inserting padding zero bytes between the end of the
and the start of the data, if there is data present. Of course if no text section and the start of the data, if there is data present. Of
SECTION directives are present, everything will go into `.text', and course if no SECTION directives are present, everything will go into
you will get nothing in the output except the code you wrote. `.text', and you will get nothing in the output except the code you
wrote.
`bin' silently ignores GLOBAL directives, and will also not complain `bin' silently ignores GLOBAL directives, and will also not complain
at EXTERN ones. You only get an error if you actually _reference_ an at EXTERN ones. You only get an error if you actually _reference_ an
@ -1324,8 +1540,8 @@ to pass directives to the MS linker.
Both `coff' and `win32' default to 32-bit assembly mode. Both `coff' and `win32' default to 32-bit assembly mode.
`obj': Microsoft 16-bit Object Module Format `obj' and `os2': Microsoft 16-bit Object Module Format
-------------------------------------------- ------------------------------------------------------
The `obj' format generates 16-bit Microsoft object files, suitable The `obj' format generates 16-bit Microsoft object files, suitable
for feeding to 16-bit versions of Microsoft C, and probably for feeding to 16-bit versions of Microsoft C, and probably
@ -1416,6 +1632,26 @@ place 32-bit code in a Use16 segment, you can use an explicit `BITS
32' override, but if you switch temporarily away from that segment, 32' override, but if you switch temporarily away from that segment,
you will have to repeat the override after coming back to it. you will have to repeat the override after coming back to it.
If you're trying to build a .COM application by linking several .OBJ
files together, you need to put `resb 0x100' at the front of the
code segment in the first object file, since otherwise the linker
will get the linking wrong.
OS/2 uses an almost exactly similar file format to DOS, with a
couple of differences, principally that OS/2 defines a pseudo-group
called FLAT, containing no segments, and every relocation is made
relative to that (so it would be equivalent to writing `label WRT
FLAT' in place of `label' _throughout_ your code). Since this would
be inconvenient to write code for, NASM implements the `os2' variant
on `obj', which provides this FLAT group itself and automatically
makes the default relocation format relative to FLAT.
NOTE TO OS/2 USERS: The OS/2 output format is new in NASM version
0.95. It hasn't been tested on any actual OS/2 systems, and I don't
know for sure that it'll work properly. Any OS/2 users are
encouraged to give it a thorough testing and report the results to
me. Thanks!
`as86': Linux as86 (bin86-0.3) `as86': Linux as86 (bin86-0.3)
------------------------------ ------------------------------
@ -1448,14 +1684,46 @@ debugging purposes. It produces a debug dump of everything that the
NASM assembly module feeds to the output driver, for the benefit of NASM assembly module feeds to the output driver, for the benefit of
people trying to write their own output drivers. people trying to write their own output drivers.
Common Problems
===============
A few problems that people repeatedly ask me about are documented
here.
NASM's design philosophy of generating exactly the code the
programmer asks for, without second-guessing or re-interpreting, has
been known to cause confusion in a couple of areas.
Firstly, several people have complained that instructions such as
`add esp,4' are assembled in a form that allocates a full four-byte
offset field to store the `4' in, even though the instruction has a
shorter form with a single-byte offset field which would work in
this case. The answer is that NASM by design doesn't try to guess
which one of these forms you want: if you want one, you code one,
and if you want the other, you code the other. The other form is
`add esp, byte 4'.
Secondly, and similarly, I've had repeated questions about
conditional jumps. The simple `jne label', in NASM, translates
directly to the old 8086 form of the conditional jump, in which the
offset can be up to 128 bytes (or thereabouts) in either direction.
NASM won't automatically generate `je $+3 / jmp label' for labels
that are further away, and neither will it generate the 386 long-
offset form of the instruction. If you want the 386-specific
conditional jump that's capable of reaching anywhere in the same
segment as the jump instruction, you want `jne near label'. If you
want an 8086-compatible `je' over another `jmp', code one
explicitly, or define a macro to do so. NASM doesn't do either of
these things for you, again by design.
Bugs Bugs
==== ====
Apart from the missing features (correct OBJ COMMON support, ELF Apart from the missing features (correct OBJ COMMON support, ELF
alignment, ELF PIC support, etc.), there are no _known_ bugs. alignment, ELF PIC support, etc.), there are no _known_ bugs.
However, any you find, with patches if possible, should be sent to However, any you find, with patches if possible, should be sent to
<jules@dcs.warwick.ac.uk> or <anakin@pobox.com>, and we'll try to <jules@earthcorp.com> or <anakin@pobox.com>, and we'll try to fix
fix them. them.
Beware of Pentium-specific instructions: Intel have provided a macro Beware of Pentium-specific instructions: Intel have provided a macro
file for MASM, to implement the eight or nine new Pentium opcodes as file for MASM, to implement the eight or nine new Pentium opcodes as

98
nasm.h
View File

@ -12,8 +12,8 @@
#define NASM_NASM_H #define NASM_NASM_H
#define NASM_MAJOR_VER 0 #define NASM_MAJOR_VER 0
#define NASM_MINOR_VER 94 #define NASM_MINOR_VER 95
#define NASM_VER "0.94" #define NASM_VER "0.95"
#ifndef NULL #ifndef NULL
#define NULL 0 #define NULL 0
@ -66,6 +66,15 @@ typedef void (*efunc) (int severity, char *fmt, ...);
#define ERR_OFFBY1 0x40 /* report error as being on the line #define ERR_OFFBY1 0x40 /* report error as being on the line
* we're just _about_ to read, not * we're just _about_ to read, not
* the one we've just read */ * the one we've just read */
/*
* These codes define specific types of suppressible warning.
*/
#define ERR_WARN_MNP 0x0100 /* macro-num-parameters warning */
#define ERR_WARN_OL 0x0200 /* orphan label (no colon, and
* alone on line) */
#define ERR_WARN_MASK 0xFF00 /* the mask for this feature */
#define ERR_WARN_SHR 8 /* how far to shift right */
#define ERR_WARN_MAX 2 /* the highest numbered one */
/* /*
* ----------------------- * -----------------------
@ -84,15 +93,74 @@ typedef int (*lfunc) (char *label, long *segment, long *offset);
typedef void (*ldfunc) (char *label, long segment, long offset, typedef void (*ldfunc) (char *label, long segment, long offset,
struct ofmt *ofmt, efunc error); struct ofmt *ofmt, efunc error);
/*
* List-file generators should look like this:
*/
typedef struct {
/*
* Called to initialise the listing file generator. Before this
* is called, the other routines will silently do nothing when
* called. The `char *' parameter is the file name to write the
* listing to.
*/
void (*init) (char *, efunc);
/*
* Called to clear stuff up and close the listing file.
*/
void (*cleanup) (void);
/*
* Called to output binary data. Parameters are: the offset;
* the data; the data type. Data types are similar to the
* output-format interface, only OUT_ADDRESS will _always_ be
* displayed as if it's relocatable, so ensure that any non-
* relocatable address has been converted to OUT_RAWDATA by
* then. Note that OUT_RAWDATA+0 is a valid data type, and is a
* dummy call used to give the listing generator an offset to
* work with when doing things like uplevel(LIST_TIMES) or
* uplevel(LIST_INCBIN).
*/
void (*output) (long, void *, unsigned long);
/*
* Called to send a text line to the listing generator. The
* `int' parameter is LIST_READ or LIST_MACRO depending on
* whether the line came directly from an input file or is the
* result of a multi-line macro expansion.
*/
void (*line) (int, char *);
/*
* Called to change one of the various levelled mechanisms in
* the listing generator. LIST_INCLUDE and LIST_MACRO can be
* used to increase the nesting level of include files and
* macro expansions; LIST_TIMES and LIST_INCBIN switch on the
* two binary-output-suppression mechanisms for large-scale
* pseudo-instructions.
*
* LIST_MACRO_NOLIST is synonymous with LIST_MACRO except that
* it indicates the beginning of the expansion of a `nolist'
* macro, so anything under that level won't be expanded unless
* it includes another file.
*/
void (*uplevel) (int);
/*
* Reverse the effects of uplevel.
*/
void (*downlevel) (int);
} ListGen;
/* /*
* Preprocessors ought to look like this: * Preprocessors ought to look like this:
*/ */
typedef struct { typedef struct {
/* /*
* Called at the start of a pass; given a file name and an * Called at the start of a pass; given a file name, an error
* error reporting function. * reporting function and a listing generator to talk to.
*/ */
void (*reset) (char *, efunc); void (*reset) (char *, efunc, ListGen *);
/* /*
* Called to fetch a line of preprocessed source. The line * Called to fetch a line of preprocessed source. The line
@ -120,9 +188,10 @@ typedef struct {
* (for local labels), whereas a number may appear anywhere *but* at the * (for local labels), whereas a number may appear anywhere *but* at the
* start. */ * start. */
#define isidstart(c) ( isalpha(c) || (c)=='_' || (c)=='.' || (c)=='?' ) #define isidstart(c) ( isalpha(c) || (c)=='_' || (c)=='.' || (c)=='?' \
|| (c)=='@' )
#define isidchar(c) ( isidstart(c) || isdigit(c) || (c)=='$' || (c)=='#' \ #define isidchar(c) ( isidstart(c) || isdigit(c) || (c)=='$' || (c)=='#' \
|| (c)=='@' || (c)=='~' ) || (c)=='~' )
/* Ditto for numeric constants. */ /* Ditto for numeric constants. */
@ -133,6 +202,14 @@ typedef struct {
#define numvalue(c) ((c)>='a' ? (c)-'a'+10 : (c)>='A' ? (c)-'A'+10 : (c)-'0') #define numvalue(c) ((c)>='a' ? (c)-'a'+10 : (c)>='A' ? (c)-'A'+10 : (c)-'0')
/*
* Data-type flags that get passed to listing-file routines.
*/
enum {
LIST_READ, LIST_MACRO, LIST_MACRO_NOLIST, LIST_INCLUDE,
LIST_INCBIN, LIST_TIMES
};
/* /*
* ----------------------------------------------------------- * -----------------------------------------------------------
* Format of the `insn' structure returned from `parser.c' and * Format of the `insn' structure returned from `parser.c' and
@ -381,6 +458,13 @@ struct ofmt {
* which case `offset' holds the _size_ of the variable). * which case `offset' holds the _size_ of the variable).
* Anything else is available for the output driver to use * Anything else is available for the output driver to use
* internally. * internally.
*
* This routine explicitly _is_ allowed to call the label
* manager to define further symbols, if it wants to, even
* though it's been called _from_ the label manager. That much
* re-entrancy is guaranteed in the label manager. However, the
* label manager will in turn call this routine, so it should
* be prepared to be re-entrant itself.
*/ */
void (*symdef) (char *name, long segment, long offset, int is_global); void (*symdef) (char *name, long segment, long offset, int is_global);

View File

@ -174,7 +174,7 @@ Bugs and Improvements
===================== =====================
There are no known bugs. However, any you find, with patches if There are no known bugs. However, any you find, with patches if
possible, should be sent to <jules@dcs.warwick.ac.uk> or possible, should be sent to <jules@earthcorp.com> or
<anakin@pobox.com>, and we'll try to fix them. Feel free to send <anakin@pobox.com>, and we'll try to fix them. Feel free to send
contributions and new features as well. contributions and new features as well.

View File

@ -153,7 +153,8 @@ static void aout_deflabel (char *name, long segment, long offset,
int pos = strslen+4; int pos = strslen+4;
struct Symbol *sym; struct Symbol *sym;
if (name[0] == '.' && name[1] == '.') { if (name[0] == '.' && name[1] == '.' && name[2] != '@') {
error (ERR_NONFATAL, "unrecognised special symbol `%s'", name);
return; return;
} }

View File

@ -161,7 +161,8 @@ static void as86_deflabel (char *name, long segment, long offset,
int is_global) { int is_global) {
struct Symbol *sym; struct Symbol *sym;
if (name[0] == '.' && name[1] == '.') { if (name[0] == '.' && name[1] == '.' && name[2] != '@') {
error (ERR_NONFATAL, "unrecognised special symbol `%s'", name);
return; return;
} }

View File

@ -241,6 +241,11 @@ static void bin_out (long segto, void *data, unsigned long type,
static void bin_deflabel (char *name, long segment, long offset, static void bin_deflabel (char *name, long segment, long offset,
int is_global) { int is_global) {
if (name[0] == '.' && name[1] == '.' && name[2] != '@') {
error (ERR_NONFATAL, "unrecognised special symbol `%s'", name);
return;
}
if (is_global == 2) { if (is_global == 2) {
error (ERR_NONFATAL, "binary output format does not support common" error (ERR_NONFATAL, "binary output format does not support common"
" variables"); " variables");

View File

@ -285,7 +285,8 @@ static void coff_deflabel (char *name, long segment, long offset,
int pos = strslen+4; int pos = strslen+4;
struct Symbol *sym; struct Symbol *sym;
if (name[0] == '.' && name[1] == '.') { if (name[0] == '.' && name[1] == '.' && name[2] != '@') {
error (ERR_NONFATAL, "unrecognised special symbol `%s'", name);
return; return;
} }

View File

@ -63,8 +63,8 @@ static long dbg_section_names (char *name, int pass, int *bits)
static void dbg_deflabel (char *name, long segment, long offset, static void dbg_deflabel (char *name, long segment, long offset,
int is_global) { int is_global) {
fprintf(dbgf,"deflabel %s := %08lx:%08lx %s (%d)\n",name,segment,offset, fprintf(dbgf,"deflabel %s := %08lx:%08lx %s (%d)\n",name,segment,offset,
is_global ? "global" : "local", is_global); is_global ? "global" : "local", is_global);
} }
static void dbg_out (long segto, void *data, unsigned long type, static void dbg_out (long segto, void *data, unsigned long type,

View File

@ -290,7 +290,8 @@ static void elf_deflabel (char *name, long segment, long offset,
int pos = strslen; int pos = strslen;
struct Symbol *sym; struct Symbol *sym;
if (name[0] == '.' && name[1] == '.') { if (name[0] == '.' && name[1] == '.' && name[2] != '@') {
error (ERR_NONFATAL, "unrecognised special symbol `%s'", name);
return; return;
} }
@ -306,11 +307,18 @@ static void elf_deflabel (char *name, long segment, long offset,
else { else {
int i; int i;
sym->section = SHN_UNDEF; sym->section = SHN_UNDEF;
for (i=0; i<nsects; i++) if (nsects == 0 && segment == def_seg) {
if (segment == sects[i]->index) { int tempint;
sym->section = i+1; if (segment != elf_section_names (".text", 2, &tempint))
break; error (ERR_PANIC, "strange segment conditions in ELF driver");
} sym->section = nsects;
} else {
for (i=0; i<nsects; i++)
if (segment == sects[i]->index) {
sym->section = i+1;
break;
}
}
} }
if (is_global == 2) { if (is_global == 2) {

View File

@ -27,11 +27,11 @@ struct ofmt *ofmt_find(char *name) /* find driver */
return NULL; return NULL;
} }
void ofmt_list(struct ofmt *deffmt) void ofmt_list(struct ofmt *deffmt, FILE *fp)
{ {
int i; int i;
for (i=0; i<ndrivers; i++) for (i=0; i<ndrivers; i++)
fprintf(stderr," %c %-7s%s\n", fprintf(fp, " %c %-7s%s\n",
drivers[i] == deffmt ? '*' : ' ', drivers[i] == deffmt ? '*' : ' ',
drivers[i]->shortname, drivers[i]->shortname,
drivers[i]->fullname); drivers[i]->fullname);

View File

@ -18,7 +18,7 @@
* OF_NO_name -- remove output format 'name' * OF_NO_name -- remove output format 'name'
* OF_DOS -- ensure that 'obj', 'bin' & 'win32' are included. * OF_DOS -- ensure that 'obj', 'bin' & 'win32' are included.
* OF_UNIX -- ensure that 'aout', 'coff' and 'elf' are in. * OF_UNIX -- ensure that 'aout', 'coff' and 'elf' are in.
* OF_OTHERS -- ensure that 'bin', 'as86' & 'rdf' are in. * OF_OTHERS -- ensure that 'bin', 'as86', 'os2' & 'rdf' are in.
* OF_ALL -- ensure that all formats are included. * OF_ALL -- ensure that all formats are included.
* *
* OF_DEFAULT=of_name -- ensure that 'name' is the default format. * OF_DEFAULT=of_name -- ensure that 'name' is the default format.
@ -37,8 +37,8 @@
#define MAX_OUTPUT_FORMATS 16 #define MAX_OUTPUT_FORMATS 16
struct ofmt *ofmt_find(char *name); struct ofmt *ofmt_find(char *);
void ofmt_list(struct ofmt *deffmt); void ofmt_list(struct ofmt *, FILE *);
void ofmt_register (struct ofmt *); void ofmt_register (struct ofmt *);
/* -------------- USER MODIFIABLE PART ---------------- */ /* -------------- USER MODIFIABLE PART ---------------- */
@ -77,6 +77,9 @@ void ofmt_register (struct ofmt *);
#ifndef OF_OBJ #ifndef OF_OBJ
#define OF_OBJ #define OF_OBJ
#endif #endif
#ifndef OF_OS2
#define OF_OS2
#endif
#ifndef OF_ELF #ifndef OF_ELF
#define OF_ELF #define OF_ELF
#endif #endif
@ -132,6 +135,9 @@ void ofmt_register (struct ofmt *);
#ifndef OF_RDF #ifndef OF_RDF
#define OF_RDF #define OF_RDF
#endif #endif
#ifndef OF_OS2
#define OF_OS2
#endif
#endif #endif
/* finally... override any format specifically specifed to be off */ /* finally... override any format specifically specifed to be off */
@ -159,6 +165,9 @@ void ofmt_register (struct ofmt *);
#ifdef OF_NO_RDF #ifdef OF_NO_RDF
#undef OF_RDF #undef OF_RDF
#endif #endif
#ifdef OF_NO_OS2
#undef OF_OS2
#endif
#ifndef OF_DEFAULT #ifndef OF_DEFAULT
#define OF_DEFAULT of_bin #define OF_DEFAULT of_bin

107
outobj.c
View File

@ -85,7 +85,7 @@ static struct Group {
long index; long index;
char *name; char *name;
} segs[GROUP_MAX]; /* ...in this */ } segs[GROUP_MAX]; /* ...in this */
} *grphead, **grptail, *obj_grp_needs_update; } *grphead, **grptail, *obj_grp_needs_update, *defgrp;
static struct ObjData { static struct ObjData {
struct ObjData *next; struct ObjData *next;
@ -99,6 +99,8 @@ static struct ObjData {
static long obj_entry_seg, obj_entry_ofs; static long obj_entry_seg, obj_entry_ofs;
static int os2;
enum RecordID { /* record ID codes */ enum RecordID { /* record ID codes */
THEADR = 0x80, /* module header */ THEADR = 0x80, /* module header */
@ -136,6 +138,7 @@ static unsigned char *obj_write_name(unsigned char *, char *);
static unsigned char *obj_write_index(unsigned char *, int); static unsigned char *obj_write_index(unsigned char *, int);
static unsigned char *obj_write_value(unsigned char *, unsigned long); static unsigned char *obj_write_value(unsigned char *, unsigned long);
static void obj_record(int, unsigned char *, unsigned char *); static void obj_record(int, unsigned char *, unsigned char *);
static int obj_directive (char *, char *, int);
static void obj_init (FILE *fp, efunc errfunc, ldfunc ldef) { static void obj_init (FILE *fp, efunc errfunc, ldfunc ldef) {
ofp = fp; ofp = fp;
@ -158,6 +161,22 @@ static void obj_init (FILE *fp, efunc errfunc, ldfunc ldef) {
datatail = &datahead; datatail = &datahead;
obj_entry_seg = NO_SEG; obj_entry_seg = NO_SEG;
obj_uppercase = FALSE; obj_uppercase = FALSE;
if (os2) {
obj_directive ("group", "FLAT", 1);
defgrp = grphead;
} else
defgrp = NULL;
}
static void dos_init (FILE *fp, efunc errfunc, ldfunc ldef) {
os2 = FALSE;
obj_init (fp, errfunc, ldef);
}
static void os2_init (FILE *fp, efunc errfunc, ldfunc ldef) {
os2 = TRUE;
obj_init (fp, errfunc, ldef);
} }
static void obj_cleanup (void) { static void obj_cleanup (void) {
@ -227,12 +246,13 @@ static void obj_deflabel (char *name, long segment,
* First check for the double-period, signifying something * First check for the double-period, signifying something
* unusual. * unusual.
*/ */
if (name[0] == '.' && name[1] == '.') { if (name[0] == '.' && name[1] == '.' && name[2] != '@') {
if (!strcmp(name, "..start")) { if (!strcmp(name, "..start")) {
obj_entry_seg = segment; obj_entry_seg = segment;
obj_entry_ofs = offset; obj_entry_ofs = offset;
return;
} }
return; error (ERR_NONFATAL, "unrecognised special symbol `%s'", name);
} }
/* /*
@ -265,6 +285,17 @@ static void obj_deflabel (char *name, long segment,
return; return;
} }
/*
* If `any_segs' is still FALSE, we might need to define a
* default segment, if they're trying to declare a label in
* `first_seg'.
*/
if (!any_segs && segment == first_seg) {
int tempint; /* ignored */
if (segment != obj_segment("__NASMDEFSEG", 2, &tempint))
error (ERR_PANIC, "strange segment conditions in OBJ driver");
}
for (seg = seghead; seg; seg = seg->next) for (seg = seghead; seg; seg = seg->next)
if (seg->index == segment) { if (seg->index == segment) {
/* /*
@ -272,7 +303,6 @@ static void obj_deflabel (char *name, long segment,
*/ */
if (is_global) { if (is_global) {
struct Public *pub; struct Public *pub;
pub = *seg->pubtail = nasm_malloc(sizeof(*pub)); pub = *seg->pubtail = nasm_malloc(sizeof(*pub));
seg->pubtail = &pub->next; seg->pubtail = &pub->next;
pub->next = NULL; pub->next = NULL;
@ -390,7 +420,8 @@ static void obj_out (long segto, void *data, unsigned long type,
datacurr->nonempty = TRUE; datacurr->nonempty = TRUE;
if (segment != NO_SEG) if (segment != NO_SEG)
obj_write_fixup (datacurr, size, obj_write_fixup (datacurr, size,
(realtype == OUT_REL2ADR ? 0 : 0x4000), (realtype == OUT_REL2ADR ||
realtype == OUT_REL4ADR ? 0 : 0x4000),
segment, wrt, segment, wrt,
(seg->currentpos - datacurr->startpos)); (seg->currentpos - datacurr->startpos));
seg->currentpos += size; seg->currentpos += size;
@ -506,10 +537,14 @@ static void obj_write_fixup (struct ObjData *data, int bytes,
/* /*
* If no WRT given, assume the natural default, which is method * If no WRT given, assume the natural default, which is method
* F5 unless we are doing an OFFSET fixup for a grouped * F5 unless we are doing an OFFSET fixup for a grouped
* segment, in which case we require F1 (group). * segment, in which case we require F1 (group). Oh, and in
* OS/2 mode we're in F1 (group) on `defgrp' _always_, by
* default.
*/ */
if (wrt == NO_SEG) { if (wrt == NO_SEG) {
if (!base && s && s->grp) if (os2)
method |= 0x10, fidx = defgrp->obj_index;
else if (!base && s && s->grp)
method |= 0x10, fidx = s->grp->obj_index; method |= 0x10, fidx = s->grp->obj_index;
else else
method |= 0x50, fidx = -1; method |= 0x50, fidx = -1;
@ -731,7 +766,7 @@ static long obj_segment (char *name, int pass, int *bits) {
static int obj_directive (char *directive, char *value, int pass) { static int obj_directive (char *directive, char *value, int pass) {
if (!strcmp(directive, "group")) { if (!strcmp(directive, "group")) {
char *p, *q; char *p, *q, *v;
if (pass == 1) { if (pass == 1) {
struct Group *grp; struct Group *grp;
struct Segment *seg; struct Segment *seg;
@ -740,6 +775,7 @@ static int obj_directive (char *directive, char *value, int pass) {
q = value; q = value;
while (*q == '.') while (*q == '.')
q++; /* hack, but a documented one */ q++; /* hack, but a documented one */
v = q;
while (*q && !isspace(*q)) while (*q && !isspace(*q))
q++; q++;
if (isspace(*q)) { if (isspace(*q)) {
@ -747,16 +783,23 @@ static int obj_directive (char *directive, char *value, int pass) {
while (*q && isspace(*q)) while (*q && isspace(*q))
q++; q++;
} }
if (!*q) { /*
error(ERR_NONFATAL, "GROUP directive contains no segments"); * Here we used to sanity-check the group directive to
return 1; * ensure nobody tried to declare a group containing no
} * segments. However, OS/2 does this as standard
* practice, so the sanity check has been removed.
*
* if (!*q) {
* error(ERR_NONFATAL,"GROUP directive contains no segments");
* return 1;
* }
*/
obj_idx = 1; obj_idx = 1;
for (grp = grphead; grp; grp = grp->next) { for (grp = grphead; grp; grp = grp->next) {
obj_idx++; obj_idx++;
if (!strcmp(grp->name, value)) { if (!strcmp(grp->name, v)) {
error(ERR_NONFATAL, "group `%s' defined twice", value); error(ERR_NONFATAL, "group `%s' defined twice", v);
return 1; return 1;
} }
} }
@ -770,7 +813,7 @@ static int obj_directive (char *directive, char *value, int pass) {
grp->name = NULL; grp->name = NULL;
obj_grp_needs_update = grp; obj_grp_needs_update = grp;
deflabel (value, grp->index+1, 0L, &of_obj, error); deflabel (v, grp->index+1, 0L, &of_obj, error);
obj_grp_needs_update = NULL; obj_grp_needs_update = NULL;
while (*q) { while (*q) {
@ -1072,12 +1115,17 @@ static void obj_write_file (void) {
/* /*
* Write a COMENT record stating that the linker's first pass * Write a COMENT record stating that the linker's first pass
* may stop processing at this point. * may stop processing at this point. Exception is if we're in
* OS/2 mode and our MODEND record specifies a start point, in
* which case, according to the OS/2 documentation, this COMENT
* should be omitted.
*/ */
recptr = record; if (!os2 || obj_entry_seg == NO_SEG) {
recptr = obj_write_rword (recptr, 0x40A2); recptr = record;
recptr = obj_write_byte (recptr, 1); recptr = obj_write_rword (recptr, 0x40A2);
obj_record (COMENT, record, recptr); recptr = obj_write_byte (recptr, 1);
obj_record (COMENT, record, recptr);
}
/* /*
* Write the LEDATA/FIXUPP pairs. * Write the LEDATA/FIXUPP pairs.
@ -1086,7 +1134,7 @@ static void obj_write_file (void) {
if (data->nonempty) { if (data->nonempty) {
obj_record (data->letype, data->ledata, data->lptr); obj_record (data->letype, data->ledata, data->lptr);
if (data->fptr != data->fixupp) if (data->fptr != data->fixupp)
obj_record (FIXUPP, data->fixupp, data->fptr); obj_record (data->ftype, data->fixupp, data->fptr);
} }
} }
@ -1218,9 +1266,22 @@ static void obj_record(int type, unsigned char *start, unsigned char *end) {
} }
struct ofmt of_obj = { struct ofmt of_obj = {
"Microsoft MS-DOS 16-bit object files", "Microsoft MS-DOS 16-bit OMF object files",
"obj", "obj",
obj_init, dos_init,
obj_out,
obj_deflabel,
obj_segment,
obj_segbase,
obj_directive,
obj_filename,
obj_cleanup
};
struct ofmt of_os2 = {
"OS/2 object files (variant of OMF)",
"os2",
os2_init,
obj_out, obj_out,
obj_deflabel, obj_deflabel,
obj_segment, obj_segment,

View File

@ -91,7 +91,7 @@ typedef struct memorybuffer {
struct memorybuffer *next; struct memorybuffer *next;
} memorybuffer; } memorybuffer;
static memorybuffer * newmembuf(){ static memorybuffer * newmembuf(void){
memorybuffer * t; memorybuffer * t;
t = nasm_malloc(sizeof(memorybuffer)); t = nasm_malloc(sizeof(memorybuffer));
@ -269,6 +269,11 @@ static void rdf_deflabel(char *name, long segment, long offset, int is_global)
static int warned_common = 0; static int warned_common = 0;
#endif #endif
if (name[0] == '.' && name[1] == '.' && name[2] != '@') {
error (ERR_NONFATAL, "unrecognised special symbol `%s'", name);
return;
}
if (is_global && segment > 4) { if (is_global && segment > 4) {
#ifdef VERBOSE_WARNINGS #ifdef VERBOSE_WARNINGS
if (! warned_common) { if (! warned_common) {

View File

@ -153,6 +153,9 @@ insn *parse_line (long segment, long offset, lfunc lookup_label, int pass,
i = nexttoken(); i = nexttoken();
if (i == ':') { /* skip over the optional colon */ if (i == ':') { /* skip over the optional colon */
i = nexttoken(); i = nexttoken();
} else if (i == 0 && pass == 1) {
error (ERR_WARNING|ERR_WARN_OL,
"label alone on a line without a colon might be in error");
} }
} else /* no label; so, moving swiftly on */ } else /* no label; so, moving swiftly on */
result->label = NULL; result->label = NULL;
@ -187,7 +190,7 @@ insn *parse_line (long segment, long offset, lfunc lookup_label, int pass,
} else { } else {
result->times = value->value; result->times = value->value;
if (value->value < 0) if (value->value < 0)
error(ERR_WARNING, "TIMES value %d is negative", error(ERR_NONFATAL, "TIMES value %d is negative",
value->value); value->value);
} }
} else { } else {
@ -318,6 +321,21 @@ insn *parse_line (long segment, long offset, lfunc lookup_label, int pass,
insn_names[result->opcode], oper_num); insn_names[result->opcode], oper_num);
} }
} }
/*
* We're about to call nexttoken(), which will eat the
* comma that we're currently sitting on between
* arguments. However, we'd better check first that it
* _is_ a comma.
*/
if (i == 0) /* also could be EOL */
break;
if (i != ',') {
error (ERR_NONFATAL, "comma expected after `%s' operand %d",
insn_names[result->opcode], oper_num);
result->opcode = -1;/* unrecoverable parse error: */
return result; /* ignore this instruction */
}
} }
if (result->opcode == I_INCBIN) { if (result->opcode == I_INCBIN) {
@ -358,6 +376,7 @@ insn *parse_line (long segment, long offset, lfunc lookup_label, int pass,
for (operand = 0; operand < 3; operand++) { for (operand = 0; operand < 3; operand++) {
expr *seg, *value; /* used most of the time */ expr *seg, *value; /* used most of the time */
int mref; /* is this going to be a memory ref? */ int mref; /* is this going to be a memory ref? */
int bracket; /* is it a [] mref, or a & mref? */
result->oprs[operand].addr_size = 0;/* have to zero this whatever */ result->oprs[operand].addr_size = 0;/* have to zero this whatever */
i = nexttoken(); i = nexttoken();
@ -397,9 +416,10 @@ insn *parse_line (long segment, long offset, lfunc lookup_label, int pass,
i = nexttoken(); i = nexttoken();
} }
if (i == '[') { /* memory reference */ if (i == '[' || i == '&') { /* memory reference */
i = nexttoken();
mref = TRUE; mref = TRUE;
bracket = (i == '[');
i = nexttoken();
if (i == TOKEN_SPECIAL) { /* check for address size override */ if (i == TOKEN_SPECIAL) { /* check for address size override */
switch ((int)tokval.t_integer) { switch ((int)tokval.t_integer) {
case S_WORD: case S_WORD:
@ -415,8 +435,10 @@ insn *parse_line (long segment, long offset, lfunc lookup_label, int pass,
} }
i = nexttoken(); i = nexttoken();
} }
} else /* immediate operand, or register */ } else { /* immediate operand, or register */
mref = FALSE; mref = FALSE;
bracket = FALSE; /* placate optimisers */
}
eval_reset(); eval_reset();
@ -454,7 +476,7 @@ insn *parse_line (long segment, long offset, lfunc lookup_label, int pass,
return result; /* ignore this instruction */ return result; /* ignore this instruction */
} }
} else seg = NULL; } else seg = NULL;
if (mref) { /* find ] at the end */ if (mref && bracket) { /* find ] at the end */
if (i != ']') { if (i != ']') {
error (ERR_NONFATAL, "parser: expecting ]"); error (ERR_NONFATAL, "parser: expecting ]");
do { /* error recovery again */ do { /* error recovery again */
@ -910,6 +932,8 @@ static int is_reloc (expr *vect) {
if (!vect->type) if (!vect->type)
return 1; return 1;
} }
if (vect->type != EXPR_WRT && vect->value != 0 && vect->value != 1)
return 0; /* segment base multiplier non-unity */
do { do {
vect++; vect++;
} while (vect->type && (vect->type == EXPR_WRT || !vect->value)); } while (vect->type && (vect->type == EXPR_WRT || !vect->value));
@ -1313,10 +1337,6 @@ static expr *evaluate (int critical) {
return NULL; return NULL;
if (i == TOKEN_WRT) { if (i == TOKEN_WRT) {
if (!is_reloc(e)) {
error(ERR_NONFATAL, "invalid left-hand operand to WRT");
return NULL;
}
i = nexttoken(); /* eat the WRT */ i = nexttoken(); /* eat the WRT */
f = expr6 (critical); f = expr6 (critical);
if (!f) if (!f)

272
preproc.c
View File

@ -24,6 +24,7 @@ typedef struct Token Token;
typedef struct Line Line; typedef struct Line Line;
typedef struct Include Include; typedef struct Include Include;
typedef struct Cond Cond; typedef struct Cond Cond;
typedef struct IncPath IncPath;
/* /*
* Store the definition of a single-line macro. * Store the definition of a single-line macro.
@ -46,6 +47,7 @@ struct MMacro {
int casesense; int casesense;
int nparam_min, nparam_max; int nparam_min, nparam_max;
int plus; /* is the last parameter greedy? */ int plus; /* is the last parameter greedy? */
int nolist; /* is this macro listing-inhibited? */
int in_progress; int in_progress;
Token **defaults, *dlist; Token **defaults, *dlist;
Line *expansion; Line *expansion;
@ -79,6 +81,11 @@ struct Context {
* the token representing `x' will have its type changed to * the token representing `x' will have its type changed to
* TOK_SMAC_PARAM, but the one representing `y' will be * TOK_SMAC_PARAM, but the one representing `y' will be
* TOK_SMAC_PARAM+1. * TOK_SMAC_PARAM+1.
*
* TOK_INTERNAL_STRING is a dirty hack: it's a single string token
* which doesn't need quotes around it. Used in the pre-include
* mechanism as an alternative to trying to find a sensible type of
* quote to use on the filename we were passed.
*/ */
struct Token { struct Token {
Token *next; Token *next;
@ -88,7 +95,8 @@ struct Token {
}; };
enum { enum {
TOK_WHITESPACE = 1, TOK_COMMENT, TOK_ID, TOK_PREPROC_ID, TOK_STRING, TOK_WHITESPACE = 1, TOK_COMMENT, TOK_ID, TOK_PREPROC_ID, TOK_STRING,
TOK_NUMBER, TOK_SMAC_END, TOK_OTHER, TOK_PS_OTHER, TOK_SMAC_PARAM TOK_NUMBER, TOK_SMAC_END, TOK_OTHER, TOK_PS_OTHER, TOK_SMAC_PARAM,
TOK_INTERNAL_STRING
}; };
/* /*
@ -110,8 +118,8 @@ enum {
* markers delimiting the end of the expansion of a given macro. * markers delimiting the end of the expansion of a given macro.
* This is for use in the cycle-tracking code. Such structures have * This is for use in the cycle-tracking code. Such structures have
* `finishes' non-NULL, and `first' NULL. All others have * `finishes' non-NULL, and `first' NULL. All others have
* `finishes' NULL, but `first' may still be non-NULL if the line * `finishes' NULL, but `first' may still be NULL if the line is
* is blank. * blank.
*/ */
struct Line { struct Line {
Line *next; Line *next;
@ -132,6 +140,16 @@ struct Include {
int lineno, lineinc; int lineno, lineinc;
}; };
/*
* Include search path. This is simply a list of strings which get
* prepended, in turn, to the name of an include file, in an
* attempt to find the file if it's not in the current directory.
*/
struct IncPath {
IncPath *next;
char *path;
};
/* /*
* Conditional assembly: we maintain a separate stack of these for * Conditional assembly: we maintain a separate stack of these for
* each level of file inclusion. (The only reason we keep the * each level of file inclusion. (The only reason we keep the
@ -195,6 +213,7 @@ static int inverse_ccs[] = {
static Context *cstk; static Context *cstk;
static Include *istk; static Include *istk;
static IncPath *ipath = NULL;
static efunc error; static efunc error;
@ -202,6 +221,10 @@ static unsigned long unique; /* unique identifier numbers */
static char *linesync, *outline; static char *linesync, *outline;
static Line *predef = NULL;
static ListGen *list;
/* /*
* The number of hash values we use for the macro lookup tables. * The number of hash values we use for the macro lookup tables.
*/ */
@ -235,13 +258,10 @@ static MMacro *defining;
static char **stdmacpos; static char **stdmacpos;
/* /*
* The pre-preprocessing stage... This function has two purposes: * The pre-preprocessing stage... This function translates line
* firstly, it translates line number indications as they emerge * number indications as they emerge from GNU cpp (`# lineno "file"
* from GNU cpp (`# lineno "file" flags') into NASM preprocessor * flags') into NASM preprocessor line number indications (`%line
* line number indications (`%line lineno file'), and secondly, it * lineno file').
* converts [INCLUDE] and [INC] old-style inclusion directives into
* the new-style `%include' form (though in the next version it
* won't do that any more).
*/ */
static char *prepreproc(char *line) { static char *prepreproc(char *line) {
int lineno, fnlen; int lineno, fnlen;
@ -258,31 +278,8 @@ static char *prepreproc(char *line) {
line = nasm_malloc(20+fnlen); line = nasm_malloc(20+fnlen);
sprintf(line, "%%line %d %.*s", lineno, fnlen, fname); sprintf(line, "%%line %d %.*s", lineno, fnlen, fname);
nasm_free (oldline); nasm_free (oldline);
return line; }
} else if (!nasm_strnicmp(line, "[include", 8)) { return line;
oldline = line;
fname = oldline+8;
fname += strspn(fname, " \t");
fnlen = strcspn(fname, "]");
line = nasm_malloc(20+fnlen);
sprintf(line, "%%include \"%.*s\"", fnlen, fname);
error (ERR_WARNING|ERR_OFFBY1, "use of [INCLUDE] is being phased out;"
" suggest `%%include'");
nasm_free (oldline);
return line;
} else if (!nasm_strnicmp(line, "[inc", 4)) {
oldline = line;
fname = oldline+4;
fname += strspn(fname, " \t");
fnlen = strcspn(fname, "]");
line = nasm_malloc(20+fnlen);
sprintf(line, "%%include \"%.*s\"", fnlen, fname);
error (ERR_WARNING|ERR_OFFBY1, "use of [INC] is being phased out;"
" suggest `%%include'");
nasm_free (oldline);
return line;
} else
return line;
} }
/* /*
@ -384,9 +381,38 @@ static char *read_line (void) {
int bufsize; int bufsize;
if (stdmacpos) { if (stdmacpos) {
if (*stdmacpos) if (*stdmacpos) {
return nasm_strdup(*stdmacpos++); char *ret = nasm_strdup(*stdmacpos++);
else { /*
* Nasty hack: here we push the contents of `predef' on
* to the top-level expansion stack, since this is the
* most convenient way to implement the pre-include and
* pre-define features.
*/
if (!*stdmacpos) {
Line *pd, *l;
Token *head, **tail, *t, *tt;
for (pd = predef; pd; pd = pd->next) {
head = NULL;
tail = &head;
for (t = pd->first; t; t = t->next) {
tt = *tail = nasm_malloc(sizeof(Token));
tt->next = NULL;
tail = &tt->next;
tt->type = t->type;
tt->text = nasm_strdup(t->text);
tt->mac = t->mac; /* always NULL here, in fact */
}
l = nasm_malloc(sizeof(Line));
l->next = istk->expansion;
l->first = head;
l->finishes = FALSE;
istk->expansion = l;
}
}
return ret;
} else {
stdmacpos = NULL; stdmacpos = NULL;
line_sync(); line_sync();
} }
@ -428,6 +454,8 @@ static char *read_line (void) {
*/ */
buffer[strcspn(buffer, "\032")] = '\0'; buffer[strcspn(buffer, "\032")] = '\0';
list->line (LIST_READ, buffer);
return buffer; return buffer;
} }
@ -599,6 +627,37 @@ static int mstrcmp(char *p, char *q, int casesense) {
return casesense ? strcmp(p,q) : nasm_stricmp(p,q); return casesense ? strcmp(p,q) : nasm_stricmp(p,q);
} }
/*
* Open an include file. This routine must always return a valid
* file pointer if it returns - it's responsible for throwing an
* ERR_FATAL and bombing out completely if not. It should also try
* the include path one by one until it finds the file or reaches
* the end of the path.
*/
static FILE *inc_fopen(char *file) {
FILE *fp;
char *prefix = "", *combine;
IncPath *ip = ipath;
int len = strlen(file);
do {
combine = nasm_malloc(strlen(prefix)+len+1);
strcpy(combine, prefix);
strcat(combine, file);
fp = fopen(combine, "r");
nasm_free (combine);
if (fp)
return fp;
prefix = ip ? ip->path : NULL;
if (ip)
ip = ip->next;
} while (prefix);
error (ERR_FATAL|ERR_OFFBY1,
"unable to open include file `%s'", file);
return NULL; /* never reached - placate compilers */
}
/* /*
* Determine if we should warn on defining a single-line macro of * Determine if we should warn on defining a single-line macro of
* name `name', with `nparam' parameters. If nparam is 0, will * name `name', with `nparam' parameters. If nparam is 0, will
@ -741,7 +800,7 @@ static int do_directive (Token *tline) {
if (tline && tline->type == TOK_WHITESPACE) if (tline && tline->type == TOK_WHITESPACE)
tline = tline->next; tline = tline->next;
if (!tline || tline->type != TOK_PREPROC_ID || if (!tline || tline->type != TOK_PREPROC_ID ||
(tline->text[1] == '%' || tline->text[1] == '$')) (tline->text[1]=='%' || tline->text[1]=='$' || tline->text[1]=='!'))
return 0; return 0;
i = -1; i = -1;
@ -790,7 +849,7 @@ static int do_directive (Token *tline) {
case PP_CLEAR: case PP_CLEAR:
if (tline->next) if (tline->next)
error(ERR_WARNING|ERR_OFFBY1, error(ERR_WARNING|ERR_OFFBY1,
"trailing garbage after `%%pop' ignored"); "trailing garbage after `%%clear' ignored");
for (j=0; j<NHASH; j++) { for (j=0; j<NHASH; j++) {
while (mmacros[j]) { while (mmacros[j]) {
MMacro *m = mmacros[j]; MMacro *m = mmacros[j];
@ -814,26 +873,28 @@ static int do_directive (Token *tline) {
tline = tline->next; tline = tline->next;
if (tline && tline->type == TOK_WHITESPACE) if (tline && tline->type == TOK_WHITESPACE)
tline = tline->next; tline = tline->next;
if (!tline || tline->type != TOK_STRING) { if (!tline || (tline->type != TOK_STRING &&
tline->type != TOK_INTERNAL_STRING)) {
error(ERR_NONFATAL|ERR_OFFBY1, "`%%include' expects a file name"); error(ERR_NONFATAL|ERR_OFFBY1, "`%%include' expects a file name");
return 3; /* but we did _something_ */ return 3; /* but we did _something_ */
} }
if (tline->next) if (tline->next)
error(ERR_WARNING|ERR_OFFBY1, error(ERR_WARNING|ERR_OFFBY1,
"trailing garbage after `%%include' ignored"); "trailing garbage after `%%include' ignored");
p = tline->text+1; /* point past the quote to the name */ if (tline->type != TOK_INTERNAL_STRING) {
p[strlen(p)-1] = '\0'; /* remove the trailing quote */ p = tline->text+1; /* point past the quote to the name */
p[strlen(p)-1] = '\0'; /* remove the trailing quote */
} else
p = tline->text; /* internal_string is easier */
inc = nasm_malloc(sizeof(Include)); inc = nasm_malloc(sizeof(Include));
inc->next = istk; inc->next = istk;
inc->conds = NULL; inc->conds = NULL;
inc->fp = fopen(p, "r"); inc->fp = inc_fopen(p);
inc->fname = nasm_strdup(p); inc->fname = nasm_strdup(p);
inc->lineno = inc->lineinc = 1; inc->lineno = inc->lineinc = 1;
inc->expansion = NULL; inc->expansion = NULL;
if (!inc->fp)
error (ERR_FATAL|ERR_OFFBY1,
"unable to open include file `%s'", p);
istk = inc; istk = inc;
list->uplevel (LIST_INCLUDE);
return 5; return 5;
case PP_PUSH: case PP_PUSH:
@ -1078,6 +1139,7 @@ static int do_directive (Token *tline) {
defining->name = nasm_strdup(tline->text); defining->name = nasm_strdup(tline->text);
defining->casesense = (i == PP_MACRO); defining->casesense = (i == PP_MACRO);
defining->plus = FALSE; defining->plus = FALSE;
defining->nolist = FALSE;
defining->in_progress = FALSE; defining->in_progress = FALSE;
tline = tline->next; tline = tline->next;
if (tline && tline->type == TOK_WHITESPACE) if (tline && tline->type == TOK_WHITESPACE)
@ -1117,6 +1179,11 @@ static int do_directive (Token *tline) {
tline = tline->next; tline = tline->next;
defining->plus = TRUE; defining->plus = TRUE;
} }
if (tline && tline->next && tline->next->type == TOK_ID &&
!nasm_stricmp(tline->next->text, ".nolist")) {
tline = tline->next;
defining->nolist = TRUE;
}
mmac = mmacros[hash(defining->name)]; mmac = mmacros[hash(defining->name)];
while (mmac) { while (mmac) {
if (!strcmp(mmac->name, defining->name) && if (!strcmp(mmac->name, defining->name) &&
@ -1253,7 +1320,7 @@ static int do_directive (Token *tline) {
* Good. We now have a macro name, a parameter count, and a * Good. We now have a macro name, a parameter count, and a
* token list (in reverse order) for an expansion. We ought * token list (in reverse order) for an expansion. We ought
* to be OK just to create an SMacro, store it, and let * to be OK just to create an SMacro, store it, and let
* tlist_free have the rest of the line (which we have * free_tlist have the rest of the line (which we have
* carefully re-terminated after chopping off the expansion * carefully re-terminated after chopping off the expansion
* from the end). * from the end).
*/ */
@ -1375,7 +1442,7 @@ static Token *expand_smacro (Token *tline) {
if (c) { if (c) {
q = t->text+1; q = t->text+1;
q += strspn(q, "$"); q += strspn(q, "$");
sprintf(buffer, "macro.%lu.", c->number); sprintf(buffer, "..@%lu.", c->number);
p = nasm_malloc (strlen(buffer)+strlen(q)+1); p = nasm_malloc (strlen(buffer)+strlen(q)+1);
strcpy (p, buffer); strcpy (p, buffer);
strcat (p, q); strcat (p, q);
@ -1411,10 +1478,12 @@ static Token *expand_smacro (Token *tline) {
for (m = head; m; m = m->next) for (m = head; m; m = m->next)
if (!mstrcmp(m->name, p, m->casesense)) if (!mstrcmp(m->name, p, m->casesense))
break; break;
if (!m) { if (!m || m->in_progress) {
/* /*
* Didn't find one: this can't be a macro call. Copy it * Either we didn't find a macro, so this can't be a
* through and ignore it. * macro call, or we found a macro which was already in
* progress, in which case we don't _treat_ this as a
* macro call. Copy it through and ignore it.
*/ */
tline->type = TOK_PS_OTHER; /* so it will get copied above */ tline->type = TOK_PS_OTHER; /* so it will get copied above */
continue; continue;
@ -1515,7 +1584,7 @@ static Token *expand_smacro (Token *tline) {
break; break;
} }
if (!m) { if (!m) {
error (ERR_WARNING|ERR_OFFBY1, error (ERR_WARNING|ERR_OFFBY1|ERR_WARN_MNP,
"macro `%s' exists, but not taking %d parameters", "macro `%s' exists, but not taking %d parameters",
mstart->text, nparam); mstart->text, nparam);
nasm_free (params); nasm_free (params);
@ -1524,15 +1593,6 @@ static Token *expand_smacro (Token *tline) {
tline->type = TOK_PS_OTHER; tline->type = TOK_PS_OTHER;
continue; continue;
} }
if (m->in_progress) {
error (ERR_NONFATAL, "self-reference in single-line macro"
" `%s'", mstart->text);
nasm_free (params);
nasm_free (paramsize);
tline = mstart;
tline->type = TOK_PS_OTHER;
continue;
}
} }
/* /*
* Expand the macro: we are placed on the last token of the * Expand the macro: we are placed on the last token of the
@ -1713,7 +1773,7 @@ static MMacro *is_mmacro (Token *tline, Token ***params_array) {
* After all that, we didn't find one with the right number of * After all that, we didn't find one with the right number of
* parameters. Issue a warning, and fail to expand the macro. * parameters. Issue a warning, and fail to expand the macro.
*/ */
error (ERR_WARNING|ERR_OFFBY1, error (ERR_WARNING|ERR_OFFBY1|ERR_WARN_MNP,
"macro `%s' exists, but not taking %d parameters", "macro `%s' exists, but not taking %d parameters",
tline->text, nparam); tline->text, nparam);
nasm_free (params); nasm_free (params);
@ -1783,7 +1843,7 @@ static int expand_mmacro (Token *tline) {
for (i = 0; params[i]; i++) { for (i = 0; params[i]; i++) {
int brace = FALSE; int brace = FALSE;
int comma = !m->plus; int comma = (!m->plus || i < nparam-1);
t = params[i]; t = params[i];
if (t && t->type == TOK_WHITESPACE) if (t && t->type == TOK_WHITESPACE)
@ -1796,12 +1856,12 @@ static int expand_mmacro (Token *tline) {
if (!t) /* end of param because EOL */ if (!t) /* end of param because EOL */
break; break;
if (comma && t->type == TOK_OTHER && !strcmp(t->text, ",")) if (comma && t->type == TOK_OTHER && !strcmp(t->text, ","))
break; /* ... because we have hit a comma */ break; /* ... because we have hit a comma */
if (comma && t->type == TOK_WHITESPACE && if (comma && t->type == TOK_WHITESPACE &&
t->next->type == TOK_OTHER && !strcmp(t->next->text, ",")) t->next->type == TOK_OTHER && !strcmp(t->next->text, ","))
break; /* ... or a space then a comma */ break; /* ... or a space then a comma */
if (brace && t->type == TOK_OTHER && !strcmp(t->text, "}")) if (brace && t->type == TOK_OTHER && !strcmp(t->text, "}"))
break; /* ... or a brace */ break; /* ... or a brace */
t = t->next; t = t->next;
paramlen[i]++; paramlen[i]++;
} }
@ -1833,6 +1893,7 @@ static int expand_mmacro (Token *tline) {
ll = nasm_malloc(sizeof(Line)); ll = nasm_malloc(sizeof(Line));
ll->next = istk->expansion; ll->next = istk->expansion;
ll->finishes = NULL; ll->finishes = NULL;
ll->first = NULL;
tail = &ll->first; tail = &ll->first;
for (t = l->first; t; t = t->next) { for (t = l->first; t; t = t->next) {
@ -1851,7 +1912,7 @@ static int expand_mmacro (Token *tline) {
switch (t->text[1]) { switch (t->text[1]) {
case '%': case '%':
type = TOK_ID; type = TOK_ID;
sprintf(tmpbuf, "macro.%lu.", unique); sprintf(tmpbuf, "..@%lu.", unique);
text = nasm_malloc(strlen(tmpbuf)+strlen(t->text+2)+1); text = nasm_malloc(strlen(tmpbuf)+strlen(t->text+2)+1);
strcpy(text, tmpbuf); strcpy(text, tmpbuf);
strcat(text, t->text+2); strcat(text, t->text+2);
@ -1923,6 +1984,7 @@ static int expand_mmacro (Token *tline) {
} }
istk->expansion = ll; istk->expansion = ll;
} }
/* /*
@ -1942,10 +2004,12 @@ static int expand_mmacro (Token *tline) {
nasm_free (params); nasm_free (params);
free_tlist (tline); free_tlist (tline);
list->uplevel (m->nolist ? LIST_MACRO_NOLIST : LIST_MACRO);
return need_sync ? 2 : 1; return need_sync ? 2 : 1;
} }
static void pp_reset (char *file, efunc errfunc) { static void pp_reset (char *file, efunc errfunc, ListGen *listgen) {
int h; int h;
error = errfunc; error = errfunc;
@ -1967,6 +2031,7 @@ static void pp_reset (char *file, efunc errfunc) {
} }
unique = 0; unique = 0;
stdmacpos = stdmac; stdmacpos = stdmac;
list = listgen;
} }
static char *pp_getline (void) { static char *pp_getline (void) {
@ -1988,18 +2053,22 @@ static char *pp_getline (void) {
tline = NULL; tline = NULL;
while (istk->expansion && istk->expansion->finishes) { while (istk->expansion && istk->expansion->finishes) {
Line *l = istk->expansion; Line *l = istk->expansion;
tline = l->first;
l->finishes->in_progress = FALSE; l->finishes->in_progress = FALSE;
istk->expansion = l->next; istk->expansion = l->next;
nasm_free (l); nasm_free (l);
list->downlevel (LIST_MACRO);
if (!istk->expansion) if (!istk->expansion)
line_sync(); line_sync();
} }
if (istk->expansion) { if (istk->expansion) {
char *p;
Line *l = istk->expansion; Line *l = istk->expansion;
tline = l->first; tline = l->first;
istk->expansion = l->next; istk->expansion = l->next;
nasm_free (l); nasm_free (l);
p = detoken(tline);
list->line (LIST_MACRO, p);
nasm_free(p);
if (!istk->expansion) if (!istk->expansion)
line_sync(); line_sync();
} else { } else {
@ -2015,6 +2084,7 @@ static char *pp_getline (void) {
error(ERR_FATAL, "expected `%%endif' before end of file"); error(ERR_FATAL, "expected `%%endif' before end of file");
i = istk; i = istk;
istk = istk->next; istk = istk->next;
list->downlevel (LIST_INCLUDE);
nasm_free (i->fname); nasm_free (i->fname);
nasm_free (i); nasm_free (i);
if (!istk) if (!istk)
@ -2141,6 +2211,70 @@ static void pp_cleanup (void) {
ctx_pop(); ctx_pop();
} }
void pp_include_path (char *path) {
IncPath *i;
i = nasm_malloc(sizeof(IncPath));
i->path = nasm_strdup(path);
i->next = ipath;
ipath = i;
}
void pp_pre_include (char *fname) {
Token *inc, *space, *name;
Line *l;
inc = nasm_malloc(sizeof(Token));
inc->next = space = nasm_malloc(sizeof(Token));
space->next = name = nasm_malloc(sizeof(Token));
name->next = NULL;
inc->type = TOK_PREPROC_ID;
inc->text = nasm_strdup("%include");
space->type = TOK_WHITESPACE;
space->text = nasm_strdup(" ");
name->type = TOK_INTERNAL_STRING;
name->text = nasm_strdup(fname);
inc->mac = space->mac = name->mac = NULL;
l = nasm_malloc(sizeof(Line));
l->next = predef;
l->first = inc;
l->finishes = FALSE;
predef = l;
}
void pp_pre_define (char *definition) {
Token *def, *space, *name;
Line *l;
char *equals;
equals = strchr(definition, '=');
def = nasm_malloc(sizeof(Token));
def->next = space = nasm_malloc(sizeof(Token));
if (equals)
*equals = ' ';
space->next = name = tokenise(definition);
if (equals)
*equals = '=';
def->type = TOK_PREPROC_ID;
def->text = nasm_strdup("%define");
space->type = TOK_WHITESPACE;
space->text = nasm_strdup(" ");
def->mac = space->mac = NULL;
l = nasm_malloc(sizeof(Line));
l->next = predef;
l->first = def;
l->finishes = FALSE;
predef = l;
}
Preproc nasmpp = { Preproc nasmpp = {
pp_reset, pp_reset,
pp_getline, pp_getline,

View File

@ -9,6 +9,10 @@
#ifndef NASM_PREPROC_H #ifndef NASM_PREPROC_H
#define NASM_PREPROC_H #define NASM_PREPROC_H
void pp_include_path (char *);
void pp_pre_include (char *);
void pp_pre_define (char *);
extern Preproc nasmpp; extern Preproc nasmpp;
#endif #endif

112
rdoff/Makefile.sc Normal file
View File

@ -0,0 +1,112 @@
# 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)

View File

@ -81,5 +81,4 @@ amply documented in the source code... look at 'rdflib.c' and 'rdlib.c',
and the relevant sections of 'ldrdf.c' to see how libraries can be and the relevant sections of 'ldrdf.c' to see how libraries can be
handled). handled).
Julian Hall (jules@dcs.warwick.ac.uk) Julian Hall <jules@earthcorp.com>

77
standard.mac Normal file
View File

@ -0,0 +1,77 @@
; Standard macro set for NASM 0.95
%define __NASM_MAJOR__ 0
%define __NASM_MINOR__ 95
%define __SECT__ ; it ought to be defined, even if as nothing
%imacro section 1+.nolist
%define __SECT__ [section %1]
__SECT__
%endmacro
%imacro segment 1+.nolist
%define __SECT__ [segment %1]
__SECT__
%endmacro
%imacro absolute 1+.nolist
%define __SECT__ [absolute %1]
__SECT__
%endmacro
%imacro struc 1.nolist
%push struc
%define %$strucname %1
[absolute 0]
%endmacro
%imacro endstruc 0.nolist
%{$strucname}_size:
%pop
__SECT__
%endmacro
%imacro istruc 1.nolist
%push istruc
%define %$strucname %1
%$strucstart:
%endmacro
%imacro at 1-2+.nolist
times %1-($-%$strucstart) db 0
%2
%endmacro
%imacro iend 0.nolist
times %{$strucname}_size-($-%$strucstart) db 0
%pop
%endmacro
%imacro extern 1+.nolist
[extern %1]
%endmacro
%imacro bits 1+.nolist
[bits %1]
%endmacro
%imacro global 1+.nolist
[global %1]
%endmacro
%imacro common 1+.nolist
[common %1]
%endmacro
%imacro org 1+.nolist
[org %1]
%endmacro
%imacro group 1+.nolist
[group %1]
%endmacro
%imacro uppercase 1+.nolist
[uppercase %1]
%endmacro
%imacro library 1+.nolist
[library %1]
%endmacro

22
sync.c
View File

@ -7,6 +7,7 @@
*/ */
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
#include <limits.h> #include <limits.h>
#include "sync.h" #include "sync.h"
@ -21,10 +22,29 @@
static struct Sync { static struct Sync {
unsigned long pos; unsigned long pos;
unsigned long length; unsigned long length;
} synx[SYNC_MAX+1]; /* synx[0] never used - who cares :) */ } *synx;
static int nsynx; static int nsynx;
void init_sync(void) { void init_sync(void) {
/*
* I'd like to allocate an array of size SYNC_MAX, then write
* `synx--' which would allow numbering the array from one
* instead of zero without wasting memory. Sadly I don't trust
* this to work in 16-bit Large model, so it's staying the way
* it is. Btw, we don't care about freeing this array, since it
* has to last for the duration of the program and will then be
* auto-freed on exit. And I'm lazy ;-)
*
* Speaking of 16-bit Large model, that's also the reason I'm
* not declaring this array statically - by doing it
* dynamically I avoid problems with the total size of DGROUP
* in Borland C.
*/
synx = malloc((SYNC_MAX+1) * sizeof(*synx));
if (!synx) {
fprintf(stderr, "ndisasm: not enough memory for sync array\n");
exit(1);
}
nsynx = 0; nsynx = 0;
} }

View File

@ -27,4 +27,5 @@ int main(void) {
function(text); function(text);
printf("this should be 0xF00E: 0x%X\n", bsssym); printf("this should be 0xF00E: 0x%X\n", bsssym);
printf("this should be 0xD00E: 0x%X\n", commvar); printf("this should be 0xD00E: 0x%X\n", commvar);
return 0;
} }