NASM 0.93

This commit is contained in:
H. Peter Anvin 2002-04-30 20:51:53 +00:00
parent ea6e34db64
commit ea8382740d
16 changed files with 1053 additions and 362 deletions

83
Changes Normal file
View File

@ -0,0 +1,83 @@
Change log for NASM
===================
0.90 released October 1996
--------------------------
First release version. First support for object file output. Other
changes from previous version (0.3x) too numerous to document.
0.91 released November 1996
---------------------------
Loads of bug fixes.
Support for RDF added.
Support for DBG debugging format added.
Support for 32-bit extensions to Microsoft OBJ format added.
Revised for Borland C: some variable names changed, makefile added.
LCC support revised to actually work.
JMP/CALL NEAR/FAR notation added.
`a16', `o16', `a32' and `o32' prefixes added.
Range checking on short jumps implemented.
MMX instruction support added.
Negative floating point constant support added.
Memory handling improved to bypass 64K barrier under DOS.
$ prefix to force treatment of reserved words as identifiers added.
Default-size mechanism for object formats added.
Compile-time configurability added.
`#', `@', `~' and `?' are now valid characters in labels.
`-e' and `-k' options in NDISASM added.
0.92 released January 1997
--------------------------
The FDIVP/FDIVRP and FSUBP/FSUBRP pairs had been inverted: this was
fixed. This also affected the LCC driver.
Fixed a bug regarding 32-bit effective addresses of the form
[other_register+ESP].
Documentary changes, notably documentation of the fact that Borland
Win32 compilers use `obj' rather than `win32' object format.
Fixed the COMENT record in OBJ files, which was formatted
incorrectly.
Fixed a bug causing segfaults in large RDF files.
OBJ format now strips initial periods from segment and group
definitions, in order to avoid complications with the local label
syntax.
Fixed a bug in disassembling far calls and jumps in NDISASM.
Added support for user-defined sections in COFF and ELF files.
Compiled the DOS binaries with a sensible amount of stack, to
prevent stack overflows on any arithmetic expression containing
parentheses.
Fixed a bug in handling of files that do not terminate in a newline.
0.93 released January 1997
--------------------------
This release went out in a great hurry after semi-crippling bugs
were found in 0.92.
Really _did_ fix the stack overflows this time. *blush*
Had problems with EA instruction sizes changing between passes, when
an offset contained a forward reference and so 4 bytes were
allocated for the offset in pass one; by pass two the symbol had
been defined and happened to be a small absolute value, so only 1
byte got allocated, causing instruction size mismatch between passes
and hence incorrect address calculations. Fixed.
Stupid bug in the revised ELF section generation fixed (associated
string-table section for .symtab was hard-coded as 7, even when this
didn't fit with the real section table). Was causing `ld' to
seg-fault under Linux.
Included a new Borland C makefile, Makefile.bc2, donated by Fox
Cutter <lmb@comtch.iea.com>.

51
Licence
View File

@ -34,10 +34,19 @@ freely redistributable software (by which we mean software that may
be obtained free of charge) without requiring permission from the
authors, as long as due credit is given to the authors of the
Software in the resulting work, as long as the authors are informed
of this action, and as long as those parts of the Software that are
used remain under this licence.
of this action if possible, and as long as those parts of the
Software that are used remain under this licence.
III. The Software, or parts thereof, may be incorporated into other
III. Modified forms of the Software may be created and distributed
as long as the authors are informed of this action if possible, as
long as the resulting work remains under this licence, as long as
the modified form of the Software is distributed with documentation
which still gives credit to the original authors of the Software,
and as long as the modified form of the Software is distributed with
a clear statement that it is not the original form of the Software
in the form that it was distributed by the authors.
IV. The Software, or parts thereof, may be incorporated into other
software which is not freely redistributable (i.e. software for
which a fee is charged), as long as permission is granted from the
authors of the Software. The authors reserve the right to grant this
@ -45,17 +54,31 @@ permission only for a fee, which may at our option take the form of
royalty payments. The authors also reserve the right to refuse to
grant permission if they deem it necessary.
IV. You may not copy, modify or distribute the Software except under
the terms given in this licence document. You may not sublicense the
Software or in any way place it under any other licence than this
one. Since you have not signed this licence, you are not of course
required to accept it; however, no other licence applies to the
Software, and nothing else grants you any permission to copy,
modify, sublicense or distribute the Software in any way. These
actions are therefore prohibited if you do not accept this licence.
V. The Software may be incorporated, in its original archive form,
into software collections or archives which are not freely
redistributable, as long as it is clearly stated that the Software
itself remains freely redistributable and remains under this licence
and no other. Such collections are deemed not to fall under article
IV of this licence.
V. There is no warranty for the Software, to the extent permitted by
applicable law. The authors provide the Software "as is" without
VI. Object files or programs generated by the Software as output do
not fall under this licence at all, and may be placed under any
licence the author wishes. The authors explicitly lay no claim to,
and assert no rights over, any programs written by other people and
assembled into object form by the Software.
VII. You may not copy, modify or distribute the Software except
under the terms given in this licence document. You may not
sublicense the Software or in any way place it under any other
licence than this one. Since you have not signed this licence, you
are not of course required to accept it; however, no other licence
applies to the Software, and nothing else grants you any permission
to copy, modify, sublicense or distribute the Software in any way.
These actions are therefore prohibited if you do not accept this
licence.
VIII. There is no warranty for the Software, to the extent permitted
by applicable law. The authors provide the Software "as is" without
warranty of any kind, either expressed or implied, including but not
limited to the implied warranties of merchantability and fitness for
a particular purpose. The entire risk as to the quality and
@ -63,7 +86,7 @@ performance of the Software is with you. Should the Software prove
defective, you assume the cost of all necessary servicing, repair or
correction.
VI. In no event, unless required by applicable law or agreed to in
IX. In no event, unless required by applicable law or agreed to in
writing, will any of the authors be liable to you for damages,
including any general, special, incidental or consequential damages,
arising out of the use or the inability to use the Software,

205
Makefile.bc2 Normal file
View File

@ -0,0 +1,205 @@
# Makefile for the Netwide Assembler under 16-bit DOS (aimed at Borland 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.
#
# This makefile is made for compile NASM and NDISASM on a 16 bit dos
# compiler like Microsoft C, or Borland C. This should work on all
# verioson of Turbo C++ and Borland C++ from version 3.0 and upwords.
# I'm not fully sure how it will handel on Microsoft C, but all the
# switches are documented, and it shouldn't be a problem to change it
# over.
#
# It does show a few of my preferances, like putting the OBJ files
# in a seperat directory, but if you just set OBJD to '.', it will
# drop them all in the current directory (though you still need to
# make the directory it's self).
#
# Most everything is remarked, and explaned in full, it should be
# easy to convert it to another compiler. I tried to make the devision
# of information logical, and easy to follow.
#
# BEFORE YOU USE THIS MAKE FILE!!!
#
# Make sure the line below is set to the propper location of your standard
# 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.
LIB =c:\\tc\\lib\\ #location standard libaries
OBJD=obj\\ #directory to put OBJ files in
CC = tcc #compiler
LINK = tlink #linker
CCFLAGS = /c /O /A /ml /n$(OBJD) #compiler flags for NASM
#/c=compile only
#/O=Optimise jumps
#/A=ANSI standard C
#/ml=Model Large
#/n$(OBJD)= put the OBJ files in the diectory given.
DCCFLAGS = /c /O /A /mh /n$(OBJD) #compiler flags for NDISASM
#/c=compile only
#/O=Optimise jumps
#/A=ANSI standard C
#/mh=Model huge
#/n$(OBJD)= put the OBJ files in the diectory given.
#NOTE: Huge modle is used, and the array in insnsd.c is large enough to
#over size the d-group in large mode.
LINKFLAGS = /c /x #linker flags
#/c=case segnificance on symboles
#/x=No map file at all
LIBRARIES = #any libaries to add, out side of the standard libary
EXE = .exe #executable file extention (keep the . as the start)
OBJ = obj #OBJ file extention
NASM_ASM=$(CC) $(CCFLAGS) $&.c #Command line for NASM
DASM_ASM=$(CC) $(DCCFLAGS) $&.c #command line for NDISASM
# NOTE: $& is used to create the file name, as it only gives the name it's
# self, where as using $* would have give the full path of the file it
# want's done. This becomes a problem if the OBJ files are in a seperate
# directory, becuse it will then try to find the source file in the OBJ
# dir.
################################################################
#The OBJ files that NASM is dependent on
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)
################################################################
#The OBJ files that NDISASM is dependent on
NDISASMOBJS = $(OBJD)ndisasm.$(OBJ) $(OBJD)disasm.$(OBJ) $(OBJD)sync.$(OBJ) \
$(OBJD)nasmlibd.$(OBJ) $(OBJD)insnsd.$(OBJ)
################################################################
#The OBJ file for the output formats.
OUTOBJ= $(OBJD)outbin.$(OBJ) $(OBJD)outaout.$(OBJ) $(OBJD)outcoff.$(OBJ) \
$(OBJD)outelf.$(OBJ) $(OBJD)outobj.$(OBJ) $(OBJD)outas86.$(OBJ) \
$(OBJD)outrdf.$(OBJ) $(OBJD)outdbg.$(OBJ)
################################################################
# Build everything
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
# No need of a map file
$(LIB)cl.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
# No need of a map file
$(LIB)ch.lib $(LIBRARIES) #Libaries needed
^
################################################################
# Dependencies for all of NASM's obj files
$(OBJD)assemble.$(OBJ): assemble.c nasm.h assemble.h insns.h
$(NASM_ASM)
$(OBJD)float.$(OBJ): float.c nasm.h
$(NASM_ASM)
$(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
$(NASM_ASM)
$(OBJD)nasmlib.$(OBJ): nasmlib.c nasm.h nasmlib.h
$(NASM_ASM)
$(OBJD)parser.$(OBJ): parser.c nasm.h nasmlib.h parser.h float.h names.c
$(NASM_ASM)
$(OBJD)insnsa.$(OBJ): insnsa.c nasm.h insns.h
$(NASM_ASM)
################################################################
# Dependencies for all of NDISASM's obj files
$(OBJD)disasm.$(OBJ): disasm.c nasm.h disasm.h sync.h insns.h names.c
$(DASM_ASM)
$(OBJD)ndisasm.$(OBJ): ndisasm.c nasm.h sync.h disasm.h
$(DASM_ASM)
$(OBJD)sync.$(OBJ): sync.c sync.h
$(DASM_ASM)
$(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.
#
# So as not to overwrite the nasmlib.obj for NASM (if I 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
# $(OBJD)nasmlibd.obj
$(OBJD)nasmlibd.$(OBJ): nasmlib.c nasm.h nasmlib.h
$(CC) $(DCCFLAGS) -o$(OBJD)nasmlibd.obj nasmlib.c
################################################################
# Dependencies for all of the output format's OBJ files
$(OBJD)outas86.$(OBJ): outas86.c nasm.h nasmlib.h
$(NASM_ASM)
$(OBJD)outaout.$(OBJ): outaout.c nasm.h nasmlib.h
$(NASM_ASM)
$(OBJD)outbin.$(OBJ): outbin.c nasm.h nasmlib.h
$(NASM_ASM)
$(OBJD)outcoff.$(OBJ): outcoff.c nasm.h nasmlib.h
$(NASM_ASM)
$(OBJD)outdbg.$(OBJ): outdbg.c nasm.h nasmlib.h
$(NASM_ASM)
$(OBJD)outelf.$(OBJ): outelf.c nasm.h nasmlib.h
$(NASM_ASM)
$(OBJD)outobj.$(OBJ): outobj.c nasm.h nasmlib.h
$(NASM_ASM)
$(OBJD)outrdf.$(OBJ): outrdf.c nasm.h nasmlib.h
$(NASM_ASM)
$(OBJD)outform.$(OBJ): outform.c outform.h nasm.h
$(NASM_ASM)
################################################################
# A quick way to delete the OBJ files as well as the binaries.
clean :
del $(OBJD)*.obj
del nasm$(EXE)
del ndisasm$(EXE)
# Makefile created by Fox Cutter <lmb@comtch.iea.com> --01/21/97

View File

@ -33,8 +33,9 @@ all : nasm$(EXE) ndisasm$(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$(EXE): $(NASMOBJS)
cl /Fenasm.exe a*.obj f*.obj insnsa.obj l*.obj na*.obj o*.obj p*.obj
cl /Fenasm.exe /F 4000 $(LINKOBJS)
ndisasm$(EXE): $(NDISASMOBJS)
cl /Fendisasm.exe $(NDISASMOBJS)

14
Readme
View File

@ -7,13 +7,19 @@ 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.
To install NASM, you will need GCC. Type `make', and then when it
has finished copy the file `nasm' (and maybe `ndisasm') to a
directory on your search path (I use /usr/local/bin on my linux
machine at home, and ~/bin on other machines where I don't have root
To install NASM on Linux, type `make', and then when it has finished
copy the file `nasm' (and maybe `ndisasm') to a directory on your
search path (maybe /usr/local/bin, or ~/bin if you don't have root
access). You may also want to copy the man page `nasm.1' (and maybe
`ndisasm.1') to somewhere sensible.
To rebuild the DOS sources, three makefiles are provided:
Makefile.dos, the one the standard release is built from, designed
for a hybrid system using Microsoft C and Borland Make (don't ask
why :-), Makefile.bor (for Borland C) and Makefile.bc2 (also for
Borland C, contributed by Fox Cutter <lmb@comtch.iea.com>, may work
better than Makefile.bor in some cases).
If you want to build a restricted version of NASM containing only
some of the object file formats, you can achieve this by adding
#defines to `outform.h' (see the file itself for documentation), or

View File

@ -72,7 +72,7 @@ static long calcsize (long, long, int, insn *, char *);
static void gencode (long, long, int, insn *, char *, long);
static int regval (operand *o);
static int matches (struct itemplate *, insn *);
static ea *process_ea (operand *, ea *, int, int);
static ea *process_ea (operand *, ea *, int, int, int);
static int chsize (operand *, int);
long assemble (long segment, long offset, int bits,
@ -363,8 +363,8 @@ static long calcsize (long segment, long offset, int bits,
default: /* can't do it by 'case' statements */
if (c>=0100 && c<=0277) { /* it's an EA */
ea ea_data;
if (!process_ea (&ins->oprs[(c>>3)&7], &ea_data, bits, 0)) {
if (!process_ea (&ins->oprs[(c>>3)&7], &ea_data, bits, 0,
ins->forw_ref)) {
errfunc (ERR_NONFATAL, "invalid effective address");
return -1;
} else
@ -598,7 +598,8 @@ static void gencode (long segment, long offset, int bits,
rfield = regval (&ins->oprs[c&7]);
else /* rfield is constant */
rfield = c & 7;
if (!process_ea (&ins->oprs[(c>>3)&7], &ea_data, bits, rfield))
if (!process_ea (&ins->oprs[(c>>3)&7], &ea_data, bits, rfield,
ins->forw_ref))
errfunc (ERR_NONFATAL, "invalid effective address");
p = bytes;
@ -733,7 +734,8 @@ static int matches (struct itemplate *itemp, insn *instruction) {
return ret;
}
static ea *process_ea (operand *input, ea *output, int addrbits, int rfield) {
static ea *process_ea (operand *input, ea *output, int addrbits, int rfield,
int forw_ref) {
if (!(REGISTER & ~input->type)) { /* it's a single register */
static int regs[] = {
R_MM0, R_EAX, R_AX, R_AL, R_MM1, R_ECX, R_CX, R_CL,
@ -789,6 +791,8 @@ static ea *process_ea (operand *input, ea *output, int addrbits, int rfield) {
b = i, i = -1;
if (((s==2 && i!=R_ESP) || s==3 || s==5 || s==9) && b==-1)
b = i, s--; /* convert 3*EAX to EAX+2*EAX */
if (s==1 && i==R_ESP) /* swap ESP into base if scale is 1 */
i = b, b = R_ESP;
if (i==R_ESP || (s!=1 && s!=2 && s!=4 && s!=8 && i!=-1))
return NULL; /* wrong, for various reasons */
@ -806,12 +810,14 @@ static ea *process_ea (operand *input, ea *output, int addrbits, int rfield) {
default: /* should never happen */
return NULL;
}
if (b==-1 || (b!=R_EBP && o==0 && seg==NO_SEG))
if (b==-1 || (b!=R_EBP && o==0 &&
seg==NO_SEG && !forw_ref))
mod = 0;
else if (o>=-128 && o<=127 && seg==NO_SEG)
else if (o>=-128 && o<=127 && seg==NO_SEG && !forw_ref)
mod = 1;
else
mod = 2;
output->sib_present = FALSE;
output->bytes = (b==-1 || mod==2 ? 4 : mod);
output->modrm = (mod<<6) | (rfield<<3) | rm;
@ -854,9 +860,10 @@ static ea *process_ea (operand *input, ea *output, int addrbits, int rfield) {
return NULL; /* panic */
}
if (b==-1 || (b!=R_EBP && o==0 && seg==NO_SEG))
if (b==-1 || (b!=R_EBP && o==0 &&
seg==NO_SEG && !forw_ref))
mod = 0;
else if (o>=-128 && o<=127 && seg==NO_SEG)
else if (o>=-128 && o<=127 && seg==NO_SEG && !forw_ref)
mod = 1;
else
mod = 2;
@ -907,9 +914,9 @@ static ea *process_ea (operand *input, ea *output, int addrbits, int rfield) {
if (rm==-1) /* can't happen, in theory */
return NULL; /* so panic if it does */
if (o==0 && seg==NO_SEG && rm!=6)
if (o==0 && seg==NO_SEG && !forw_ref && rm!=6)
mod = 0;
else if (o>=-128 && o<=127 && seg==NO_SEG)
else if (o>=-128 && o<=127 && seg==NO_SEG && !forw_ref)
mod = 1;
else
mod = 2;

View File

@ -125,7 +125,7 @@ BTS reg32,reg32 \321\300\2\x0F\xAB\101 386
BTS rm16,imm \320\300\2\x0F\xBA\205\25 386
BTS rm32,imm \321\300\2\x0F\xBA\205\25 386
CALL imm \322\1\xE8\64 8086
CALL imm|far \322\1\x9A\34\37 8086
CALL imm|far \322\1\x9A\34\37 8086,ND
CALL imm:imm \322\1\x9A\35\30 8086
CALL imm16:imm \320\1\x9A\31\30 8086
CALL imm:imm16 \320\1\x9A\31\30 8086
@ -256,16 +256,16 @@ FDIV fpureg|to \1\xDC\10\xF0 8086,FPU
FDIV fpureg,fpu0 \1\xDC\10\xF0 8086,FPU
FDIV fpureg \1\xD8\10\xF0 8086,FPU
FDIV fpu0,fpureg \1\xD8\11\xF0 8086,FPU
FDIVP fpureg,fpu0 \1\xDE\10\xF0 8086,FPU
FDIVP fpureg \1\xDE\10\xF0 8086,FPU
FDIVP fpureg,fpu0 \1\xDE\10\xF8 8086,FPU
FDIVP fpureg \1\xDE\10\xF8 8086,FPU
FDIVR mem32 \300\1\xD8\207 8086,FPU
FDIVR mem64 \300\1\xDC\207 8086,FPU
FDIVR fpureg|to \1\xDC\10\xF8 8086,FPU
FDIVR fpureg,fpu0 \1\xDC\10\xF8 8086,FPU
FDIVR fpureg \1\xD8\10\xF8 8086,FPU
FDIVR fpu0,fpureg \1\xD8\11\xF8 8086,FPU
FDIVRP fpureg \1\xDE\10\xF8 8086,FPU
FDIVRP fpureg,fpu0 \1\xDE\10\xF8 8086,FPU
FDIVRP fpureg \1\xDE\10\xF0 8086,FPU
FDIVRP fpureg,fpu0 \1\xDE\10\xF0 8086,FPU
FENI void \2\xDB\xE0 8086,FPU
FFREE fpureg \1\xDD\10\xC0 8086,FPU
FIADD mem32 \300\1\xDA\200 8086,FPU
@ -345,16 +345,16 @@ FSUB fpureg|to \1\xDC\10\xE0 8086,FPU
FSUB fpureg,fpu0 \1\xDC\10\xE0 8086,FPU
FSUB fpureg \1\xD8\10\xE0 8086,FPU
FSUB fpu0,fpureg \1\xD8\11\xE0 8086,FPU
FSUBP fpureg \1\xDE\10\xE0 8086,FPU
FSUBP fpureg,fpu0 \1\xDE\10\xE0 8086,FPU
FSUBP fpureg \1\xDE\10\xE8 8086,FPU
FSUBP fpureg,fpu0 \1\xDE\10\xE8 8086,FPU
FSUBR mem32 \300\1\xD8\205 8086,FPU
FSUBR mem64 \300\1\xDC\205 8086,FPU
FSUBR fpureg|to \1\xDC\10\xE8 8086,FPU
FSUBR fpureg,fpu0 \1\xDC\10\xE8 8086,FPU
FSUBR fpureg \1\xD8\10\xE8 8086,FPU
FSUBR fpu0,fpureg \1\xD8\11\xE8 8086,FPU
FSUBRP fpureg \1\xDE\10\xE8 8086,FPU
FSUBRP fpureg,fpu0 \1\xDE\10\xE8 8086,FPU
FSUBRP fpureg \1\xDE\10\xE0 8086,FPU
FSUBRP fpureg,fpu0 \1\xDE\10\xE0 8086,FPU
FTST void \2\xD9\xE4 8086,FPU
FUCOM fpureg \1\xDD\10\xE0 386,FPU
FUCOMI fpureg \1\xDB\10\xE8 P6,FPU
@ -423,7 +423,7 @@ JCXZ imm \320\1\xE3\50 8086
JECXZ imm \321\1\xE3\50 386
JMP imm|short \1\xEB\50 8086
JMP imm \322\1\xE9\64 8086
JMP imm|far \322\1\xEA\34\37 8086
JMP imm|far \322\1\xEA\34\37 8086,ND
JMP imm:imm \322\1\xEA\35\30 8086
JMP imm16:imm \320\1\xEA\31\30 8086
JMP imm:imm16 \320\1\xEA\31\30 8086

View File

@ -241,17 +241,17 @@ reg: ADDD(reg,reg) "faddp st1\n"
reg: ADDF(reg,memf) "fadd %1\n"
reg: ADDF(reg,reg) "faddp st1\n"
reg: DIVD(reg,memf) "fdiv %1\n"
reg: DIVD(reg,reg) "fdivrp st1\n"
reg: DIVD(reg,reg) "fdivp st1\n"
reg: DIVF(reg,memf) "fdiv %1\n"
reg: DIVF(reg,reg) "fdivrp st1\n"
reg: DIVF(reg,reg) "fdivp st1\n"
reg: MULD(reg,memf) "fmul %1\n"
reg: MULD(reg,reg) "fmulp st1\n"
reg: MULF(reg,memf) "fmul %1\n"
reg: MULF(reg,reg) "fmulp st1\n"
reg: SUBD(reg,memf) "fsub %1\n"
reg: SUBD(reg,reg) "fsubrp st1\n"
reg: SUBD(reg,reg) "fsubp st1\n"
reg: SUBF(reg,memf) "fsub %1\n"
reg: SUBF(reg,reg) "fsubrp st1\n"
reg: SUBF(reg,reg) "fsubp st1\n"
reg: CVFD(reg) "# CVFD\n"
reg: CVDF(reg) "sub esp,4\nfstp dword [esp]\nfld dword [esp]\nadd esp,4\n" 12

39
nasm.c
View File

@ -40,7 +40,9 @@ static int sb = 16; /* by default */
static long current_seg;
static struct RAA *offsets;
static long abs_offset;
#define OFFSET_DELTA 256
static struct SAA *forwrefs; /* keep track of forward references */
static int forwline;
/*
* get/set current offset...
@ -58,6 +60,7 @@ int main(int argc, char **argv) {
nasm_set_malloc_error (report_error);
offsets = raa_init();
forwrefs = saa_init ((long)sizeof(int));
seg_init();
@ -201,7 +204,7 @@ static void assemble_file (char *fname) {
lineno++;
if (buffer[strlen(buffer)-1] == '\n') {
buffer[strlen(buffer)-1] = '\0';
} else {
} else if (!feof(fp)) {
/*
* We have a line that's too long. Throw an error, read
* to EOL, and ignore the line for assembly purposes.
@ -212,10 +215,14 @@ static void assemble_file (char *fname) {
buffer[strlen(buffer)-1] != '\n');
continue; /* read another line */
}
/*
* Handle spurious ^Z, which may be inserted by some file
* transfer utilities.
*/
buffer[strcspn(buffer, "\032")] = '\0';
/* here we parse our directives; this is not handled by the 'real'
* parser. */
if ( (i = getkw (buffer, &value)) ) {
switch (i) {
case 1: /* [SEGMENT n] */
@ -306,6 +313,8 @@ static void assemble_file (char *fname) {
long offs = get_curr_ofs;
parse_line (current_seg, offs, lookup_label,
1, buffer, &output_ins, ofmt, report_error);
if (output_ins.forw_ref)
*(int *)saa_wstruct(forwrefs) = lineno;
if (output_ins.opcode == I_EQU) {
/*
* Special `..' EQUs get processed in pass two.
@ -358,6 +367,14 @@ static void assemble_file (char *fname) {
/* pass two */
pass = 2;
rewind (fp);
saa_rewind (forwrefs);
{
int *p = saa_rstruct (forwrefs);
if (p)
forwline = *p;
else
forwline = -1;
}
current_seg = ofmt->section(NULL, pass, &sb);
raa_free (offsets);
offsets = raa_init();
@ -377,9 +394,14 @@ static void assemble_file (char *fname) {
lineno++;
if (buffer[strlen(buffer)-1] == '\n')
buffer[strlen(buffer)-1] = '\0';
else
else if (!feof(fp))
report_error (ERR_PANIC,
"too-long line got through from pass one");
/*
* Handle spurious ^Z, which may be inserted by some file
* transfer utilities.
*/
buffer[strcspn(buffer, "\032")] = '\0';
/* here we parse our directives; this is not handled by
* the 'real' parser. */
@ -452,6 +474,15 @@ static void assemble_file (char *fname) {
long offs = get_curr_ofs;
parse_line (current_seg, offs, lookup_label, 2,
buffer, &output_ins, ofmt, report_error);
if (lineno == forwline) {
int *p = saa_rstruct (forwrefs);
if (p)
forwline = *p;
else
forwline = -1;
output_ins.forw_ref = TRUE;
} else
output_ins.forw_ref = FALSE;
obuf = buffer;
if (output_ins.label)
define_label_stub (output_ins.label, report_error);

186
nasm.doc
View File

@ -16,7 +16,8 @@ that maybe someone ought to write one.
since it's designed to be a back end to gcc, which always feeds it
correct code. So its error checking is minimal. Also its syntax is
horrible, from the point of view of anyone trying to actually
_write_ anything in it. Plus you can't write 16-bit code in it.
_write_ anything in it. Plus you can't write 16-bit code in it
(properly).
- AS86 is Linux specific, and (my version at least) doesn't seem to
have much (or any) documentation.
@ -255,7 +256,8 @@ ordinary opcodes, so you can code trivial unrolled loops in it:
times 100 movsb
Note that there is no effective difference between `times 100 resb
1' and `resb 100'.
1' and `resb 100', except that the latter will be assembled about
100 times faster due to the internal structure of the assembler.
Effective Addresses
===================
@ -402,7 +404,8 @@ generate code to read a byte from [DS:SI], no matter what the size
of the segment. There are also explicit operand-size override
prefixes, `o16' and `o32', which will optionally generate 0x66
bytes, but these are provided for completeness and should never have
to be used.
to be used. (Note that NASM does not support the LODS, STOS, MOVS
etc. forms of the string instructions.)
Constants
=========
@ -517,6 +520,15 @@ this can be used for alignment, as shown below:
times ($$-$) & 3 nop ; pad with NOPs to 4-byte boundary
Note that this technique aligns to a four-byte boundary with respect
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.)
SEG and WRT
===========
@ -612,6 +624,21 @@ yet. On pass two, `b' is known, so line two can define `a' properly.
Unfortunately, line 1 needed `a' to be defined properly, so this
code will not assemble using only two passes.
There's a related issue: in an effective address such as
`[eax+offset]', the value of `offset' can be stored as either 1 or 4
bytes. NASM will use the one-byte form if it knows it can, to save
space, but will therefore be fooled by the following:
mov eax,[ebx+offset]
offset equ 10
In this case, although `offset' is a small value and could easily
fit into the one-byte form of the instruction, when NASM sees the
instruction in the first pass it doesn't know what `offset' is, and
for all it knows `offset' could be a symbol requiring relocation. So
it will allocate the full four bytes for the value of `offset'. This
can be solved by defining `offset' before it's used.
Local Labels
============
@ -724,7 +751,8 @@ Output Formats
==============
The current output formats supported are `bin', `aout', `coff',
`elf' and `win32'.
`elf', `as86', `obj', `win32', `rdf', and the debug pseudo-format
`dbg'.
`bin': flat-form binary
-----------------------
@ -742,20 +770,20 @@ to be loaded into memory at the address `addr'. So a DOS .COM file
should state [ORG 0x100], and a DOS .SYS file should state [ORG 0].
There should be _one_ ORG directive, at most, in an assembly file:
NASM does not support the use of ORG to jump around inside an object
file, like MASM does (see the `Bugs' section for a use of the ORG
directive not supported by NASM).
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 all formats, 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 (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.
`bin' silently ignores GLOBAL directives, and will also not complain
at EXTERN ones. You only get an error if you actually _reference_ an
@ -775,6 +803,42 @@ These two object formats are the ones used under Linux. They have no
format-specific directives, and their default output filename is
`filename.o'.
`aout' defines the three standard sections `.text', `.data' and
`.bss'. `elf' defines these three, but can also support user-defined
section names, which can be declared along with section attributes
like this:
[section foo align=32 exec]
[section bar write nobits]
The available options are:
- A section can be `progbits' (the default) or `nobits'. `nobits'
sections are BSS: their contents are not stored in the object
file, and the only thing you can sensibly do in one is RESB.
`progbits' are normal sections.
- A section can be `exec' (indicating that it contains executable
code), or `noexec' (the default).
- A section can be `write' (indicating that it should be writable
when linked), or `nowrite' (the default).
- A section can be `alloc' (indicating that its contents should be
loaded into program VM at load time; the default) or `noalloc'
(for storing comments and things that don't form part of the
loaded program).
- You can specify a power of two for the section alignment by
writing `align=64' or similar.
The attributes of the default sections `.text', `.data' and `.bss'
can also be redefined from their defaults. The NASM defaults are:
[section .text align=16 alloc exec nowrite progbits]
[section .data align=4 alloc write noexec progbits]
[section .bss align=4 alloc write noexec nobits]
ELF is a much more featureful object-file format than a.out: in
particular it has enough features to support the writing of position
independent code by means of a global offset table, and position
@ -793,17 +857,17 @@ The `coff' format generates standard Unix COFF object files, which
can be fed to (for example) the DJGPP linker. Its default output
filename, like the other Unix formats, is `filename.o'.
The `win32' format generates Win32 (Windows 95 or Intel-platform
Windows NT) object files, which nominally use the COFF standard, but
in fact are not compatible. Its default output filename is
`filename.obj'.
The `win32' format generates Microsoft Win32 (Windows 95 or
Intel-platform Windows NT) object files, which nominally use the
COFF standard, but in fact are not compatible. Its default output
filename is `filename.obj'.
`coff' and `win32' are not quite compatible formats, due to the fact
that Microsoft's interpretation of the term `relative relocation'
does not seem to be the same as the interpretation used by anyone
else. It is therefore more correct to state that Win32 uses a
_variant_ of COFF. The object files will not therefore produce
correct output when fed to each other's linkers.
correct output when fed to each other's linkers. (I've tried it!)
In addition to this subtle incompatibility, Win32 also defines
extensions to basic COFF, such as a mechanism for importing symbols
@ -824,7 +888,31 @@ interests of not generating incorrect code, NASM will not allow this
form of reference to be written to a Win32 object file. (Standard
COFF, or at least the DJGPP linker, seems to be able to cope with
this contingency. Although that may be due to the executable having
a zero load address.)
a zero load address...)
Note also that Borland Win32 compilers reportedly do not use this
object file format: while Borland linkers will output Win32-COFF
type executables, their object format is the same as the old DOS OBJ
format. So if you are using a Borland compiler, don't use the
`win32' object format, just use `obj' and declare all your segments
as `USE32'.
Both `coff' and `win32' support, in addition to the three standard
section names `.text', `.data' and `.bss', the ability to define
your own sections. Currently (this may change in the future) you can
provide the options `text' (or `code'), `data' or `bss' to determine
the type of section. Win32 also allows `info', which is an
informational section type used by Microsoft C compilers to store
linker directives. So you can do:
[section .mysect code] ; defines an extra code section
or maybe, in Win32,
[section .drectve info] ; defines an MS-compatible directive section
db '-defaultlib:LIBC -defaultlib:OLDNAMES '
to pass directives to the MS linker.
Both `coff' and `win32' default to 32-bit assembly mode.
@ -863,27 +951,37 @@ segment address:
[SEGMENT SCREEN ABSOLUTE=0xB800]
This is an alternative to the ALIGN keyword.
The ABSOLUTE and ALIGN keywords are mutually exclusive.
The format-specific directive GROUP allows segment grouping: [GROUP
DGROUP DATA BSS] defines the group DGROUP to contain segments DATA
and BSS.
Segments are defined as part of their group by default: if `var' is
declared in segment `data', which is part of group `dgroup', then
`SEG var' returns `dgroup', and `var' signifies the offset of `var'
relative to the beginning of `dgroup'. You must use `var WRT data'
to get the offset of `var' relative to the beginning of its
Segments are defined as part of their group by default: if variable
`var' is declared in segment `data', which is part of group
`dgroup', then the expression `SEG var' is equivalent to the
expression `dgroup', and the expression `var' evaluates to the
offset of the variable `var' relative to the beginning of the group
`dgroup'. You must use the expression `var WRT data' to get the
offset of the variable `var' relative to the beginning of its
_segment_.
NASM allows a segment to be in two groups, but will generate a
warning. References to the symbols in that segment will be resolved
relative to the _first_ group it is defined in.
NASM allows a segment to be part of more than one group (like A86,
and unlike TASM), but will generate a warning (unlike A86!).
References to the symbols in that segment will be resolved relative
to the _first_ group it is defined in.
The directive [UPPERCASE] causes all symbol, segment and group names
output to the object file to be uppercased. The actual _assembly_ is
still case sensitive.
To avoid getting tangled up in NASM's local label mechanism, segment
and group names have leading periods stripped when they are defined.
Thus, the directive [SEGMENT .text] will define a segment called
`text', which will clash with any other symbol called `text', and
you will _not_ be able to reference the segment base as `.text', but
only as `text'.
Common variables in OBJ files can be `near' or `far': currently,
NASM has a horribly grotty way to support that, which is that if you
specify the common variable's size as negative, it will be near, and
@ -914,10 +1012,10 @@ to it.
`as86': Linux as86 (bin86-0.3)
------------------------------
This output format replicates the format used to pass data between
the Linux x86 assembler and linker, as86 and ld86. Its default file
name, yet again, is `filename.o'. Its default segment-size attribute
is 16 bits.
This output format attempts to replicate the format used to pass
data between the Linux x86 assembler and linker, as86 and ld86. Its
default file name, yet again, is `filename.o'. Its default
segment-size attribute is 16 bits.
`rdf': Relocatable Dynamic Object File Format
---------------------------------------------
@ -959,14 +1057,14 @@ instruction as these macros do: this is due to a bug in the _macro_,
not in NASM. The macro works by generating an SIDT instruction (if I
remember rightly), which has almost exactly the right form, then
using ORG to back up a bit and do a DB over the top of one of the
opcode bytes. The trouble is that Intel overlooked (or were unable
to allow for) the possibility that the SIDT instruction may contain
an 0x66 or 0x67 operand or address size prefix. If this happens, the
ORG will back up by the wrong amount, and the macro will generate
incorrect code. NASM gets it right. This, also, is not a bug in
NASM, so please don't report it as one. (Also please note that the
ORG directive in NASM doesn't work this way, and so you can't do
equivalent tricks with it...)
opcode bytes. The trouble is that Intel overlooked (or MASM syntax
didn't let them allow for) the possibility that the SIDT instruction
may contain an 0x66 or 0x67 operand or address size prefix. If this
happens, the ORG will back up by the wrong amount, and the macro
will generate incorrect code. NASM gets it right. This, also, is not
a bug in NASM, so please don't report it as one. (Also please note
that the ORG directive in NASM doesn't work this way, and so you
can't do equivalent tricks with it...)
That's All Folks!
=================

5
nasm.h
View File

@ -12,8 +12,8 @@
#define NASM_H
#define NASM_MAJOR_VER 0
#define NASM_MINOR_VER 91
#define NASM_VER "0.91"
#define NASM_MINOR_VER 93
#define NASM_VER "0.93"
#ifndef NULL
#define NULL 0
@ -268,6 +268,7 @@ typedef struct { /* an instruction itself */
operand oprs[3]; /* the operands, defined as above */
extop *eops; /* extended operands */
int times; /* repeat count (TIMES prefix) */
int forw_ref; /* is there a forward reference? */
} insn;
/*

334
outcoff.c
View File

@ -70,6 +70,11 @@ struct Reloc {
struct Reloc *next;
long address; /* relative to _start_ of section */
long symbol; /* symbol number */
enum {
SECT_SYMBOLS,
ABS_SYMBOL,
REAL_SYMBOLS
} symbase; /* relocation for symbol number :) */
int relative; /* TRUE or FALSE */
};
@ -92,42 +97,32 @@ struct Section {
int nrelocs;
long index;
struct Reloc *head, **tail;
unsigned long flags; /* section flags */
char name[9];
long pos, relpos;
};
static struct Section stext, sdata;
static unsigned long bsslen;
static long bssindex;
#define TEXT_FLAGS (win32 ? 0x60500020L : 0x20L)
#define DATA_FLAGS (win32 ? 0xC0300040L : 0x40L)
#define BSS_FLAGS (win32 ? 0xC0300080L : 0x80L)
#define INFO_FLAGS 0x00100A00L
#define SECT_DELTA 32
static struct Section **sects;
static int nsects, sectlen;
static struct SAA *syms;
static unsigned long nsyms;
static long def_seg;
static int initsym;
static struct RAA *bsym, *symval;
static struct SAA *strs;
static unsigned long strslen;
/*
* The symbol table contains a double entry for the file name, a
* double entry for each of the three sections, and an absolute
* symbol referencing address zero, followed by the _real_ symbols.
* That's nine extra symbols.
*/
#define SYM_INITIAL 9
/*
* Symbol table indices we can relocate relative to.
*/
#define SYM_ABS_SEG 8
#define SYM_TEXT_SEG 2
#define SYM_DATA_SEG 4
#define SYM_BSS_SEG 6
/*
* The section header table ends at this offset: 0x14 for the
* header, plus 0x28 for each of three sections.
*/
#define COFF_HDRS_END 0x8c
static void coff_gen_init(FILE *, efunc);
static void coff_sect_write (struct Section *, unsigned char *,
unsigned long);
@ -151,45 +146,72 @@ static void coff_std_init(FILE *fp, efunc errfunc, ldfunc ldef) {
static void coff_gen_init(FILE *fp, efunc errfunc) {
coffp = fp;
error = errfunc;
stext.data = saa_init(1L); stext.head = NULL; stext.tail = &stext.head;
sdata.data = saa_init(1L); sdata.head = NULL; sdata.tail = &sdata.head;
stext.len = sdata.len = bsslen = 0;
stext.nrelocs = sdata.nrelocs = 0;
stext.index = seg_alloc();
sdata.index = seg_alloc();
bssindex = seg_alloc();
sects = NULL;
nsects = sectlen = 0;
syms = saa_init((long)sizeof(struct Symbol));
nsyms = 0;
bsym = raa_init();
symval = raa_init();
strs = saa_init(1L);
strslen = 0;
def_seg = seg_alloc();
}
static void coff_cleanup(void) {
struct Reloc *r;
int i;
coff_write();
fclose (coffp);
saa_free (stext.data);
while (stext.head) {
r = stext.head;
stext.head = stext.head->next;
nasm_free (r);
}
saa_free (sdata.data);
while (sdata.head) {
r = sdata.head;
sdata.head = sdata.head->next;
nasm_free (r);
for (i=0; i<nsects; i++) {
if (sects[i]->data)
saa_free (sects[i]->data);
while (sects[i]->head) {
r = sects[i]->head;
sects[i]->head = sects[i]->head->next;
nasm_free (r);
}
}
nasm_free (sects);
saa_free (syms);
raa_free (bsym);
raa_free (symval);
saa_free (strs);
}
static int coff_make_section (char *name, unsigned long flags) {
struct Section *s;
s = nasm_malloc (sizeof(*s));
if (flags != BSS_FLAGS)
s->data = saa_init (1L);
else
s->data = NULL;
s->head = NULL;
s->tail = &s->head;
s->len = 0;
s->nrelocs = 0;
if (!strcmp(name, ".text"))
s->index = def_seg;
else
s->index = seg_alloc();
strncpy (s->name, name, 8);
s->name[8] = '\0';
s->flags = flags;
if (nsects >= sectlen)
sects = nasm_realloc (sects, (sectlen += SECT_DELTA)*sizeof(*sects));
sects[nsects++] = s;
return nsects-1;
}
static long coff_section_names (char *name, int pass, int *bits) {
char *p;
unsigned long flags;
int i;
/*
* Default is 32 bits.
*/
@ -197,16 +219,65 @@ static long coff_section_names (char *name, int pass, int *bits) {
*bits = 32;
if (!name)
return stext.index;
return def_seg;
if (!strcmp(name, ".text"))
return stext.index;
else if (!strcmp(name, ".data"))
return sdata.index;
else if (!strcmp(name, ".bss"))
return bssindex;
else
return NO_SEG;
p = name;
while (*p && !isspace(*p)) p++;
if (*p) *p++ = '\0';
if (strlen(p) > 8) {
error (ERR_WARNING, "COFF section names limited to 8 characters:"
" truncating");
p[8] = '\0';
}
flags = 0;
while (*p && isspace(*p)) p++;
while (*p) {
char *q = p;
while (*p && !isspace(*p)) p++;
if (*p) *p++ = '\0';
while (*p && isspace(*p)) p++;
if (!nasm_stricmp(q, "code") || !nasm_stricmp(q, "text")) {
flags = TEXT_FLAGS;
} else if (!nasm_stricmp(q, "data")) {
flags = DATA_FLAGS;
} else if (!nasm_stricmp(q, "bss")) {
flags = BSS_FLAGS;
} else if (!nasm_stricmp(q, "info")) {
if (win32)
flags = INFO_FLAGS;
else {
flags = DATA_FLAGS; /* gotta do something */
error (ERR_NONFATAL, "standard COFF does not support"
" informational sections");
}
}
}
for (i=0; i<nsects; i++)
if (!strcmp(name, sects[i]->name))
break;
if (i == nsects) {
if (!strcmp(name, ".text") && !flags)
i = coff_make_section (name, TEXT_FLAGS);
else if (!strcmp(name, ".data") && !flags)
i = coff_make_section (name, DATA_FLAGS);
else if (!strcmp(name, ".bss") && !flags)
i = coff_make_section (name, BSS_FLAGS);
else if (flags)
i = coff_make_section (name, flags);
else
i = coff_make_section (name, TEXT_FLAGS);
if (flags)
sects[i]->flags = flags;
} else if (pass == 1) {
if (flags)
error (ERR_WARNING, "section attributes ignored on"
" redeclaration of section `%s'", name);
}
return sects[i]->index;
}
static void coff_deflabel (char *name, long segment, long offset,
@ -232,15 +303,16 @@ static void coff_deflabel (char *name, long segment, long offset,
sym->is_global = !!is_global;
if (segment == NO_SEG)
sym->section = -1; /* absolute symbol */
else if (segment == stext.index)
sym->section = 1; /* .text */
else if (segment == sdata.index)
sym->section = 2; /* .data */
else if (segment == bssindex)
sym->section = 3; /* .bss */
else {
sym->section = 0; /* undefined */
sym->is_global = TRUE;
int i;
sym->section = 0;
for (i=0; i<nsects; i++)
if (segment == sects[i]->index) {
sym->section = i+1;
break;
}
if (!sym->section)
sym->is_global = TRUE;
}
if (is_global == 2)
sym->value = offset;
@ -251,8 +323,7 @@ static void coff_deflabel (char *name, long segment, long offset,
* define the references from external-symbol segment numbers
* to these symbol records.
*/
if (segment != NO_SEG && segment != stext.index &&
segment != sdata.index && segment != bssindex)
if (sym->section == 0)
bsym = raa_write (bsym, segment, nsyms);
if (segment != NO_SEG)
@ -270,11 +341,20 @@ static long coff_add_reloc (struct Section *sect, long segment,
r->next = NULL;
r->address = sect->len;
r->symbol = (segment == NO_SEG ? SYM_ABS_SEG :
segment == stext.index ? SYM_TEXT_SEG :
segment == sdata.index ? SYM_DATA_SEG :
segment == bssindex ? SYM_BSS_SEG :
raa_read (bsym, segment) + SYM_INITIAL);
if (segment == NO_SEG)
r->symbol = 0, r->symbase = ABS_SYMBOL;
else {
int i;
r->symbase = REAL_SYMBOLS;
for (i=0; i<nsects; i++)
if (segment == sects[i]->index) {
r->symbol = i*2;
r->symbase = SECT_SYMBOLS;
break;
}
if (r->symbase == REAL_SYMBOLS)
r->symbol = raa_read (bsym, segment);
}
r->relative = relative;
sect->nrelocs++;
@ -282,7 +362,7 @@ static long coff_add_reloc (struct Section *sect, long segment,
/*
* Return the fixup for standard COFF common variables.
*/
if (r->symbol >= SYM_INITIAL && !win32)
if (r->symbase == REAL_SYMBOLS && !win32)
return raa_read (symval, segment);
else
return 0;
@ -293,6 +373,7 @@ static void coff_out (long segto, void *data, unsigned long type,
struct Section *s;
long realbytes = type & OUT_SIZMASK;
unsigned char mydata[4], *p;
int i;
if (wrt != NO_SEG) {
wrt = NO_SEG; /* continue to do _something_ */
@ -311,37 +392,38 @@ static void coff_out (long segto, void *data, unsigned long type,
return;
}
if (segto == stext.index)
s = &stext;
else if (segto == sdata.index)
s = &sdata;
else if (segto == bssindex)
s = NULL;
else {
error(ERR_WARNING, "attempt to assemble code in"
" segment %d: defaulting to `.text'", segto);
s = &stext;
s = NULL;
for (i=0; i<nsects; i++)
if (segto == sects[i]->index) {
s = sects[i];
break;
}
if (!s) {
int tempint; /* ignored */
if (segto != coff_section_names (".text", 2, &tempint))
error (ERR_PANIC, "strange segment conditions in COFF driver");
else
s = sects[nsects-1];
}
if (!s && type != OUT_RESERVE) {
error(ERR_WARNING, "attempt to initialise memory in the"
" BSS section: ignored");
if (!s->data && type != OUT_RESERVE) {
error(ERR_WARNING, "attempt to initialise memory in"
" BSS section `%s': ignored", s->name);
if (type == OUT_REL2ADR)
realbytes = 2;
else if (type == OUT_REL4ADR)
realbytes = 4;
bsslen += realbytes;
s->len += realbytes;
return;
}
if (type == OUT_RESERVE) {
if (s) {
if (s->data) {
error(ERR_WARNING, "uninitialised space declared in"
" %s section: zeroing",
(segto == stext.index ? "code" : "data"));
" non-BSS section `%s': zeroing", s->name);
coff_sect_write (s, NULL, realbytes);
} else
bsslen += realbytes;
s->len += realbytes;
} else if (type == OUT_RAWDATA) {
if (segment != NO_SEG)
error(ERR_PANIC, "OUT_RAWDATA with other than NO_SEG");
@ -404,25 +486,35 @@ static int coff_directives (char *directive, char *value, int pass) {
}
static void coff_write (void) {
long textpos, textrelpos, datapos, datarelpos, sympos;
long hdrs_end, pos, sympos, vsize;
int i;
/*
* Work out how big the file will get.
* Work out how big the file will get. Calculate the start of
* the `real' symbols at the same time.
*/
textpos = COFF_HDRS_END;
textrelpos = textpos + stext.len;
datapos = textrelpos + stext.nrelocs * 10;
datarelpos = datapos + sdata.len;
sympos = datarelpos + sdata.nrelocs * 10;
pos = hdrs_end = 0x14 + 0x28 * nsects;
initsym = 3; /* two for the file, one absolute */
for (i=0; i<nsects; i++) {
if (sects[i]->data) {
sects[i]->pos = pos;
pos += sects[i]->len;
sects[i]->relpos = pos;
pos += 10 * sects[i]->nrelocs;
} else
sects[i]->pos = sects[i]->relpos = 0L;
initsym += 2; /* two for each section */
}
sympos = pos;
/*
* Output the COFF header.
*/
fwriteshort (0x14C, coffp); /* MACHINE_i386 */
fwriteshort (3, coffp); /* number of sections */
fwriteshort (nsects, coffp); /* number of sections */
fwritelong (time(NULL), coffp); /* time stamp */
fwritelong (sympos, coffp);
fwritelong (nsyms + SYM_INITIAL, coffp);
fwritelong (nsyms + initsym, coffp);
fwriteshort (0, coffp); /* no optional header */
/* Flags: 32-bit, no line numbers. Win32 doesn't even bother with them. */
fwriteshort (win32 ? 0 : 0x104, coffp);
@ -430,27 +522,22 @@ static void coff_write (void) {
/*
* Output the section headers.
*/
coff_section_header (".text", 0L, stext.len, textpos,
textrelpos, stext.nrelocs,
(win32 ? 0x60500020L : 0x20L));
coff_section_header (".data", stext.len, sdata.len, datapos,
datarelpos, sdata.nrelocs,
(win32 ? 0xC0300040L : 0x40L));
coff_section_header (".bss", stext.len+sdata.len, bsslen, 0L, 0L, 0,
(win32 ? 0xC0300080L : 0x80L));
vsize = 0L;
for (i=0; i<nsects; i++) {
coff_section_header (sects[i]->name, vsize, sects[i]->len,
sects[i]->pos, sects[i]->relpos,
sects[i]->nrelocs, sects[i]->flags);
vsize += sects[i]->len;
}
/*
* Output the text section, and its relocations.
* Output the sections and their relocations.
*/
saa_fpwrite (stext.data, coffp);
coff_write_relocs (&stext);
/*
* Output the data section, and its relocations.
*/
saa_fpwrite (sdata.data, coffp);
coff_write_relocs (&sdata);
for (i=0; i<nsects; i++)
if (sects[i]->data) {
saa_fpwrite (sects[i]->data, coffp);
coff_write_relocs (sects[i]);
}
/*
* Output the symbol and string tables.
@ -484,7 +571,9 @@ static void coff_write_relocs (struct Section *s) {
for (r = s->head; r; r = r->next) {
fwritelong (r->address, coffp);
fwritelong (r->symbol, coffp);
fwritelong (r->symbol + (r->symbase == REAL_SYMBOLS ? initsym :
r->symbase == ABS_SYMBOL ? initsym-1 :
r->symbase == SECT_SYMBOLS ? 2 : 0), coffp);
/*
* Strange: Microsoft's COFF documentation says 0x03 for an
* absolute relocation, but both Visual C++ and DJGPP agree
@ -531,17 +620,12 @@ static void coff_write_symbols (void) {
*/
memset (filename, 0, 18); /* useful zeroed buffer */
coff_symbol (".text", 0L, 0L, 1, 3, 1);
fwritelong (stext.len, coffp);
fwriteshort (stext.nrelocs, coffp);
fwrite (filename, 12, 1, coffp);
coff_symbol (".data", 0L, 0L, 2, 3, 1);
fwritelong (sdata.len, coffp);
fwriteshort (sdata.nrelocs, coffp);
fwrite (filename, 12, 1, coffp);
coff_symbol (".bss", 0L, 0L, 3, 3, 1);
fwritelong (bsslen, coffp);
fwrite (filename, 14, 1, coffp);
for (i=0; i<nsects; i++) {
coff_symbol (sects[i]->name, 0L, 0L, i+1, 3, 1);
fwritelong (sects[i]->len, coffp);
fwriteshort (sects[i]->nrelocs, coffp);
fwrite (filename, 12, 1, coffp);
}
/*
* The absolute symbol, for relative-to-absolute relocations.

363
outelf.c
View File

@ -32,20 +32,39 @@ struct Symbol {
long value; /* address, or COMMON variable size */
};
#define SHT_PROGBITS 1
#define SHT_NOBITS 8
#define SHF_WRITE 1
#define SHF_ALLOC 2
#define SHF_EXECINSTR 4
struct Section {
struct SAA *data;
unsigned long len, size, nrelocs;
long index;
int type; /* SHT_PROGBITS or SHT_NOBITS */
int align; /* alignment: power of two */
unsigned long flags; /* section flags */
char *name;
struct SAA *rel;
long rellen;
struct Reloc *head, **tail;
};
static struct Section stext, sdata;
static unsigned long bsslen;
static long bssindex;
#define SECT_DELTA 32
static struct Section **sects;
static int nsects, sectlen;
#define SHSTR_DELTA 256
static char *shstrtab;
static int shstrtablen, shstrtabsize;
static struct SAA *syms;
static unsigned long nlocals, nglobs;
static long def_seg;
static struct RAA *bsym;
static struct SAA *strs;
@ -86,51 +105,92 @@ static void elf_section_header (int, int, int, void *, int, long,
static void elf_write_sections (void);
static struct SAA *elf_build_symtab (long *, long *);
static struct SAA *elf_build_reltab (long *, struct Reloc *);
static void add_sectname (char *, char *);
static void elf_init(FILE *fp, efunc errfunc, ldfunc ldef) {
elffp = fp;
error = errfunc;
(void) ldef; /* placate optimisers */
stext.data = saa_init(1L); stext.head = NULL; stext.tail = &stext.head;
sdata.data = saa_init(1L); sdata.head = NULL; sdata.tail = &sdata.head;
stext.len = stext.size = sdata.len = sdata.size = bsslen = 0;
stext.nrelocs = sdata.nrelocs = 0;
stext.index = seg_alloc();
sdata.index = seg_alloc();
bssindex = seg_alloc();
sects = NULL;
nsects = sectlen = 0;
syms = saa_init((long)sizeof(struct Symbol));
nlocals = nglobs = 0;
bsym = raa_init();
strs = saa_init(1L);
saa_wbytes (strs, "\0", 1L);
saa_wbytes (strs, elf_module, (long)(strlen(elf_module)+1));
strslen = 2+strlen(elf_module);
shstrtab = NULL;
shstrtablen = shstrtabsize = 0;;
add_sectname ("", "");
def_seg = seg_alloc();
}
static void elf_cleanup(void) {
struct Reloc *r;
int i;
elf_write();
fclose (elffp);
saa_free (stext.data);
while (stext.head) {
r = stext.head;
stext.head = stext.head->next;
nasm_free (r);
}
saa_free (sdata.data);
while (sdata.head) {
r = sdata.head;
sdata.head = sdata.head->next;
nasm_free (r);
for (i=0; i<nsects; i++) {
if (sects[i]->type != SHT_NOBITS)
saa_free (sects[i]->data);
if (sects[i]->head)
saa_free (sects[i]->rel);
while (sects[i]->head) {
r = sects[i]->head;
sects[i]->head = sects[i]->head->next;
nasm_free (r);
}
}
nasm_free (sects);
saa_free (syms);
raa_free (bsym);
saa_free (strs);
}
static void add_sectname (char *firsthalf, char *secondhalf) {
int len = strlen(firsthalf)+strlen(secondhalf);
while (shstrtablen + len + 1 > shstrtabsize)
shstrtab = nasm_realloc (shstrtab, (shstrtabsize += SHSTR_DELTA));
strcpy (shstrtab+shstrtablen, firsthalf);
strcat (shstrtab+shstrtablen, secondhalf);
shstrtablen += len+1;
}
static int elf_make_section (char *name, int type, int flags, int align) {
struct Section *s;
s = nasm_malloc (sizeof(*s));
if (type != SHT_NOBITS)
s->data = saa_init (1L);
s->head = NULL;
s->tail = &s->head;
s->len = s->size = 0;
s->nrelocs = 0;
if (!strcmp(name, ".text"))
s->index = def_seg;
else
s->index = seg_alloc();
add_sectname ("", name);
s->name = nasm_malloc (1+strlen(name));
strcpy (s->name, name);
s->type = type;
s->flags = flags;
s->align = align;
if (nsects >= sectlen)
sects = nasm_realloc (sects, (sectlen += SECT_DELTA)*sizeof(*sects));
sects[nsects++] = s;
return nsects-1;
}
static long elf_section_names (char *name, int pass, int *bits) {
char *p;
int flags_and, flags_or, type, align, i;
/*
* Default is 32 bits.
*/
@ -138,16 +198,91 @@ static long elf_section_names (char *name, int pass, int *bits) {
*bits = 32;
if (!name)
return stext.index;
return def_seg;
if (!strcmp(name, ".text"))
return stext.index;
else if (!strcmp(name, ".data"))
return sdata.index;
else if (!strcmp(name, ".bss"))
return bssindex;
else
p = name;
while (*p && !isspace(*p)) p++;
if (*p) *p++ = '\0';
flags_and = flags_or = type = align = 0;
while (*p && isspace(*p)) p++;
while (*p) {
char *q = p;
while (*p && !isspace(*p)) p++;
if (*p) *p++ = '\0';
while (*p && isspace(*p)) p++;
if (!nasm_strnicmp(q, "align=", 6)) {
align = atoi(q+6);
if (align == 0)
align = 1;
if ( (align-1) & align ) { /* means it's not a power of two */
error (ERR_NONFATAL, "section alignment %d is not"
" a power of two", align);
align = 1;
}
} else if (!nasm_stricmp(q, "alloc")) {
flags_and |= SHF_ALLOC;
flags_or |= SHF_ALLOC;
} else if (!nasm_stricmp(q, "noalloc")) {
flags_and |= SHF_ALLOC;
flags_or &= ~SHF_ALLOC;
} else if (!nasm_stricmp(q, "exec")) {
flags_and |= SHF_EXECINSTR;
flags_or |= SHF_EXECINSTR;
} else if (!nasm_stricmp(q, "noexec")) {
flags_and |= SHF_EXECINSTR;
flags_or &= ~SHF_EXECINSTR;
} else if (!nasm_stricmp(q, "write")) {
flags_and |= SHF_WRITE;
flags_or |= SHF_WRITE;
} else if (!nasm_stricmp(q, "nowrite")) {
flags_and |= SHF_WRITE;
flags_or &= ~SHF_WRITE;
} else if (!nasm_stricmp(q, "progbits")) {
type = SHT_PROGBITS;
} else if (!nasm_stricmp(q, "nobits")) {
type = SHT_NOBITS;
}
}
if (!strcmp(name, ".comment") ||
!strcmp(name, ".shstrtab") ||
!strcmp(name, ".symtab") ||
!strcmp(name, ".strtab")) {
error (ERR_NONFATAL, "attempt to redefine reserved section"
"name `%s'", name);
return NO_SEG;
}
for (i=0; i<nsects; i++)
if (!strcmp(name, sects[i]->name))
break;
if (i == nsects) {
if (!strcmp(name, ".text"))
i = elf_make_section (name, SHT_PROGBITS,
SHF_ALLOC | SHF_EXECINSTR, 16);
else if (!strcmp(name, ".data"))
i = elf_make_section (name, SHT_PROGBITS,
SHF_ALLOC | SHF_WRITE, 4);
else if (!strcmp(name, ".bss"))
i = elf_make_section (name, SHT_NOBITS,
SHF_ALLOC | SHF_WRITE, 4);
else
i = elf_make_section (name, SHT_PROGBITS, SHF_ALLOC, 1);
if (type)
sects[i]->type = type;
if (align)
sects[i]->align = align;
sects[i]->flags &= ~flags_and;
sects[i]->flags |= flags_or;
} else if (pass == 1) {
if (type || align || flags_and)
error (ERR_WARNING, "section attributes ignored on"
" redeclaration of section `%s'", name);
}
return sects[i]->index;
}
static void elf_deflabel (char *name, long segment, long offset,
@ -168,14 +303,15 @@ static void elf_deflabel (char *name, long segment, long offset,
sym->type = is_global ? SYM_GLOBAL : 0;
if (segment == NO_SEG)
sym->section = SHN_ABS;
else if (segment == stext.index)
sym->section = 1;
else if (segment == sdata.index)
sym->section = 2;
else if (segment == bssindex)
sym->section = 3;
else
else {
int i;
sym->section = SHN_UNDEF;
for (i=0; i<nsects; i++)
if (segment == sects[i]->index) {
sym->section = i+1;
break;
}
}
if (is_global == 2) {
sym->value = offset;
@ -200,11 +336,17 @@ static void elf_add_reloc (struct Section *sect, long segment,
r->next = NULL;
r->address = sect->len;
r->symbol = (segment == NO_SEG ? 5 :
segment == stext.index ? 2 :
segment == sdata.index ? 3 :
segment == bssindex ? 4 :
GLOBAL_TEMP_BASE + raa_read(bsym, segment));
if (segment == NO_SEG)
r->symbol = 2;
else {
int i;
r->symbol = 0;
for (i=0; i<nsects; i++)
if (segment == sects[i]->index)
r->symbol = i+3;
if (!r->symbol)
r->symbol = GLOBAL_TEMP_BASE + raa_read(bsym, segment);
}
r->relative = relative;
sect->nrelocs++;
@ -215,6 +357,7 @@ static void elf_out (long segto, void *data, unsigned long type,
struct Section *s;
long realbytes = type & OUT_SIZMASK;
unsigned char mydata[4], *p;
int i;
if (wrt != NO_SEG) {
wrt = NO_SEG; /* continue to do _something_ */
@ -233,37 +376,38 @@ static void elf_out (long segto, void *data, unsigned long type,
return;
}
if (segto == stext.index)
s = &stext;
else if (segto == sdata.index)
s = &sdata;
else if (segto == bssindex)
s = NULL;
else {
error(ERR_WARNING, "attempt to assemble code in"
" segment %d: defaulting to `.text'", segto);
s = &stext;
s = NULL;
for (i=0; i<nsects; i++)
if (segto == sects[i]->index) {
s = sects[i];
break;
}
if (!s) {
int tempint; /* ignored */
if (segto != elf_section_names (".text", 2, &tempint))
error (ERR_PANIC, "strange segment conditions in ELF driver");
else
s = sects[nsects-1];
}
if (!s && type != OUT_RESERVE) {
error(ERR_WARNING, "attempt to initialise memory in the"
" BSS section: ignored");
if (s->type == SHT_NOBITS && type != OUT_RESERVE) {
error(ERR_WARNING, "attempt to initialise memory in"
" BSS section `%s': ignored", s->name);
if (type == OUT_REL2ADR)
realbytes = 2;
else if (type == OUT_REL4ADR)
realbytes = 4;
bsslen += realbytes;
s->len += realbytes;
return;
}
if (type == OUT_RESERVE) {
if (s) {
if (s->type == SHT_PROGBITS) {
error(ERR_WARNING, "uninitialised space declared in"
" %s section: zeroing",
(segto == stext.index ? "code" : "data"));
" non-BSS section `%s': zeroing", s->name);
elf_sect_write (s, NULL, realbytes);
} else
bsslen += realbytes;
s->len += realbytes;
} else if (type == OUT_RAWDATA) {
if (segment != NO_SEG)
error(ERR_PANIC, "OUT_RAWDATA with other than NO_SEG");
@ -303,41 +447,31 @@ static void elf_out (long segto, void *data, unsigned long type,
static void elf_write(void) {
int nsections, align;
char shstrtab[80], *p;
int shstrtablen, commlen;
char *p;
int commlen;
char comment[64];
int i;
struct SAA *symtab, *reltext, *reldata;
long symtablen, symtablocal, reltextlen, reldatalen;
struct SAA *symtab;
long symtablen, symtablocal;
/*
* Work out how many sections we will have.
*
* Fixed sections are:
* SHN_UNDEF .text .data .bss .comment .shstrtab .symtab .strtab
*
* Optional sections are:
* .rel.text .rel.data
*
* (.rel.bss makes very little sense;-)
* Work out how many sections we will have. We have SHN_UNDEF,
* then the flexible user sections, then the four fixed
* sections `.comment', `.shstrtab', `.symtab' and `.strtab',
* then optionally relocation sections for the user sections.
*/
nsections = 8;
*shstrtab = '\0';
shstrtablen = 1;
shstrtablen += 1+sprintf(shstrtab+shstrtablen, ".text");
shstrtablen += 1+sprintf(shstrtab+shstrtablen, ".data");
shstrtablen += 1+sprintf(shstrtab+shstrtablen, ".bss");
shstrtablen += 1+sprintf(shstrtab+shstrtablen, ".comment");
shstrtablen += 1+sprintf(shstrtab+shstrtablen, ".shstrtab");
shstrtablen += 1+sprintf(shstrtab+shstrtablen, ".symtab");
shstrtablen += 1+sprintf(shstrtab+shstrtablen, ".strtab");
if (stext.head) {
nsections++;
shstrtablen += 1+sprintf(shstrtab+shstrtablen, ".rel.text");
}
if (sdata.head) {
nsections++;
shstrtablen += 1+sprintf(shstrtab+shstrtablen, ".rel.data");
nsections = 5; /* SHN_UNDEF and the fixed ones */
add_sectname ("", ".comment");
add_sectname ("", ".shstrtab");
add_sectname ("", ".symtab");
add_sectname ("", ".strtab");
for (i=0; i<nsects; i++) {
nsections++; /* for the section itself */
if (sects[i]->head) {
nsections++; /* for its relocations */
add_sectname (".rel", sects[i]->name);
}
}
/*
@ -362,8 +496,8 @@ static void elf_write(void) {
fwriteshort (0, elffp); /* no program header table, again */
fwriteshort (0, elffp); /* still no program header table */
fwriteshort (0x28, elffp); /* size of section header */
fwriteshort (nsections, elffp); /* number of sections */
fwriteshort (5, elffp); /* string table section index for
fwriteshort (nsections, elffp); /* number of sections */
fwriteshort (nsects+2, elffp); /* string table section index for
* section header table */
fwritelong (0L, elffp); /* align to 0x40 bytes */
fwritelong (0L, elffp);
@ -373,8 +507,10 @@ static void elf_write(void) {
* Build the symbol table and relocation tables.
*/
symtab = elf_build_symtab (&symtablen, &symtablocal);
reltext = elf_build_reltab (&reltextlen, stext.head);
reldata = elf_build_reltab (&reldatalen, sdata.head);
for (i=0; i<nsects; i++)
if (sects[i]->head)
sects[i]->rel = elf_build_reltab (&sects[i]->rellen,
sects[i]->head);
/*
* Now output the section header table.
@ -387,15 +523,13 @@ static void elf_write(void) {
elf_section_header (0, 0, 0, NULL, FALSE, 0L, 0, 0, 0, 0); /* SHN_UNDEF */
p = shstrtab+1;
elf_section_header (p - shstrtab, 1, 6, stext.data, TRUE,
stext.len, 0, 0, 16, 0); /* .text */
p += strlen(p)+1;
elf_section_header (p - shstrtab, 1, 3, sdata.data, TRUE,
sdata.len, 0, 0, 4, 0); /* .data */
p += strlen(p)+1;
elf_section_header (p - shstrtab, 8, 3, NULL, TRUE,
bsslen, 0, 0, 4, 0); /* .bss */
p += strlen(p)+1;
for (i=0; i<nsects; i++) {
elf_section_header (p - shstrtab, sects[i]->type, sects[i]->flags,
(sects[i]->type == SHT_PROGBITS ?
sects[i]->data : NULL), TRUE,
sects[i]->len, 0, 0, sects[i]->align, 0);
p += strlen(p)+1;
}
elf_section_header (p - shstrtab, 1, 0, comment, FALSE,
(long)commlen, 0, 0, 1, 0);/* .comment */
p += strlen(p)+1;
@ -403,19 +537,14 @@ static void elf_write(void) {
(long)shstrtablen, 0, 0, 1, 0);/* .shstrtab */
p += strlen(p)+1;
elf_section_header (p - shstrtab, 2, 0, symtab, TRUE,
symtablen, 7, symtablocal, 4, 16);/* .symtab */
symtablen, nsects+4, symtablocal, 4, 16);/* .symtab */
p += strlen(p)+1;
elf_section_header (p - shstrtab, 3, 0, strs, TRUE,
strslen, 0, 0, 1, 0); /* .strtab */
if (reltext) {
for (i=0; i<nsects; i++) if (sects[i]->head) {
p += strlen(p)+1;
elf_section_header (p - shstrtab, 9, 0, reltext, TRUE,
reltextlen, 6, 1, 4, 8); /* .rel.text */
}
if (reldata) {
p += strlen(p)+1;
elf_section_header (p - shstrtab, 9, 0, reldata, TRUE,
reldatalen, 6, 2, 4, 8); /* .rel.data */
elf_section_header (p - shstrtab, 9, 0, sects[i]->rel, TRUE,
sects[i]->rellen, 6, i+1, 4, 8);
}
fwrite (align_str, align, 1, elffp);
@ -426,10 +555,6 @@ static void elf_write(void) {
elf_write_sections();
saa_free (symtab);
if (reltext)
saa_free (reltext);
if (reldata)
saa_free (reldata);
}
static struct SAA *elf_build_symtab (long *len, long *local) {
@ -461,16 +586,16 @@ static struct SAA *elf_build_symtab (long *len, long *local) {
(*local)++;
/*
* Now four standard symbols defining segments, for relocation
* Now some standard symbols defining the segments, for relocation
* purposes.
*/
for (i = 1; i <= 4; i++) {
for (i = 1; i <= nsects+1; i++) {
p = entry;
WRITELONG (p, 0); /* no symbol name */
WRITELONG (p, 0); /* offset zero */
WRITELONG (p, 0); /* size zero */
WRITESHORT (p, 3); /* local section-type thing */
WRITESHORT (p, (i==4 ? SHN_ABS : i)); /* the section id */
WRITESHORT (p, (i==1 ? SHN_ABS : i-1)); /* the section id */
saa_wbytes (s, entry, 16L);
*len += 16;
(*local)++;

View File

@ -575,6 +575,8 @@ static long obj_segment (char *name, int pass, int *bits) {
* Look for segment attributes.
*/
attrs = 0;
while (*name == '.')
name++; /* hack, but a documented one */
p = name;
while (*p && !isspace(*p))
p++;
@ -736,6 +738,8 @@ static int obj_directive (char *directive, char *value, int pass) {
int obj_idx;
q = value;
while (*q == '.')
q++; /* hack, but a documented one */
while (*q && !isspace(*q))
q++;
if (isspace(*q)) {
@ -847,7 +851,7 @@ static void obj_write_file (void) {
struct Public *pub;
struct External *ext;
struct ObjData *data;
static unsigned char boast[] = "The Netwide Assembler " NASM_VER;
static char boast[] = "The Netwide Assembler " NASM_VER;
int lname_idx, rectype;
/*
@ -862,7 +866,7 @@ static void obj_write_file (void) {
*/
recptr = record;
recptr = obj_write_rword (recptr, 0); /* comment type zero */
recptr = obj_write_data (recptr, boast, sizeof(boast)-1);
recptr = obj_write_name (recptr, boast);
obj_record (COMENT, record, recptr);
/*

View File

@ -27,7 +27,7 @@
typedef short int16; /* not sure if this will be required to be altered
at all... best to typedef it just in case */
const char *RDOFFId = "RDOFF1"; /* written to the start of RDOFF files */
static const char *RDOFFId = "RDOFF1"; /* written to start of RDOFF files */
/* the records that can be found in the RDOFF header */
@ -88,7 +88,7 @@ typedef struct memorybuffer {
struct memorybuffer *next;
} memorybuffer;
memorybuffer * newmembuf(){
static memorybuffer * newmembuf(){
memorybuffer * t;
t = nasm_malloc(sizeof(memorybuffer));
@ -98,7 +98,7 @@ memorybuffer * newmembuf(){
return t;
}
void membufwrite(memorybuffer *b, void *data, int bytes) {
static void membufwrite(memorybuffer *b, void *data, int bytes) {
int16 w;
long l;
@ -114,6 +114,7 @@ void membufwrite(memorybuffer *b, void *data, int bytes) {
b->next = newmembuf();
membufwrite(b->next,data,bytes);
return;
}
switch(bytes) {
@ -145,7 +146,7 @@ void membufwrite(memorybuffer *b, void *data, int bytes) {
}
}
void membufdump(memorybuffer *b,FILE *fp)
static void membufdump(memorybuffer *b,FILE *fp)
{
if (!b) return;
@ -154,13 +155,13 @@ void membufdump(memorybuffer *b,FILE *fp)
membufdump(b->next,fp);
}
int membuflength(memorybuffer *b)
static int membuflength(memorybuffer *b)
{
if (!b) return 0;
return b->length + membuflength(b->next);
}
void freemembuf(memorybuffer *b)
static void freemembuf(memorybuffer *b)
{
if (!b) return;
freemembuf(b->next);
@ -173,16 +174,15 @@ void freemembuf(memorybuffer *b)
/* global variables set during the initialisation phase */
memorybuffer *seg[2]; /* seg 0 = code, seg 1 = data */
memorybuffer *header; /* relocation/import/export records */
static memorybuffer *seg[2]; /* seg 0 = code, seg 1 = data */
static memorybuffer *header; /* relocation/import/export records */
FILE *ofile;
static FILE *ofile;
int seg_warned;
static efunc error;
int segtext,segdata,segbss;
long bsslength;
static int segtext,segdata,segbss;
static long bsslength;
static void rdf_init(FILE *fp, efunc errfunc, ldfunc ldef)
{
@ -406,7 +406,7 @@ static void rdf_cleanup (void) {
/* should write imported & exported symbol declarations to header here */
/* generate the output file... */
fwrite("RDOFF1",6,1,ofile); /* file type magic number */
fwrite(RDOFFId,6,1,ofile); /* file type magic number */
if (bsslength != 0) /* reserve BSS */
{

View File

@ -113,12 +113,15 @@ static struct ofmt *outfmt;
static long seg, ofs;
static int forward;
insn *parse_line (long segment, long offset, lfunc lookup_label, int pass,
char *buffer, insn *result, struct ofmt *output,
efunc errfunc) {
int operand;
int critical;
forward = result->forw_ref = FALSE;
q = tempstorage;
bufptr = buffer;
labelfunc = lookup_label;
@ -384,6 +387,8 @@ insn *parse_line (long segment, long offset, lfunc lookup_label, int pass,
eval_reset();
value = evaluate (critical);
if (forward)
result->forw_ref = TRUE;
if (!value) { /* error in evaluator */
result->opcode = -1; /* unrecoverable parse error: */
return result; /* ignore this instruction */
@ -407,6 +412,8 @@ insn *parse_line (long segment, long offset, lfunc lookup_label, int pass,
i = nexttoken();
}
value = evaluate (critical);
if (forward)
result->forw_ref = TRUE;
/* and get the offset */
if (!value) { /* but, error in evaluator */
result->opcode = -1; /* unrecoverable parse error: */
@ -492,18 +499,33 @@ insn *parse_line (long segment, long offset, lfunc lookup_label, int pass,
e++;
} else
result->oprs[operand].wrt = NO_SEG;
if (e->type != 0) { /* is there a segment id? */
if (e->type < EXPR_SEGBASE) {
error (ERR_NONFATAL,
"invalid effective address");
result->opcode = -1;
return result;
} else
result->oprs[operand].segment = (e->type -
EXPR_SEGBASE);
/*
* Look for a segment base type.
*/
if (e->type && e->type < EXPR_SEGBASE) {
error (ERR_NONFATAL, "invalid effective address");
result->opcode = -1;
return result;
}
while (e->type && e->value == 0)
e++;
if (e->type && e->value != 1) {
error (ERR_NONFATAL, "invalid effective address");
result->opcode = -1;
return result;
}
if (e->type) {
result->oprs[operand].segment = e->type-EXPR_SEGBASE;
e++;
} else
result->oprs[operand].segment = NO_SEG;
while (e->type && e->value == 0)
e++;
if (e->type) {
error (ERR_NONFATAL, "invalid effective address");
result->opcode = -1;
return result;
}
}
} else {
o = 0;
@ -1242,6 +1264,7 @@ static expr *expr6(int critical) {
tokval.t_charptr);
return NULL;
} else {
forward = TRUE;
label_seg = seg;
label_ofs = ofs;
}