summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Changes83
-rw-r--r--Licence51
-rw-r--r--Makefile.bc2205
-rw-r--r--Makefile.dos3
-rw-r--r--Readme14
-rw-r--r--assemble.c29
-rw-r--r--insns.dat20
-rw-r--r--lcc/x86nasm.md8
-rw-r--r--nasm.c39
-rw-r--r--nasm.doc188
-rw-r--r--nasm.h5
-rw-r--r--outcoff.c334
-rw-r--r--outelf.c363
-rw-r--r--outobj.c8
-rw-r--r--outrdf.c26
-rw-r--r--parser.c41
16 files changed, 1054 insertions, 363 deletions
diff --git a/Changes b/Changes
new file mode 100644
index 00000000..a2af8910
--- /dev/null
+++ b/Changes
@@ -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>.
diff --git a/Licence b/Licence
index 8cd2f6d9..5856d404 100644
--- a/Licence
+++ b/Licence
@@ -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.
+
+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.
-V. There is no warranty for the Software, to the extent permitted by
-applicable law. The authors provide the Software "as is" without
+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,
diff --git a/Makefile.bc2 b/Makefile.bc2
new file mode 100644
index 00000000..f160fada
--- /dev/null
+++ b/Makefile.bc2
@@ -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
diff --git a/Makefile.dos b/Makefile.dos
index cb757087..ebf655d6 100644
--- a/Makefile.dos
+++ b/Makefile.dos
@@ -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)
diff --git a/Readme b/Readme
index 5a036feb..5033c58e 100644
--- a/Readme
+++ b/Readme
@@ -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
diff --git a/assemble.c b/assemble.c
index bab6f292..b4aed4c5 100644
--- a/assemble.c
+++ b/assemble.c
@@ -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;
diff --git a/insns.dat b/insns.dat
index f410613b..40196ecd 100644
--- a/insns.dat
+++ b/insns.dat
@@ -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
diff --git a/lcc/x86nasm.md b/lcc/x86nasm.md
index d7091225..54d0be6c 100644
--- a/lcc/x86nasm.md
+++ b/lcc/x86nasm.md
@@ -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
diff --git a/nasm.c b/nasm.c
index f4c75c43..38e11c45 100644
--- a/nasm.c
+++ b/nasm.c
@@ -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);
diff --git a/nasm.doc b/nasm.doc
index dd2073bb..dae974b6 100644
--- a/nasm.doc
+++ b/nasm.doc
@@ -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).
-
-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.
+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.
`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!
=================
diff --git a/nasm.h b/nasm.h
index 9609667f..4f1d2b16 100644
--- a/nasm.h
+++ b/nasm.h
@@ -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;
/*
diff --git a/outcoff.c b/outcoff.c
index c3ae712d..2d4ceba3 100644
--- a/outcoff.c
+++ b/outcoff.c
@@ -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;
+
+ 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");
+ }
+ }
+ }
- 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;
+ 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));
-
- /*
- * Output the text section, and its relocations.
- */
- saa_fpwrite (stext.data, coffp);
- coff_write_relocs (&stext);
+ 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 data section, and its relocations.
+ * Output the sections and their 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.
diff --git a/outelf.c b/outelf.c
index b84bae3a..56ee4fd8 100644
--- a/outelf.c
+++ b/outelf.c
@@ -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;
+
+ 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, ".text"))
- return stext.index;
- else if (!strcmp(name, ".data"))
- return sdata.index;
- else if (!strcmp(name, ".bss"))
- return bssindex;
- else
+ 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) {
- p += strlen(p)+1;
- elf_section_header (p - shstrtab, 9, 0, reltext, TRUE,
- reltextlen, 6, 1, 4, 8); /* .rel.text */
- }
- if (reldata) {
+ for (i=0; i<nsects; i++) if (sects[i]->head) {
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)++;
diff --git a/outobj.c b/outobj.c
index b33b72de..1bb30de7 100644
--- a/outobj.c
+++ b/outobj.c
@@ -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);
/*
diff --git a/outrdf.c b/outrdf.c
index 24fd4808..47ddd277 100644
--- a/outrdf.c
+++ b/outrdf.c
@@ -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 */
{
diff --git a/parser.c b/parser.c
index 14c7a5ba..a45bf0da 100644
--- a/parser.c
+++ b/parser.c
@@ -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;
}