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
Cutter <lmb@comtch.iea.com>.
0.94 not released yet
---------------------
0.94 released April 1997
------------------------
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
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.
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) \
outbin.$(OBJ) outaout.$(OBJ) outcoff.$(OBJ) outelf.$(OBJ) \
outobj.$(OBJ) outas86.$(OBJ) outrdf.$(OBJ) outdbg.$(OBJ) \
preproc.$(OBJ)
preproc.$(OBJ) listing.$(OBJ)
NDISASMOBJS = ndisasm.$(OBJ) disasm.$(OBJ) sync.$(OBJ) nasmlib.$(OBJ) \
insnsd.$(OBJ)
@ -45,26 +45,30 @@ nasm$(EXE): $(NASMOBJS)
ndisasm$(EXE): $(NDISASMOBJS)
$(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
float.$(OBJ): float.c nasm.h
insnsa.$(OBJ): insnsa.c nasm.h insns.h
insnsd.$(OBJ): insnsd.c nasm.h insns.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
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
ndisasm.$(OBJ): ndisasm.c nasm.h nasmlib.h sync.h disasm.h
outaout.$(OBJ): outaout.c nasm.h nasmlib.h outform.h
outas86.$(OBJ): outas86.c nasm.h nasmlib.h outform.h
outbin.$(OBJ): outbin.c nasm.h nasmlib.h outform.h
outcoff.$(OBJ): outcoff.c nasm.h nasmlib.h outform.h
outdbg.$(OBJ): outdbg.c nasm.h nasmlib.h outform.h
outelf.$(OBJ): outelf.c nasm.h nasmlib.h outform.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
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
# 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
# gzip, GNU tar and a sensible version of zip readily available.
DOSEXES = nasm.exe ndisasm.exe
MANPAGES = nasm.man ndisasm.man
.SUFFIXES: .man .1
@ -102,5 +105,5 @@ MANPAGES = nasm.man ndisasm.man
.1.man:
-man ./$< | ul > $@
dist: $(AUTOSRCS) $(MANPAGES) $(DOSEXES) clean
dist: $(AUTOSRCS) $(MANPAGES) clean
makedist.sh

View File

@ -27,20 +27,43 @@
# 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
# 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
OBJD=obj\\ #directory to put OBJ files in
EXED=.\ #directory to put the EXE files.
CC = tcc #compiler
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
#/O=Optimise jumps
#/A=ANSI standard C
#/ml=Model Large
#/m$(NASMSize>=the model to use
#/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
#/O=Optimise jumps
#/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) \
$(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
@ -96,17 +120,17 @@ all : nasm$(EXE) ndisasm$(EXE)
#NASM, NDISASM compile, I hope it's self explanitorie
nasm$(EXE): $(NASMOBJS) $(OUTOBJ)
$(LINK) $(LINKFLAGS) @&&^ #command for the linker
$(LIB)c0l.obj $(NASMOBJS) $(OUTOBJ) #OBJ file list,
nasm$(EXE) #EXE file name
$(LINK) $(LINKFLAGS) @&&^ #command for the linker
$(LIB)c0$(NASMSize).obj $(NASMOBJS) $(OUTOBJ) #OBJ file list
$(EXED)nasm$(EXE) #EXE file name
# No need of a map file
$(LIB)cl.lib $(LIBRARIES) #Libaries needed
$(LIB)c$(NASMSize).lib $(LIBRARIES) #Libaries needed
^
ndisasm$(EXE): $(NDISASMOBJS)
$(LINK) $(LINKFLAGS) @&&^ #command for the linker
$(LIB)c0h.obj $(NDISASMOBJS) #OBJ file list
ndisasm$(EXE) #EXE file name
$(EXED)ndisasm$(EXE) #EXE file name
# No need of a map file
$(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
$(NASM_ASM)
$(OBJD)nasm.$(OBJ): nasm.c nasm.h nasmlib.h parser.h assemble.h labels.h
outform.h
$(OBJD)listing.$(OBJ): listing.c nasm.h nasmlib.h listing.h
$(NASM_ASM)
$(OBJD)nasm.$(OBJ): nasm.c nasm.h nasmlib.h parser.h assemble.h labels.h \
listing.h outform.h
$(NASM_ASM)
$(OBJD)nasmlib.$(OBJ): nasmlib.c nasm.h nasmlib.h
@ -155,10 +182,10 @@ $(OBJD)insnsd.$(OBJ): insnsd.c nasm.h insns.h
$(DASM_ASM)
# 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,
# but in huge.
# for NASM, as it's could be the wrong model size, so we have to compile it
# 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.
#
# the -o... switch tells it the name to compile the obj file to, right here
@ -205,4 +232,4 @@ clean :
del nasm$(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)
NASMOBJS3 = outbin.$(OBJ) outaout.$(OBJ) outcoff.$(OBJ) outelf.$(OBJ)
NASMOBJS4 = outobj.$(OBJ) outas86.$(OBJ) outdbg.$(OBJ) outrdf.$(OBJ)
NASMOBJS5 = preproc.$(OBJ)
NASMOBJS5 = preproc.$(OBJ) listing.$(OBJ)
NASMOBJS = $(NASMOBJS1) $(NASMOBJS2) $(NASMOBJS3) $(NASMOBJS4) $(NASMOBJS5)
@ -57,7 +57,9 @@ float.$(OBJ): float.c nasm.h
insnsa.$(OBJ): insnsa.c nasm.h insns.h
insnsd.$(OBJ): insnsd.c nasm.h insns.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
ndisasm.$(OBJ): ndisasm.c nasm.h sync.h disasm.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
# know it's silly, but...)
CC = cl
CCFLAGS = /c /O /AL
CC = cl /c /O /AL
QCL = qcl /c /AL
LINK = cl
LINKFLAGS =
LIBRARIES =
@ -19,13 +19,13 @@ EXE = .exe#
OBJ = obj#
.c.$(OBJ):
$(CC) $(CCFLAGS) $*.c
$(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)
preproc.$(OBJ) listing.$(OBJ)
NDISASMOBJS = ndisasm.$(OBJ) disasm.$(OBJ) sync.$(OBJ) nasmlib.$(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
float.$(OBJ): float.c nasm.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
ndisasm.$(OBJ): ndisasm.c nasm.h sync.h disasm.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
# since they're just data.
insnsa.$(OBJ): insnsa.c nasm.h insns.h
qcl /c /AL insnsa.c
$(QCL) insnsa.c
insnsd.$(OBJ): insnsd.c nasm.h insns.h
qcl /c /AL insnsd.c
$(QCL) insnsd.c
clean :
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) \
outbin.$(OBJ) outaout.$(OBJ) outcoff.$(OBJ) outelf.$(OBJ) \
outobj.$(OBJ) outas86.$(OBJ) outrdf.$(OBJ) outdbg.$(OBJ) \
preproc.$(OBJ)
preproc.$(OBJ) listing.$(OBJ)
NDISASMOBJS = ndisasm.$(OBJ) disasm.$(OBJ) sync.$(OBJ) nasmlib.$(OBJ) \
insnsd.$(OBJ)
@ -92,7 +92,9 @@ float.$(OBJ): float.c nasm.h
insnsa.$(OBJ): insnsa.c nasm.h insns.h
insnsd.$(OBJ): insnsd.c nasm.h insns.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
ndisasm.$(OBJ): ndisasm.c nasm.h sync.h disasm.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) \
outbin.$(OBJ) outaout.$(OBJ) outcoff.$(OBJ) outelf.$(OBJ) \
outobj.$(OBJ) outas86.$(OBJ) outrdf.$(OBJ) outdbg.$(OBJ) \
preproc.$(OBJ)
preproc.$(OBJ) listing.$(OBJ)
NDISASMOBJS = ndisasm.$(OBJ) disasm.$(OBJ) sync.$(OBJ) nasmlib.$(OBJ) \
insnsd.$(OBJ)
@ -92,7 +92,9 @@ float.$(OBJ): float.c nasm.h
insnsa.$(OBJ): insnsa.c nasm.h insns.h
insnsd.$(OBJ): insnsd.c nasm.h insns.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
ndisasm.$(OBJ): ndisasm.c nasm.h sync.h disasm.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
prototype general-purpose x86 assembler. It will currently output
flat-form binary files, a.out, COFF and ELF Unix object files,
Microsoft 16-bit DOS and Win32 object files, the as86 object format,
and a home-grown format called RDF.
Microsoft Win32 and 16-bit DOS object files, OS/2 object files, the
as86 object format, and a home-grown format called RDF.
Also included is NDISASM, a prototype x86 binary-file disassembler
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.
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
why :-)
- Makefile.bor (for Borland C)
- Makefile.bc2 (also for Borland C, contributed by Fox Cutter
<lmb@comtch.iea.com>, may work better than Makefile.bor in some
cases).
- Makefile.dos, the one I build the standard 16-bit releases from,
designed for a hybrid system using Microsoft C and Borland Make
(don't ask why :-)
- Makefile.vc, for Microsoft Visual C++ compiling to a Win32
command-line application. This is the one I build the standard
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
executable. Contributed by Dominik Behr.
- Makefile.wcw, also for Watcom C, compiling to a Win32 command-
line application. Also contributed by Dominik Behr.
I don't guarantee that any of those, other than Makefile.dos, work,
since I don't have the compilers to test them myself. Also be
warned: I have had various conflicting reports regarding building
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
it doesn't work under Huge model either.
I can't guarantee that all of those makefiles work, because I don't
have all of those compilers. However, Makefile.dos and Makefile.vc
work on my system, and so do Makefile.bor and Makefile.bc2.
Be careful with Borland C: there have been various conflicting
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
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
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
<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 "nasm.h"
#include "nasmlib.h"
#include "assemble.h"
#include "insns.h"
@ -67,6 +68,7 @@ typedef struct {
static efunc errfunc;
static struct ofmt *outfmt;
static ListGen *list;
static long calcsize (long, long, int, insn *, char *);
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 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,
insn *instruction, struct ofmt *output, efunc error) {
insn *instruction, struct ofmt *output, efunc error,
ListGen *listgen) {
int j, size_prob;
long insn_end, itimes;
long start = offset;
@ -84,6 +127,7 @@ long assemble (long segment, long offset, int bits,
errfunc = error; /* to pass to other functions */
outfmt = output; /* likewise */
list = listgen; /* and again */
if (instruction->opcode == -1)
return 0;
@ -114,16 +158,16 @@ long assemble (long segment, long offset, int bits,
"one-byte relocation attempted");
else {
unsigned char c = e->offset;
outfmt->output (segment, &c, OUT_RAWDATA+1,
NO_SEG, NO_SEG);
out (offset, segment, &c, OUT_RAWDATA+1,
NO_SEG, NO_SEG);
}
} else if (wsize > 5) {
errfunc (ERR_NONFATAL, "integer supplied to a D%c"
" instruction", wsize==8 ? 'Q' : 'T');
} else
outfmt->output (segment, &e->offset,
OUT_ADDRESS+wsize, e->segment,
e->wrt);
out (offset, segment, &e->offset,
OUT_ADDRESS+wsize, e->segment,
e->wrt);
offset += wsize;
} else if (e->type == EOT_DB_STRING) {
int align;
@ -131,15 +175,25 @@ long assemble (long segment, long offset, int bits,
align = (-e->stringlen) % wsize;
if (align < 0)
align += wsize;
outfmt->output (segment, e->stringval,
OUT_RAWDATA+e->stringlen, NO_SEG, NO_SEG);
out (offset, segment, e->stringval,
OUT_RAWDATA+e->stringlen, NO_SEG, NO_SEG);
if (align)
outfmt->output (segment, "\0\0\0\0",
OUT_RAWDATA+align, NO_SEG, NO_SEG);
out (offset, segment, "\0\0\0\0",
OUT_RAWDATA+align, NO_SEG, NO_SEG);
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;
}
@ -170,6 +224,12 @@ long assemble (long segment, long offset, int bits,
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--) {
fseek (fp,
(instruction->eops->next ?
@ -189,11 +249,21 @@ long assemble (long segment, long offset, int bits,
" reading file `%s'", fname);
return 0; /* it doesn't much matter... */
}
outfmt->output (segment, buf, OUT_RAWDATA+m,
NO_SEG, NO_SEG);
out (offset, segment, buf, OUT_RAWDATA+m,
NO_SEG, NO_SEG);
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);
return instruction->times * len;
}
@ -257,13 +327,23 @@ long assemble (long segment, long offset, int bits,
"invalid instruction prefix");
}
if (c != 0)
outfmt->output (segment, &c, OUT_RAWDATA+1,
NO_SEG, NO_SEG);
out (offset, segment, &c, OUT_RAWDATA+1,
NO_SEG, NO_SEG);
offset++;
}
gencode (segment, offset, bits, instruction, codes, insn_end);
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;
} else if (m > 0) {
size_prob = m;
@ -473,7 +553,7 @@ static void gencode (long segment, long offset, int bits,
while (*codes) switch (c = *codes++) {
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;
offset += c;
break;
@ -486,7 +566,7 @@ static void gencode (long segment, long offset, int bits,
default:
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++;
break;
case 05: case 07:
@ -496,48 +576,48 @@ static void gencode (long segment, long offset, int bits,
default:
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++;
break;
case 010: case 011: case 012:
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;
break;
case 017:
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;
break;
case 014: case 015: case 016:
if (ins->oprs[c-014].offset < -128 || ins->oprs[c-014].offset > 127)
errfunc (ERR_WARNING, "signed byte value exceeds bounds");
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;
break;
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");
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;
break;
case 024: case 025: case 026:
if (ins->oprs[c-024].offset < 0 || ins->oprs[c-024].offset > 255)
errfunc (ERR_WARNING, "unsigned byte value exceeds bounds");
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;
break;
case 030: case 031: case 032:
if (ins->oprs[c-030].segment == NO_SEG &&
ins->oprs[c-030].wrt == NO_SEG &&
(ins->oprs[c-030].offset < -32768L ||
(ins->oprs[c-030].offset < -65536L ||
ins->oprs[c-030].offset > 65535L))
errfunc (ERR_WARNING, "word value exceeds bounds");
data = ins->oprs[c-030].offset;
outfmt->output (segment, &data, OUT_ADDRESS+2,
out (offset, segment, &data, OUT_ADDRESS+2,
ins->oprs[c-030].segment, ins->oprs[c-030].wrt);
offset += 2;
break;
@ -545,10 +625,10 @@ static void gencode (long segment, long offset, int bits,
data = ins->oprs[c-034].offset;
size = ((ins->oprs[c-034].addr_size ?
ins->oprs[c-034].addr_size : bits) == 16 ? 2 : 4);
if (size==16 && (data < -32768L || data > 65535L))
if (size==16 && (data < -65536L || data > 65535L))
errfunc (ERR_WARNING, "word value exceeds bounds");
outfmt->output (segment, &data, OUT_ADDRESS+size,
ins->oprs[c-034].segment, ins->oprs[c-034].wrt);
out (offset, segment, &data, OUT_ADDRESS+size,
ins->oprs[c-034].segment, ins->oprs[c-034].wrt);
offset += size;
break;
case 037:
@ -556,15 +636,15 @@ static void gencode (long segment, long offset, int bits,
errfunc (ERR_NONFATAL, "value referenced by FAR is not"
" relocatable");
data = 0L;
outfmt->output (segment, &data, OUT_ADDRESS+2,
outfmt->segbase(1+ins->oprs[0].segment),
out (offset, segment, &data, OUT_ADDRESS+2,
outfmt->segbase(1+ins->oprs[0].segment),
ins->oprs[0].wrt);
offset += 2;
break;
case 040: case 041: case 042:
data = ins->oprs[c-040].offset;
outfmt->output (segment, &data, OUT_ADDRESS+4,
ins->oprs[c-040].segment, ins->oprs[c-040].wrt);
out (offset, segment, &data, OUT_ADDRESS+4,
ins->oprs[c-040].segment, ins->oprs[c-040].wrt);
offset += 4;
break;
case 050: case 051: case 052:
@ -574,17 +654,18 @@ static void gencode (long segment, long offset, int bits,
if (data > 127 || data < -128)
errfunc (ERR_NONFATAL, "short jump is out of range");
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;
break;
case 060: case 061: case 062:
if (ins->oprs[c-060].segment != segment) {
data = ins->oprs[c-060].offset;
outfmt->output (segment, &data, OUT_REL2ADR+insn_end-offset,
ins->oprs[c-060].segment, ins->oprs[c-060].wrt);
out (offset, segment, &data, OUT_REL2ADR+insn_end-offset,
ins->oprs[c-060].segment, ins->oprs[c-060].wrt);
} else {
data = ins->oprs[c-060].offset - insn_end;
outfmt->output (segment, &data, OUT_ADDRESS+2, NO_SEG, NO_SEG);
out (offset, segment, &data,
OUT_ADDRESS+2, NO_SEG, NO_SEG);
}
offset += 2;
break;
@ -594,30 +675,33 @@ static void gencode (long segment, long offset, int bits,
if (ins->oprs[c-064].segment != segment) {
data = ins->oprs[c-064].offset;
size = (bits == 16 ? OUT_REL2ADR : OUT_REL4ADR);
outfmt->output (segment, &data, size+insn_end-offset,
ins->oprs[c-064].segment, ins->oprs[c-064].wrt);
out (offset, segment, &data, size+insn_end-offset,
ins->oprs[c-064].segment, ins->oprs[c-064].wrt);
size = (bits == 16 ? 2 : 4);
} else {
data = ins->oprs[c-064].offset - insn_end;
outfmt->output (segment, &data, OUT_ADDRESS+size, NO_SEG, NO_SEG);
out (offset, segment, &data,
OUT_ADDRESS+size, NO_SEG, NO_SEG);
}
offset += size;
break;
case 070: case 071: case 072:
if (ins->oprs[c-070].segment != segment) {
data = ins->oprs[c-070].offset;
outfmt->output (segment, &data, OUT_REL4ADR+insn_end-offset,
ins->oprs[c-070].segment, ins->oprs[c-070].wrt);
out (offset, segment, &data, OUT_REL4ADR+insn_end-offset,
ins->oprs[c-070].segment, ins->oprs[c-070].wrt);
} else {
data = ins->oprs[c-070].offset - insn_end;
outfmt->output (segment, &data, OUT_ADDRESS+4, NO_SEG, NO_SEG);
out (offset, segment, &data,
OUT_ADDRESS+4, NO_SEG, NO_SEG);
}
offset += 4;
break;
case 0300: case 0301: case 0302:
if (chsize (&ins->oprs[c-0300], bits)) {
*bytes = 0x67;
outfmt->output (segment, bytes, OUT_RAWDATA+1, NO_SEG, NO_SEG);
out (offset, segment, bytes,
OUT_RAWDATA+1, NO_SEG, NO_SEG);
offset += 1;
} else
offset += 0;
@ -625,7 +709,8 @@ static void gencode (long segment, long offset, int bits,
case 0310:
if (bits==32) {
*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;
} else
offset += 0;
@ -633,7 +718,8 @@ static void gencode (long segment, long offset, int bits,
case 0311:
if (bits==16) {
*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;
} else
offset += 0;
@ -643,7 +729,8 @@ static void gencode (long segment, long offset, int bits,
case 0320:
if (bits==32) {
*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;
} else
offset += 0;
@ -651,7 +738,8 @@ static void gencode (long segment, long offset, int bits,
case 0321:
if (bits==16) {
*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;
} else
offset += 0;
@ -660,7 +748,8 @@ static void gencode (long segment, long offset, int bits,
break;
case 0330:
*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;
break;
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");
else {
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;
}
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...
*/
outfmt->output (segment, bytes, OUT_RAWDATA+(long)(p-bytes),
NO_SEG, NO_SEG);
out (offset, segment, bytes, OUT_RAWDATA+(long)(p-bytes),
NO_SEG, NO_SEG);
s = p-bytes;
switch (ea_data.bytes) {
@ -703,16 +793,16 @@ static void gencode (long segment, long offset, int bits,
break;
case 1:
*bytes = ins->oprs[(c>>3)&7].offset;
outfmt->output (segment, bytes, OUT_RAWDATA+1,
NO_SEG, NO_SEG);
out (offset, segment, bytes, OUT_RAWDATA+1,
NO_SEG, NO_SEG);
s++;
break;
case 2:
case 4:
data = ins->oprs[(c>>3)&7].offset;
outfmt->output (segment, &data, OUT_ADDRESS+ea_data.bytes,
ins->oprs[(c>>3)&7].segment,
ins->oprs[(c>>3)&7].wrt);
out (offset, segment, &data,
OUT_ADDRESS+ea_data.bytes,
ins->oprs[(c>>3)&7].segment, ins->oprs[(c>>3)&7].wrt);
s += ea_data.bytes;
break;
}

View File

@ -12,6 +12,7 @@
long insn_size (long segment, long offset, int bits,
insn *instruction, efunc error);
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

View File

@ -96,8 +96,8 @@ static int whichreg(long regflags, int regval) {
static char *whichcond(int condval) {
static int conds[] = {
C_O, C_NO, C_B, C_AE, C_E, C_NE, C_BE, C_A,
C_S, C_NS, C_PE, C_PO, C_L, C_GE, C_LE, C_G
C_O, C_NO, C_C, C_NC, C_Z, C_NZ, C_NA, C_A,
C_S, C_NS, C_PE, C_PO, C_L, C_NL, C_NG, C_G
};
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;
unsigned short mult[MANT_WORDS], *m, bit;
long tenpwr, twopwr;
@ -69,7 +70,8 @@ static void flconvert(char *string, unsigned short *mant, long *exponent) {
if (!seendot)
seendot = TRUE;
else {
fprintf(stderr, "too many periods!\n");
error (ERR_NONFATAL,
"too many periods in floating-point constant");
return;
}
} else if (*string >= '0' && *string <= '9') {
@ -84,7 +86,9 @@ static void flconvert(char *string, unsigned short *mant, long *exponent) {
tenpwr++;
}
} else {
fprintf(stderr, "`%c' is invalid char\n", *string);
error (ERR_NONFATAL,
"floating-point constant: `%c' is invalid character",
*string);
return;
}
string++;
@ -209,7 +213,7 @@ static int to_double(char *str, long sign, unsigned char *result,
sign = (sign < 0 ? 0x8000L : 0L);
flconvert (str, mant, &exponent);
flconvert (str, mant, &exponent, error);
if (mant[0] & 0x8000) {
/*
* Non-zero.
@ -269,7 +273,7 @@ static int to_float(char *str, long sign, unsigned char *result,
sign = (sign < 0 ? 0x8000L : 0L);
flconvert (str, mant, &exponent);
flconvert (str, mant, &exponent, error);
if (mant[0] & 0x8000) {
/*
* Non-zero.
@ -322,7 +326,7 @@ static int to_ldoub(char *str, long sign, unsigned char *result,
sign = (sign < 0 ? 0x8000L : 0L);
flconvert (str, mant, &exponent);
flconvert (str, mant, &exponent, error);
if (mant[0] & 0x8000) {
/*
* Non-zero.

View File

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

View File

@ -15,8 +15,10 @@ look like:
| float.c |
| |
+--- assemble.c ---+
nasm.c ---+ | +--- nasmlib.c
| insnsa.c |
| | |
nasm.c ---+ insnsa.c +--- nasmlib.c
| |
+--- listing.c ----+
| |
+---- labels.c ----+
| |
@ -25,9 +27,9 @@ look like:
+----- *out.c -----+
In other words, each of `preproc.c', `parser.c', `assemble.c',
`labels.c', `outform.c' and each of the output format modules
`*out.c' are independent modules, which do not inter-communicate
except through the main program.
`labels.c', `listing.c', `outform.c' and each of the output format
modules `*out.c' are independent modules, which do not directly
inter-communicate except through the main program.
The Netwide *Disassembler* is not intended to be particularly
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
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
---------

View File

@ -133,7 +133,8 @@ void define_label_stub (char *label, efunc error) {
lptr = find_label (label, 1);
if (!lptr)
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 */
prevlabel = lptr->defn.label;
else if (!*prevlabel)
else if (label[1] != '.' && !*prevlabel)
error(ERR_NONFATAL, "attempt to define a local label before any"
" non-local labels");
@ -282,6 +283,7 @@ static char *perm_copy (char *string1, char *string2) {
if (perm_tail->size - perm_tail->usage < len) {
perm_tail->next = (struct permts *)nasm_malloc(sizeof(struct permts));
perm_tail = perm_tail->next;
perm_tail->next = NULL;
perm_tail->size = PERMTS_SIZE;
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 */
static char *stdmac[] = {
"%define __NASM_MAJOR__ 0",
"%define __NASM_MINOR__ 95",
"%define __SECT__",
"%imacro section 1+",
"%imacro section 1+.nolist",
"%define __SECT__ [section %1]",
"__SECT__",
"%endmacro",
"%imacro segment 1+",
"%imacro segment 1+.nolist",
"%define __SECT__ [segment %1]",
"__SECT__",
"%endmacro",
"%imacro absolute 1+",
"%imacro absolute 1+.nolist",
"%define __SECT__ [absolute %1]",
"__SECT__",
"%endmacro",
"%imacro struc 1",
"%imacro struc 1.nolist",
"%push struc",
"%define %$strucname %1",
"[absolute 0]",
"%endmacro",
"%imacro endstruc 0",
"%imacro endstruc 0.nolist",
"%{$strucname}_size:",
"%pop",
"__SECT__",
"%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]",
"%endmacro",
"%imacro bits 1+",
"%imacro bits 1+.nolist",
"[bits %1]",
"%endmacro",
"%imacro global 1+",
"%imacro global 1+.nolist",
"[global %1]",
"%endmacro",
"%imacro common 1+",
"%imacro common 1+.nolist",
"[common %1]",
"%endmacro",
"%imacro org 1+",
"%imacro org 1+.nolist",
"[org %1]",
"%endmacro",
"%imacro group 1+",
"%imacro group 1+.nolist",
"[group %1]",
"%endmacro",
"%imacro uppercase 1+",
"%imacro uppercase 1+.nolist",
"[uppercase %1]",
"%endmacro",
"%imacro library 1+",
"%imacro library 1+.nolist",
"[library %1]",
"%endmacro",
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",
"fdivrpficompfidivrfisubrfldenvfldl2efldl2t",
"fldlg2fldln2fpatanfprem1frstorfscalefsetpm",
"fstenvfsubrpfucomifucompinvlpgloopneloopnz",
"paddsbpaddswpmulhwpmullwpsubsbpsubswpushad",
"pushawpushfdpushfwsetnaesetnbesetngesetnle",
"wbinvd", 9);
"fstenvfsubrpfucomifucompincbininvlpgloopne",
"loopnzpaddsbpaddswpmulhwpmullwpsubsbpsubsw",
"pushadpushawpushfdpushfwsetnaesetnbesetnge",
"setnlewbinvd", 9);
variable nasm_kw_7 = strncat("cmovnaecmovnbecmovngecmovnlecmpxchgfcmovbe",
"fcmovnbfcmovnefcmovnufdecstpfincstpfrndint",
"fsincosfucomipfucomppfxtractfyl2xp1loadall",

350
nasm.c
View File

@ -19,6 +19,7 @@
#include "assemble.h"
#include "labels.h"
#include "outform.h"
#include "listing.h"
static void report_error (int, char *, ...);
static void parse_cmdline (int, char **);
@ -30,6 +31,7 @@ static void usage(void);
static char *obuf;
static char inname[FILENAME_MAX];
static char outname[FILENAME_MAX];
static char listname[FILENAME_MAX];
static char realout[FILENAME_MAX];
static int lineno; /* for error reporting */
static int lineinc; /* set by [LINE] or [ONELINE] */
@ -40,6 +42,8 @@ static struct ofmt *ofmt = NULL;
static FILE *ofile = NULL;
static int sb = 16; /* by default */
static int use_stdout = FALSE; /* by default, errors to stderr */
static long current_seg;
static struct RAA *offsets;
static long abs_offset;
@ -53,13 +57,38 @@ static int preprocess_only;
/* used by error function to report location */
static char currentfile[FILENAME_MAX];
/*
* Which of the suppressible warnings are suppressed. Entry zero
* doesn't do anything. Initial defaults are given here.
*/
static char suppressed[1+ERR_WARN_MAX] = {
0, FALSE, TRUE
};
/*
* 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
* to output. It's used when someone explicitly requests that NASM
* 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 void no_pp_cleanup (void);
static Preproc no_pp = {
@ -111,7 +140,7 @@ int main(int argc, char **argv) {
"unable to open output file `%s'", outname);
} else
ofile = NULL;
preproc->reset (inname, report_error);
preproc->reset (inname, report_error, &nasmlist);
strcpy(currentfile,inname);
lineno = 0;
lineinc = 1;
@ -130,8 +159,15 @@ int main(int argc, char **argv) {
if (ofile && terminate_after_phase)
remove(outname);
} 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) {
ofmt->filename (inname, realout, report_error);
strcpy(outname, realout);
}
@ -140,15 +176,29 @@ int main(int argc, char **argv) {
report_error (ERR_FATAL | ERR_NOFILE,
"unable to open output file `%s'", outname);
}
/*
* We must call init_labels() before ofmt->init() since
* some object formats will want to define labels in their
* init routines. (eg OS/2 defines the FLAT group)
*/
init_labels ();
ofmt->init (ofile, report_error, define_label);
assemble_file (inname);
if (!terminate_after_phase) {
ofmt->cleanup ();
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);
if (listname[0])
remove(listname);
}
}
if (want_usage)
@ -156,78 +206,171 @@ int main(int argc, char **argv) {
raa_free (offsets);
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) {
char *param;
char *envreal, *envcopy, *p, *q, *arg, *prevarg;
char separator = ' ';
*inname = *outname = '\0';
while (--argc) {
char *p = *++argv;
if (p[0]=='-') {
switch (p[1]) {
case 'o': /* these parameters take values */
case 'f':
if (p[2]) /* the parameter's in the option */
param = p+2;
else if (!argv[1]) {
report_error (ERR_NONFATAL | ERR_NOFILE | ERR_USAGE,
"option `-%c' requires an argument",
p[1]);
break;
} else
--argc, param = *++argv;
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);
}
}
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);
*inname = *outname = *listname = '\0';
/*
* First, process the NASM environment variable.
*/
envreal = getenv("NASM");
arg = NULL;
if (envreal) {
envcopy = nasm_strdup(envreal);
p = envcopy;
if (*p && *p != '-')
separator = *p++;
while (*p) {
q = p;
while (*p && *p != separator) p++;
while (*p == separator) *p++ = '\0';
prevarg = arg;
arg = q;
if (process_arg (prevarg, arg))
arg = NULL;
}
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)
report_error (ERR_NONFATAL | ERR_NOFILE | ERR_USAGE,
"no input file specified");
@ -239,12 +382,10 @@ static void assemble_file (char *fname) {
int i, rn_error;
long seg;
init_labels ();
/* pass one */
pass = 1;
current_seg = ofmt->section(NULL, pass, &sb);
preproc->reset(fname, report_error);
preproc->reset(fname, report_error, &nasmlist);
strcpy(currentfile,fname);
lineno = 0;
lineinc = 1;
@ -378,15 +519,19 @@ static void assemble_file (char *fname) {
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)
report_error (ERR_NONFATAL,
"EQU not preceded by label");
else if (output_ins.label[0] != '.' ||
output_ins.label[1] != '.') {
output_ins.label[1] != '.' ||
output_ins.label[2] == '@') {
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,
output_ins.oprs[0].segment,
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 & COLON) &&
output_ins.oprs[0].segment == NO_SEG &&
output_ins.oprs[0].wrt == NO_SEG &&
(output_ins.oprs[1].type & IMMEDIATE) &&
output_ins.oprs[1].segment == NO_SEG) {
output_ins.oprs[1].segment == NO_SEG &&
output_ins.oprs[1].wrt == NO_SEG) {
define_label (output_ins.label,
output_ins.oprs[0].offset | SEG_ABS,
output_ins.oprs[1].offset,
@ -430,6 +577,8 @@ static void assemble_file (char *fname) {
/* pass two */
pass = 2;
saa_rewind (forwrefs);
if (*listname)
nasmlist.init(listname, report_error);
{
int *p = saa_rstruct (forwrefs);
if (p)
@ -440,7 +589,7 @@ static void assemble_file (char *fname) {
current_seg = ofmt->section(NULL, pass, &sb);
raa_free (offsets);
offsets = raa_init();
preproc->reset(fname, report_error);
preproc->reset(fname, report_error, &nasmlist);
strcpy(currentfile,fname);
lineno = 0;
lineinc = 1;
@ -542,10 +691,12 @@ static void assemble_file (char *fname) {
define_label_stub (output_ins.label, report_error);
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] == '.' &&
output_ins.label[1] == '.') {
output_ins.label[1] == '.' &&
output_ins.label[2] != '@') {
if (output_ins.operands == 1 &&
(output_ins.oprs[0].type & IMMEDIATE)) {
define_label (output_ins.label,
@ -567,13 +718,14 @@ static void assemble_file (char *fname) {
}
}
offs += assemble (current_seg, offs, sb,
&output_ins, ofmt, report_error);
&output_ins, ofmt, report_error, &nasmlist);
cleanup_insn (&output_ins);
set_curr_ofs (offs);
}
nasm_free (line);
}
preproc->cleanup();
nasmlist.cleanup();
}
static int getkw (char *buf, char **value) {
@ -601,6 +753,7 @@ static int getkw (char *buf, char **value) {
*value = buf;
} else {
*buf++ = '\0';
while (isspace(*buf)) buf++; /* beppu - skip leading whitespace */
*value = buf;
while (*buf!=']') buf++;
*buf++ = '\0';
@ -625,20 +778,28 @@ static int getkw (char *buf, char **value) {
static void report_error (int severity, char *fmt, ...) {
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)
fputs ("nasm: ", stderr);
fputs ("nasm: ", use_stdout ? stdout : stderr);
else
fprintf (stderr, "%s:%d: ", currentfile,
fprintf (use_stdout ? stdout : stderr, "%s:%d: ", currentfile,
lineno + (severity & ERR_OFFBY1 ? lineinc : 0));
if ( (severity & ERR_MASK) == ERR_WARNING)
fputs ("warning: ", stderr);
fputs ("warning: ", use_stdout ? stdout : stderr);
else if ( (severity & ERR_MASK) == ERR_PANIC)
fputs ("panic: ", stderr);
fputs ("panic: ", use_stdout ? stdout : stderr);
va_start (ap, fmt);
vfprintf (stderr, fmt, ap);
fputc ('\n', stderr);
vfprintf (use_stdout ? stdout : stderr, fmt, ap);
fputc ('\n', use_stdout ? stdout : stderr);
if (severity & ERR_USAGE)
want_usage = TRUE;
@ -666,7 +827,7 @@ static void report_error (int severity, char *fmt, ...) {
}
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) {
@ -688,13 +849,16 @@ static void register_output_formats(void) {
#ifdef OF_AS86
extern struct ofmt of_as86;
#endif
/* DOS formats: OBJ, Win32 */
/* DOS and DOS-ish formats: OBJ, OS/2, Win32 */
#ifdef OF_OBJ
extern struct ofmt of_obj;
#endif
#ifdef OF_WIN32
extern struct ofmt of_win32;
#endif
#ifdef OF_OS2
extern struct ofmt of_os2;
#endif
#ifdef OF_RDF
extern struct ofmt of_rdf;
#endif
@ -723,6 +887,9 @@ static void register_output_formats(void) {
#ifdef OF_WIN32
ofmt_register (&of_win32);
#endif
#ifdef OF_OS2
ofmt_register (&of_os2);
#endif
#ifdef OF_RDF
ofmt_register (&of_rdf);
#endif
@ -740,12 +907,13 @@ static void register_output_formats(void) {
static FILE *no_pp_fp;
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_fp = fopen(file, "r");
if (!no_pp_fp)
no_pp_err (ERR_FATAL | ERR_NOFILE,
"unable to open input file `%s'", file);
(void) listgen; /* placate compilers */
}
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'.
To get usage instructions from NASM, try typing `nasm -h'. This will
also list the available output file formats, and what they are.
To produce a listing file, with the hex codes output from NASM
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
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
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
==========================
@ -106,7 +199,11 @@ LABEL: INSTRUCTION OPERANDS ; COMMENT
`LABEL' defines a label pointing to that point in the source. There
are no restrictions on white space: labels may have white space
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, `_', `$', `#', `@',
`~', `?', 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
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
===================
@ -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
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
====================================================
@ -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
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
know of will easily support this. NASM can, by means of the `word'
and `dword' specifiers. So you can code
code a 32-bit far jump in a 16-bit segment; not all assemblers will
easily support this. NASM can, by means of the `word' and `dword'
specifiers. So you can code
call 1234h:5678h ; this uses the default segment size
call word 1234h:5678h ; this is guaranteed to be 16-bit
call dword 1234h:56789ABCh ; and this is guaranteed 32-bit
jmp 1234h:5678h ; this uses the default segment size
jmp word 1234h:5678h ; this is guaranteed to be 16-bit
jmp dword 1234h:56789ABCh ; and this is guaranteed 32-bit
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
(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
have already stated that an effective address expression such as
`[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
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
TIMES to align to page boundaries. (Of course, the OBJ file format
can happily cope with page alignment, provided you specify that
segment attribute.)
TIMES to align to page boundaries. (Of course, the `obj' and `os2'
file formats can happily cope with page alignment, provided you
specify that segment attribute.)
SEG and WRT
===========
NASM contains the capability for its object file formats (currently,
only `obj' makes use of this) to permit programs to directly refer
to the segment-base values of their segments. This is achieved
either by the object format defining the segment names as symbols
(`obj' does this), or by the use of the SEG operator.
only `obj' and its variant `os2' make use of this) to permit
programs to directly refer to the segment-base values of their
segments. This is achieved either by the object format defining the
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
defined in a segment, will yield the segment base value of that
segment. (In `obj' format, symbols defined in segments which are
grouped are considered to be primarily a member of the _group_, not
the segment, and the return value of SEG reflects this.)
segment. (In `obj' and `os2' format, symbols defined in segments
which are grouped are considered to be primarily a member of the
_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
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
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
are documented with the formats. (See `obj', in particular, for some
unusual behaviour.)
are documented with the formats. (See `obj' and `os2', in
particular, for some unusual behaviour.)
`SECTION name' or `SEGMENT name' changes which section the code you
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
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
_fully_ supported in the `obj' file format: see the section on `obj'
for details.
_fully_ supported in the `obj' or `os2' file format: see the section
on `obj' for details.
`STRUC structure' begins the definition of a data structure, and
`ENDSTRUC' ends it. The structure shown above may be defined,
@ -766,8 +881,8 @@ exactly equivalently, using STRUC as follows:
struc st
stLong resd 1
stWord resw 1
stByte1 resb 1
stByte2 resb 1
stByte resb 1
stStr resb 32
endstruc
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
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
`SECTION' (and `SEGMENT') user-level directives don't just call the
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
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
present, the `bin' and `obj' formats define extra directives, which
are specified below.
present, the `bin', `obj' and `os2' formats define extra directives,
which are specified below.
The Preprocessor
================
@ -841,7 +981,30 @@ all to expand to `bar'.
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
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
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
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
--------------------
@ -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
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
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
called. (Of course the above code could have easily been coded using
`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
defining labels of this shape themselves.
@ -923,7 +1109,7 @@ modifier on the `%macro' line:
%endmacro
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
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
@ -1002,9 +1188,9 @@ defined:
which will expand to something like
jnae macro.1234.skip
jnae ..@1234.skip
mov ax,bx
macro.1234.skip:
..@1234.skip:
Note that `%+1' will allow CXZ or ECXZ to be passed as condition
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'.
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
--------------------
@ -1054,9 +1262,12 @@ File Inclusion
--------------
You can include a file using the `%include' directive. Included
files are only searched for in the current directory: there isn't
(yet - if there's demand for it it could be arranged) any default
search path for standard include files.
files are searched for in the current directory, and then in all
directories specified on the command line with the `-i' option.
(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
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
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
-----------------
@ -1159,8 +1374,8 @@ Output Formats
==============
The current output formats supported are `bin', `aout', `coff',
`elf', `as86', `obj', `win32', `rdf', and the debug pseudo-format
`dbg'.
`elf', `as86', `obj', `os2', `win32', `rdf', and the debug
pseudo-format `dbg'.
`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
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
section names `.text', `.data' and `.bss'. The layout is that
`.text' comes first in the output file, followed by `.data', and
notionally followed by `.bss'. So if you declare a BSS section in a
flat binary file, references to the BSS section will refer to space
past the end of the actual file. The `.data' and `.bss' sections are
considered to be aligned on four-byte boundaries: this is achieved
by inserting padding zero bytes between the end of the text section
and the start of the data, if there is data present. Of course if no
SECTION directives are present, everything will go into `.text', and
you will get nothing in the output except the code you wrote.
Like almost all formats (but not `obj' or `os2'), the `bin' format
defines the section names `.text', `.data' and `.bss'. The layout is
that `.text' comes first in the output file, followed by `.data',
and notionally followed by `.bss'. So if you declare a BSS section
in a flat binary file, references to the BSS section will refer to
space past the end of the actual file. The `.data' and `.bss'
sections are considered to be aligned on four-byte boundaries: this
is achieved by inserting padding zero bytes between the end of the
text section and the start of the data, if there is data present. Of
course if no SECTION directives are present, everything will go into
`.text', and you will get nothing in the output except the code you
wrote.
`bin' silently ignores GLOBAL directives, and will also not complain
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.
`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
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,
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)
------------------------------
@ -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
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
====
Apart from the missing features (correct OBJ COMMON support, ELF
alignment, ELF PIC support, etc.), there are no _known_ bugs.
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
fix them.
<jules@earthcorp.com> or <anakin@pobox.com>, and we'll try to fix
them.
Beware of Pentium-specific instructions: Intel have provided a macro
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_MAJOR_VER 0
#define NASM_MINOR_VER 94
#define NASM_VER "0.94"
#define NASM_MINOR_VER 95
#define NASM_VER "0.95"
#ifndef NULL
#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
* we're just _about_ to read, not
* 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,
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:
*/
typedef struct {
/*
* Called at the start of a pass; given a file name and an
* error reporting function.
* Called at the start of a pass; given a file name, an error
* 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
@ -120,9 +188,10 @@ typedef struct {
* (for local labels), whereas a number may appear anywhere *but* at the
* 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)=='#' \
|| (c)=='@' || (c)=='~' )
|| (c)=='~' )
/* 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')
/*
* 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
@ -381,6 +458,13 @@ struct ofmt {
* which case `offset' holds the _size_ of the variable).
* Anything else is available for the output driver to use
* 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);

View File

@ -174,7 +174,7 @@ Bugs and Improvements
=====================
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
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;
struct Symbol *sym;
if (name[0] == '.' && name[1] == '.') {
if (name[0] == '.' && name[1] == '.' && name[2] != '@') {
error (ERR_NONFATAL, "unrecognised special symbol `%s'", name);
return;
}

View File

@ -161,7 +161,8 @@ static void as86_deflabel (char *name, long segment, long offset,
int is_global) {
struct Symbol *sym;
if (name[0] == '.' && name[1] == '.') {
if (name[0] == '.' && name[1] == '.' && name[2] != '@') {
error (ERR_NONFATAL, "unrecognised special symbol `%s'", name);
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,
int is_global) {
if (name[0] == '.' && name[1] == '.' && name[2] != '@') {
error (ERR_NONFATAL, "unrecognised special symbol `%s'", name);
return;
}
if (is_global == 2) {
error (ERR_NONFATAL, "binary output format does not support common"
" variables");

View File

@ -285,7 +285,8 @@ static void coff_deflabel (char *name, long segment, long offset,
int pos = strslen+4;
struct Symbol *sym;
if (name[0] == '.' && name[1] == '.') {
if (name[0] == '.' && name[1] == '.' && name[2] != '@') {
error (ERR_NONFATAL, "unrecognised special symbol `%s'", name);
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,
int is_global) {
fprintf(dbgf,"deflabel %s := %08lx:%08lx %s (%d)\n",name,segment,offset,
is_global ? "global" : "local", is_global);
fprintf(dbgf,"deflabel %s := %08lx:%08lx %s (%d)\n",name,segment,offset,
is_global ? "global" : "local", is_global);
}
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;
struct Symbol *sym;
if (name[0] == '.' && name[1] == '.') {
if (name[0] == '.' && name[1] == '.' && name[2] != '@') {
error (ERR_NONFATAL, "unrecognised special symbol `%s'", name);
return;
}
@ -306,11 +307,18 @@ static void elf_deflabel (char *name, long segment, long offset,
else {
int i;
sym->section = SHN_UNDEF;
for (i=0; i<nsects; i++)
if (segment == sects[i]->index) {
sym->section = i+1;
break;
}
if (nsects == 0 && segment == def_seg) {
int tempint;
if (segment != elf_section_names (".text", 2, &tempint))
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) {

View File

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

View File

@ -18,7 +18,7 @@
* OF_NO_name -- remove output format 'name'
* OF_DOS -- ensure that 'obj', 'bin' & 'win32' are included.
* 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_DEFAULT=of_name -- ensure that 'name' is the default format.
@ -37,8 +37,8 @@
#define MAX_OUTPUT_FORMATS 16
struct ofmt *ofmt_find(char *name);
void ofmt_list(struct ofmt *deffmt);
struct ofmt *ofmt_find(char *);
void ofmt_list(struct ofmt *, FILE *);
void ofmt_register (struct ofmt *);
/* -------------- USER MODIFIABLE PART ---------------- */
@ -77,6 +77,9 @@ void ofmt_register (struct ofmt *);
#ifndef OF_OBJ
#define OF_OBJ
#endif
#ifndef OF_OS2
#define OF_OS2
#endif
#ifndef OF_ELF
#define OF_ELF
#endif
@ -132,6 +135,9 @@ void ofmt_register (struct ofmt *);
#ifndef OF_RDF
#define OF_RDF
#endif
#ifndef OF_OS2
#define OF_OS2
#endif
#endif
/* finally... override any format specifically specifed to be off */
@ -159,6 +165,9 @@ void ofmt_register (struct ofmt *);
#ifdef OF_NO_RDF
#undef OF_RDF
#endif
#ifdef OF_NO_OS2
#undef OF_OS2
#endif
#ifndef OF_DEFAULT
#define OF_DEFAULT of_bin

107
outobj.c
View File

@ -85,7 +85,7 @@ static struct Group {
long index;
char *name;
} segs[GROUP_MAX]; /* ...in this */
} *grphead, **grptail, *obj_grp_needs_update;
} *grphead, **grptail, *obj_grp_needs_update, *defgrp;
static struct ObjData {
struct ObjData *next;
@ -99,6 +99,8 @@ static struct ObjData {
static long obj_entry_seg, obj_entry_ofs;
static int os2;
enum RecordID { /* record ID codes */
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_value(unsigned char *, unsigned long);
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) {
ofp = fp;
@ -158,6 +161,22 @@ static void obj_init (FILE *fp, efunc errfunc, ldfunc ldef) {
datatail = &datahead;
obj_entry_seg = NO_SEG;
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) {
@ -227,12 +246,13 @@ static void obj_deflabel (char *name, long segment,
* First check for the double-period, signifying something
* unusual.
*/
if (name[0] == '.' && name[1] == '.') {
if (name[0] == '.' && name[1] == '.' && name[2] != '@') {
if (!strcmp(name, "..start")) {
obj_entry_seg = segment;
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;
}
/*
* 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)
if (seg->index == segment) {
/*
@ -272,7 +303,6 @@ static void obj_deflabel (char *name, long segment,
*/
if (is_global) {
struct Public *pub;
pub = *seg->pubtail = nasm_malloc(sizeof(*pub));
seg->pubtail = &pub->next;
pub->next = NULL;
@ -390,7 +420,8 @@ static void obj_out (long segto, void *data, unsigned long type,
datacurr->nonempty = TRUE;
if (segment != NO_SEG)
obj_write_fixup (datacurr, size,
(realtype == OUT_REL2ADR ? 0 : 0x4000),
(realtype == OUT_REL2ADR ||
realtype == OUT_REL4ADR ? 0 : 0x4000),
segment, wrt,
(seg->currentpos - datacurr->startpos));
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
* 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 (!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;
else
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) {
if (!strcmp(directive, "group")) {
char *p, *q;
char *p, *q, *v;
if (pass == 1) {
struct Group *grp;
struct Segment *seg;
@ -740,6 +775,7 @@ static int obj_directive (char *directive, char *value, int pass) {
q = value;
while (*q == '.')
q++; /* hack, but a documented one */
v = q;
while (*q && !isspace(*q))
q++;
if (isspace(*q)) {
@ -747,16 +783,23 @@ static int obj_directive (char *directive, char *value, int pass) {
while (*q && isspace(*q))
q++;
}
if (!*q) {
error(ERR_NONFATAL, "GROUP directive contains no segments");
return 1;
}
/*
* Here we used to sanity-check the group directive to
* 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;
for (grp = grphead; grp; grp = grp->next) {
obj_idx++;
if (!strcmp(grp->name, value)) {
error(ERR_NONFATAL, "group `%s' defined twice", value);
if (!strcmp(grp->name, v)) {
error(ERR_NONFATAL, "group `%s' defined twice", v);
return 1;
}
}
@ -770,7 +813,7 @@ static int obj_directive (char *directive, char *value, int pass) {
grp->name = NULL;
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;
while (*q) {
@ -1072,12 +1115,17 @@ static void obj_write_file (void) {
/*
* 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;
recptr = obj_write_rword (recptr, 0x40A2);
recptr = obj_write_byte (recptr, 1);
obj_record (COMENT, record, recptr);
if (!os2 || obj_entry_seg == NO_SEG) {
recptr = record;
recptr = obj_write_rword (recptr, 0x40A2);
recptr = obj_write_byte (recptr, 1);
obj_record (COMENT, record, recptr);
}
/*
* Write the LEDATA/FIXUPP pairs.
@ -1086,7 +1134,7 @@ static void obj_write_file (void) {
if (data->nonempty) {
obj_record (data->letype, data->ledata, data->lptr);
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 = {
"Microsoft MS-DOS 16-bit object files",
"Microsoft MS-DOS 16-bit OMF object files",
"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_deflabel,
obj_segment,

View File

@ -91,7 +91,7 @@ typedef struct memorybuffer {
struct memorybuffer *next;
} memorybuffer;
static memorybuffer * newmembuf(){
static memorybuffer * newmembuf(void){
memorybuffer * t;
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;
#endif
if (name[0] == '.' && name[1] == '.' && name[2] != '@') {
error (ERR_NONFATAL, "unrecognised special symbol `%s'", name);
return;
}
if (is_global && segment > 4) {
#ifdef VERBOSE_WARNINGS
if (! warned_common) {

View File

@ -153,6 +153,9 @@ insn *parse_line (long segment, long offset, lfunc lookup_label, int pass,
i = nexttoken();
if (i == ':') { /* skip over the optional colon */
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 */
result->label = NULL;
@ -187,7 +190,7 @@ insn *parse_line (long segment, long offset, lfunc lookup_label, int pass,
} else {
result->times = value->value;
if (value->value < 0)
error(ERR_WARNING, "TIMES value %d is negative",
error(ERR_NONFATAL, "TIMES value %d is negative",
value->value);
}
} else {
@ -318,6 +321,21 @@ insn *parse_line (long segment, long offset, lfunc lookup_label, int pass,
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) {
@ -358,6 +376,7 @@ insn *parse_line (long segment, long offset, lfunc lookup_label, int pass,
for (operand = 0; operand < 3; operand++) {
expr *seg, *value; /* used most of the time */
int mref; /* is this going to be a memory ref? */
int bracket; /* is it a [] mref, or a & mref? */
result->oprs[operand].addr_size = 0;/* have to zero this whatever */
i = nexttoken();
@ -397,9 +416,10 @@ insn *parse_line (long segment, long offset, lfunc lookup_label, int pass,
i = nexttoken();
}
if (i == '[') { /* memory reference */
i = nexttoken();
if (i == '[' || i == '&') { /* memory reference */
mref = TRUE;
bracket = (i == '[');
i = nexttoken();
if (i == TOKEN_SPECIAL) { /* check for address size override */
switch ((int)tokval.t_integer) {
case S_WORD:
@ -415,8 +435,10 @@ insn *parse_line (long segment, long offset, lfunc lookup_label, int pass,
}
i = nexttoken();
}
} else /* immediate operand, or register */
} else { /* immediate operand, or register */
mref = FALSE;
bracket = FALSE; /* placate optimisers */
}
eval_reset();
@ -454,7 +476,7 @@ insn *parse_line (long segment, long offset, lfunc lookup_label, int pass,
return result; /* ignore this instruction */
}
} else seg = NULL;
if (mref) { /* find ] at the end */
if (mref && bracket) { /* find ] at the end */
if (i != ']') {
error (ERR_NONFATAL, "parser: expecting ]");
do { /* error recovery again */
@ -910,6 +932,8 @@ static int is_reloc (expr *vect) {
if (!vect->type)
return 1;
}
if (vect->type != EXPR_WRT && vect->value != 0 && vect->value != 1)
return 0; /* segment base multiplier non-unity */
do {
vect++;
} while (vect->type && (vect->type == EXPR_WRT || !vect->value));
@ -1313,10 +1337,6 @@ static expr *evaluate (int critical) {
return NULL;
if (i == TOKEN_WRT) {
if (!is_reloc(e)) {
error(ERR_NONFATAL, "invalid left-hand operand to WRT");
return NULL;
}
i = nexttoken(); /* eat the WRT */
f = expr6 (critical);
if (!f)

272
preproc.c
View File

@ -24,6 +24,7 @@ typedef struct Token Token;
typedef struct Line Line;
typedef struct Include Include;
typedef struct Cond Cond;
typedef struct IncPath IncPath;
/*
* Store the definition of a single-line macro.
@ -46,6 +47,7 @@ struct MMacro {
int casesense;
int nparam_min, nparam_max;
int plus; /* is the last parameter greedy? */
int nolist; /* is this macro listing-inhibited? */
int in_progress;
Token **defaults, *dlist;
Line *expansion;
@ -79,6 +81,11 @@ struct Context {
* the token representing `x' will have its type changed to
* TOK_SMAC_PARAM, but the one representing `y' will be
* 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 {
Token *next;
@ -88,7 +95,8 @@ struct Token {
};
enum {
TOK_WHITESPACE = 1, TOK_COMMENT, TOK_ID, TOK_PREPROC_ID, TOK_STRING,
TOK_NUMBER, TOK_SMAC_END, TOK_OTHER, TOK_PS_OTHER, TOK_SMAC_PARAM
TOK_NUMBER, TOK_SMAC_END, TOK_OTHER, TOK_PS_OTHER, TOK_SMAC_PARAM,
TOK_INTERNAL_STRING
};
/*
@ -110,8 +118,8 @@ enum {
* markers delimiting the end of the expansion of a given macro.
* This is for use in the cycle-tracking code. Such structures have
* `finishes' non-NULL, and `first' NULL. All others have
* `finishes' NULL, but `first' may still be non-NULL if the line
* is blank.
* `finishes' NULL, but `first' may still be NULL if the line is
* blank.
*/
struct Line {
Line *next;
@ -132,6 +140,16 @@ struct Include {
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
* each level of file inclusion. (The only reason we keep the
@ -195,6 +213,7 @@ static int inverse_ccs[] = {
static Context *cstk;
static Include *istk;
static IncPath *ipath = NULL;
static efunc error;
@ -202,6 +221,10 @@ static unsigned long unique; /* unique identifier numbers */
static char *linesync, *outline;
static Line *predef = NULL;
static ListGen *list;
/*
* The number of hash values we use for the macro lookup tables.
*/
@ -235,13 +258,10 @@ static MMacro *defining;
static char **stdmacpos;
/*
* The pre-preprocessing stage... This function has two purposes:
* firstly, it translates line number indications as they emerge
* from GNU cpp (`# lineno "file" flags') into NASM preprocessor
* line number indications (`%line lineno file'), and secondly, it
* 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).
* The pre-preprocessing stage... This function translates line
* number indications as they emerge from GNU cpp (`# lineno "file"
* flags') into NASM preprocessor line number indications (`%line
* lineno file').
*/
static char *prepreproc(char *line) {
int lineno, fnlen;
@ -258,31 +278,8 @@ static char *prepreproc(char *line) {
line = nasm_malloc(20+fnlen);
sprintf(line, "%%line %d %.*s", lineno, fnlen, fname);
nasm_free (oldline);
return line;
} else if (!nasm_strnicmp(line, "[include", 8)) {
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;
}
return line;
}
/*
@ -384,9 +381,38 @@ static char *read_line (void) {
int bufsize;
if (stdmacpos) {
if (*stdmacpos)
return nasm_strdup(*stdmacpos++);
else {
if (*stdmacpos) {
char *ret = nasm_strdup(*stdmacpos++);
/*
* 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;
line_sync();
}
@ -428,6 +454,8 @@ static char *read_line (void) {
*/
buffer[strcspn(buffer, "\032")] = '\0';
list->line (LIST_READ, 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);
}
/*
* 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
* 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)
tline = tline->next;
if (!tline || tline->type != TOK_PREPROC_ID ||
(tline->text[1] == '%' || tline->text[1] == '$'))
(tline->text[1]=='%' || tline->text[1]=='$' || tline->text[1]=='!'))
return 0;
i = -1;
@ -790,7 +849,7 @@ static int do_directive (Token *tline) {
case PP_CLEAR:
if (tline->next)
error(ERR_WARNING|ERR_OFFBY1,
"trailing garbage after `%%pop' ignored");
"trailing garbage after `%%clear' ignored");
for (j=0; j<NHASH; j++) {
while (mmacros[j]) {
MMacro *m = mmacros[j];
@ -814,26 +873,28 @@ static int do_directive (Token *tline) {
tline = tline->next;
if (tline && tline->type == TOK_WHITESPACE)
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");
return 3; /* but we did _something_ */
}
if (tline->next)
error(ERR_WARNING|ERR_OFFBY1,
"trailing garbage after `%%include' ignored");
p = tline->text+1; /* point past the quote to the name */
p[strlen(p)-1] = '\0'; /* remove the trailing quote */
if (tline->type != TOK_INTERNAL_STRING) {
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->next = istk;
inc->conds = NULL;
inc->fp = fopen(p, "r");
inc->fp = inc_fopen(p);
inc->fname = nasm_strdup(p);
inc->lineno = inc->lineinc = 1;
inc->expansion = NULL;
if (!inc->fp)
error (ERR_FATAL|ERR_OFFBY1,
"unable to open include file `%s'", p);
istk = inc;
list->uplevel (LIST_INCLUDE);
return 5;
case PP_PUSH:
@ -1078,6 +1139,7 @@ static int do_directive (Token *tline) {
defining->name = nasm_strdup(tline->text);
defining->casesense = (i == PP_MACRO);
defining->plus = FALSE;
defining->nolist = FALSE;
defining->in_progress = FALSE;
tline = tline->next;
if (tline && tline->type == TOK_WHITESPACE)
@ -1117,6 +1179,11 @@ static int do_directive (Token *tline) {
tline = tline->next;
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)];
while (mmac) {
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
* token list (in reverse order) for an expansion. We ought
* 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
* from the end).
*/
@ -1375,7 +1442,7 @@ static Token *expand_smacro (Token *tline) {
if (c) {
q = t->text+1;
q += strspn(q, "$");
sprintf(buffer, "macro.%lu.", c->number);
sprintf(buffer, "..@%lu.", c->number);
p = nasm_malloc (strlen(buffer)+strlen(q)+1);
strcpy (p, buffer);
strcat (p, q);
@ -1411,10 +1478,12 @@ static Token *expand_smacro (Token *tline) {
for (m = head; m; m = m->next)
if (!mstrcmp(m->name, p, m->casesense))
break;
if (!m) {
if (!m || m->in_progress) {
/*
* Didn't find one: this can't be a macro call. Copy it
* through and ignore it.
* Either we didn't find a macro, so this can't be a
* macro call, or we found a macro which was already in
* progress, in which case we don't _treat_ this as a
* macro call. Copy it through and ignore it.
*/
tline->type = TOK_PS_OTHER; /* so it will get copied above */
continue;
@ -1515,7 +1584,7 @@ static Token *expand_smacro (Token *tline) {
break;
}
if (!m) {
error (ERR_WARNING|ERR_OFFBY1,
error (ERR_WARNING|ERR_OFFBY1|ERR_WARN_MNP,
"macro `%s' exists, but not taking %d parameters",
mstart->text, nparam);
nasm_free (params);
@ -1524,15 +1593,6 @@ static Token *expand_smacro (Token *tline) {
tline->type = TOK_PS_OTHER;
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
@ -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
* 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",
tline->text, nparam);
nasm_free (params);
@ -1783,7 +1843,7 @@ static int expand_mmacro (Token *tline) {
for (i = 0; params[i]; i++) {
int brace = FALSE;
int comma = !m->plus;
int comma = (!m->plus || i < nparam-1);
t = params[i];
if (t && t->type == TOK_WHITESPACE)
@ -1796,12 +1856,12 @@ static int expand_mmacro (Token *tline) {
if (!t) /* end of param because EOL */
break;
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 &&
t->next->type == TOK_OTHER && !strcmp(t->next->text, ","))
break; /* ... or a space then a comma */
if (brace && t->type == TOK_OTHER && !strcmp(t->text, "}"))
break; /* ... or a brace */
break; /* ... or a brace */
t = t->next;
paramlen[i]++;
}
@ -1833,6 +1893,7 @@ static int expand_mmacro (Token *tline) {
ll = nasm_malloc(sizeof(Line));
ll->next = istk->expansion;
ll->finishes = NULL;
ll->first = NULL;
tail = &ll->first;
for (t = l->first; t; t = t->next) {
@ -1851,7 +1912,7 @@ static int expand_mmacro (Token *tline) {
switch (t->text[1]) {
case '%':
type = TOK_ID;
sprintf(tmpbuf, "macro.%lu.", unique);
sprintf(tmpbuf, "..@%lu.", unique);
text = nasm_malloc(strlen(tmpbuf)+strlen(t->text+2)+1);
strcpy(text, tmpbuf);
strcat(text, t->text+2);
@ -1923,6 +1984,7 @@ static int expand_mmacro (Token *tline) {
}
istk->expansion = ll;
}
/*
@ -1942,10 +2004,12 @@ static int expand_mmacro (Token *tline) {
nasm_free (params);
free_tlist (tline);
list->uplevel (m->nolist ? LIST_MACRO_NOLIST : LIST_MACRO);
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;
error = errfunc;
@ -1967,6 +2031,7 @@ static void pp_reset (char *file, efunc errfunc) {
}
unique = 0;
stdmacpos = stdmac;
list = listgen;
}
static char *pp_getline (void) {
@ -1988,18 +2053,22 @@ static char *pp_getline (void) {
tline = NULL;
while (istk->expansion && istk->expansion->finishes) {
Line *l = istk->expansion;
tline = l->first;
l->finishes->in_progress = FALSE;
istk->expansion = l->next;
nasm_free (l);
list->downlevel (LIST_MACRO);
if (!istk->expansion)
line_sync();
}
if (istk->expansion) {
char *p;
Line *l = istk->expansion;
tline = l->first;
istk->expansion = l->next;
nasm_free (l);
p = detoken(tline);
list->line (LIST_MACRO, p);
nasm_free(p);
if (!istk->expansion)
line_sync();
} else {
@ -2015,6 +2084,7 @@ static char *pp_getline (void) {
error(ERR_FATAL, "expected `%%endif' before end of file");
i = istk;
istk = istk->next;
list->downlevel (LIST_INCLUDE);
nasm_free (i->fname);
nasm_free (i);
if (!istk)
@ -2141,6 +2211,70 @@ static void pp_cleanup (void) {
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 = {
pp_reset,
pp_getline,

View File

@ -9,6 +9,10 @@
#ifndef 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;
#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
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 <stdlib.h>
#include <limits.h>
#include "sync.h"
@ -21,10 +22,29 @@
static struct Sync {
unsigned long pos;
unsigned long length;
} synx[SYNC_MAX+1]; /* synx[0] never used - who cares :) */
} *synx;
static int nsynx;
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;
}

View File

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