mirror of
https://github.com/netwide-assembler/nasm.git
synced 2025-03-19 18:00:23 +08:00
NASM 0.93
This commit is contained in:
parent
ea6e34db64
commit
ea8382740d
83
Changes
Normal file
83
Changes
Normal 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
51
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.
|
||||
|
||||
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
205
Makefile.bc2
Normal 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
|
@ -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
14
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
|
||||
|
29
assemble.c
29
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;
|
||||
|
20
insns.dat
20
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
|
||||
|
@ -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
39
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);
|
||||
|
186
nasm.doc
186
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).
|
||||
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
5
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;
|
||||
|
||||
/*
|
||||
|
334
outcoff.c
334
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;
|
||||
|
||||
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
363
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;
|
||||
|
||||
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 (§s[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)++;
|
||||
|
8
outobj.c
8
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);
|
||||
|
||||
/*
|
||||
|
26
outrdf.c
26
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 */
|
||||
{
|
||||
|
41
parser.c
41
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;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user