mirror of
https://github.com/netwide-assembler/nasm
synced 2026-08-26 16:23:04 -04:00
NASM 0.96
This commit is contained in:
parent
6768eb71d8
commit
76690a12ad
74 changed files with 18239 additions and 3854 deletions
166
Changes
166
Changes
|
|
@ -129,8 +129,8 @@ be output when absolute labels were made global.
|
|||
|
||||
Updates to RDOFF subdirectory, and changes to outrdf.c.
|
||||
|
||||
0.95 released July 1997
|
||||
-----------------------
|
||||
0.95 not released yet
|
||||
---------------------
|
||||
|
||||
Fixed yet another ELF bug. This one manifested if the user relied on
|
||||
the default segment, and attempted to define global symbols without
|
||||
|
|
@ -241,3 +241,165 @@ can be implemented.
|
|||
Fixed the implementation of WRT, which was too restrictive in that
|
||||
you couldn't do `mov ax,[di+abc wrt dgroup]' because (di+abc) wasn't
|
||||
a relocatable reference.
|
||||
|
||||
0.96 not released yet
|
||||
---------------------
|
||||
|
||||
Fixed a bug whereby, if `nasm sourcefile' would cause a filename
|
||||
collision warning and put output into `nasm.out', then `nasm
|
||||
sourcefile -o outputfile' still gave the warning even though the
|
||||
`-o' was honoured.
|
||||
|
||||
Fixed name pollution under Digital UNIX: one of its header files
|
||||
defined R_SP, which broke the enum in nasm.h.
|
||||
|
||||
Fixed minor instruction table problems: FUCOM and FUCOMP didn't have
|
||||
two-operand forms; NDISASM didn't recognise the longer register
|
||||
forms of PUSH and POP (eg FF F3 for PUSH BX); TEST mem,imm32 was
|
||||
flagged as undocumented; the 32-bit forms of CMOV had 16-bit operand
|
||||
size prefixes; `AAD imm' and `AAM imm' are no longer flagged as
|
||||
undocumented because the Intel Architecture reference documents
|
||||
them.
|
||||
|
||||
Fixed a problem with the local-label mechanism, whereby strange
|
||||
types of symbol (EQUs, auto-defined OBJ segment base symbols)
|
||||
interfered with the `previous global label' value and screwed up
|
||||
local labels.
|
||||
|
||||
Fixed a bug whereby the stub preprocessor didn't communicate with
|
||||
the listing file generator, so that the -a and -l options in
|
||||
conjunction would produce a useless listing file.
|
||||
|
||||
Merged `os2' object file format back into `obj', after discovering
|
||||
that `obj' _also_ shouldn't have a link pass separator in a module
|
||||
containing a non-trivial MODEND. Flat segments are now declared
|
||||
using the FLAT attribute. `os2' is no longer a valid object format
|
||||
name: use `obj'.
|
||||
|
||||
Removed the fixed-size temporary storage in the evaluator. Very very
|
||||
long expressions (like `mov ax,1+1+1+1+...' for two hundred 1s or
|
||||
so) should now no longer crash NASM.
|
||||
|
||||
Fixed a bug involving segfaults on disassembly of MMX instructions,
|
||||
by changing the meaning of one of the operand-type flags in nasm.h.
|
||||
This may cause other apparently unrelated MMX problems; it needs to
|
||||
be tested thoroughly.
|
||||
|
||||
Fixed some buffer overrun problems with large OBJ output files.
|
||||
Thanks to DJ Delorie for the bug report and fix.
|
||||
|
||||
Made preprocess-only mode actually listen to the %line markers as it
|
||||
prints them, so that it can report errors more sanely.
|
||||
|
||||
Re-designed the evaluator to keep more sensible track of expressions
|
||||
involving forward references: can now cope with previously-nightmare
|
||||
situations such as
|
||||
mov ax,foo | bar
|
||||
foo equ 1
|
||||
bar equ 2
|
||||
|
||||
Added the ALIGN and ALIGNB standard macros.
|
||||
|
||||
Added PIC support in ELF: use of WRT to obtain the four extra
|
||||
relocation types needed.
|
||||
|
||||
Added the ability for output file formats to define their own
|
||||
extensions to the GLOBAL, COMMON and EXTERN directives.
|
||||
|
||||
Implemented common-variable alignment, and global-symbol type and
|
||||
size declarations, in ELF.
|
||||
|
||||
Implemented NEAR and FAR keywords for common variables, plus
|
||||
far-common element size specification, in OBJ.
|
||||
|
||||
Added a feature whereby EXTERNs and COMMONs in OBJ can be given a
|
||||
default WRT specification (either a segment or a group).
|
||||
|
||||
Transformed the Unix NASM archive into an auto-configuring package.
|
||||
|
||||
Added a sanity-check for people applying SEG to things which are
|
||||
already segment bases: this previously went unnoticed by the SEG
|
||||
processing and caused OBJ-driver panics later.
|
||||
|
||||
Added the ability, in OBJ format, to deal with `MOV EAX,<segment>'
|
||||
type references: OBJ doesn't directly support dword-size segment
|
||||
base fixups, but as long as the low two bytes of the constant term
|
||||
are zero, a word-size fixup can be generated instead and it will
|
||||
work.
|
||||
|
||||
Added the ability to specify sections' alignment requirements in
|
||||
Win32 object files and pure binary files.
|
||||
|
||||
Added preprocess-time expression evaluation: the %assign (and
|
||||
%iassign) directive and the bare %if (and %elif) conditional. Added
|
||||
relational operators to the evaluator, for use only in %if
|
||||
constructs: the standard relationals = < > <= >= <> (and C-like
|
||||
synonyms == and !=) plus low-precedence logical operators &&, ^^ and
|
||||
||.
|
||||
|
||||
Added a preprocessor repeat construct: %rep / %exitrep / %endrep.
|
||||
|
||||
Added the __FILE__ and __LINE__ standard macros.
|
||||
|
||||
Added a sanity check for number constants being greater than
|
||||
0xFFFFFFFF. The warning can be disabled.
|
||||
|
||||
Added the %0 token whereby a variadic multi-line macro can tell how
|
||||
many parameters it's been given in a specific invocation.
|
||||
|
||||
Added %rotate, allowing multi-line macro parameters to be cycled.
|
||||
|
||||
Added the `*' option for the maximum parameter count on multi-line
|
||||
macros, allowing them to take arbitrarily many parameters.
|
||||
|
||||
Added the ability for the user-level forms of EXTERN, GLOBAL and
|
||||
COMMON to take more than one argument.
|
||||
|
||||
Added the IMPORT and EXPORT directives in OBJ format, to deal with
|
||||
Windows DLLs.
|
||||
|
||||
Added some more preprocessor %if constructs: %ifidn / %ifidni (exact
|
||||
textual identity), and %ifid / %ifnum / %ifstr (token type testing).
|
||||
|
||||
Added the ability to distinguish SHL AX,1 (the 8086 version) from
|
||||
SHL AX,BYTE 1 (the 286-and-upwards version whose constant happens to
|
||||
be 1).
|
||||
|
||||
Added NetBSD/FreeBSD/OpenBSD's variant of a.out format, complete
|
||||
with PIC shared library features.
|
||||
|
||||
Changed NASM's idiosyncratic handling of FCLEX, FDISI, FENI, FINIT,
|
||||
FSAVE, FSTCW, FSTENV, and FSTSW to bring it into line with the
|
||||
otherwise accepted standard. The previous behaviour, though it was a
|
||||
deliberate feature, was a deliberate feature based on a
|
||||
misunderstanding. Apologies for the inconvenience.
|
||||
|
||||
Improved the flexibility of ABSOLUTE: you can now give it an
|
||||
expression rather than being restricted to a constant, and it can
|
||||
take relocatable arguments as well.
|
||||
|
||||
Added the ability for a variable to be declared as EXTERN multiple
|
||||
times, and the subsequent definitions are just ignored.
|
||||
|
||||
We now allow instruction prefixes (CS, DS, LOCK, REPZ etc) to be
|
||||
alone on a line (without a following instruction).
|
||||
|
||||
Improved sanity checks on whether the arguments to EXTERN, GLOBAL
|
||||
and COMMON are valid identifiers.
|
||||
|
||||
Added misc/exebin.mac to allow direct generation of .EXE files by
|
||||
hacking up an EXE header using DB and DW; also added test/binexe.asm
|
||||
to demonstrate the use of this. Thanks to Yann Guidon for
|
||||
contributing the EXE header code.
|
||||
|
||||
ndisasm forgot to check whether the input file had been successfully
|
||||
opened. Now it does. Doh!
|
||||
|
||||
Added the Cyrix extensions to the MMX instruction set.
|
||||
|
||||
Added a hinting mechanism to allow [EAX+EBX] and [EBX+EAX] to be
|
||||
assembled differently. This is important since [ESI+EBP] and
|
||||
[EBP+ESI] have different default base segment registers.
|
||||
|
||||
Added support for the PharLap OMF extension for 4096-byte segment
|
||||
alignment.
|
||||
|
|
|
|||
109
Makefile
109
Makefile
|
|
@ -1,109 +0,0 @@
|
|||
# Makefile for the Netwide Assembler
|
||||
#
|
||||
# The Netwide Assembler is copyright (C) 1996 Simon Tatham and
|
||||
# Julian Hall. All rights reserved. The software is
|
||||
# redistributable under the licence given in the file "Licence"
|
||||
# distributed in the NASM archive.
|
||||
#
|
||||
# This Makefile is designed for use under Unix (probably fairly
|
||||
# portably). It can also be used without change to build NASM using
|
||||
# DJGPP. The makefile "Makefile.dos" can be used to build NASM using
|
||||
# a 16-bit DOS C compiler such as Microsoft C.
|
||||
#
|
||||
# The `make dist' section at the end of the Makefile is not
|
||||
# guaranteed to work anywhere except Linux. Come to think of it,
|
||||
# I'm not sure I want to guarantee it to work anywhere except on
|
||||
# _my_ computer. :-)
|
||||
|
||||
CC = gcc
|
||||
CCFLAGS = -c -g -O -Wall -ansi -pedantic
|
||||
LINK = gcc
|
||||
LINKFLAGS = -o nasm
|
||||
DLINKFLAGS = -o ndisasm
|
||||
LIBRARIES =
|
||||
STRIP = strip
|
||||
EXE =#
|
||||
OBJ = o#
|
||||
|
||||
.c.$(OBJ):
|
||||
$(CC) $(CCFLAGS) $*.c
|
||||
|
||||
NASMOBJS = nasm.$(OBJ) nasmlib.$(OBJ) float.$(OBJ) insnsa.$(OBJ) \
|
||||
assemble.$(OBJ) labels.$(OBJ) parser.$(OBJ) outform.$(OBJ) \
|
||||
outbin.$(OBJ) outaout.$(OBJ) outcoff.$(OBJ) outelf.$(OBJ) \
|
||||
outobj.$(OBJ) outas86.$(OBJ) outrdf.$(OBJ) outdbg.$(OBJ) \
|
||||
preproc.$(OBJ) listing.$(OBJ)
|
||||
|
||||
NDISASMOBJS = ndisasm.$(OBJ) disasm.$(OBJ) sync.$(OBJ) nasmlib.$(OBJ) \
|
||||
insnsd.$(OBJ)
|
||||
|
||||
all : nasm$(EXE) ndisasm$(EXE)
|
||||
|
||||
nasm$(EXE): $(NASMOBJS)
|
||||
$(LINK) $(LINKFLAGS) $(NASMOBJS) $(LIBRARIES)
|
||||
|
||||
ndisasm$(EXE): $(NDISASMOBJS)
|
||||
$(LINK) $(DLINKFLAGS) $(NDISASMOBJS) $(LIBRARIES)
|
||||
|
||||
assemble.$(OBJ): assemble.c nasm.h nasmlib.h assemble.h insns.h
|
||||
disasm.$(OBJ): disasm.c nasm.h disasm.h sync.h insns.h names.c
|
||||
float.$(OBJ): float.c nasm.h
|
||||
insnsa.$(OBJ): insnsa.c nasm.h insns.h
|
||||
insnsd.$(OBJ): insnsd.c nasm.h insns.h
|
||||
labels.$(OBJ): labels.c nasm.h nasmlib.h
|
||||
listing.$(OBJ): listing.c nasm.h nasmlib.h listing.h
|
||||
macros.$(OBJ): macros.c
|
||||
names.$(OBJ): names.c
|
||||
nasm.$(OBJ): nasm.c nasm.h nasmlib.h preproc.h parser.h assemble.h labels.h \
|
||||
outform.h listing.h
|
||||
nasmlib.$(OBJ): nasmlib.c nasm.h nasmlib.h
|
||||
ndisasm.$(OBJ): ndisasm.c nasm.h nasmlib.h sync.h disasm.h
|
||||
outaout.$(OBJ): outaout.c nasm.h nasmlib.h outform.h
|
||||
outas86.$(OBJ): outas86.c nasm.h nasmlib.h outform.h
|
||||
outbin.$(OBJ): outbin.c nasm.h nasmlib.h outform.h
|
||||
outcoff.$(OBJ): outcoff.c nasm.h nasmlib.h outform.h
|
||||
outdbg.$(OBJ): outdbg.c nasm.h nasmlib.h outform.h
|
||||
outelf.$(OBJ): outelf.c nasm.h nasmlib.h outform.h
|
||||
outform.$(OBJ): outform.c outform.h nasm.h
|
||||
outobj.$(OBJ): outobj.c nasm.h nasmlib.h outform.h
|
||||
outrdf.$(OBJ): outrdf.c nasm.h nasmlib.h outform.h
|
||||
parser.$(OBJ): parser.c nasm.h nasmlib.h parser.h float.h names.c
|
||||
preproc.$(OBJ): preproc.c nasm.h nasmlib.h macros.c
|
||||
sync.$(OBJ): sync.c sync.h
|
||||
|
||||
# These two source files are automagically generated from a single
|
||||
# instruction-table file by a Perl script. They're distributed,
|
||||
# though, so it isn't necessary to have Perl just to recompile NASM
|
||||
# from the distribution.
|
||||
|
||||
AUTOSRCS = insnsa.c insnsd.c
|
||||
$(AUTOSRCS): insns.dat insns.pl
|
||||
perl insns.pl
|
||||
|
||||
# This source file is generated from the standard macros file
|
||||
# `standard.mac' by another Perl script. Again, it's part of the
|
||||
# standard distribution.
|
||||
|
||||
macros.c: standard.mac
|
||||
perl macros.pl
|
||||
|
||||
# Clean the whole thing up after compilation.
|
||||
|
||||
clean :
|
||||
rm -f $(NASMOBJS) $(NDISASMOBJS) nasm$(EXE) ndisasm$(EXE)
|
||||
make -C rdoff clean
|
||||
make -C test clean
|
||||
|
||||
# Here the `make dist' section begins. Nothing is guaranteed hereafter
|
||||
# unless you're using the Makefile under Linux, running bash, with
|
||||
# gzip, GNU tar and a sensible version of zip readily available.
|
||||
|
||||
MANPAGES = nasm.man ndisasm.man
|
||||
|
||||
.SUFFIXES: .man .1
|
||||
|
||||
.1.man:
|
||||
-man ./$< | ul > $@
|
||||
|
||||
dist: $(AUTOSRCS) $(MANPAGES) clean
|
||||
makedist.sh
|
||||
|
|
@ -69,7 +69,7 @@ DCCFLAGS = /d /c /O /A /mh /n$(OBJD) #compiler flags for NDISASM
|
|||
#/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
|
||||
#NOTE: Huge model 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
|
||||
|
|
@ -95,7 +95,7 @@ DASM_ASM=$(CC) $(DCCFLAGS) $&.c #command line for NDISASM
|
|||
NASMOBJS = $(OBJD)nasm.$(OBJ) $(OBJD)nasmlib.$(OBJ) $(OBJD)float.$(OBJ) \
|
||||
$(OBJD)insnsa.$(OBJ) $(OBJD)assemble.$(OBJ) $(OBJD)labels.$(OBJ) \
|
||||
$(OBJD)parser.$(OBJ) $(OBJD)outform.$(OBJ) $(OBJD)preproc.$(OBJ) \
|
||||
$(OBJD)listing.$(OBJ)
|
||||
$(OBJD)listing.$(OBJ) $(OBJD)eval.$(OBJ)
|
||||
|
||||
################################################################
|
||||
#The OBJ files that NDISASM is dependent on
|
||||
|
|
@ -150,6 +150,9 @@ $(OBJD)labels.$(OBJ): labels.c nasm.h nasmlib.h
|
|||
$(OBJD)listing.$(OBJ): listing.c nasm.h nasmlib.h listing.h
|
||||
$(NASM_ASM)
|
||||
|
||||
$(OBJD)eval.$(OBJ): eval.c nasm.h nasmlib.h eval.h
|
||||
$(NASM_ASM)
|
||||
|
||||
$(OBJD)nasm.$(OBJ): nasm.c nasm.h nasmlib.h parser.h assemble.h labels.h \
|
||||
listing.h outform.h
|
||||
$(NASM_ASM)
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ NASMOBJS1 = nasm.$(OBJ) nasmlib.$(OBJ) float.$(OBJ) insnsa.$(OBJ)
|
|||
NASMOBJS2 = assemble.$(OBJ) labels.$(OBJ) parser.$(OBJ) outform.$(OBJ)
|
||||
NASMOBJS3 = outbin.$(OBJ) outaout.$(OBJ) outcoff.$(OBJ) outelf.$(OBJ)
|
||||
NASMOBJS4 = outobj.$(OBJ) outas86.$(OBJ) outdbg.$(OBJ) outrdf.$(OBJ)
|
||||
NASMOBJS5 = preproc.$(OBJ) listing.$(OBJ)
|
||||
NASMOBJS5 = preproc.$(OBJ) listing.$(OBJ) eval.$(OBJ)
|
||||
|
||||
NASMOBJS = $(NASMOBJS1) $(NASMOBJS2) $(NASMOBJS3) $(NASMOBJS4) $(NASMOBJS5)
|
||||
|
||||
|
|
@ -53,6 +53,7 @@ ndisasm$(EXE): $(NDISASMOBJS)
|
|||
|
||||
assemble.$(OBJ): assemble.c nasm.h assemble.h insns.h
|
||||
disasm.$(OBJ): disasm.c nasm.h disasm.h sync.h insns.h names.c
|
||||
eval.$(OBJ): eval.c nasm.h nasmlib.h eval.h
|
||||
float.$(OBJ): float.c nasm.h
|
||||
insnsa.$(OBJ): insnsa.c nasm.h insns.h
|
||||
insnsd.$(OBJ): insnsd.c nasm.h insns.h
|
||||
|
|
|
|||
|
|
@ -10,8 +10,8 @@
|
|||
# It's been tested with Microsoft C 5.x plus Borland Make. (Yes, I
|
||||
# know it's silly, but...)
|
||||
|
||||
CC = cl /c /O /AL
|
||||
QCL = qcl /c /AL
|
||||
CC = cl /c /O /AL /Gt
|
||||
QCL = qcl /c /AL /Gt
|
||||
LINK = cl
|
||||
LINKFLAGS =
|
||||
LIBRARIES =
|
||||
|
|
@ -25,7 +25,7 @@ NASMOBJS = nasm.$(OBJ) nasmlib.$(OBJ) float.$(OBJ) insnsa.$(OBJ) \
|
|||
assemble.$(OBJ) labels.$(OBJ) parser.$(OBJ) outform.$(OBJ) \
|
||||
outbin.$(OBJ) outaout.$(OBJ) outcoff.$(OBJ) outelf.$(OBJ) \
|
||||
outobj.$(OBJ) outas86.$(OBJ) outrdf.$(OBJ) outdbg.$(OBJ) \
|
||||
preproc.$(OBJ) listing.$(OBJ)
|
||||
preproc.$(OBJ) listing.$(OBJ) eval.$(OBJ)
|
||||
|
||||
NDISASMOBJS = ndisasm.$(OBJ) disasm.$(OBJ) sync.$(OBJ) nasmlib.$(OBJ) \
|
||||
insnsd.$(OBJ)
|
||||
|
|
@ -34,7 +34,7 @@ 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
|
||||
LINKOBJS = a*.obj e*.obj f*.obj insnsa.obj l*.obj na*.obj o*.obj p*.obj
|
||||
nasm$(EXE): $(NASMOBJS)
|
||||
cl /Fenasm.exe /F 4000 $(LINKOBJS)
|
||||
|
||||
|
|
@ -43,6 +43,7 @@ ndisasm$(EXE): $(NDISASMOBJS)
|
|||
|
||||
assemble.$(OBJ): assemble.c nasm.h assemble.h insns.h
|
||||
disasm.$(OBJ): disasm.c nasm.h disasm.h sync.h insns.h names.c
|
||||
eval.$(OBJ): eval.c eval.h nasm.h nasmlib.h
|
||||
float.$(OBJ): float.c nasm.h
|
||||
labels.$(OBJ): labels.c nasm.h nasmlib.h
|
||||
listing.$(OBJ): listing.c nasm.h nasmlib.h listing.h
|
||||
|
|
|
|||
99
Makefile.in
Normal file
99
Makefile.in
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
#
|
||||
# Auto-configuring Makefile for the Netwide Assembler.
|
||||
#
|
||||
# The Netwide Assembler is copyright (C) 1996 Simon Tatham and
|
||||
# Julian Hall. All rights reserved. The software is
|
||||
# redistributable under the licence given in the file "Licence"
|
||||
# distributed in the NASM archive.
|
||||
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
prefix = @prefix@
|
||||
exec_prefix = @exec_prefix@
|
||||
bindir = @bindir@
|
||||
mandir = @mandir@
|
||||
|
||||
CC = @CC@
|
||||
CFLAGS = @CFLAGS@ @GCCFLAGS@ -I$(srcdir) -I.
|
||||
|
||||
INSTALL = @INSTALL@
|
||||
INSTALL_PROGRAM = @INSTALL_PROGRAM@
|
||||
INSTALL_DATA = @INSTALL_DATA@
|
||||
|
||||
.c.o:
|
||||
$(CC) -c $(CFLAGS) $<
|
||||
|
||||
NASM = nasm.o nasmlib.o float.o insnsa.o assemble.o labels.o \
|
||||
parser.o outform.o outbin.o outaout.o outcoff.o outelf.o \
|
||||
outobj.o outas86.o outrdf.o outdbg.o preproc.o listing.o \
|
||||
eval.o
|
||||
|
||||
NDISASM = ndisasm.o disasm.o sync.o nasmlib.o insnsd.o
|
||||
|
||||
all: nasm ndisasm
|
||||
|
||||
nasm: $(NASM)
|
||||
$(CC) -o nasm $(NASM)
|
||||
|
||||
ndisasm: $(NDISASM)
|
||||
$(CC) -o ndisasm $(NDISASM)
|
||||
|
||||
assemble.o: assemble.c nasm.h nasmlib.h assemble.h insns.h
|
||||
disasm.o: disasm.c nasm.h disasm.h sync.h insns.h names.c
|
||||
eval.o: eval.c eval.h nasm.h nasmlib.h
|
||||
float.o: float.c nasm.h
|
||||
insnsa.o: insnsa.c nasm.h insns.h
|
||||
insnsd.o: insnsd.c nasm.h insns.h
|
||||
labels.o: labels.c nasm.h nasmlib.h
|
||||
listing.o: listing.c nasm.h nasmlib.h listing.h
|
||||
nasm.o: nasm.c nasm.h nasmlib.h preproc.h parser.h assemble.h labels.h \
|
||||
outform.h listing.h
|
||||
nasmlib.o: nasmlib.c nasm.h nasmlib.h
|
||||
ndisasm.o: ndisasm.c nasm.h nasmlib.h sync.h disasm.h
|
||||
outaout.o: outaout.c nasm.h nasmlib.h outform.h
|
||||
outas86.o: outas86.c nasm.h nasmlib.h outform.h
|
||||
outbin.o: outbin.c nasm.h nasmlib.h outform.h
|
||||
outcoff.o: outcoff.c nasm.h nasmlib.h outform.h
|
||||
outdbg.o: outdbg.c nasm.h nasmlib.h outform.h
|
||||
outelf.o: outelf.c nasm.h nasmlib.h outform.h
|
||||
outform.o: outform.c outform.h nasm.h
|
||||
outobj.o: outobj.c nasm.h nasmlib.h outform.h
|
||||
outrdf.o: outrdf.c nasm.h nasmlib.h outform.h
|
||||
parser.o: parser.c nasm.h nasmlib.h parser.h float.h names.c
|
||||
preproc.o: preproc.c nasm.h nasmlib.h macros.c
|
||||
sync.o: sync.c sync.h
|
||||
|
||||
# These two source files are automagically generated from a single
|
||||
# instruction-table file by a Perl script. They're distributed,
|
||||
# though, so it isn't necessary to have Perl just to recompile NASM
|
||||
# from the distribution.
|
||||
|
||||
insnsa.c insnsd.c: insns.dat insns.pl
|
||||
perl $(srcdir)/insns.pl $(srcdir)/insns.dat
|
||||
|
||||
# This source file is generated from the standard macros file
|
||||
# `standard.mac' by another Perl script. Again, it's part of the
|
||||
# standard distribution.
|
||||
|
||||
macros.c: standard.mac macros.pl
|
||||
perl $(srcdir)/macros.pl $(srcdir)/standard.mac
|
||||
|
||||
install: nasm ndisasm
|
||||
$(INSTALL_PROGRAM) nasm $(bindir)/nasm
|
||||
$(INSTALL_PROGRAM) ndisasm $(bindir)/ndisasm
|
||||
$(INSTALL_DATA) $(srcdir)/nasm.1 $(mandir)/man1/nasm.1
|
||||
$(INSTALL_DATA) $(srcdir)/ndisasm.1 $(mandir)/man1/ndisasm.1
|
||||
|
||||
clean:
|
||||
rm -f *.o nasm ndisasm
|
||||
cd rdoff; $(MAKE) clean
|
||||
|
||||
spotless: clean
|
||||
rm -f config.* Makefile
|
||||
cd rdoff; $(MAKE) spotless
|
||||
|
||||
rdf:
|
||||
cd rdoff; $(MAKE)
|
||||
|
||||
rdf_install install_rdf:
|
||||
cd rdoff; $(MAKE) install
|
||||
130
Makefile.sc
130
Makefile.sc
|
|
@ -1,222 +1,114 @@
|
|||
# Makefile for the Netwide Assembler under 32-bit Windows(tm)
|
||||
|
||||
# Makefile for the Netwide Assembler under 32-bit DOS(tm)
|
||||
#
|
||||
|
||||
# The Netwide Assembler is copyright (C) 1996 Simon Tatham and
|
||||
|
||||
# Julian Hall. All rights reserved. The software is
|
||||
|
||||
# redistributable under the licence given in the file "Licence"
|
||||
|
||||
# distributed in the NASM archive.
|
||||
|
||||
#
|
||||
|
||||
# This Makefile is designed to build NASM using the 32-bit WIN32 C
|
||||
|
||||
# compiler Symantec(tm) C++ 7.5, provided you have a MAKE-utility
|
||||
|
||||
# that's compatible to SMAKE.
|
||||
|
||||
|
||||
|
||||
CC = sc
|
||||
|
||||
CCFLAGS = -c -a1 -mn -Nc -w2 -w7 -o+time -5
|
||||
|
||||
CCFLAGS = -c -a1 -mx -Nc -w2 -w7 -o+time -5
|
||||
# -5 optimize for pentium (tm)
|
||||
|
||||
# -c compile only
|
||||
|
||||
# -o-all no optimizations (to avoid problems in disasm.c)
|
||||
|
||||
# -o+time optimize for speed
|
||||
|
||||
# -o+space optimize for size
|
||||
|
||||
# -A1 byte alignment for structures
|
||||
|
||||
# -mn compile for Win32 executable
|
||||
|
||||
# -mx compile for DOS386 (DOSX) executable
|
||||
# -Nc create COMDAT records
|
||||
|
||||
# -w2 possible unattended assignment: off
|
||||
|
||||
# -w7 for loops with empty instruction-body
|
||||
|
||||
|
||||
|
||||
LINK = link
|
||||
|
||||
LINKFLAGS = /noi /exet:NT /su:console
|
||||
|
||||
LINKFLAGS = /noi /exet:DOSX
|
||||
# /noignorecase all symbols are case-sensitive
|
||||
|
||||
# /exet:NT Exetype: NT (Win32)
|
||||
|
||||
# /exet:DOSX Exetype: DOSX (DOS32)
|
||||
# /su:console Subsystem: Console (Console-App)
|
||||
|
||||
|
||||
|
||||
LIBRARIES =
|
||||
|
||||
EXE = .exe
|
||||
|
||||
OBJ = obj
|
||||
|
||||
|
||||
|
||||
.c.$(OBJ):
|
||||
|
||||
$(CC) $(CCFLAGS) $*.c
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#
|
||||
|
||||
# modules needed for different programs
|
||||
|
||||
#
|
||||
|
||||
|
||||
|
||||
NASMOBJS = nasm.$(OBJ) nasmlib.$(OBJ) float.$(OBJ) insnsa.$(OBJ) \
|
||||
|
||||
assemble.$(OBJ) labels.$(OBJ) parser.$(OBJ) outform.$(OBJ) \
|
||||
|
||||
outbin.$(OBJ) outaout.$(OBJ) outcoff.$(OBJ) outelf.$(OBJ) \
|
||||
|
||||
outobj.$(OBJ) outas86.$(OBJ) outrdf.$(OBJ) outdbg.$(OBJ) \
|
||||
|
||||
preproc.$(OBJ) listing.$(OBJ)
|
||||
|
||||
|
||||
preproc.$(OBJ) listing.$(OBJ) eval.$(OBJ)
|
||||
|
||||
NDISASMOBJS = ndisasm.$(OBJ) disasm.$(OBJ) sync.$(OBJ) nasmlib.$(OBJ) \
|
||||
|
||||
insnsd.$(OBJ)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#
|
||||
|
||||
# programs to create
|
||||
|
||||
#
|
||||
|
||||
|
||||
|
||||
all : nasm$(EXE) ndisasm$(EXE)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#
|
||||
|
||||
# We have to have a horrible kludge here to get round the 128 character
|
||||
|
||||
# limit, as usual... we'll simply use LNK-files :)
|
||||
|
||||
#
|
||||
|
||||
nasm$(EXE): $(NASMOBJS)
|
||||
|
||||
$(LINK) $(LINKFLAGS) @<<
|
||||
|
||||
$(NASMOBJS)
|
||||
|
||||
nasm.exe;
|
||||
|
||||
cx.obj $(NASMOBJS)
|
||||
nasm.exe
|
||||
<<
|
||||
|
||||
|
||||
|
||||
ndisasm$(EXE): $(NDISASMOBJS)
|
||||
|
||||
$(LINK) $(LINKFLAGS) @<<
|
||||
|
||||
$(NDISASMOBJS)
|
||||
|
||||
ndisasm.exe;
|
||||
|
||||
cx.obj $(NDISASMOBJS)
|
||||
ndisasm.exe
|
||||
<<
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#
|
||||
|
||||
# modules for programs
|
||||
|
||||
#
|
||||
|
||||
|
||||
|
||||
disasm.$(OBJ): disasm.c nasm.h disasm.h sync.h insns.h names.c
|
||||
|
||||
assemble.$(OBJ): assemble.c nasm.h assemble.h insns.h
|
||||
|
||||
eval.$(OBJ): eval.c nasm.h nasmlib.h eval.h
|
||||
float.$(OBJ): float.c nasm.h
|
||||
|
||||
labels.$(OBJ): labels.c nasm.h nasmlib.h
|
||||
|
||||
listing.$(OBJ): listing.c nasm.h nasmlib.h listing.h
|
||||
|
||||
nasm.$(OBJ): nasm.c nasm.h nasmlib.h parser.h assemble.h labels.h \
|
||||
|
||||
listing.h outform.h
|
||||
|
||||
nasmlib.$(OBJ): nasmlib.c nasm.h nasmlib.h
|
||||
|
||||
ndisasm.$(OBJ): ndisasm.c nasm.h sync.h disasm.h
|
||||
|
||||
outas86.$(OBJ): outas86.c nasm.h nasmlib.h
|
||||
|
||||
outaout.$(OBJ): outaout.c nasm.h nasmlib.h
|
||||
|
||||
outbin.$(OBJ): outbin.c nasm.h nasmlib.h
|
||||
|
||||
outcoff.$(OBJ): outcoff.c nasm.h nasmlib.h
|
||||
|
||||
outdbg.$(OBJ): outdbg.c nasm.h nasmlib.h
|
||||
|
||||
outelf.$(OBJ): outelf.c nasm.h nasmlib.h
|
||||
|
||||
outobj.$(OBJ): outobj.c nasm.h nasmlib.h
|
||||
|
||||
outrdf.$(OBJ): outrdf.c nasm.h nasmlib.h
|
||||
|
||||
outform.$(OBJ): outform.c outform.h nasm.h
|
||||
|
||||
parser.$(OBJ): parser.c nasm.h nasmlib.h parser.h float.h names.c
|
||||
|
||||
preproc.$(OBJ): preproc.c macros.c preproc.h nasm.h nasmlib.h
|
||||
|
||||
sync.$(OBJ): sync.c sync.h
|
||||
|
||||
insnsa.$(OBJ): insnsa.c nasm.h insns.h
|
||||
|
||||
insnsd.$(OBJ): insnsd.c nasm.h insns.h
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
clean :
|
||||
|
||||
del *.obj
|
||||
|
||||
del nasm$(EXE)
|
||||
|
||||
del ndisasm$(EXE)
|
||||
|
||||
|
|
|
|||
114
Makefile.scw
Normal file
114
Makefile.scw
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
# Makefile for the Netwide Assembler under 32-bit Windows(tm)
|
||||
#
|
||||
# The Netwide Assembler is copyright (C) 1996 Simon Tatham and
|
||||
# Julian Hall. All rights reserved. The software is
|
||||
# redistributable under the licence given in the file "Licence"
|
||||
# distributed in the NASM archive.
|
||||
#
|
||||
# This Makefile is designed to build NASM using the 32-bit WIN32 C
|
||||
# compiler Symantec(tm) C++ 7.5, provided you have a MAKE-utility
|
||||
# that's compatible to SMAKE.
|
||||
|
||||
CC = sc
|
||||
CCFLAGS = -c -a1 -mn -Nc -w2 -w7 -o+time -5
|
||||
# -5 optimize for pentium (tm)
|
||||
# -c compile only
|
||||
# -o-all no optimizations (to avoid problems in disasm.c)
|
||||
# -o+time optimize for speed
|
||||
# -o+space optimize for size
|
||||
# -A1 byte alignment for structures
|
||||
# -mn compile for Win32 executable
|
||||
# -mx compile for DOS386 (DOSX) executable
|
||||
# -Nc create COMDAT records
|
||||
# -w2 possible unattended assignment: off
|
||||
# -w7 for loops with empty instruction-body
|
||||
|
||||
LINK = link
|
||||
LINKFLAGS = /noi /exet:NT /su:console
|
||||
# /noignorecase all symbols are case-sensitive
|
||||
# /exet:NT Exetype: NT (Win32)
|
||||
# /exet:DOSX Exetype: DOSX (DOS32)
|
||||
# /su:console Subsystem: Console (Console-App)
|
||||
|
||||
LIBRARIES =
|
||||
EXE = .exe
|
||||
OBJ = obj
|
||||
|
||||
.c.$(OBJ):
|
||||
$(CC) $(CCFLAGS) $*.c
|
||||
|
||||
|
||||
#
|
||||
# modules needed for different programs
|
||||
#
|
||||
|
||||
NASMOBJS = nasm.$(OBJ) nasmlib.$(OBJ) float.$(OBJ) insnsa.$(OBJ) \
|
||||
assemble.$(OBJ) labels.$(OBJ) parser.$(OBJ) outform.$(OBJ) \
|
||||
outbin.$(OBJ) outaout.$(OBJ) outcoff.$(OBJ) outelf.$(OBJ) \
|
||||
outobj.$(OBJ) outas86.$(OBJ) outrdf.$(OBJ) outdbg.$(OBJ) \
|
||||
preproc.$(OBJ) listing.$(OBJ) eval.$(OBJ)
|
||||
|
||||
NDISASMOBJS = ndisasm.$(OBJ) disasm.$(OBJ) sync.$(OBJ) nasmlib.$(OBJ) \
|
||||
insnsd.$(OBJ)
|
||||
|
||||
|
||||
#
|
||||
# programs to create
|
||||
#
|
||||
|
||||
all : nasmw$(EXE) ndisasmw$(EXE)
|
||||
|
||||
|
||||
#
|
||||
# We have to have a horrible kludge here to get round the 128 character
|
||||
# limit, as usual... we'll simply use LNK-files :)
|
||||
#
|
||||
nasmw$(EXE): $(NASMOBJS)
|
||||
$(LINK) $(LINKFLAGS) @<<
|
||||
$(NASMOBJS)
|
||||
nasmw.exe;
|
||||
<<
|
||||
|
||||
ndisasmw$(EXE): $(NDISASMOBJS)
|
||||
$(LINK) $(LINKFLAGS) @<<
|
||||
$(NDISASMOBJS)
|
||||
ndisasmw.exe;
|
||||
<<
|
||||
|
||||
|
||||
|
||||
#
|
||||
# modules for programs
|
||||
#
|
||||
|
||||
disasm.$(OBJ): disasm.c nasm.h disasm.h sync.h insns.h names.c
|
||||
assemble.$(OBJ): assemble.c nasm.h assemble.h insns.h
|
||||
eval.$(OBJ): eval.c nasm.h nasmlib.h eval.h
|
||||
float.$(OBJ): float.c nasm.h
|
||||
labels.$(OBJ): labels.c nasm.h nasmlib.h
|
||||
listing.$(OBJ): listing.c nasm.h nasmlib.h listing.h
|
||||
nasm.$(OBJ): nasm.c nasm.h nasmlib.h parser.h assemble.h labels.h \
|
||||
listing.h outform.h
|
||||
nasmlib.$(OBJ): nasmlib.c nasm.h nasmlib.h
|
||||
ndisasm.$(OBJ): ndisasm.c nasm.h sync.h disasm.h
|
||||
outas86.$(OBJ): outas86.c nasm.h nasmlib.h
|
||||
outaout.$(OBJ): outaout.c nasm.h nasmlib.h
|
||||
outbin.$(OBJ): outbin.c nasm.h nasmlib.h
|
||||
outcoff.$(OBJ): outcoff.c nasm.h nasmlib.h
|
||||
outdbg.$(OBJ): outdbg.c nasm.h nasmlib.h
|
||||
outelf.$(OBJ): outelf.c nasm.h nasmlib.h
|
||||
outobj.$(OBJ): outobj.c nasm.h nasmlib.h
|
||||
outrdf.$(OBJ): outrdf.c nasm.h nasmlib.h
|
||||
outform.$(OBJ): outform.c outform.h nasm.h
|
||||
parser.$(OBJ): parser.c nasm.h nasmlib.h parser.h float.h names.c
|
||||
preproc.$(OBJ): preproc.c macros.c preproc.h nasm.h nasmlib.h
|
||||
sync.$(OBJ): sync.c sync.h
|
||||
insnsa.$(OBJ): insnsa.c nasm.h insns.h
|
||||
insnsd.$(OBJ): insnsd.c nasm.h insns.h
|
||||
|
||||
|
||||
|
||||
clean :
|
||||
del *.obj
|
||||
del nasmw$(EXE)
|
||||
del ndisasmw$(EXE)
|
||||
97
Makefile.unx
Normal file
97
Makefile.unx
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
# Unix fall-back makefile for the Netwide Assembler. For use if
|
||||
# `configure' fails to generate a workable Makefile.
|
||||
#
|
||||
# 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.
|
||||
|
||||
# You may need to adjust these values.
|
||||
|
||||
prefix = /usr/local
|
||||
CC = cc
|
||||
CFLAGS = -O -I.
|
||||
|
||||
# You _shouldn't_ need to adjust anything below this line.
|
||||
|
||||
exec_prefix = ${prefix}
|
||||
bindir = ${exec_prefix}/bin
|
||||
mandir = ${prefix}/man
|
||||
|
||||
INSTALL = install -c
|
||||
INSTALL_PROGRAM = ${INSTALL}
|
||||
INSTALL_DATA = ${INSTALL} -m 644
|
||||
|
||||
.c.o:
|
||||
$(CC) -c $(CFLAGS) $*.c
|
||||
|
||||
NASM = nasm.o nasmlib.o float.o insnsa.o assemble.o labels.o \
|
||||
parser.o outform.o outbin.o outaout.o outcoff.o outelf.o \
|
||||
outobj.o outas86.o outrdf.o outdbg.o preproc.o listing.o \
|
||||
eval.o
|
||||
|
||||
NDISASM = ndisasm.o disasm.o sync.o nasmlib.o insnsd.o
|
||||
|
||||
all: nasm ndisasm
|
||||
|
||||
nasm: $(NASM)
|
||||
$(CC) -o nasm $(NASM)
|
||||
|
||||
ndisasm: $(NDISASM)
|
||||
$(CC) -o ndisasm $(NDISASM)
|
||||
|
||||
assemble.o: assemble.c nasm.h nasmlib.h assemble.h insns.h
|
||||
disasm.o: disasm.c nasm.h disasm.h sync.h insns.h names.c
|
||||
eval.o: eval.c eval.h nasm.h nasmlib.h
|
||||
float.o: float.c nasm.h
|
||||
insnsa.o: insnsa.c nasm.h insns.h
|
||||
insnsd.o: insnsd.c nasm.h insns.h
|
||||
labels.o: labels.c nasm.h nasmlib.h
|
||||
listing.o: listing.c nasm.h nasmlib.h listing.h
|
||||
nasm.o: nasm.c nasm.h nasmlib.h preproc.h parser.h assemble.h labels.h \
|
||||
outform.h listing.h
|
||||
nasmlib.o: nasmlib.c nasm.h nasmlib.h
|
||||
ndisasm.o: ndisasm.c nasm.h nasmlib.h sync.h disasm.h
|
||||
outaout.o: outaout.c nasm.h nasmlib.h outform.h
|
||||
outas86.o: outas86.c nasm.h nasmlib.h outform.h
|
||||
outbin.o: outbin.c nasm.h nasmlib.h outform.h
|
||||
outcoff.o: outcoff.c nasm.h nasmlib.h outform.h
|
||||
outdbg.o: outdbg.c nasm.h nasmlib.h outform.h
|
||||
outelf.o: outelf.c nasm.h nasmlib.h outform.h
|
||||
outform.o: outform.c outform.h nasm.h
|
||||
outobj.o: outobj.c nasm.h nasmlib.h outform.h
|
||||
outrdf.o: outrdf.c nasm.h nasmlib.h outform.h
|
||||
parser.o: parser.c nasm.h nasmlib.h parser.h float.h names.c
|
||||
preproc.o: preproc.c nasm.h nasmlib.h macros.c
|
||||
sync.o: sync.c sync.h
|
||||
|
||||
# These two source files are automagically generated from a single
|
||||
# instruction-table file by a Perl script. They're distributed,
|
||||
# though, so it isn't necessary to have Perl just to recompile NASM
|
||||
# from the distribution.
|
||||
|
||||
insnsa.c insnsd.c: insns.dat insns.pl
|
||||
perl insns.pl insns.dat
|
||||
|
||||
# This source file is generated from the standard macros file
|
||||
# `standard.mac' by another Perl script. Again, it's part of the
|
||||
# standard distribution.
|
||||
|
||||
macros.c: standard.mac macros.pl
|
||||
perl macros.pl standard.mac
|
||||
|
||||
install: nasm ndisasm
|
||||
$(INSTALL_PROGRAM) nasm $(bindir)/nasm
|
||||
$(INSTALL_PROGRAM) ndisasm $(bindir)/ndisasm
|
||||
$(INSTALL_DATA) nasm.1 $(mandir)/man1/nasm.1
|
||||
$(INSTALL_DATA) ndisasm.1 $(mandir)/man1/ndisasm.1
|
||||
|
||||
clean:
|
||||
rm -f *.o nasm ndisasm
|
||||
$(MAKE) -C rdoff clean
|
||||
|
||||
rdf:
|
||||
$(MAKE) -C rdoff
|
||||
|
||||
rdf_install install_rdf:
|
||||
$(MAKE) -C rdoff install
|
||||
|
|
@ -24,7 +24,7 @@ NASMOBJS = nasm.$(OBJ) nasmlib.$(OBJ) float.$(OBJ) insnsa.$(OBJ) \
|
|||
assemble.$(OBJ) labels.$(OBJ) parser.$(OBJ) outform.$(OBJ) \
|
||||
outbin.$(OBJ) outaout.$(OBJ) outcoff.$(OBJ) outelf.$(OBJ) \
|
||||
outobj.$(OBJ) outas86.$(OBJ) outrdf.$(OBJ) outdbg.$(OBJ) \
|
||||
preproc.$(OBJ) listing.$(OBJ)
|
||||
preproc.$(OBJ) listing.$(OBJ) eval.$(OBJ)
|
||||
|
||||
NDISASMOBJS = ndisasm.$(OBJ) disasm.$(OBJ) sync.$(OBJ) nasmlib.$(OBJ) \
|
||||
insnsd.$(OBJ)
|
||||
|
|
@ -33,7 +33,7 @@ all : nasm$(SUFFIX)$(EXE) ndisasm$(SUFFIX)$(EXE)
|
|||
|
||||
# We have to have a horrible kludge here to get round the 128 character
|
||||
# limit, as usual...
|
||||
LINKOBJS = a*.obj f*.obj insnsa.obj l*.obj na*.obj o*.obj p*.obj
|
||||
LINKOBJS = a*.obj e*.obj f*.obj insnsa.obj l*.obj na*.obj o*.obj p*.obj
|
||||
nasm$(SUFFIX)$(EXE): $(NASMOBJS)
|
||||
cl /Fenasm$(SUFFIX).exe $(LINKOBJS)
|
||||
|
||||
|
|
@ -42,6 +42,7 @@ ndisasm$(SUFFIX)$(EXE): $(NDISASMOBJS)
|
|||
|
||||
assemble.$(OBJ): assemble.c nasm.h assemble.h insns.h
|
||||
disasm.$(OBJ): disasm.c nasm.h disasm.h sync.h insns.h names.c
|
||||
eval.$(OBJ): eval.c nasm.h nasmlib.h eval.h
|
||||
float.$(OBJ): float.c nasm.h
|
||||
labels.$(OBJ): labels.c nasm.h nasmlib.h
|
||||
listing.$(OBJ): listing.c nasm.h nasmlib.h listing.h
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ NASMOBJS = nasm.$(OBJ) nasmlib.$(OBJ) float.$(OBJ) insnsa.$(OBJ) \
|
|||
assemble.$(OBJ) labels.$(OBJ) parser.$(OBJ) outform.$(OBJ) \
|
||||
outbin.$(OBJ) outaout.$(OBJ) outcoff.$(OBJ) outelf.$(OBJ) \
|
||||
outobj.$(OBJ) outas86.$(OBJ) outrdf.$(OBJ) outdbg.$(OBJ) \
|
||||
preproc.$(OBJ) listing.$(OBJ)
|
||||
preproc.$(OBJ) listing.$(OBJ) eval.$(OBJ)
|
||||
|
||||
NDISASMOBJS = ndisasm.$(OBJ) disasm.$(OBJ) sync.$(OBJ) nasmlib.$(OBJ) \
|
||||
insnsd.$(OBJ)
|
||||
|
|
@ -62,10 +62,12 @@ NASM.LNK: makefile.wc
|
|||
echo N nasm.exe > NASM.LNK
|
||||
echo F nasm.$(OBJ) >> NASM.LNK
|
||||
echo F nasmlib.$(OBJ) >> NASM.LNK
|
||||
echo F eval.$(OBJ) >> NASM.LNK
|
||||
echo F float.$(OBJ) >> NASM.LNK
|
||||
echo F insnsa.$(OBJ) >> NASM.LNK
|
||||
echo F assemble.$(OBJ) >> NASM.LNK
|
||||
echo F labels.$(OBJ) >> NASM.LNK
|
||||
echo F listing.$(OBJ) >> NASM.LNK
|
||||
echo F parser.$(OBJ) >> NASM.LNK
|
||||
echo F preproc.$(OBJ) >> NASM.LNK
|
||||
echo F outform.$(OBJ) >> NASM.LNK
|
||||
|
|
@ -88,6 +90,7 @@ NDISASM.LNK: makefile.wc
|
|||
|
||||
assemble.$(OBJ): assemble.c nasm.h assemble.h insns.h
|
||||
disasm.$(OBJ): disasm.c nasm.h disasm.h sync.h insns.h names.c
|
||||
eval.$(OBJ): eval.c nasm.h nasmlib.h eval.h
|
||||
float.$(OBJ): float.c nasm.h
|
||||
insnsa.$(OBJ): insnsa.c nasm.h insns.h
|
||||
insnsd.$(OBJ): insnsd.c nasm.h insns.h
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ NASMOBJS = nasm.$(OBJ) nasmlib.$(OBJ) float.$(OBJ) insnsa.$(OBJ) \
|
|||
assemble.$(OBJ) labels.$(OBJ) parser.$(OBJ) outform.$(OBJ) \
|
||||
outbin.$(OBJ) outaout.$(OBJ) outcoff.$(OBJ) outelf.$(OBJ) \
|
||||
outobj.$(OBJ) outas86.$(OBJ) outrdf.$(OBJ) outdbg.$(OBJ) \
|
||||
preproc.$(OBJ) listing.$(OBJ)
|
||||
preproc.$(OBJ) listing.$(OBJ) eval.$(OBJ)
|
||||
|
||||
NDISASMOBJS = ndisasm.$(OBJ) disasm.$(OBJ) sync.$(OBJ) nasmlib.$(OBJ) \
|
||||
insnsd.$(OBJ)
|
||||
|
|
@ -62,10 +62,12 @@ NASM.LNK: makefile.wcw
|
|||
echo N nasm.exe > NASM.LNK
|
||||
echo F nasm.$(OBJ) >> NASM.LNK
|
||||
echo F nasmlib.$(OBJ) >> NASM.LNK
|
||||
echo F eval.$(OBJ) >> NASM.LNK
|
||||
echo F float.$(OBJ) >> NASM.LNK
|
||||
echo F insnsa.$(OBJ) >> NASM.LNK
|
||||
echo F assemble.$(OBJ) >> NASM.LNK
|
||||
echo F labels.$(OBJ) >> NASM.LNK
|
||||
echo F listing.$(OBJ) >> NASM.LNK
|
||||
echo F parser.$(OBJ) >> NASM.LNK
|
||||
echo F preproc.$(OBJ) >> NASM.LNK
|
||||
echo F outform.$(OBJ) >> NASM.LNK
|
||||
|
|
@ -88,6 +90,7 @@ NDISASM.LNK: makefile.wcw
|
|||
|
||||
assemble.$(OBJ): assemble.c nasm.h assemble.h insns.h
|
||||
disasm.$(OBJ): disasm.c nasm.h disasm.h sync.h insns.h names.c
|
||||
eval.$(OBJ): eval.c nasm.h nasmlib.h eval.h
|
||||
float.$(OBJ): float.c nasm.h
|
||||
insnsa.$(OBJ): insnsa.c nasm.h insns.h
|
||||
insnsd.$(OBJ): insnsd.c nasm.h insns.h
|
||||
|
|
|
|||
30
Readme
30
Readme
|
|
@ -13,6 +13,11 @@ 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 install under DOS, if you don't need to rebuild from the sources,
|
||||
you can just copy nasm.exe and ndisasm.exe (16-bit DOS executables),
|
||||
or nasmw.exe and ndisasmw.exe (Win32 console applications - less
|
||||
likely to run out of memory), to somewhere on your PATH.
|
||||
|
||||
To rebuild the DOS sources, various makefiles are provided:
|
||||
|
||||
- Makefile.dos, the one I build the standard 16-bit releases from,
|
||||
|
|
@ -26,7 +31,11 @@ To rebuild the DOS sources, various makefiles are provided:
|
|||
- Makefile.bc2, also for Borland C, contributed by Fox Cutter.
|
||||
Reported to work better than Makefile.bor on some systems.
|
||||
|
||||
- Makefile.sc, for Symantec C++. Contributed by Mark Junker.
|
||||
- Makefile.sc, for Symantec C++, compiling to a 32-bit extended DOS
|
||||
executable.. Contributed by Mark Junker.
|
||||
- Makefile.scw, also for Symantec C++, compiling to a Win32 command-
|
||||
line application. Also contributed by Mark Junker.
|
||||
|
||||
- Makefile.wc, for Watcom C, compiling to a 32-bit extended DOS
|
||||
executable. Contributed by Dominik Behr.
|
||||
- Makefile.wcw, also for Watcom C, compiling to a Win32 command-
|
||||
|
|
@ -53,6 +62,9 @@ NDISASM.EXE) into standalone executables incorporating Tran's
|
|||
PMODE/W DOS extender, rather than depending on an external extender
|
||||
program.
|
||||
|
||||
Some of the Windows makefiles produce executables called nasmw.exe
|
||||
and ndisasmw.exe, and some don't. Be prepared for either...
|
||||
|
||||
If you're trying to unpack the DOS (.ZIP format) archive under Unix
|
||||
instead of using the .tar.gz version, you can save some time by
|
||||
doing `unzip -aL', which will convert the DOS-format text files to
|
||||
|
|
@ -65,9 +77,9 @@ equivalently by adding compiler command line options in the
|
|||
Makefile.
|
||||
|
||||
There is a machine description file for the `LCC' retargetable C
|
||||
compiler, in the directory `lcc', along with instructions for its
|
||||
use. This means that NASM can now be used as the code-generator back
|
||||
end for a useful C compiler.
|
||||
compiler (version 3.6), in the directory `lcc', along with
|
||||
instructions for its use. This means that NASM can now be used as
|
||||
the code-generator back end for a useful C compiler.
|
||||
|
||||
Michael `Wuschel' Tippach has ported his DOS extender `WDOSX' to
|
||||
enable it to work with the 32-bit binary files NASM can output: the
|
||||
|
|
@ -83,7 +95,11 @@ JED programmers' editor (see http://space.mit.edu/~davis/jed.html
|
|||
for details about JED). The comment at the start of the file gives
|
||||
instructions on how to install the mode. This directory also
|
||||
contains a file (`magic') containing lines to add to /etc/magic on
|
||||
Unix systems to allow the `file' command to recognise RDF files.
|
||||
Unix systems to allow the `file' command to recognise RDF files, and
|
||||
a zip file (`exasm.zip') containing the necessary files for syntax
|
||||
highlighting in the Aurora DOS editor. (The Aurora files were
|
||||
contributed by <U993847220@aol.com>; I haven't tested them as I
|
||||
don't have Aurora.)
|
||||
|
||||
The `rdoff' directory contains sources for a linker and loader for
|
||||
the RDF object file format, to run under Linux, and also
|
||||
|
|
@ -93,7 +109,9 @@ For information about how you can distribute and use NASM, see the
|
|||
file Licence. We were tempted to put NASM under the GPL, but decided
|
||||
that in many ways it was too restrictive for developers.
|
||||
|
||||
For information about how to use NASM, see `nasm.doc'. For
|
||||
For information about how to use NASM, see the various forms of
|
||||
documentation in the `doc' directory: documentation is provided in
|
||||
HTML, PostScript, plain text, Texinfo, and Windows Help formats. For
|
||||
information about how to use NDISASM, see `ndisasm.doc'. For
|
||||
information about the internal structure of NASM, see
|
||||
`internal.doc'. (In particular, _please_ read `internal.doc' before
|
||||
|
|
|
|||
97
Wishlist
Normal file
97
Wishlist
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
NASM Wishlist
|
||||
=============
|
||||
|
||||
- PUSH WORD EAX silently becomes PUSH EAX. Should warn.
|
||||
|
||||
- ndisasm hangs at eof.
|
||||
|
||||
- missing heading in documentation - some subsect in chapter 4.
|
||||
|
||||
- Add support for lcc 4.0.
|
||||
* If-when this happens, remember to bump the `supported lcc
|
||||
version' number in Readme.
|
||||
|
||||
- Re-work the evaluator, again, with a per-object-format fixup
|
||||
routine, so as to be able to cope with section offsets "really"
|
||||
being pure numbers; should be able to allow at _least_ the two
|
||||
common idioms
|
||||
TIMES 510-$ DB 0 ; bootsector
|
||||
MOV AX,(PROG_END-100H)/16 ; .COM TSR
|
||||
Would need to call the fixup throughout the evaluator, and the
|
||||
fixup would have to be allowed to return UNKNOWN on pass one if it
|
||||
had to. (_Always_ returning UNKNOWN on pass one, though a lovely
|
||||
clean design, breaks the first of the above examples.)
|
||||
|
||||
- Preprocessor identifier concatenation?
|
||||
|
||||
- Arbitrary section names in `bin'.
|
||||
|
||||
- Ability to read from a pipe. Obviously not useful under dos, so
|
||||
memory problems with storing entire input file aren't a problem
|
||||
either.
|
||||
|
||||
- Subsection support?
|
||||
|
||||
- A good ALIGN mechanism, similar to GAS's. GAS pads out space by
|
||||
means of the following (32-bit) instructions:
|
||||
8DB42600000000 lea esi,[esi+0x0]
|
||||
8DB600000000 lea esi,[esi+0x0]
|
||||
8D742600 lea esi,[esi+0x0]
|
||||
8D7600 lea esi,[esi+0x0]
|
||||
8D36 lea esi,[esi]
|
||||
90 nop
|
||||
It uses up to two of these instructions to do up to 14-byte pads;
|
||||
when more than 14 bytes are needed, it issues a (short) jump to
|
||||
the end of the padded section and then NOPs the rest. Come up with
|
||||
a similar scheme for 16 bit mode, and also come up with a way to
|
||||
use it - internal to the assembler, so that programs using ALIGN
|
||||
don't knock over preprocess-only mode.
|
||||
Also re-work the macro form so that when given one argument in a
|
||||
code section it calls this feature.
|
||||
|
||||
- Possibly a means whereby FP constants can be specified as
|
||||
immediate operands to non-FP instructions.
|
||||
* Possible syntax: MOV EAX,FLOAT 1.2 to get a single-precision FP
|
||||
constant. Then maybe MOV EAX,HI_FLOAT 1.2 and MOV EAX,LO_FLOAT
|
||||
1.2 to get the two halves of a double-precision one. Best to
|
||||
ignore extended-precision in case it bites.
|
||||
* Alternatively, maybe MOV EAX,FLOAT(4,0-4,1.2) to get bytes 0-4
|
||||
(ie 0-3) of a 4-byte constant. Then HI_FLOAT is FLOAT(8,4-8,x)
|
||||
and LO_FLOAT is FLOAT(8,0-4,x). But this version allows two-byte
|
||||
chunks, one-byte chunks, even stranger chunks, and pieces of
|
||||
ten-byte reals to be bandied around as well.
|
||||
|
||||
- A UNION macro might be quite cool, now that ABSOLUTE is sane
|
||||
enough to be able to handle it.
|
||||
|
||||
- An equivalent to gcc's ## stringify operator, plus string
|
||||
concatenation, somehow implemented without undue ugliness, so as
|
||||
to be able to do `%include "/my/path/%1"' in a macro, or something
|
||||
similar...
|
||||
|
||||
- Actually _do_ something with the processor, privileged and
|
||||
undocumented flags in the instruction table.
|
||||
|
||||
- Maybe NEC V20/V30 instructions?
|
||||
|
||||
- Yet more object formats.
|
||||
* Possibly direct support for .EXE files?
|
||||
|
||||
- Debug information, in all formats it can be usefully done in.
|
||||
* including line-number record support.
|
||||
|
||||
- Symbol map in binary format. Format-specific options...
|
||||
|
||||
- REDESIGN: Think about EQU dependency, and about start-point
|
||||
specification in OBJ. Possibly re-think directive support.
|
||||
|
||||
- Think about a wrapper program like gcc? Possibly invent a _patch_
|
||||
for gcc so that it can take .asm files on the command line?
|
||||
|
||||
- If a wrapper happens, think about adding an option to cause the
|
||||
resulting executable file to be executed immediately, thus
|
||||
allowing NASM source files to have #!... (probably silly)
|
||||
|
||||
- Multi-platform support? If so: definitely Alpha; possibly Java
|
||||
byte code; probably ARM/StrongARM; maybe Sparc; maybe Mips; maybe
|
||||
Vax. Perhaps Z80 and 6502, just for a laugh?
|
||||
88
assemble.c
88
assemble.c
|
|
@ -592,22 +592,40 @@ static void gencode (long segment, long offset, int bits,
|
|||
case 014: case 015: case 016:
|
||||
if (ins->oprs[c-014].offset < -128 || ins->oprs[c-014].offset > 127)
|
||||
errfunc (ERR_WARNING, "signed byte value exceeds bounds");
|
||||
bytes[0] = ins->oprs[c-014].offset;
|
||||
out (offset, segment, bytes, OUT_RAWDATA+1, NO_SEG, NO_SEG);
|
||||
if (ins->oprs[c-014].segment != NO_SEG) {
|
||||
data = ins->oprs[c-014].offset;
|
||||
out (offset, segment, &data, OUT_ADDRESS+1,
|
||||
ins->oprs[c-014].segment, ins->oprs[c-014].wrt);
|
||||
} else {
|
||||
bytes[0] = ins->oprs[c-014].offset;
|
||||
out (offset, segment, bytes, OUT_RAWDATA+1, NO_SEG, NO_SEG);
|
||||
}
|
||||
offset += 1;
|
||||
break;
|
||||
case 020: case 021: case 022:
|
||||
if (ins->oprs[c-020].offset < -256 || ins->oprs[c-020].offset > 255)
|
||||
errfunc (ERR_WARNING, "byte value exceeds bounds");
|
||||
bytes[0] = ins->oprs[c-020].offset;
|
||||
out (offset, segment, bytes, OUT_RAWDATA+1, NO_SEG, NO_SEG);
|
||||
if (ins->oprs[c-020].segment != NO_SEG) {
|
||||
data = ins->oprs[c-020].offset;
|
||||
out (offset, segment, &data, OUT_ADDRESS+1,
|
||||
ins->oprs[c-020].segment, ins->oprs[c-020].wrt);
|
||||
} else {
|
||||
bytes[0] = ins->oprs[c-020].offset;
|
||||
out (offset, segment, bytes, OUT_RAWDATA+1, NO_SEG, NO_SEG);
|
||||
}
|
||||
offset += 1;
|
||||
break;
|
||||
case 024: case 025: case 026:
|
||||
if (ins->oprs[c-024].offset < 0 || ins->oprs[c-024].offset > 255)
|
||||
errfunc (ERR_WARNING, "unsigned byte value exceeds bounds");
|
||||
bytes[0] = ins->oprs[c-024].offset;
|
||||
out (offset, segment, bytes, OUT_RAWDATA+1, NO_SEG, NO_SEG);
|
||||
if (ins->oprs[c-024].segment != NO_SEG) {
|
||||
data = ins->oprs[c-024].offset;
|
||||
out (offset, segment, &data, OUT_ADDRESS+1,
|
||||
ins->oprs[c-024].segment, ins->oprs[c-024].wrt);
|
||||
} else {
|
||||
bytes[0] = ins->oprs[c-024].offset;
|
||||
out (offset, segment, bytes, OUT_RAWDATA+1, NO_SEG, NO_SEG);
|
||||
}
|
||||
offset += 1;
|
||||
break;
|
||||
case 030: case 031: case 032:
|
||||
|
|
@ -757,8 +775,9 @@ static void gencode (long segment, long offset, int bits,
|
|||
errfunc (ERR_PANIC, "non-constant BSS size in pass two");
|
||||
else {
|
||||
long size = ins->oprs[0].offset << (c-0340);
|
||||
out (offset, segment, NULL,
|
||||
OUT_RESERVE+size, NO_SEG, NO_SEG);
|
||||
if (size > 0)
|
||||
out (offset, segment, NULL,
|
||||
OUT_RESERVE+size, NO_SEG, NO_SEG);
|
||||
offset += size;
|
||||
}
|
||||
break;
|
||||
|
|
@ -792,9 +811,16 @@ static void gencode (long segment, long offset, int bits,
|
|||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
*bytes = ins->oprs[(c>>3)&7].offset;
|
||||
out (offset, segment, bytes, OUT_RAWDATA+1,
|
||||
NO_SEG, NO_SEG);
|
||||
if (ins->oprs[(c>>3)&7].segment != NO_SEG) {
|
||||
data = ins->oprs[(c>>3)&7].offset;
|
||||
out (offset, segment, &data, OUT_ADDRESS+1,
|
||||
ins->oprs[(c>>3)&7].segment,
|
||||
ins->oprs[(c>>3)&7].wrt);
|
||||
} else {
|
||||
*bytes = ins->oprs[(c>>3)&7].offset;
|
||||
out (offset, segment, bytes, OUT_RAWDATA+1,
|
||||
NO_SEG, NO_SEG);
|
||||
}
|
||||
s++;
|
||||
break;
|
||||
case 2:
|
||||
|
|
@ -887,6 +913,9 @@ static int matches (struct itemplate *itemp, insn *instruction) {
|
|||
if (itemp->flags & IF_SB) {
|
||||
size = BITS8;
|
||||
oprs = itemp->operands;
|
||||
} else if (itemp->flags & IF_SW) {
|
||||
size = BITS16;
|
||||
oprs = itemp->operands;
|
||||
} else if (itemp->flags & IF_SD) {
|
||||
size = BITS32;
|
||||
oprs = itemp->operands;
|
||||
|
|
@ -939,6 +968,8 @@ static ea *process_ea (operand *input, ea *output, int addrbits, int rfield,
|
|||
} else { /* it's an indirection */
|
||||
int i=input->indexreg, b=input->basereg, s=input->scale;
|
||||
long o=input->offset, seg=input->segment;
|
||||
int hb=input->hintbase, ht=input->hinttype;
|
||||
int t;
|
||||
|
||||
if (s==0) i = -1; /* make this easy, at least */
|
||||
|
||||
|
|
@ -960,11 +991,15 @@ static ea *process_ea (operand *input, ea *output, int addrbits, int rfield,
|
|||
return NULL;
|
||||
|
||||
/* now reorganise base/index */
|
||||
if (s == 1 && b != i && b != -1 && i != -1 &&
|
||||
((hb==b&&ht==EAH_NOTBASE) || (hb==i&&ht==EAH_MAKEBASE)))
|
||||
t = b, b = i, i = t; /* swap if hints say so */
|
||||
if (b==i) /* convert EAX+2*EAX to 3*EAX */
|
||||
b = -1, s++;
|
||||
if (b==-1 && s==1) /* single register should be base */
|
||||
b = i, i = -1;
|
||||
if (((s==2 && i!=R_ESP) || s==3 || s==5 || s==9) && b==-1)
|
||||
if (b==-1 && s==1 && !(hb == i && ht == EAH_NOTBASE))
|
||||
b = i, i = -1; /* make single reg base, unless hint */
|
||||
if (((s==2 && i!=R_ESP && !(input->eaflags & EAF_TIMESTWO)) ||
|
||||
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;
|
||||
|
|
@ -986,11 +1021,15 @@ static ea *process_ea (operand *input, ea *output, int addrbits, int rfield,
|
|||
return NULL;
|
||||
}
|
||||
if (b==-1 || (b!=R_EBP && o==0 &&
|
||||
seg==NO_SEG && !forw_ref))
|
||||
seg==NO_SEG && !forw_ref &&
|
||||
!(input->eaflags &
|
||||
(EAF_BYTEOFFS|EAF_WORDOFFS))))
|
||||
mod = 0;
|
||||
else if (o>=-128 && o<=127 && seg==NO_SEG && !forw_ref)
|
||||
else if (input->eaflags & EAF_BYTEOFFS ||
|
||||
(o>=-128 && o<=127 && seg==NO_SEG && !forw_ref &&
|
||||
!(input->eaflags & EAF_WORDOFFS))) {
|
||||
mod = 1;
|
||||
else
|
||||
} else
|
||||
mod = 2;
|
||||
|
||||
output->sib_present = FALSE;
|
||||
|
|
@ -1036,9 +1075,13 @@ static ea *process_ea (operand *input, ea *output, int addrbits, int rfield,
|
|||
}
|
||||
|
||||
if (b==-1 || (b!=R_EBP && o==0 &&
|
||||
seg==NO_SEG && !forw_ref))
|
||||
seg==NO_SEG && !forw_ref &&
|
||||
!(input->eaflags &
|
||||
(EAF_BYTEOFFS|EAF_WORDOFFS))))
|
||||
mod = 0;
|
||||
else if (o>=-128 && o<=127 && seg==NO_SEG && !forw_ref)
|
||||
else if (input->eaflags & EAF_BYTEOFFS ||
|
||||
(o>=-128 && o<=127 && seg==NO_SEG && !forw_ref &&
|
||||
!(input->eaflags & EAF_WORDOFFS)))
|
||||
mod = 1;
|
||||
else
|
||||
mod = 2;
|
||||
|
|
@ -1089,9 +1132,12 @@ 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 && !forw_ref && rm!=6)
|
||||
if (o==0 && seg==NO_SEG && !forw_ref && rm!=6 &&
|
||||
!(input->eaflags & (EAF_BYTEOFFS|EAF_WORDOFFS)))
|
||||
mod = 0;
|
||||
else if (o>=-128 && o<=127 && seg==NO_SEG && !forw_ref)
|
||||
else if (input->eaflags & EAF_BYTEOFFS ||
|
||||
(o>=-128 && o<=127 && seg==NO_SEG && !forw_ref &&
|
||||
!(input->eaflags & EAF_WORDOFFS)))
|
||||
mod = 1;
|
||||
else
|
||||
mod = 2;
|
||||
|
|
|
|||
27
disasm.c
27
disasm.c
|
|
@ -73,6 +73,10 @@ static int whichreg(long regflags, int regval) {
|
|||
return R_ST0;
|
||||
if (!(REG_CS & ~regflags))
|
||||
return R_CS;
|
||||
if (!(REG_DESS & ~regflags))
|
||||
return (regval == 0 || regval == 2 || regval == 3 ? sreg[regval] : 0);
|
||||
if (!(REG_FSGS & ~regflags))
|
||||
return (regval == 4 || regval == 5 ? sreg[regval] : 0);
|
||||
if (!((REGMEM|BITS8) & ~regflags))
|
||||
return reg8[regval];
|
||||
if (!((REGMEM|BITS16) & ~regflags))
|
||||
|
|
@ -488,11 +492,22 @@ long disasm (unsigned char *data, char *output, int segsize, long offset,
|
|||
* Final check to make sure the types of r/m match up.
|
||||
*/
|
||||
for (i = 0; i < (*p)->operands; i++)
|
||||
if (((ins.oprs[i].segment & SEG_RMREG) &&
|
||||
if (
|
||||
|
||||
/* If it's a mem-only EA but we have a register, die. */
|
||||
((ins.oprs[i].segment & SEG_RMREG) &&
|
||||
!(MEMORY & ~(*p)->opd[i])) ||
|
||||
|
||||
/* If it's a reg-only EA but we have a memory ref, die. */
|
||||
(!(ins.oprs[i].segment & SEG_RMREG) &&
|
||||
!(REGNORM & ~(*p)->opd[i]) &&
|
||||
!((*p)->opd[i] & REG_SMASK)))
|
||||
!((*p)->opd[i] & REG_SMASK)) ||
|
||||
|
||||
/* Register type mismatch (eg FS vs REG_DESS): die. */
|
||||
((((*p)->opd[i] & (REGISTER | FPUREG)) ||
|
||||
(ins.oprs[i].segment & SEG_RMREG)) &&
|
||||
!whichreg ((*p)->opd[i], ins.oprs[i].basereg)))
|
||||
|
||||
works = FALSE;
|
||||
if (works)
|
||||
break;
|
||||
|
|
@ -559,7 +574,7 @@ long disasm (unsigned char *data, char *output, int segsize, long offset,
|
|||
ins.oprs[i].basereg = whichreg ((*p)->opd[i],
|
||||
ins.oprs[i].basereg);
|
||||
slen += sprintf(output+slen, "%s",
|
||||
reg_names[ins.oprs[i].basereg]);
|
||||
reg_names[ins.oprs[i].basereg-EXPR_REG_START]);
|
||||
} else if (!(UNITY & ~(*p)->opd[i])) {
|
||||
output[slen++] = '1';
|
||||
} else if ( (*p)->opd[i] & IMMEDIATE ) {
|
||||
|
|
@ -617,14 +632,16 @@ long disasm (unsigned char *data, char *output, int segsize, long offset,
|
|||
}
|
||||
if (ins.oprs[i].basereg != -1) {
|
||||
slen += sprintf(output+slen, "%s",
|
||||
reg_names[ins.oprs[i].basereg]);
|
||||
reg_names[(ins.oprs[i].basereg -
|
||||
EXPR_REG_START)]);
|
||||
started = TRUE;
|
||||
}
|
||||
if (ins.oprs[i].indexreg != -1) {
|
||||
if (started)
|
||||
output[slen++] = '+';
|
||||
slen += sprintf(output+slen, "%s",
|
||||
reg_names[ins.oprs[i].indexreg]);
|
||||
reg_names[(ins.oprs[i].indexreg -
|
||||
EXPR_REG_START)]);
|
||||
if (ins.oprs[i].scale > 1)
|
||||
slen += sprintf(output+slen, "*%d", ins.oprs[i].scale);
|
||||
started = TRUE;
|
||||
|
|
|
|||
8530
doc/nasmdoc.src
Normal file
8530
doc/nasmdoc.src
Normal file
File diff suppressed because it is too large
Load diff
2134
doc/rdsrc.pl
Normal file
2134
doc/rdsrc.pl
Normal file
File diff suppressed because it is too large
Load diff
761
eval.c
Normal file
761
eval.c
Normal file
|
|
@ -0,0 +1,761 @@
|
|||
/* eval.c expression evaluator for the Netwide Assembler
|
||||
*
|
||||
* The Netwide Assembler is copyright (C) 1996 Simon Tatham and
|
||||
* Julian Hall. All rights reserved. The software is
|
||||
* redistributable under the licence given in the file "Licence"
|
||||
* distributed in the NASM archive.
|
||||
*
|
||||
* initial version 27/iii/95 by Simon Tatham
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "nasm.h"
|
||||
#include "nasmlib.h"
|
||||
#include "eval.h"
|
||||
|
||||
static expr **tempexprs = NULL;
|
||||
static int ntempexprs, tempexprs_size = 0;
|
||||
#define TEMPEXPRS_DELTA 128
|
||||
|
||||
static expr *tempexpr;
|
||||
static int ntempexpr, tempexpr_size;
|
||||
#define TEMPEXPR_DELTA 8
|
||||
|
||||
static scanner scan;
|
||||
static void *scpriv;
|
||||
static struct tokenval *tokval;
|
||||
static efunc error;
|
||||
static int i;
|
||||
static int seg, ofs;
|
||||
static char *label = NULL, special_empty_string[] = "";
|
||||
static lfunc labelfunc;
|
||||
static struct ofmt *outfmt;
|
||||
static int *forward;
|
||||
|
||||
static struct eval_hints *hint;
|
||||
|
||||
/*
|
||||
* Construct a temporary expression.
|
||||
*/
|
||||
static void begintemp(void) {
|
||||
tempexpr = NULL;
|
||||
tempexpr_size = ntempexpr = 0;
|
||||
}
|
||||
|
||||
static void addtotemp(long type, long value) {
|
||||
while (ntempexpr >= tempexpr_size) {
|
||||
tempexpr_size += TEMPEXPR_DELTA;
|
||||
tempexpr = nasm_realloc(tempexpr,
|
||||
tempexpr_size*sizeof(*tempexpr));
|
||||
}
|
||||
tempexpr[ntempexpr].type = type;
|
||||
tempexpr[ntempexpr++].value = value;
|
||||
}
|
||||
|
||||
static expr *finishtemp(void) {
|
||||
addtotemp (0L, 0L); /* terminate */
|
||||
while (ntempexprs >= tempexprs_size) {
|
||||
tempexprs_size += TEMPEXPRS_DELTA;
|
||||
tempexprs = nasm_realloc(tempexprs,
|
||||
tempexprs_size*sizeof(*tempexprs));
|
||||
}
|
||||
return tempexprs[ntempexprs++] = tempexpr;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add two vector datatypes. We have some bizarre behaviour on far-
|
||||
* absolute segment types: we preserve them during addition _only_
|
||||
* if one of the segments is a truly pure scalar.
|
||||
*/
|
||||
static expr *add_vectors(expr *p, expr *q) {
|
||||
int preserve;
|
||||
|
||||
preserve = is_really_simple(p) || is_really_simple(q);
|
||||
|
||||
begintemp();
|
||||
|
||||
while (p->type && q->type &&
|
||||
p->type < EXPR_SEGBASE+SEG_ABS &&
|
||||
q->type < EXPR_SEGBASE+SEG_ABS) {
|
||||
int lasttype;
|
||||
|
||||
if (p->type > q->type) {
|
||||
addtotemp(q->type, q->value);
|
||||
lasttype = q++->type;
|
||||
} else if (p->type < q->type) {
|
||||
addtotemp(p->type, p->value);
|
||||
lasttype = p++->type;
|
||||
} else { /* *p and *q have same type */
|
||||
addtotemp(p->type, p->value + q->value);
|
||||
lasttype = p->type;
|
||||
p++, q++;
|
||||
}
|
||||
if (lasttype == EXPR_UNKNOWN) {
|
||||
return finishtemp();
|
||||
}
|
||||
}
|
||||
while (p->type &&
|
||||
(preserve || p->type < EXPR_SEGBASE+SEG_ABS)) {
|
||||
addtotemp(p->type, p->value);
|
||||
p++;
|
||||
}
|
||||
while (q->type &&
|
||||
(preserve || q->type < EXPR_SEGBASE+SEG_ABS)) {
|
||||
addtotemp(q->type, q->value);
|
||||
q++;
|
||||
}
|
||||
|
||||
return finishtemp();
|
||||
}
|
||||
|
||||
/*
|
||||
* Multiply a vector by a scalar. Strip far-absolute segment part
|
||||
* if present.
|
||||
*
|
||||
* Explicit treatment of UNKNOWN is not required in this routine,
|
||||
* since it will silently do the Right Thing anyway.
|
||||
*
|
||||
* If `affect_hints' is set, we also change the hint type to
|
||||
* NOTBASE if a MAKEBASE hint points at a register being
|
||||
* multiplied. This allows [eax*1+ebx] to hint EBX rather than EAX
|
||||
* as the base register.
|
||||
*/
|
||||
static expr *scalar_mult(expr *vect, long scalar, int affect_hints) {
|
||||
expr *p = vect;
|
||||
|
||||
while (p->type && p->type < EXPR_SEGBASE+SEG_ABS) {
|
||||
p->value = scalar * (p->value);
|
||||
if (hint && hint->type == EAH_MAKEBASE &&
|
||||
p->type == hint->base && affect_hints)
|
||||
hint->type = EAH_NOTBASE;
|
||||
p++;
|
||||
}
|
||||
p->type = 0;
|
||||
|
||||
return vect;
|
||||
}
|
||||
|
||||
static expr *scalarvect (long scalar) {
|
||||
begintemp();
|
||||
addtotemp(EXPR_SIMPLE, scalar);
|
||||
return finishtemp();
|
||||
}
|
||||
|
||||
static expr *unknown_expr (void) {
|
||||
begintemp();
|
||||
addtotemp(EXPR_UNKNOWN, 1L);
|
||||
return finishtemp();
|
||||
}
|
||||
|
||||
/*
|
||||
* The SEG operator: calculate the segment part of a relocatable
|
||||
* value. Return NULL, as usual, if an error occurs. Report the
|
||||
* error too.
|
||||
*/
|
||||
static expr *segment_part (expr *e) {
|
||||
long seg;
|
||||
|
||||
if (is_unknown(e))
|
||||
return unknown_expr();
|
||||
|
||||
if (!is_reloc(e)) {
|
||||
error(ERR_NONFATAL, "cannot apply SEG to a non-relocatable value");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
seg = reloc_seg(e);
|
||||
if (seg == NO_SEG) {
|
||||
error(ERR_NONFATAL, "cannot apply SEG to a non-relocatable value");
|
||||
return NULL;
|
||||
} else if (seg & SEG_ABS) {
|
||||
return scalarvect(seg & ~SEG_ABS);
|
||||
} else if (seg & 1) {
|
||||
error(ERR_NONFATAL, "SEG applied to something which"
|
||||
" is already a segment base");
|
||||
return NULL;
|
||||
}
|
||||
else {
|
||||
long base = outfmt->segbase(seg+1);
|
||||
|
||||
begintemp();
|
||||
addtotemp((base == NO_SEG ? EXPR_UNKNOWN : EXPR_SEGBASE+base), 1L);
|
||||
return finishtemp();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Recursive-descent parser. Called with a single boolean operand,
|
||||
* which is TRUE if the evaluation is critical (i.e. unresolved
|
||||
* symbols are an error condition). Must update the global `i' to
|
||||
* reflect the token after the parsed string. May return NULL.
|
||||
*
|
||||
* evaluate() should report its own errors: on return it is assumed
|
||||
* that if NULL has been returned, the error has already been
|
||||
* reported.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Grammar parsed is:
|
||||
*
|
||||
* expr : bexpr [ WRT expr6 ]
|
||||
* bexpr : rexp0 or expr0 depending on relative-mode setting
|
||||
* rexp0 : rexp1 [ {||} rexp1...]
|
||||
* rexp1 : rexp2 [ {^^} rexp2...]
|
||||
* rexp2 : rexp3 [ {&&} rexp3...]
|
||||
* rexp3 : expr0 [ {=,==,<>,!=,<,>,<=,>=} expr0 ]
|
||||
* expr0 : expr1 [ {|} expr1...]
|
||||
* expr1 : expr2 [ {^} expr2...]
|
||||
* expr2 : expr3 [ {&} expr3...]
|
||||
* expr3 : expr4 [ {<<,>>} expr4...]
|
||||
* expr4 : expr5 [ {+,-} expr5...]
|
||||
* expr5 : expr6 [ {*,/,%,//,%%} expr6...]
|
||||
* expr6 : { ~,+,-,SEG } expr6
|
||||
* | (bexpr)
|
||||
* | symbol
|
||||
* | $
|
||||
* | number
|
||||
*/
|
||||
|
||||
static expr *rexp0(int), *rexp1(int), *rexp2(int), *rexp3(int);
|
||||
|
||||
static expr *expr0(int), *expr1(int), *expr2(int), *expr3(int);
|
||||
static expr *expr4(int), *expr5(int), *expr6(int);
|
||||
|
||||
static expr *(*bexpr)(int);
|
||||
|
||||
static expr *rexp0(int critical) {
|
||||
expr *e, *f;
|
||||
|
||||
e = rexp1(critical);
|
||||
if (!e)
|
||||
return NULL;
|
||||
while (i == TOKEN_DBL_OR) {
|
||||
i = scan(scpriv, tokval);
|
||||
f = rexp1(critical);
|
||||
if (!f)
|
||||
return NULL;
|
||||
if (!(is_simple(e) || is_just_unknown(e)) ||
|
||||
!(is_simple(f) || is_just_unknown(f))) {
|
||||
error(ERR_NONFATAL, "`|' operator may only be applied to"
|
||||
" scalar values");
|
||||
}
|
||||
if (is_just_unknown(e) || is_just_unknown(f))
|
||||
e = unknown_expr();
|
||||
else
|
||||
e = scalarvect ((long) (reloc_value(e) || reloc_value(f)));
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
static expr *rexp1(int critical) {
|
||||
expr *e, *f;
|
||||
|
||||
e = rexp2(critical);
|
||||
if (!e)
|
||||
return NULL;
|
||||
while (i == TOKEN_DBL_XOR) {
|
||||
i = scan(scpriv, tokval);
|
||||
f = rexp2(critical);
|
||||
if (!f)
|
||||
return NULL;
|
||||
if (!(is_simple(e) || is_just_unknown(e)) ||
|
||||
!(is_simple(f) || is_just_unknown(f))) {
|
||||
error(ERR_NONFATAL, "`^' operator may only be applied to"
|
||||
" scalar values");
|
||||
}
|
||||
if (is_just_unknown(e) || is_just_unknown(f))
|
||||
e = unknown_expr();
|
||||
else
|
||||
e = scalarvect ((long) (!reloc_value(e) ^ !reloc_value(f)));
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
static expr *rexp2(int critical) {
|
||||
expr *e, *f;
|
||||
|
||||
e = rexp3(critical);
|
||||
if (!e)
|
||||
return NULL;
|
||||
while (i == TOKEN_DBL_AND) {
|
||||
i = scan(scpriv, tokval);
|
||||
f = rexp3(critical);
|
||||
if (!f)
|
||||
return NULL;
|
||||
if (!(is_simple(e) || is_just_unknown(e)) ||
|
||||
!(is_simple(f) || is_just_unknown(f))) {
|
||||
error(ERR_NONFATAL, "`&' operator may only be applied to"
|
||||
" scalar values");
|
||||
}
|
||||
if (is_just_unknown(e) || is_just_unknown(f))
|
||||
e = unknown_expr();
|
||||
else
|
||||
e = scalarvect ((long) (reloc_value(e) && reloc_value(f)));
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
static expr *rexp3(int critical) {
|
||||
expr *e, *f;
|
||||
long v;
|
||||
|
||||
e = expr0(critical);
|
||||
if (!e)
|
||||
return NULL;
|
||||
while (i == TOKEN_EQ || i == TOKEN_LT || i == TOKEN_GT ||
|
||||
i == TOKEN_NE || i == TOKEN_LE || i == TOKEN_GE) {
|
||||
int j = i;
|
||||
i = scan(scpriv, tokval);
|
||||
f = expr0(critical);
|
||||
if (!f)
|
||||
return NULL;
|
||||
e = add_vectors (e, scalar_mult(f, -1L, FALSE));
|
||||
switch (j) {
|
||||
case TOKEN_EQ: case TOKEN_NE:
|
||||
if (is_unknown(e))
|
||||
v = -1; /* means unknown */
|
||||
else if (!is_really_simple(e) || reloc_value(e) != 0)
|
||||
v = (j == TOKEN_NE); /* unequal, so return TRUE if NE */
|
||||
else
|
||||
v = (j == TOKEN_EQ); /* equal, so return TRUE if EQ */
|
||||
break;
|
||||
default:
|
||||
if (is_unknown(e))
|
||||
v = -1; /* means unknown */
|
||||
else if (!is_really_simple(e)) {
|
||||
error(ERR_NONFATAL, "`%s': operands differ by a non-scalar",
|
||||
(j == TOKEN_LE ? "<=" : j == TOKEN_LT ? "<" :
|
||||
j == TOKEN_GE ? ">=" : ">"));
|
||||
v = 0; /* must set it to _something_ */
|
||||
} else {
|
||||
int vv = reloc_value(e);
|
||||
if (vv == 0)
|
||||
v = (j == TOKEN_LE || j == TOKEN_GE);
|
||||
else if (vv > 0)
|
||||
v = (j == TOKEN_GE || j == TOKEN_GT);
|
||||
else /* vv < 0 */
|
||||
v = (j == TOKEN_LE || j == TOKEN_LT);
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (v == -1)
|
||||
e = unknown_expr();
|
||||
else
|
||||
e = scalarvect(v);
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
static expr *expr0(int critical) {
|
||||
expr *e, *f;
|
||||
|
||||
e = expr1(critical);
|
||||
if (!e)
|
||||
return NULL;
|
||||
while (i == '|') {
|
||||
i = scan(scpriv, tokval);
|
||||
f = expr1(critical);
|
||||
if (!f)
|
||||
return NULL;
|
||||
if (!(is_simple(e) || is_just_unknown(e)) ||
|
||||
!(is_simple(f) || is_just_unknown(f))) {
|
||||
error(ERR_NONFATAL, "`|' operator may only be applied to"
|
||||
" scalar values");
|
||||
}
|
||||
if (is_just_unknown(e) || is_just_unknown(f))
|
||||
e = unknown_expr();
|
||||
else
|
||||
e = scalarvect (reloc_value(e) | reloc_value(f));
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
static expr *expr1(int critical) {
|
||||
expr *e, *f;
|
||||
|
||||
e = expr2(critical);
|
||||
if (!e)
|
||||
return NULL;
|
||||
while (i == '^') {
|
||||
i = scan(scpriv, tokval);
|
||||
f = expr2(critical);
|
||||
if (!f)
|
||||
return NULL;
|
||||
if (!(is_simple(e) || is_just_unknown(e)) ||
|
||||
!(is_simple(f) || is_just_unknown(f))) {
|
||||
error(ERR_NONFATAL, "`^' operator may only be applied to"
|
||||
" scalar values");
|
||||
}
|
||||
if (is_just_unknown(e) || is_just_unknown(f))
|
||||
e = unknown_expr();
|
||||
else
|
||||
e = scalarvect (reloc_value(e) ^ reloc_value(f));
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
static expr *expr2(int critical) {
|
||||
expr *e, *f;
|
||||
|
||||
e = expr3(critical);
|
||||
if (!e)
|
||||
return NULL;
|
||||
while (i == '&') {
|
||||
i = scan(scpriv, tokval);
|
||||
f = expr3(critical);
|
||||
if (!f)
|
||||
return NULL;
|
||||
if (!(is_simple(e) || is_just_unknown(e)) ||
|
||||
!(is_simple(f) || is_just_unknown(f))) {
|
||||
error(ERR_NONFATAL, "`&' operator may only be applied to"
|
||||
" scalar values");
|
||||
}
|
||||
if (is_just_unknown(e) || is_just_unknown(f))
|
||||
e = unknown_expr();
|
||||
else
|
||||
e = scalarvect (reloc_value(e) & reloc_value(f));
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
static expr *expr3(int critical) {
|
||||
expr *e, *f;
|
||||
|
||||
e = expr4(critical);
|
||||
if (!e)
|
||||
return NULL;
|
||||
while (i == TOKEN_SHL || i == TOKEN_SHR) {
|
||||
int j = i;
|
||||
i = scan(scpriv, tokval);
|
||||
f = expr4(critical);
|
||||
if (!f)
|
||||
return NULL;
|
||||
if (!(is_simple(e) || is_just_unknown(e)) ||
|
||||
!(is_simple(f) || is_just_unknown(f))) {
|
||||
error(ERR_NONFATAL, "shift operator may only be applied to"
|
||||
" scalar values");
|
||||
} else if (is_just_unknown(e) || is_just_unknown(f)) {
|
||||
e = unknown_expr();
|
||||
} else switch (j) {
|
||||
case TOKEN_SHL:
|
||||
e = scalarvect (reloc_value(e) << reloc_value(f));
|
||||
break;
|
||||
case TOKEN_SHR:
|
||||
e = scalarvect (((unsigned long)reloc_value(e)) >>
|
||||
reloc_value(f));
|
||||
break;
|
||||
}
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
static expr *expr4(int critical) {
|
||||
expr *e, *f;
|
||||
|
||||
e = expr5(critical);
|
||||
if (!e)
|
||||
return NULL;
|
||||
while (i == '+' || i == '-') {
|
||||
int j = i;
|
||||
i = scan(scpriv, tokval);
|
||||
f = expr5(critical);
|
||||
if (!f)
|
||||
return NULL;
|
||||
switch (j) {
|
||||
case '+':
|
||||
e = add_vectors (e, f);
|
||||
break;
|
||||
case '-':
|
||||
e = add_vectors (e, scalar_mult(f, -1L, FALSE));
|
||||
break;
|
||||
}
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
static expr *expr5(int critical) {
|
||||
expr *e, *f;
|
||||
|
||||
e = expr6(critical);
|
||||
if (!e)
|
||||
return NULL;
|
||||
while (i == '*' || i == '/' || i == '%' ||
|
||||
i == TOKEN_SDIV || i == TOKEN_SMOD) {
|
||||
int j = i;
|
||||
i = scan(scpriv, tokval);
|
||||
f = expr6(critical);
|
||||
if (!f)
|
||||
return NULL;
|
||||
if (j != '*' && (!(is_simple(e) || is_just_unknown(e)) ||
|
||||
!(is_simple(f) || is_just_unknown(f)))) {
|
||||
error(ERR_NONFATAL, "division operator may only be applied to"
|
||||
" scalar values");
|
||||
return NULL;
|
||||
}
|
||||
if (j != '*' && !is_unknown(f) && reloc_value(f) == 0) {
|
||||
error(ERR_NONFATAL, "division by zero");
|
||||
return NULL;
|
||||
}
|
||||
switch (j) {
|
||||
case '*':
|
||||
if (is_simple(e))
|
||||
e = scalar_mult (f, reloc_value(e), TRUE);
|
||||
else if (is_simple(f))
|
||||
e = scalar_mult (e, reloc_value(f), TRUE);
|
||||
else if (is_just_unknown(e) && is_just_unknown(f))
|
||||
e = unknown_expr();
|
||||
else {
|
||||
error(ERR_NONFATAL, "unable to multiply two "
|
||||
"non-scalar objects");
|
||||
return NULL;
|
||||
}
|
||||
break;
|
||||
case '/':
|
||||
if (is_just_unknown(e) || is_just_unknown(f))
|
||||
e = unknown_expr();
|
||||
else
|
||||
e = scalarvect (((unsigned long)reloc_value(e)) /
|
||||
((unsigned long)reloc_value(f)));
|
||||
break;
|
||||
case '%':
|
||||
if (is_just_unknown(e) || is_just_unknown(f))
|
||||
e = unknown_expr();
|
||||
else
|
||||
e = scalarvect (((unsigned long)reloc_value(e)) %
|
||||
((unsigned long)reloc_value(f)));
|
||||
break;
|
||||
case TOKEN_SDIV:
|
||||
if (is_just_unknown(e) || is_just_unknown(f))
|
||||
e = unknown_expr();
|
||||
else
|
||||
e = scalarvect (((signed long)reloc_value(e)) /
|
||||
((signed long)reloc_value(f)));
|
||||
break;
|
||||
case TOKEN_SMOD:
|
||||
if (is_just_unknown(e) || is_just_unknown(f))
|
||||
e = unknown_expr();
|
||||
else
|
||||
e = scalarvect (((signed long)reloc_value(e)) %
|
||||
((signed long)reloc_value(f)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
static expr *expr6(int critical) {
|
||||
long type;
|
||||
expr *e;
|
||||
long label_seg, label_ofs;
|
||||
|
||||
if (i == '-') {
|
||||
i = scan(scpriv, tokval);
|
||||
e = expr6(critical);
|
||||
if (!e)
|
||||
return NULL;
|
||||
return scalar_mult (e, -1L, FALSE);
|
||||
} else if (i == '+') {
|
||||
i = scan(scpriv, tokval);
|
||||
return expr6(critical);
|
||||
} else if (i == '~') {
|
||||
i = scan(scpriv, tokval);
|
||||
e = expr6(critical);
|
||||
if (!e)
|
||||
return NULL;
|
||||
if (is_just_unknown(e))
|
||||
return unknown_expr();
|
||||
else if (!is_simple(e)) {
|
||||
error(ERR_NONFATAL, "`~' operator may only be applied to"
|
||||
" scalar values");
|
||||
return NULL;
|
||||
}
|
||||
return scalarvect(~reloc_value(e));
|
||||
} else if (i == TOKEN_SEG) {
|
||||
i = scan(scpriv, tokval);
|
||||
e = expr6(critical);
|
||||
if (!e)
|
||||
return NULL;
|
||||
e = segment_part(e);
|
||||
if (is_unknown(e) && critical) {
|
||||
error(ERR_NONFATAL, "unable to determine segment base");
|
||||
return NULL;
|
||||
}
|
||||
return e;
|
||||
} else if (i == '(') {
|
||||
i = scan(scpriv, tokval);
|
||||
e = bexpr(critical);
|
||||
if (!e)
|
||||
return NULL;
|
||||
if (i != ')') {
|
||||
error(ERR_NONFATAL, "expecting `)'");
|
||||
return NULL;
|
||||
}
|
||||
i = scan(scpriv, tokval);
|
||||
return e;
|
||||
} else if (i == TOKEN_NUM || i == TOKEN_REG || i == TOKEN_ID ||
|
||||
i == TOKEN_HERE || i == TOKEN_BASE) {
|
||||
begintemp();
|
||||
switch (i) {
|
||||
case TOKEN_NUM:
|
||||
addtotemp(EXPR_SIMPLE, tokval->t_integer);
|
||||
break;
|
||||
case TOKEN_REG:
|
||||
addtotemp(tokval->t_integer, 1L);
|
||||
if (hint && hint->type == EAH_NOHINT)
|
||||
hint->base = tokval->t_integer, hint->type = EAH_MAKEBASE;
|
||||
break;
|
||||
case TOKEN_ID:
|
||||
case TOKEN_HERE:
|
||||
case TOKEN_BASE:
|
||||
/*
|
||||
* If "label" begins with "%", this indicates that no
|
||||
* symbol, Here or Base references are valid because we
|
||||
* are in preprocess-only mode.
|
||||
*/
|
||||
if (*label == '%') {
|
||||
error(ERR_NONFATAL,
|
||||
"%s not supported in preprocess-only mode",
|
||||
(i == TOKEN_ID ? "symbol references" :
|
||||
i == TOKEN_HERE ? "`$'" : "`$$'"));
|
||||
addtotemp(EXPR_UNKNOWN, 1L);
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Since the whole line is parsed before the label it
|
||||
* defines is given to the label manager, we have
|
||||
* problems with lines such as
|
||||
*
|
||||
* end: TIMES 512-(end-start) DB 0
|
||||
*
|
||||
* where `end' is not known on pass one, despite not
|
||||
* really being a forward reference, and due to
|
||||
* criticality it is _needed_. Hence we check our label
|
||||
* against the currently defined one, and do our own
|
||||
* resolution of it if we have to.
|
||||
*/
|
||||
type = EXPR_SIMPLE; /* might get overridden by UNKNOWN */
|
||||
if (i == TOKEN_BASE) {
|
||||
label_seg = seg;
|
||||
label_ofs = 0;
|
||||
} else if (i == TOKEN_HERE || !strcmp(tokval->t_charptr, label)) {
|
||||
label_seg = seg;
|
||||
label_ofs = ofs;
|
||||
} else if (!labelfunc(tokval->t_charptr,&label_seg,&label_ofs)) {
|
||||
if (critical == 2) {
|
||||
error (ERR_NONFATAL, "symbol `%s' undefined",
|
||||
tokval->t_charptr);
|
||||
return NULL;
|
||||
} else if (critical == 1) {
|
||||
error (ERR_NONFATAL, "symbol `%s' not defined before use",
|
||||
tokval->t_charptr);
|
||||
return NULL;
|
||||
} else {
|
||||
if (forward)
|
||||
*forward = TRUE;
|
||||
type = EXPR_UNKNOWN;
|
||||
label_seg = NO_SEG;
|
||||
label_ofs = 1;
|
||||
}
|
||||
}
|
||||
addtotemp(type, label_ofs);
|
||||
if (label_seg!=NO_SEG)
|
||||
addtotemp(EXPR_SEGBASE + label_seg, 1L);
|
||||
break;
|
||||
}
|
||||
i = scan(scpriv, tokval);
|
||||
return finishtemp();
|
||||
} else {
|
||||
error(ERR_NONFATAL, "expression syntax error");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void eval_global_info (struct ofmt *output, lfunc lookup_label) {
|
||||
outfmt = output;
|
||||
labelfunc = lookup_label;
|
||||
}
|
||||
|
||||
void eval_info (char *labelname, long segment, long offset) {
|
||||
if (label != special_empty_string)
|
||||
nasm_free (label);
|
||||
if (labelname)
|
||||
label = nasm_strdup(labelname);
|
||||
else {
|
||||
label = special_empty_string;
|
||||
seg = segment;
|
||||
ofs = offset;
|
||||
}
|
||||
}
|
||||
|
||||
expr *evaluate (scanner sc, void *scprivate, struct tokenval *tv,
|
||||
int *fwref, int critical, efunc report_error,
|
||||
struct eval_hints *hints) {
|
||||
expr *e;
|
||||
expr *f = NULL;
|
||||
|
||||
hint = hints;
|
||||
if (hint)
|
||||
hint->type = EAH_NOHINT;
|
||||
|
||||
if (critical & 0x10) {
|
||||
critical &= ~0x10;
|
||||
bexpr = rexp0;
|
||||
} else
|
||||
bexpr = expr0;
|
||||
|
||||
scan = sc;
|
||||
scpriv = scprivate;
|
||||
tokval = tv;
|
||||
error = report_error;
|
||||
forward = fwref;
|
||||
|
||||
if (tokval->t_type == TOKEN_INVALID)
|
||||
i = scan(scpriv, tokval);
|
||||
else
|
||||
i = tokval->t_type;
|
||||
|
||||
while (ntempexprs) /* initialise temporary storage */
|
||||
nasm_free (tempexprs[--ntempexprs]);
|
||||
|
||||
e = bexpr (critical);
|
||||
if (!e)
|
||||
return NULL;
|
||||
|
||||
if (i == TOKEN_WRT) {
|
||||
i = scan(scpriv, tokval); /* eat the WRT */
|
||||
f = expr6 (critical);
|
||||
if (!f)
|
||||
return NULL;
|
||||
}
|
||||
e = scalar_mult (e, 1L, FALSE); /* strip far-absolute segment part */
|
||||
if (f) {
|
||||
expr *g;
|
||||
if (is_just_unknown(f))
|
||||
g = unknown_expr();
|
||||
else {
|
||||
long value;
|
||||
begintemp();
|
||||
if (!is_reloc(f)) {
|
||||
error(ERR_NONFATAL, "invalid right-hand operand to WRT");
|
||||
return NULL;
|
||||
}
|
||||
value = reloc_seg(f);
|
||||
if (value == NO_SEG)
|
||||
value = reloc_value(f) | SEG_ABS;
|
||||
else if (!(value & SEG_ABS) && !(value % 2) && critical) {
|
||||
error(ERR_NONFATAL, "invalid right-hand operand to WRT");
|
||||
return NULL;
|
||||
}
|
||||
addtotemp(EXPR_WRT, value);
|
||||
g = finishtemp();
|
||||
}
|
||||
e = add_vectors (e, g);
|
||||
}
|
||||
return e;
|
||||
}
|
||||
34
eval.h
Normal file
34
eval.h
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
/* eval.h header file for eval.c
|
||||
*
|
||||
* The Netwide Assembler is copyright (C) 1996 Simon Tatham and
|
||||
* Julian Hall. All rights reserved. The software is
|
||||
* redistributable under the licence given in the file "Licence"
|
||||
* distributed in the NASM archive.
|
||||
*/
|
||||
|
||||
#ifndef NASM_EVAL_H
|
||||
#define NASM_EVAL_H
|
||||
|
||||
/*
|
||||
* Called once to tell the evaluator what output format is
|
||||
* providing segment-base details, and what function can be used to
|
||||
* look labels up.
|
||||
*/
|
||||
void eval_global_info (struct ofmt *output, lfunc lookup_label);
|
||||
|
||||
/*
|
||||
* Called to set the information the evaluator needs: the value of
|
||||
* $ is set from `segment' and `offset' if `labelname' is NULL, and
|
||||
* otherwise the name of the current line's label is set from
|
||||
* `labelname' instead.
|
||||
*/
|
||||
void eval_info (char *labelname, long segment, long offset);
|
||||
|
||||
/*
|
||||
* The evaluator itself.
|
||||
*/
|
||||
expr *evaluate (scanner sc, void *scprivate, struct tokenval *tv,
|
||||
int *fwref, int critical, efunc report_error,
|
||||
struct eval_hints *hints);
|
||||
|
||||
#endif
|
||||
535
insns.bas
Normal file
535
insns.bas
Normal file
|
|
@ -0,0 +1,535 @@
|
|||
' INFO_1: Converter for INSNS.DAT to INSNSA.C and INSNSD.C
|
||||
'
|
||||
' INFO_2: Written by Mark Junker in 1997
|
||||
' InterNet: mjs@prg.hannover.sgh-net.de
|
||||
' FIDO: Mark Junker@2:2437/47.21
|
||||
'
|
||||
' COMMENT: While I wrote this program I often asked me, if it isn't easier
|
||||
' to write an interpreter for pearl-scripts :]
|
||||
'
|
||||
' COMMENT: To start the program press SHIFT+F5 within the QBasic IDE
|
||||
' or start it from the command-line with QBASIC /RUN MACROS
|
||||
'
|
||||
|
||||
DEFINT A-Z
|
||||
|
||||
DECLARE FUNCTION ReplaceOp$ (a$)
|
||||
DECLARE FUNCTION StrTrimLeft$ (a$, b$)
|
||||
DECLARE FUNCTION StrTrimRight$ (a$, b$)
|
||||
DECLARE FUNCTION StrTrim$ (a$, b$)
|
||||
DECLARE SUB StrSplitString (SplitString$, SplitChars$, SplitField$(), SplitCount%)
|
||||
DECLARE FUNCTION Min% (a%, b%)
|
||||
DECLARE FUNCTION StrInstrLeft% (SearchStart%, SearchIn$, SearchFor$)
|
||||
DECLARE FUNCTION StrAscii% (a$)
|
||||
|
||||
|
||||
CONST MaxOpCodeBase = 3
|
||||
CONST MaxOpCodeType = 8
|
||||
|
||||
CLS
|
||||
DIM LineData$(1 TO 2)
|
||||
DIM StrucData$(1 TO 5)
|
||||
DIM OpCodeList$(0 TO 255)
|
||||
DIM OpCodeByte(1 TO MaxOpCodeType, 1 TO MaxOpCodeBase)
|
||||
DIM OpCodeStat(1 TO 10) ' don't need mode :)
|
||||
|
||||
Instructs$ = ""
|
||||
LineOfs$ = ""
|
||||
|
||||
OPEN "I", 1, "insns.dat"
|
||||
OPEN "B", 3, "insns.tmp"
|
||||
|
||||
qt$ = CHR$(34)
|
||||
crlf$ = CHR$(13) + CHR$(10)
|
||||
|
||||
|
||||
'
|
||||
' preprocessing the current file
|
||||
'
|
||||
|
||||
HexChar$ = "0123456789ABCDEF"
|
||||
|
||||
PRINT "Preprocessing INSNS.DAT"
|
||||
OpCodes = 0
|
||||
OpCodeDebug = 0
|
||||
NowLineOfs& = 1
|
||||
lineNr = 0
|
||||
WHILE NOT EOF(1)
|
||||
lineNr = lineNr + 1
|
||||
IF (lineNr AND 15) = 0 THEN
|
||||
LOCATE , 1
|
||||
PRINT lineNr, OpCodes, OpCodeDebug;
|
||||
END IF
|
||||
|
||||
LINE INPUT #1, l$
|
||||
CALL StrSplitString(l$, ";", LineData$(), SplitCount)
|
||||
IF SplitCount THEN
|
||||
LineData$(1) = StrTrim$(LineData$(1), CHR$(9) + " ")
|
||||
IF LEN(LineData$(1)) THEN
|
||||
CALL StrSplitString(LineData$(1), " ", StrucData$(), cntSplit)
|
||||
IF cntSplit <> 4 THEN
|
||||
PRINT "line"; lineNr; " does not contain four fields"
|
||||
END
|
||||
END IF
|
||||
|
||||
tst$ = UCASE$(StrucData$(2))
|
||||
res$ = ""
|
||||
cnt% = 1
|
||||
isfirst = 1
|
||||
op = 1
|
||||
p = StrInstrLeft(1, tst$ + ",", "|:,")
|
||||
WHILE p
|
||||
h$ = ReplaceOp$(MID$(tst$, op, p - op))
|
||||
IF LEN(h$) THEN
|
||||
SELECT CASE MID$(tst$, p, 1)
|
||||
CASE ""
|
||||
IF isfirst THEN
|
||||
res$ = res$ + h$
|
||||
ELSE
|
||||
res$ = res$ + "|" + h$
|
||||
END IF
|
||||
isfirst = 0
|
||||
CASE ","
|
||||
IF isfirst THEN
|
||||
res$ = res$ + h$ + ","
|
||||
ELSE
|
||||
res$ = res$ + "|" + h$ + ","
|
||||
END IF
|
||||
cnt% = cnt% + 1
|
||||
isfirst = 1
|
||||
CASE "|"
|
||||
IF isfirst THEN
|
||||
res$ = res$ + h$
|
||||
ELSE
|
||||
res$ = res$ + "|" + h$
|
||||
END IF
|
||||
isfirst = 0
|
||||
CASE ":"
|
||||
res$ = res$ + h$ + "|COLON,"
|
||||
cnt% = cnt% + 1
|
||||
END SELECT
|
||||
END IF
|
||||
op = p + 1
|
||||
p = StrInstrLeft(op, tst$ + ",", "|:,")
|
||||
WEND
|
||||
FOR a = cnt% + 1 TO 3
|
||||
res$ = res$ + ",0"
|
||||
NEXT
|
||||
StrucData$(2) = res$
|
||||
IF LEFT$(res$, 2) = "0," THEN cnt% = cnt% - 1
|
||||
StrucData$(5) = LTRIM$(STR$(cnt%))
|
||||
|
||||
NoDebug = 0
|
||||
res$ = ""
|
||||
tst$ = UCASE$(StrucData$(4))
|
||||
op = 1
|
||||
p = INSTR(tst$ + ",", ",")
|
||||
isfirst = 1
|
||||
WHILE p
|
||||
h$ = MID$(tst$, op, p - op)
|
||||
IF h$ = "ND" THEN
|
||||
NoDebug = 1
|
||||
ELSE
|
||||
IF isfirst THEN
|
||||
res$ = res$ + "IF_" + h$
|
||||
ELSE
|
||||
res$ = res$ + "|IF_" + h$
|
||||
END IF
|
||||
isfirst = 0
|
||||
END IF
|
||||
op = p + 1
|
||||
p = INSTR(op, tst$ + ",", ",")
|
||||
WEND
|
||||
StrucData$(4) = res$
|
||||
|
||||
tst$ = UCASE$(StrucData$(3))
|
||||
SELECT CASE tst$
|
||||
CASE "IGNORE"
|
||||
GOTO skipOpCode
|
||||
CASE "\0", "\340"
|
||||
OpCodeDebug = OpCodeDebug + 1 ' don't forget to increment
|
||||
GOTO skipOpCode
|
||||
END SELECT
|
||||
|
||||
AddRegs = 0
|
||||
AddCCode = 0
|
||||
NextIsOpCode = 0
|
||||
opCodeVal$ = ""
|
||||
op = 1
|
||||
p = INSTR(tst$ + "\", "\")
|
||||
DO WHILE p
|
||||
h$ = MID$(tst$, op, p - op)
|
||||
IF LEFT$(h$, 1) = "X" THEN
|
||||
opCodeVal$ = CHR$(VAL("&H" + MID$(h$, 2)))
|
||||
EXIT DO
|
||||
ELSE
|
||||
SELECT CASE h$
|
||||
CASE "1", "2", "3"
|
||||
NextIsOpCode = 1
|
||||
CASE "4"
|
||||
opCodeVal$ = CHR$(&H7) + CHR$(&H17) + CHR$(&H1F)
|
||||
EXIT DO
|
||||
CASE "5"
|
||||
opCodeVal$ = CHR$(&HA1) + CHR$(&HA9)
|
||||
EXIT DO
|
||||
CASE "6"
|
||||
opCodeVal$ = CHR$(&H6) + CHR$(&HE) + CHR$(&H16) + CHR$(&H1E)
|
||||
EXIT DO
|
||||
CASE "7"
|
||||
opCodeVal$ = CHR$(&HA0) + CHR$(&HA8)
|
||||
EXIT DO
|
||||
CASE "10", "11", "12"
|
||||
NextIsOpCode = 1
|
||||
AddRegs = VAL(h$) - 9
|
||||
CASE "330"
|
||||
NextIsOpCode = 1
|
||||
AddCCode = VAL(h$) - 329
|
||||
CASE "17"
|
||||
opCodeVal$ = CHR$(0)
|
||||
EXIT DO
|
||||
CASE ELSE
|
||||
IF NextIsOpCode THEN
|
||||
PRINT "Line:"; lineNr
|
||||
PRINT "Unknown value: " + h$
|
||||
END
|
||||
END IF
|
||||
END SELECT
|
||||
END IF
|
||||
op = p + 1
|
||||
p = INSTR(op, tst$ + "\", "\")
|
||||
LOOP
|
||||
IF (p = 0) THEN
|
||||
PRINT "No opcode found in line"; lineNr
|
||||
PRINT "Line:"
|
||||
PRINT l$
|
||||
END
|
||||
END IF
|
||||
|
||||
IF NoDebug = 0 THEN
|
||||
FOR a = 1 TO LEN(opCodeVal$)
|
||||
h = ASC(MID$(opCodeVal$, a, 1))
|
||||
OpCodeStr$ = MKI$(OpCodeDebug)
|
||||
IF AddRegs THEN
|
||||
EndNr = 7
|
||||
ELSEIF AddCCode THEN
|
||||
EndNr = 15
|
||||
ELSE
|
||||
EndNr = 0
|
||||
END IF
|
||||
FOR b = 0 TO EndNr
|
||||
OpCodeList$(h + b) = OpCodeList$(h + b) + OpCodeStr$
|
||||
NEXT
|
||||
NEXT
|
||||
OpCodeDebug = OpCodeDebug + 1
|
||||
END IF
|
||||
|
||||
skipOpCode:
|
||||
OpCodes = OpCodes + 1
|
||||
LineOfs$ = LineOfs$ + MKL$(NowLineOfs&)
|
||||
LineLg = 1
|
||||
h$ = CHR$(NoDebug)
|
||||
PUT #3, NowLineOfs&, h$
|
||||
NowLineOfs& = NowLineOfs& + 1
|
||||
FOR a = 1 TO 5
|
||||
lg = LEN(StrucData$(a))
|
||||
h$ = CHR$(lg) + StrucData$(a)
|
||||
PUT #3, NowLineOfs&, h$
|
||||
NowLineOfs& = NowLineOfs& + lg + 1
|
||||
LineLg = LineLg + lg + 1
|
||||
NEXT
|
||||
LineOfs$ = LineOfs$ + MKI$(LineLg)
|
||||
END IF
|
||||
END IF
|
||||
WEND
|
||||
LOCATE , 1
|
||||
PRINT lineNr, OpCodes, OpCodeDebug
|
||||
|
||||
|
||||
'
|
||||
' creating insnsa.c
|
||||
'
|
||||
|
||||
|
||||
PRINT "Creating INSNSA.C"
|
||||
|
||||
OPEN "O", 2, "insnsa.c"
|
||||
strBegStart$ = "static struct itemplate instrux_"
|
||||
strBegEnd$ = "[] = {"
|
||||
strEnd$ = " {-1}" + crlf$ + "};" + crlf$
|
||||
|
||||
PRINT #2, "/* This file auto-generated from insns.dat by insns.bas - don't edit it */"
|
||||
PRINT #2, ""
|
||||
PRINT #2, "#include <stdio.h>"
|
||||
PRINT #2, "#include " + qt$ + "nasm.h" + qt$
|
||||
PRINT #2, "#include " + qt$ + "insns.h" + qt$
|
||||
PRINT #2, ""
|
||||
|
||||
oldOpCode$ = ""
|
||||
pOfs = 1
|
||||
FOR a = 1 TO OpCodes
|
||||
LineOfs& = CVL(MID$(LineOfs$, pOfs, 4))
|
||||
l$ = SPACE$(CVI(MID$(LineOfs$, pOfs + 4, 2)))
|
||||
pOfs = pOfs + 6
|
||||
GET #3, LineOfs&, l$
|
||||
|
||||
' split data into fields
|
||||
NoDebug = ASC(LEFT$(l$, 1))
|
||||
pLn = 2
|
||||
FOR b = 1 TO 5
|
||||
lgLn = ASC(MID$(l$, pLn, 1))
|
||||
StrucData$(b) = MID$(l$, pLn + 1, lgLn)
|
||||
pLn = pLn + lgLn + 1
|
||||
NEXT
|
||||
|
||||
IF oldOpCode$ <> StrucData$(1) THEN
|
||||
Instructs$ = Instructs$ + StrucData$(1) + CHR$(0)
|
||||
IF LEN(oldOpCode$) THEN PRINT #2, strEnd$
|
||||
PRINT #2, strBegStart$ + StrucData$(1) + strBegEnd$
|
||||
oldOpCode$ = StrucData$(1)
|
||||
END IF
|
||||
SELECT CASE UCASE$(StrucData$(3))
|
||||
CASE "IGNORE"
|
||||
CASE ELSE
|
||||
PRINT #2, " {I_" + oldOpCode$ + ", " + StrucData$(5) + ", {" + StrucData$(2) + "}, " + qt$ + StrucData$(3) + qt$ + ", " + StrucData$(4) + "},"
|
||||
END SELECT
|
||||
NEXT
|
||||
IF LEN(oldOpCode$) THEN PRINT #2, strEnd$
|
||||
|
||||
PRINT #2, "struct itemplate *nasm_instructions[] = {"
|
||||
op = 1
|
||||
p = INSTR(Instructs$, CHR$(0))
|
||||
WHILE p
|
||||
h$ = MID$(Instructs$, op, p - op)
|
||||
PRINT #2, " instrux_" + h$ + ","
|
||||
op = p + 1
|
||||
p = INSTR(op, Instructs$, CHR$(0))
|
||||
WEND
|
||||
PRINT #2, "};"
|
||||
|
||||
CLOSE 2
|
||||
|
||||
|
||||
|
||||
'
|
||||
' creating insnsd.c
|
||||
'
|
||||
|
||||
|
||||
PRINT "Creating INSNSD.C"
|
||||
|
||||
OPEN "O", 2, "insnsd.c"
|
||||
|
||||
PRINT #2, "/* This file auto-generated from insns.dat by insns.bas - don't edit it */"
|
||||
PRINT #2, ""
|
||||
PRINT #2, "#include <stdio.h>"
|
||||
PRINT #2, "#include " + qt$ + "nasm.h" + qt$
|
||||
PRINT #2, "#include " + qt$ + "insns.h" + qt$
|
||||
PRINT #2, ""
|
||||
|
||||
|
||||
PRINT #2, "static struct itemplate instrux[] = {"
|
||||
pOfs = 1
|
||||
FOR a = 1 TO OpCodes
|
||||
LineOfs& = CVL(MID$(LineOfs$, pOfs, 4))
|
||||
l$ = SPACE$(CVI(MID$(LineOfs$, pOfs + 4, 2)))
|
||||
pOfs = pOfs + 6
|
||||
GET #3, LineOfs&, l$
|
||||
|
||||
' split data into fields
|
||||
NoDebug = ASC(LEFT$(l$, 1))
|
||||
pLn = 2
|
||||
FOR b = 1 TO 5
|
||||
lgLn = ASC(MID$(l$, pLn, 1))
|
||||
StrucData$(b) = MID$(l$, pLn + 1, lgLn)
|
||||
pLn = pLn + lgLn + 1
|
||||
NEXT
|
||||
|
||||
IF NoDebug OR (UCASE$(StrucData$(3)) = "IGNORE") THEN
|
||||
' ignorieren
|
||||
ELSE
|
||||
PRINT #2, " {I_" + StrucData$(1) + ", " + StrucData$(5) + ", {" + StrucData$(2) + "}, " + qt$ + StrucData$(3) + qt$ + ", " + StrucData$(4) + "},"
|
||||
END IF
|
||||
NEXT
|
||||
PRINT #2, " {-1}" + crlf$ + "};" + crlf$
|
||||
|
||||
|
||||
OpCodeBegS$ = "static struct itemplate *itable_"
|
||||
OpCodeBegE$ = "[] = {"
|
||||
OpCodeEnd$ = " NULL" + crlf$ + "};" + crlf$
|
||||
|
||||
FOR a = 0 TO 255
|
||||
PRINT #2, OpCodeBegS$ + RIGHT$("00" + HEX$(a), 2) + OpCodeBegE$
|
||||
h$ = OpCodeList$(a)
|
||||
FOR b = 1 TO LEN(h$) STEP 2
|
||||
OpCodePos = CVI(MID$(h$, b, 2))
|
||||
PRINT #2, " instrux +" + STR$(OpCodePos) + ","
|
||||
NEXT
|
||||
PRINT #2, OpCodeEnd$
|
||||
NEXT
|
||||
|
||||
PRINT #2, "struct itemplate **itable[] = {"
|
||||
FOR a = 0 TO 255
|
||||
PRINT #2, " itable_" + RIGHT$("00" + HEX$(a), 2) + ","
|
||||
NEXT
|
||||
PRINT #2, "};"
|
||||
|
||||
CLOSE 2
|
||||
|
||||
|
||||
|
||||
CLOSE 3
|
||||
KILL "insns.tmp"
|
||||
CLOSE 1
|
||||
SYSTEM
|
||||
|
||||
FUNCTION ReplaceOp$ (a$)
|
||||
tst$ = UCASE$(a$)
|
||||
SELECT CASE tst$
|
||||
' CASE "ND"
|
||||
' ReplaceOp$ = ""
|
||||
CASE "VOID", ""
|
||||
ReplaceOp$ = "0"
|
||||
CASE "IMM"
|
||||
ReplaceOp$ = "IMMEDIATE"
|
||||
CASE "MEM"
|
||||
ReplaceOp$ = "MEMORY"
|
||||
CASE "MEM8", "MEM16", "MEM32", "MEM64", "MEM80"
|
||||
ReplaceOp$ = "MEMORY|BITS" + MID$(tst$, 4)
|
||||
CASE "REG8", "REG16", "REG32"
|
||||
ReplaceOp$ = tst$
|
||||
CASE "RM8", "RM16", "RM32"
|
||||
ReplaceOp$ = "REGMEM|BITS" + MID$(tst$, 3)
|
||||
CASE "IMM8", "IMM16", "IMM32"
|
||||
ReplaceOp$ = "IMMEDIATE|BITS" + MID$(tst$, 4)
|
||||
CASE ELSE
|
||||
ReplaceOp$ = tst$
|
||||
END SELECT
|
||||
END FUNCTION
|
||||
|
||||
FUNCTION Min% (a%, b%)
|
||||
IF a% < b% THEN Min% = a% ELSE Min% = b%
|
||||
END FUNCTION
|
||||
|
||||
FUNCTION StrAscii (a$)
|
||||
IF LEN(a$) = 0 THEN
|
||||
StrAscii = -1
|
||||
ELSE
|
||||
StrAscii = ASC(a$)
|
||||
END IF
|
||||
END FUNCTION
|
||||
|
||||
' same as =INSTR(SearchStart, SearchIn, ANY SearchFor$) in PowerBASIC(tm)
|
||||
'
|
||||
FUNCTION StrInstrLeft (SearchStart, SearchIn$, SearchFor$)
|
||||
ValuesCount = LEN(SearchFor$)
|
||||
MaxValue = LEN(SearchIn$) + 1
|
||||
MinValue = MaxValue
|
||||
FOR Counter1 = 1 TO ValuesCount
|
||||
SearchChar$ = MID$(SearchFor$, Counter1, 1)
|
||||
hVal2 = INSTR(SearchStart, SearchIn$, SearchChar$)
|
||||
IF hVal2 > 0 THEN MinValue = Min%(hVal2, MinValue)
|
||||
NEXT
|
||||
IF MinValue = MaxValue THEN MinValue = 0
|
||||
StrInstrLeft = MinValue
|
||||
END FUNCTION
|
||||
|
||||
'
|
||||
' This is a very damn fuckin' shit version of this splitting routine.
|
||||
' At this time, it's not very useful :]
|
||||
'
|
||||
SUB StrSplitString (SplitString$, SplitChars$, SplitField$(), SplitCount)
|
||||
StartIndex = LBOUND(SplitField$)
|
||||
LastIndex = UBOUND(SplitField$)
|
||||
ActualIndex& = StartIndex
|
||||
SplitCount = 0
|
||||
|
||||
LastPos = 1
|
||||
FoundPos = StrInstrLeft(LastPos, SplitString$, SplitChars$ + CHR$(34))
|
||||
GetDirect = 0
|
||||
EndLoop = 0
|
||||
TempString$ = ""
|
||||
DO WHILE FoundPos > 0
|
||||
FoundCharVal = StrAscii(MID$(SplitString$, FoundPos, 1))
|
||||
PosDiff = (FoundPos - LastPos) + 1
|
||||
SELECT CASE FoundCharVal
|
||||
CASE 34
|
||||
TempString$ = TempString$ + MID$(SplitString$, LastPos, PosDiff - 1)
|
||||
SELECT CASE EndLoop
|
||||
CASE 0
|
||||
EndLoop = 2
|
||||
CASE 3
|
||||
EndLoop = 0
|
||||
END SELECT
|
||||
CASE ELSE
|
||||
TempString$ = TempString$ + MID$(SplitString$, LastPos, PosDiff - 1)
|
||||
SplitField$(ActualIndex&) = TempString$
|
||||
TempString$ = ""
|
||||
ActualIndex& = ActualIndex& + 1
|
||||
IF ActualIndex& > LastIndex THEN
|
||||
ActualIndex& = LastIndex
|
||||
EndLoop = 1
|
||||
END IF
|
||||
END SELECT
|
||||
SELECT CASE EndLoop
|
||||
CASE 0
|
||||
DO
|
||||
LastPos = FoundPos + 1
|
||||
FoundPos = StrInstrLeft(LastPos, SplitString$, SplitChars$)
|
||||
LOOP WHILE LastPos = FoundPos
|
||||
FoundPos = StrInstrLeft(LastPos, SplitString$, SplitChars$ + CHR$(34))
|
||||
CASE 1
|
||||
FoundPos = 0
|
||||
LastPos = LEN(SplitString$) + 1
|
||||
CASE 2
|
||||
EndLoop = 3
|
||||
LastPos = FoundPos + 1
|
||||
FoundPos = StrInstrLeft(LastPos, SplitString$, CHR$(34))
|
||||
IF FoundPos = 0 THEN
|
||||
SplitString$ = SplitString$ + CHR$(34)
|
||||
FoundPos = LEN(SplitString$)
|
||||
END IF
|
||||
END SELECT
|
||||
LOOP
|
||||
IF EndLoop = 0 THEN
|
||||
IF LEN(TempString$) > 0 THEN
|
||||
SplitField$(ActualIndex&) = TempString$
|
||||
ELSEIF LastPos <= LEN(SplitString$) THEN
|
||||
SplitField$(ActualIndex&) = MID$(SplitString$, LastPos)
|
||||
ELSE
|
||||
ActualIndex& = ActualIndex& - 1
|
||||
END IF
|
||||
END IF
|
||||
FOR a = ActualIndex& + 1 TO LastIndex
|
||||
SplitField$(a) = ""
|
||||
NEXT
|
||||
SplitCount = (ActualIndex& - StartIndex) + 1
|
||||
END SUB
|
||||
|
||||
FUNCTION StrTrim$ (a$, b$)
|
||||
StrTrim$ = StrTrimRight$(StrTrimLeft$(a$, b$), b$)
|
||||
END FUNCTION
|
||||
|
||||
FUNCTION StrTrimLeft$ (a$, b$) 'public
|
||||
p = 0
|
||||
l = LEN(a$)
|
||||
DO
|
||||
p = p + 1
|
||||
t$ = MID$(a$, p, 1)
|
||||
LOOP WHILE (p < l) AND (INSTR(b$, t$) > 0)
|
||||
StrTrimLeft$ = MID$(a$, p)
|
||||
END FUNCTION
|
||||
|
||||
FUNCTION StrTrimRight$ (a$, b$) 'public
|
||||
l = LEN(a$)
|
||||
p = l + 1
|
||||
DO
|
||||
p = p - 1
|
||||
IF p > 0 THEN
|
||||
t$ = MID$(a$, p, 1)
|
||||
ELSE
|
||||
t$ = ""
|
||||
END IF
|
||||
LOOP WHILE (p > 0) AND (INSTR(b$, t$) > 0)
|
||||
StrTrimRight$ = LEFT$(a$, p)
|
||||
END FUNCTION
|
||||
|
||||
155
insns.dat
155
insns.dat
|
|
@ -14,9 +14,9 @@
|
|||
|
||||
AAA void \1\x37 8086
|
||||
AAD void \2\xD5\x0A 8086
|
||||
AAD imm \1\xD5\24 8086,UNDOC
|
||||
AAD imm \1\xD5\24 8086
|
||||
AAM void \2\xD4\x0A 8086
|
||||
AAM imm \1\xD4\24 8086,UNDOC
|
||||
AAM imm \1\xD4\24 8086
|
||||
AAS void \1\x3F 8086
|
||||
ADC mem,reg8 \300\1\x10\101 8086,SM
|
||||
ADC reg8,reg8 \300\1\x10\101 8086
|
||||
|
|
@ -225,7 +225,7 @@ FBLD mem \300\1\xDF\204 8086,FPU
|
|||
FBSTP mem80 \300\1\xDF\206 8086,FPU
|
||||
FBSTP mem \300\1\xDF\206 8086,FPU
|
||||
FCHS void \2\xD9\xE0 8086,FPU
|
||||
FCLEX void \2\xDB\xE2 8086,FPU
|
||||
FCLEX void \3\x9B\xDB\xE2 8086,FPU
|
||||
FCMOVB fpureg \1\xDA\10\xC0 P6,FPU
|
||||
FCMOVB fpu0,fpureg \1\xDA\11\xC0 P6,FPU
|
||||
FCMOVBE fpureg \1\xDA\10\xD0 P6,FPU
|
||||
|
|
@ -257,7 +257,7 @@ FCOMP fpu0,fpureg \1\xD8\11\xD8 8086,FPU
|
|||
FCOMPP void \2\xDE\xD9 8086,FPU
|
||||
FCOS void \2\xD9\xFF 386,FPU
|
||||
FDECSTP void \2\xD9\xF6 8086,FPU
|
||||
FDISI void \2\xDB\xE1 8086,FPU
|
||||
FDISI void \3\x9B\xDB\xE1 8086,FPU
|
||||
FDIV mem32 \300\1\xD8\206 8086,FPU
|
||||
FDIV mem64 \300\1\xDC\206 8086,FPU
|
||||
FDIV fpureg|to \1\xDC\10\xF8 8086,FPU
|
||||
|
|
@ -274,7 +274,7 @@ FDIVR fpureg \1\xD8\10\xF8 8086,FPU
|
|||
FDIVR fpu0,fpureg \1\xD8\11\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
|
||||
FENI void \3\x9B\xDB\xE0 8086,FPU
|
||||
FFREE fpureg \1\xDD\10\xC0 8086,FPU
|
||||
FIADD mem32 \300\1\xDA\200 8086,FPU
|
||||
FIADD mem16 \300\1\xDE\200 8086,FPU
|
||||
|
|
@ -292,7 +292,7 @@ FILD mem64 \300\1\xDF\205 8086,FPU
|
|||
FIMUL mem32 \300\1\xDA\201 8086,FPU
|
||||
FIMUL mem16 \300\1\xDE\201 8086,FPU
|
||||
FINCSTP void \2\xD9\xF7 8086,FPU
|
||||
FINIT void \2\xDB\xE3 8086,FPU
|
||||
FINIT void \3\x9B\xDB\xE3 8086,FPU
|
||||
FIST mem32 \300\1\xDB\202 8086,FPU
|
||||
FIST mem16 \300\1\xDF\202 8086,FPU
|
||||
FISTP mem32 \300\1\xDB\203 8086,FPU
|
||||
|
|
@ -323,14 +323,23 @@ FMUL fpureg \1\xD8\10\xC8 8086,FPU
|
|||
FMUL fpu0,fpureg \1\xD8\11\xC8 8086,FPU
|
||||
FMULP fpureg \1\xDE\10\xC8 8086,FPU
|
||||
FMULP fpureg,fpu0 \1\xDE\10\xC8 8086,FPU
|
||||
FNCLEX void \2\xDB\xE2 8086,FPU
|
||||
FNDISI void \2\xDB\xE1 8086,FPU
|
||||
FNENI void \2\xDB\xE0 8086,FPU
|
||||
FNINIT void \2\xDB\xE3 8086,FPU
|
||||
FNOP void \2\xD9\xD0 8086,FPU
|
||||
FNSAVE mem \300\1\xDD\206 8086,FPU
|
||||
FNSTCW mem \300\1\xD9\207 8086,FPU,SW
|
||||
FNSTENV mem \300\1\xD9\206 8086,FPU
|
||||
FNSTSW mem \300\1\xDD\207 8086,FPU,SW
|
||||
FNSTSW reg_ax \2\xDF\xE0 286,FPU
|
||||
FPATAN void \2\xD9\xF3 8086,FPU
|
||||
FPREM void \2\xD9\xF8 8086,FPU
|
||||
FPREM1 void \2\xD9\xF5 386,FPU
|
||||
FPTAN void \2\xD9\xF2 8086,FPU
|
||||
FRNDINT void \2\xD9\xFC 8086,FPU
|
||||
FRSTOR mem \300\1\xDD\204 8086,FPU
|
||||
FSAVE mem \300\1\xDD\206 8086,FPU
|
||||
FSAVE mem \300\2\x9B\xDD\206 8086,FPU
|
||||
FSCALE void \2\xD9\xFD 8086,FPU
|
||||
FSETPM void \2\xDB\xE4 286,FPU
|
||||
FSIN void \2\xD9\xFE 386,FPU
|
||||
|
|
@ -339,14 +348,14 @@ FSQRT void \2\xD9\xFA 8086,FPU
|
|||
FST mem32 \300\1\xD9\202 8086,FPU
|
||||
FST mem64 \300\1\xDD\202 8086,FPU
|
||||
FST fpureg \1\xDD\10\xD0 8086,FPU
|
||||
FSTCW mem \300\1\xD9\207 8086,FPU,SW
|
||||
FSTENV mem \300\1\xD9\206 8086,FPU
|
||||
FSTCW mem \300\2\x9B\xD9\207 8086,FPU,SW
|
||||
FSTENV mem \300\2\x9B\xD9\206 8086,FPU
|
||||
FSTP mem32 \300\1\xD9\203 8086,FPU
|
||||
FSTP mem64 \300\1\xDD\203 8086,FPU
|
||||
FSTP mem80 \300\1\xDB\207 8086,FPU
|
||||
FSTP fpureg \1\xDD\10\xD8 8086,FPU
|
||||
FSTSW mem \300\1\xDD\207 8086,FPU,SW
|
||||
FSTSW reg_ax \2\xDF\xE0 286,FPU
|
||||
FSTSW mem \300\2\x9B\xDD\207 8086,FPU,SW
|
||||
FSTSW reg_ax \3\x9B\xDF\xE0 286,FPU
|
||||
FSUB mem32 \300\1\xD8\204 8086,FPU
|
||||
FSUB mem64 \300\1\xDC\204 8086,FPU
|
||||
FSUB fpureg|to \1\xDC\10\xE8 8086,FPU
|
||||
|
|
@ -365,11 +374,13 @@ 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
|
||||
FUCOM fpu0,fpureg \1\xDD\11\xE0 386,FPU
|
||||
FUCOMI fpureg \1\xDB\10\xE8 P6,FPU
|
||||
FUCOMI fpu0,fpureg \1\xDB\11\xE8 P6,FPU
|
||||
FUCOMIP fpureg \1\xDF\10\xE8 P6,FPU
|
||||
FUCOMIP fpu0,fpureg \1\xDF\11\xE8 P6,FPU
|
||||
FUCOMP fpureg \1\xDD\10\xE8 386,FPU
|
||||
FUCOMP fpu0,fpureg \1\xDD\11\xE8 386,FPU
|
||||
FUCOMPP void \2\xDA\xE9 386,FPU
|
||||
FXAM void \2\xD9\xE5 8086,FPU
|
||||
FXCH void \2\xD9\xC9 8086,FPU
|
||||
|
|
@ -384,7 +395,7 @@ IBTS mem,reg16 \320\300\2\x0F\xA7\101 386,SW,UNDOC,ND
|
|||
IBTS reg16,reg16 \320\300\2\x0F\xA7\101 386,UNDOC,ND
|
||||
IBTS mem,reg32 \321\300\2\x0F\xA7\101 386,SD,UNDOC,ND
|
||||
IBTS reg32,reg32 \321\300\2\x0F\xA7\101 386,UNDOC,ND
|
||||
ICEBP void \1\xF1 286,UNDOC
|
||||
ICEBP void \1\xF1 P6,ND
|
||||
IDIV rm8 \300\1\xF6\207 8086
|
||||
IDIV rm16 \320\300\1\xF7\207 8086
|
||||
IDIV rm32 \321\300\1\xF7\207 386
|
||||
|
|
@ -398,7 +409,7 @@ IMUL reg32,reg32 \321\301\2\x0F\xAF\110 386
|
|||
IMUL reg16,mem,imm8 \320\301\1\x6B\110\16 286,SM
|
||||
IMUL reg16,reg16,imm8 \320\301\1\x6B\110\16 286
|
||||
IMUL reg16,mem,imm \320\301\1\x69\110\32 286,SM
|
||||
IMUL reg16,reg16,imm \320\301\1\x69\110\32 286
|
||||
IMUL reg16,reg16,imm \320\301\1\x69\110\32 286,SM
|
||||
IMUL reg32,mem,imm8 \321\301\1\x6B\110\16 386,SM
|
||||
IMUL reg32,reg32,imm8 \321\301\1\x6B\110\16 386
|
||||
IMUL reg32,mem,imm \321\301\1\x69\110\42 386,SM
|
||||
|
|
@ -423,8 +434,8 @@ INSB void \1\x6C 186
|
|||
INSD void \321\1\x6D 386
|
||||
INSW void \320\1\x6D 186
|
||||
INT imm \1\xCD\24 8086
|
||||
INT01 void \1\xF1 286,UNDOC
|
||||
INT1 void \1\xF1 286,UNDOC
|
||||
INT01 void \1\xF1 P6,ND
|
||||
INT1 void \1\xF1 P6
|
||||
INT3 void \1\xCC 8086
|
||||
INTO void \1\xCE 8086
|
||||
INVD void \2\x0F\x08 486
|
||||
|
|
@ -506,16 +517,21 @@ LSS reg32,mem \321\301\2\x0F\xB2\110 386
|
|||
LTR mem \300\1\x0F\17\203 286,PRIV
|
||||
LTR mem16 \300\1\x0F\17\203 286,PRIV
|
||||
LTR reg16 \300\1\x0F\17\203 286,PRIV
|
||||
MOV mem,reg_cs \300\1\x8C\101 8086,SM
|
||||
MOV mem,reg_dess \300\1\x8C\101 8086,SM
|
||||
MOV mem,reg_fsgs \300\1\x8C\101 386,SM
|
||||
MOV reg16,reg_cs \300\1\x8C\101 8086
|
||||
MOV reg16,reg_dess \300\1\x8C\101 8086
|
||||
MOV reg16,reg_fsgs \300\1\x8C\101 386
|
||||
MOV reg_dess,mem \301\1\x8E\110 8086,SM
|
||||
MOV reg_dess,reg16 \301\1\x8E\110 8086
|
||||
MOV reg_fsgs,mem \301\1\x8E\110 386,SM
|
||||
MOV reg_fsgs,reg16 \301\1\x8E\110 386
|
||||
MOV mem,reg_cs \320\300\1\x8C\201 8086,SM
|
||||
MOV mem,reg_dess \320\300\1\x8C\101 8086,SM
|
||||
MOV mem,reg_fsgs \320\300\1\x8C\101 386,SM
|
||||
MOV reg16,reg_cs \320\300\1\x8C\201 8086
|
||||
MOV reg16,reg_dess \320\300\1\x8C\101 8086
|
||||
MOV reg16,reg_fsgs \320\300\1\x8C\101 386
|
||||
MOV rm32,reg_cs \321\300\1\x8C\201 8086
|
||||
MOV rm32,reg_dess \321\300\1\x8C\101 8086
|
||||
MOV rm32,reg_fsgs \321\300\1\x8C\101 386
|
||||
MOV reg_dess,mem \320\301\1\x8E\110 8086,SM
|
||||
MOV reg_fsgs,mem \320\301\1\x8E\110 386,SM
|
||||
MOV reg_dess,reg16 \320\301\1\x8E\110 8086
|
||||
MOV reg_fsgs,reg16 \320\301\1\x8E\110 386
|
||||
MOV reg_dess,rm32 \321\301\1\x8E\110 8086
|
||||
MOV reg_fsgs,rm32 \321\301\1\x8E\110 386
|
||||
MOV reg_al,mem_offs \301\1\xA0\35 8086,SM
|
||||
MOV reg_ax,mem_offs \301\320\1\xA1\35 8086,SM
|
||||
MOV reg_eax,mem_offs \301\321\1\xA1\35 386,SM
|
||||
|
|
@ -624,6 +640,8 @@ PADDD mmxreg,mem \301\2\x0F\xFE\110 PENT,MMX,SM
|
|||
PADDD mmxreg,mmxreg \2\x0F\xFE\110 PENT,MMX
|
||||
PADDSB mmxreg,mem \301\2\x0F\xEC\110 PENT,MMX,SM
|
||||
PADDSB mmxreg,mmxreg \2\x0F\xEC\110 PENT,MMX
|
||||
PADDSIW mmxreg,mem \301\2\x0F\x51\110 PENT,MMX,SM,CYRIX
|
||||
PADDSIW mmxreg,mmxreg \2\x0F\x51\110 PENT,MMX,CYRIX
|
||||
PADDSW mmxreg,mem \301\2\x0F\xED\110 PENT,MMX,SM
|
||||
PADDSW mmxreg,mmxreg \2\x0F\xED\110 PENT,MMX
|
||||
PADDUSB mmxreg,mem \301\2\x0F\xDC\110 PENT,MMX,SM
|
||||
|
|
@ -636,6 +654,8 @@ PAND mmxreg,mem \301\2\x0F\xDB\110 PENT,MMX,SM
|
|||
PAND mmxreg,mmxreg \2\x0F\xDB\110 PENT,MMX
|
||||
PANDN mmxreg,mem \301\2\x0F\xDF\110 PENT,MMX,SM
|
||||
PANDN mmxreg,mmxreg \2\x0F\xDF\110 PENT,MMX
|
||||
PAVEB mmxreg,mem \301\2\x0F\x50\110 PENT,MMX,SM,CYRIX
|
||||
PAVEB mmxreg,mmxreg \2\x0F\x50\110 PENT,MMX,CYRIX
|
||||
PCMPEQB mmxreg,mem \301\2\x0F\x74\110 PENT,MMX,SM
|
||||
PCMPEQB mmxreg,mmxreg \2\x0F\x74\110 PENT,MMX
|
||||
PCMPEQD mmxreg,mem \301\2\x0F\x76\110 PENT,MMX,SM
|
||||
|
|
@ -648,19 +668,31 @@ PCMPGTD mmxreg,mem \301\2\x0F\x66\110 PENT,MMX,SM
|
|||
PCMPGTD mmxreg,mmxreg \2\x0F\x66\110 PENT,MMX
|
||||
PCMPGTW mmxreg,mem \301\2\x0F\x65\110 PENT,MMX,SM
|
||||
PCMPGTW mmxreg,mmxreg \2\x0F\x65\110 PENT,MMX
|
||||
PDISTIB mmxreg,mem \301\2\x0F\x54\110 PENT,MMX,SM,CYRIX
|
||||
PMACHRIW mmxreg,mem \301\2\x0F\x5E\110 PENT,MMX,SM,CYRIX
|
||||
PMADDWD mmxreg,mem \301\2\x0F\xF5\110 PENT,MMX,SM
|
||||
PMADDWD mmxreg,mmxreg \2\x0F\xF5\110 PENT,MMX
|
||||
PMAGW mmxreg,mem \301\2\x0F\x52\110 PENT,MMX,SM,CYRIX
|
||||
PMAGW mmxreg,mmxreg \2\x0F\x52\110 PENT,MMX,CYRIX
|
||||
PMULHRW mmxreg,mem \301\2\x0F\x59\110 PENT,MMX,SM,CYRIX
|
||||
PMULHRW mmxreg,mmxreg \2\x0F\x59\110 PENT,MMX,CYRIX
|
||||
PMULHRIW mmxreg,mem \301\2\x0F\x5D\110 PENT,MMX,SM,CYRIX
|
||||
PMULHRIW mmxreg,mmxreg \2\x0F\x5D\110 PENT,MMX,CYRIX
|
||||
PMULHW mmxreg,mem \301\2\x0F\xE5\110 PENT,MMX,SM
|
||||
PMULHW mmxreg,mmxreg \2\x0F\xE5\110 PENT,MMX
|
||||
PMULLW mmxreg,mem \301\2\x0F\xD5\110 PENT,MMX,SM
|
||||
PMULLW mmxreg,mmxreg \2\x0F\xD5\110 PENT,MMX
|
||||
POP mem16 \320\300\1\x8F\200 8086
|
||||
POP mem32 \321\300\1\x8F\200 386
|
||||
PMVGEZB mmxreg,mem \301\2\x0F\x5C\110 PENT,MMX,SM,CYRIX
|
||||
PMVLZB mmxreg,mem \301\2\x0F\x5B\110 PENT,MMX,SM,CYRIX
|
||||
PMVNZB mmxreg,mem \301\2\x0F\x5A\110 PENT,MMX,SM,CYRIX
|
||||
PMVZB mmxreg,mem \301\2\x0F\x58\110 PENT,MMX,SM,CYRIX
|
||||
POP reg16 \320\10\x58 8086
|
||||
POP reg32 \321\10\x58 386
|
||||
POP rm16 \320\300\1\x8F\200 8086
|
||||
POP rm32 \321\300\1\x8F\200 386
|
||||
POP reg_cs \1\x0F 8086,UNDOC,ND
|
||||
POP reg_dess \4 8086
|
||||
POP reg_fsgs \1\x0F\5 386
|
||||
POP reg16 \320\10\x58 8086
|
||||
POP reg32 \321\10\x58 386
|
||||
POPA void \322\1\x61 186
|
||||
POPAD void \321\1\x61 386
|
||||
POPAW void \320\1\x61 186
|
||||
|
|
@ -699,6 +731,8 @@ PSUBD mmxreg,mem \301\2\x0F\xFA\110 PENT,MMX,SM
|
|||
PSUBD mmxreg,mmxreg \2\x0F\xFA\110 PENT,MMX
|
||||
PSUBSB mmxreg,mem \301\2\x0F\xE8\110 PENT,MMX,SM
|
||||
PSUBSB mmxreg,mmxreg \2\x0F\xE8\110 PENT,MMX
|
||||
PSUBSIW mmxreg,mem \301\2\x0F\x55\110 PENT,MMX,SM,CYRIX
|
||||
PSUBSIW mmxreg,mmxreg \2\x0F\x55\110 PENT,MMX,CYRIX
|
||||
PSUBSW mmxreg,mem \301\2\x0F\xE9\110 PENT,MMX,SM
|
||||
PSUBSW mmxreg,mmxreg \2\x0F\xE9\110 PENT,MMX
|
||||
PSUBUSB mmxreg,mem \301\2\x0F\xD8\110 PENT,MMX,SM
|
||||
|
|
@ -719,12 +753,12 @@ PUNPCKLDQ mmxreg,mem \301\2\x0F\x62\110 PENT,MMX,SM
|
|||
PUNPCKLDQ mmxreg,mmxreg \2\x0F\x62\110 PENT,MMX
|
||||
PUNPCKLWD mmxreg,mem \301\2\x0F\x61\110 PENT,MMX,SM
|
||||
PUNPCKLWD mmxreg,mmxreg \2\x0F\x61\110 PENT,MMX
|
||||
PUSH mem16 \320\300\1\xFF\206 8086
|
||||
PUSH mem32 \321\300\1\xFF\206 386
|
||||
PUSH reg_fsgs \1\x0F\7 386
|
||||
PUSH reg_sreg \6 8086
|
||||
PUSH reg16 \320\10\x50 8086
|
||||
PUSH reg32 \321\10\x50 386
|
||||
PUSH rm16 \320\300\1\xFF\206 8086
|
||||
PUSH rm32 \321\300\1\xFF\206 386
|
||||
PUSH reg_fsgs \1\x0F\7 386
|
||||
PUSH reg_sreg \6 8086
|
||||
PUSH imm8 \1\x6A\14 286
|
||||
PUSH imm16 \320\1\x68\30 286
|
||||
PUSH imm32 \321\1\x68\40 386
|
||||
|
|
@ -738,22 +772,22 @@ PXOR mmxreg,mem \301\2\x0F\xEF\110 PENT,MMX,SM
|
|||
PXOR mmxreg,mmxreg \2\x0F\xEF\110 PENT,MMX
|
||||
RCL rm8,unity \300\1\xD0\202 8086
|
||||
RCL rm8,reg_cl \300\1\xD2\202 8086
|
||||
RCL rm8,imm \300\1\xC0\202\25 286
|
||||
RCL rm8,imm \300\1\xC0\202\25 286,SB
|
||||
RCL rm16,unity \320\300\1\xD1\202 8086
|
||||
RCL rm16,reg_cl \320\300\1\xD3\202 8086
|
||||
RCL rm16,imm \320\300\1\xC1\202\25 286
|
||||
RCL rm16,imm \320\300\1\xC1\202\25 286,SB
|
||||
RCL rm32,unity \321\300\1\xD1\202 386
|
||||
RCL rm32,reg_cl \321\300\1\xD3\202 386
|
||||
RCL rm32,imm \321\300\1\xC1\202\25 386
|
||||
RCL rm32,imm \321\300\1\xC1\202\25 386,SB
|
||||
RCR rm8,unity \300\1\xD0\203 8086
|
||||
RCR rm8,reg_cl \300\1\xD2\203 8086
|
||||
RCR rm8,imm \300\1\xC0\203\25 286
|
||||
RCR rm8,imm \300\1\xC0\203\25 286,SB
|
||||
RCR rm16,unity \320\300\1\xD1\203 8086
|
||||
RCR rm16,reg_cl \320\300\1\xD3\203 8086
|
||||
RCR rm16,imm \320\300\1\xC1\203\25 286
|
||||
RCR rm16,imm \320\300\1\xC1\203\25 286,SB
|
||||
RCR rm32,unity \321\300\1\xD1\203 386
|
||||
RCR rm32,reg_cl \321\300\1\xD3\203 386
|
||||
RCR rm32,imm \321\300\1\xC1\203\25 386
|
||||
RCR rm32,imm \321\300\1\xC1\203\25 386,SB
|
||||
RDMSR void \2\x0F\x32 PENT
|
||||
RDPMC void \2\x0F\x33 P6
|
||||
RDTSC void \2\x0F\x31 PENT
|
||||
|
|
@ -770,43 +804,43 @@ RETN void \1\xC3 8086
|
|||
RETN imm \1\xC2\30 8086
|
||||
ROL rm8,unity \300\1\xD0\200 8086
|
||||
ROL rm8,reg_cl \300\1\xD2\200 8086
|
||||
ROL rm8,imm \300\1\xC0\200\25 286
|
||||
ROL rm8,imm \300\1\xC0\200\25 286,SB
|
||||
ROL rm16,unity \320\300\1\xD1\200 8086
|
||||
ROL rm16,reg_cl \320\300\1\xD3\200 8086
|
||||
ROL rm16,imm \320\300\1\xC1\200\25 286
|
||||
ROL rm16,imm \320\300\1\xC1\200\25 286,SB
|
||||
ROL rm32,unity \321\300\1\xD1\200 386
|
||||
ROL rm32,reg_cl \321\300\1\xD3\200 386
|
||||
ROL rm32,imm \321\300\1\xC1\200\25 386
|
||||
ROL rm32,imm \321\300\1\xC1\200\25 386,SB
|
||||
ROR rm8,unity \300\1\xD0\201 8086
|
||||
ROR rm8,reg_cl \300\1\xD2\201 8086
|
||||
ROR rm8,imm \300\1\xC0\201\25 286
|
||||
ROR rm8,imm \300\1\xC0\201\25 286,SB
|
||||
ROR rm16,unity \320\300\1\xD1\201 8086
|
||||
ROR rm16,reg_cl \320\300\1\xD3\201 8086
|
||||
ROR rm16,imm \320\300\1\xC1\201\25 286
|
||||
ROR rm16,imm \320\300\1\xC1\201\25 286,SB
|
||||
ROR rm32,unity \321\300\1\xD1\201 386
|
||||
ROR rm32,reg_cl \321\300\1\xD3\201 386
|
||||
ROR rm32,imm \321\300\1\xC1\201\25 386
|
||||
ROR rm32,imm \321\300\1\xC1\201\25 386,SB
|
||||
RSM void \2\x0F\xAA PENT
|
||||
SAHF void \1\x9E 8086
|
||||
SAL rm8,unity \300\1\xD0\204 8086,ND
|
||||
SAL rm8,reg_cl \300\1\xD2\204 8086,ND
|
||||
SAL rm8,imm \300\1\xC0\204\25 286,ND
|
||||
SAL rm8,imm \300\1\xC0\204\25 286,ND,SB
|
||||
SAL rm16,unity \320\300\1\xD1\204 8086,ND
|
||||
SAL rm16,reg_cl \320\300\1\xD3\204 8086,ND
|
||||
SAL rm16,imm \320\300\1\xC1\204\25 286,ND
|
||||
SAL rm16,imm \320\300\1\xC1\204\25 286,ND,SB
|
||||
SAL rm32,unity \321\300\1\xD1\204 386,ND
|
||||
SAL rm32,reg_cl \321\300\1\xD3\204 386,ND
|
||||
SAL rm32,imm \321\300\1\xC1\204\25 386,ND
|
||||
SAL rm32,imm \321\300\1\xC1\204\25 386,ND,SB
|
||||
SALC void \1\xD6 8086,UNDOC
|
||||
SAR rm8,unity \300\1\xD0\207 8086
|
||||
SAR rm8,reg_cl \300\1\xD2\207 8086
|
||||
SAR rm8,imm \300\1\xC0\207\25 286
|
||||
SAR rm8,imm \300\1\xC0\207\25 286,SB
|
||||
SAR rm16,unity \320\300\1\xD1\207 8086
|
||||
SAR rm16,reg_cl \320\300\1\xD3\207 8086
|
||||
SAR rm16,imm \320\300\1\xC1\207\25 286
|
||||
SAR rm16,imm \320\300\1\xC1\207\25 286,SB
|
||||
SAR rm32,unity \321\300\1\xD1\207 386
|
||||
SAR rm32,reg_cl \321\300\1\xD3\207 386
|
||||
SAR rm32,imm \321\300\1\xC1\207\25 386
|
||||
SAR rm32,imm \321\300\1\xC1\207\25 386,SB
|
||||
SBB mem,reg8 \300\1\x18\101 8086,SM
|
||||
SBB reg8,reg8 \300\1\x18\101 8086
|
||||
SBB mem,reg16 \320\300\1\x19\101 8086,SM
|
||||
|
|
@ -836,13 +870,13 @@ SCASW void \320\1\xAF 8086
|
|||
SGDT mem \300\2\x0F\x01\200 286,PRIV
|
||||
SHL rm8,unity \300\1\xD0\204 8086
|
||||
SHL rm8,reg_cl \300\1\xD2\204 8086
|
||||
SHL rm8,imm \300\1\xC0\204\25 286
|
||||
SHL rm8,imm \300\1\xC0\204\25 286,SB
|
||||
SHL rm16,unity \320\300\1\xD1\204 8086
|
||||
SHL rm16,reg_cl \320\300\1\xD3\204 8086
|
||||
SHL rm16,imm \320\300\1\xC1\204\25 286
|
||||
SHL rm16,imm \320\300\1\xC1\204\25 286,SB
|
||||
SHL rm32,unity \321\300\1\xD1\204 386
|
||||
SHL rm32,reg_cl \321\300\1\xD3\204 386
|
||||
SHL rm32,imm \321\300\1\xC1\204\25 386
|
||||
SHL rm32,imm \321\300\1\xC1\204\25 386,SB
|
||||
SHLD mem,reg16,imm \300\320\2\x0F\xA4\101\26 386,SM2
|
||||
SHLD reg16,reg16,imm \300\320\2\x0F\xA4\101\26 386,SM2
|
||||
SHLD mem,reg32,imm \300\321\2\x0F\xA4\101\26 386,SM2
|
||||
|
|
@ -853,13 +887,13 @@ SHLD mem,reg32,reg_cl \300\321\2\x0F\xA5\101 386,SM
|
|||
SHLD reg32,reg32,reg_cl \300\321\2\x0F\xA5\101 386
|
||||
SHR rm8,unity \300\1\xD0\205 8086
|
||||
SHR rm8,reg_cl \300\1\xD2\205 8086
|
||||
SHR rm8,imm \300\1\xC0\205\25 286
|
||||
SHR rm8,imm \300\1\xC0\205\25 286,SB
|
||||
SHR rm16,unity \320\300\1\xD1\205 8086
|
||||
SHR rm16,reg_cl \320\300\1\xD3\205 8086
|
||||
SHR rm16,imm \320\300\1\xC1\205\25 286
|
||||
SHR rm16,imm \320\300\1\xC1\205\25 286,SB
|
||||
SHR rm32,unity \321\300\1\xD1\205 386
|
||||
SHR rm32,reg_cl \321\300\1\xD3\205 386
|
||||
SHR rm32,imm \321\300\1\xC1\205\25 386
|
||||
SHR rm32,imm \321\300\1\xC1\205\25 386,SB
|
||||
SHRD mem,reg16,imm \300\320\2\x0F\xAC\101\26 386,SM2
|
||||
SHRD reg16,reg16,imm \300\320\2\x0F\xAC\101\26 386,SM2
|
||||
SHRD mem,reg32,imm \300\321\2\x0F\xAC\101\26 386,SM2
|
||||
|
|
@ -874,6 +908,7 @@ SLDT mem16 \300\1\x0F\17\200 286,PRIV
|
|||
SLDT reg16 \300\1\x0F\17\200 286,PRIV
|
||||
SMI void \1\xF1 386,UNDOC
|
||||
SMSW mem \300\2\x0F\x01\204 286,PRIV
|
||||
SMSW mem16 \300\2\x0F\x01\204 286,PRIV
|
||||
SMSW reg16 \300\2\x0F\x01\204 286,PRIV
|
||||
STC void \1\xF9 8086
|
||||
STD void \1\xFD 8086
|
||||
|
|
@ -921,7 +956,7 @@ TEST rm16,imm \320\300\1\xF7\200\31 8086,SM
|
|||
TEST rm32,imm \321\300\1\xF7\200\41 386,SM
|
||||
TEST mem,imm8 \300\1\xF6\200\21 8086,SM
|
||||
TEST mem,imm16 \320\300\1\xF7\200\31 8086,SM
|
||||
TEST mem,imm32 \321\300\1\xF7\200\41 386,UNDOC,SM
|
||||
TEST mem,imm32 \321\300\1\xF7\200\41 386,SM
|
||||
UMOV mem,reg8 \300\2\x0F\x10\101 386,UNDOC,SM
|
||||
UMOV reg8,reg8 \300\2\x0F\x10\101 386,UNDOC
|
||||
UMOV mem,reg16 \320\300\2\x0F\x11\101 386,UNDOC,SM
|
||||
|
|
@ -995,8 +1030,8 @@ XOR mem,imm16 \320\300\1\x81\206\31 8086,SM
|
|||
XOR mem,imm32 \321\300\1\x81\206\41 386,SM
|
||||
CMOVcc reg16,mem \320\301\1\x0F\330\x40\110 P6,SM
|
||||
CMOVcc reg16,reg16 \320\301\1\x0F\330\x40\110 P6
|
||||
CMOVcc reg32,mem \320\301\1\x0F\330\x40\110 P6,SM
|
||||
CMOVcc reg32,reg32 \320\301\1\x0F\330\x40\110 P6
|
||||
CMOVcc reg32,mem \321\301\1\x0F\330\x40\110 P6,SM
|
||||
CMOVcc reg32,reg32 \321\301\1\x0F\330\x40\110 P6
|
||||
Jcc imm|near \322\1\x0F\330\x80\64 386
|
||||
Jcc imm \330\x70\50 8086
|
||||
Jcc imm|short \330\x70\50 8086
|
||||
|
|
|
|||
1
insns.h
1
insns.h
|
|
@ -56,6 +56,7 @@ struct itemplate {
|
|||
#define IF_486 0x0400 /* 486+ instruction */
|
||||
#define IF_PENT 0x0500 /* Pentium instruction */
|
||||
#define IF_P6 0x0600 /* P6 instruction */
|
||||
#define IF_CYRIX 0x0800 /* Cyrix-specific instruction */
|
||||
#define IF_PMASK 0x0F00 /* the mask for processor types */
|
||||
#define IF_PRIV 0x1000 /* it's a privileged instruction */
|
||||
#define IF_UNDOC 0x2000 /* it's an undocumented instruction */
|
||||
|
|
|
|||
3
insns.pl
3
insns.pl
|
|
@ -9,7 +9,8 @@
|
|||
|
||||
print STDERR "Reading insns.dat...\n";
|
||||
|
||||
open (F, "insns.dat") || die "unable to open insns.dat";
|
||||
$fname = "insns.dat" unless $fname = $ARGV[0];
|
||||
open (F, $fname) || die "unable to open $fname";
|
||||
|
||||
$line = 0;
|
||||
$opcodes = 0;
|
||||
|
|
|
|||
87
labels.c
87
labels.c
|
|
@ -29,15 +29,20 @@
|
|||
#define PERMTS_SIZE 4096 /* size of text blocks */
|
||||
|
||||
/* values for label.defn.is_global */
|
||||
#define DEFINED_BIT 1
|
||||
#define GLOBAL_BIT 2
|
||||
#define EXTERN_BIT 4
|
||||
|
||||
#define NOT_DEFINED_YET 0
|
||||
#define LOCAL_SYMBOL 1
|
||||
#define GLOBAL_SYMBOL 2
|
||||
#define GLOBAL_PLACEHOLDER 3
|
||||
#define TYPE_MASK 3
|
||||
#define LOCAL_SYMBOL (DEFINED_BIT)
|
||||
#define GLOBAL_PLACEHOLDER (GLOBAL_BIT)
|
||||
#define GLOBAL_SYMBOL (DEFINED_BIT|GLOBAL_BIT)
|
||||
|
||||
union label { /* actual label structures */
|
||||
struct {
|
||||
long segment, offset;
|
||||
char *label;
|
||||
char *label, *special;
|
||||
int is_global;
|
||||
} defn;
|
||||
struct {
|
||||
|
|
@ -62,6 +67,8 @@ static char *perm_copy (char *string1, char *string2);
|
|||
|
||||
static char *prevlabel;
|
||||
|
||||
static int initialised = FALSE;
|
||||
|
||||
/*
|
||||
* Internal routine: finds the `union label' corresponding to the
|
||||
* given label name. Creates a new one, if it isn't found, and if
|
||||
|
|
@ -107,6 +114,7 @@ static union label *find_label (char *label, int create) {
|
|||
|
||||
lfree[hash]->admin.movingon = BOGUS_VALUE;
|
||||
lfree[hash]->defn.label = perm_copy (prev, label);
|
||||
lfree[hash]->defn.special = NULL;
|
||||
lfree[hash]->defn.is_global = NOT_DEFINED_YET;
|
||||
return lfree[hash]++;
|
||||
} else
|
||||
|
|
@ -116,9 +124,11 @@ static union label *find_label (char *label, int create) {
|
|||
int lookup_label (char *label, long *segment, long *offset) {
|
||||
union label *lptr;
|
||||
|
||||
if (!initialised)
|
||||
return 0;
|
||||
|
||||
lptr = find_label (label, 0);
|
||||
if (lptr && (lptr->defn.is_global == LOCAL_SYMBOL ||
|
||||
lptr->defn.is_global == GLOBAL_SYMBOL)) {
|
||||
if (lptr && (lptr->defn.is_global & DEFINED_BIT)) {
|
||||
*segment = lptr->defn.segment;
|
||||
*offset = lptr->defn.offset;
|
||||
return 1;
|
||||
|
|
@ -126,6 +136,19 @@ int lookup_label (char *label, long *segment, long *offset) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int is_extern (char *label) {
|
||||
union label *lptr;
|
||||
|
||||
if (!initialised)
|
||||
return 0;
|
||||
|
||||
lptr = find_label (label, 0);
|
||||
if (lptr && (lptr->defn.is_global & EXTERN_BIT))
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
void define_label_stub (char *label, efunc error) {
|
||||
union label *lptr;
|
||||
|
||||
|
|
@ -138,26 +161,22 @@ void define_label_stub (char *label, efunc error) {
|
|||
}
|
||||
}
|
||||
|
||||
void define_label (char *label, long segment, long offset,
|
||||
struct ofmt *ofmt, efunc error) {
|
||||
void define_label (char *label, long segment, long offset, char *special,
|
||||
int is_norm, int isextrn, struct ofmt *ofmt, efunc error) {
|
||||
union label *lptr;
|
||||
|
||||
lptr = find_label (label, 1);
|
||||
switch (lptr->defn.is_global) {
|
||||
case NOT_DEFINED_YET:
|
||||
lptr->defn.is_global = LOCAL_SYMBOL;
|
||||
break;
|
||||
case GLOBAL_PLACEHOLDER:
|
||||
lptr->defn.is_global = GLOBAL_SYMBOL;
|
||||
break;
|
||||
default:
|
||||
if (lptr->defn.is_global & DEFINED_BIT) {
|
||||
error(ERR_NONFATAL, "symbol `%s' redefined", label);
|
||||
return;
|
||||
}
|
||||
lptr->defn.is_global |= DEFINED_BIT;
|
||||
if (isextrn)
|
||||
lptr->defn.is_global |= EXTERN_BIT;
|
||||
|
||||
if (label[0] != '.') /* not local, but not special either */
|
||||
if (label[0] != '.' && is_norm) /* not local, but not special either */
|
||||
prevlabel = lptr->defn.label;
|
||||
else if (label[1] != '.' && !*prevlabel)
|
||||
else if (label[0] == '.' && label[1] != '.' && !*prevlabel)
|
||||
error(ERR_NONFATAL, "attempt to define a local label before any"
|
||||
" non-local labels");
|
||||
|
||||
|
|
@ -165,25 +184,20 @@ void define_label (char *label, long segment, long offset,
|
|||
lptr->defn.offset = offset;
|
||||
|
||||
ofmt->symdef (lptr->defn.label, segment, offset,
|
||||
lptr->defn.is_global == GLOBAL_SYMBOL);
|
||||
!!(lptr->defn.is_global & GLOBAL_BIT),
|
||||
special ? special : lptr->defn.special);
|
||||
}
|
||||
|
||||
void define_common (char *label, long segment, long size,
|
||||
void define_common (char *label, long segment, long size, char *special,
|
||||
struct ofmt *ofmt, efunc error) {
|
||||
union label *lptr;
|
||||
|
||||
lptr = find_label (label, 1);
|
||||
switch (lptr->defn.is_global) {
|
||||
case NOT_DEFINED_YET:
|
||||
lptr->defn.is_global = LOCAL_SYMBOL;
|
||||
break;
|
||||
case GLOBAL_PLACEHOLDER:
|
||||
lptr->defn.is_global = GLOBAL_SYMBOL;
|
||||
break;
|
||||
default:
|
||||
if (lptr->defn.is_global & DEFINED_BIT) {
|
||||
error(ERR_NONFATAL, "symbol `%s' redefined", label);
|
||||
return;
|
||||
}
|
||||
lptr->defn.is_global |= DEFINED_BIT;
|
||||
|
||||
if (label[0] != '.') /* not local, but not special either */
|
||||
prevlabel = lptr->defn.label;
|
||||
|
|
@ -194,10 +208,11 @@ void define_common (char *label, long segment, long size,
|
|||
lptr->defn.segment = segment;
|
||||
lptr->defn.offset = 0;
|
||||
|
||||
ofmt->symdef (lptr->defn.label, segment, size, 2);
|
||||
ofmt->symdef (lptr->defn.label, segment, size, 2,
|
||||
special ? special : lptr->defn.special);
|
||||
}
|
||||
|
||||
void declare_as_global (char *label, efunc error) {
|
||||
void declare_as_global (char *label, char *special, efunc error) {
|
||||
union label *lptr;
|
||||
|
||||
if (islocal(label)) {
|
||||
|
|
@ -206,16 +221,18 @@ void declare_as_global (char *label, efunc error) {
|
|||
return;
|
||||
}
|
||||
lptr = find_label (label, 1);
|
||||
switch (lptr->defn.is_global) {
|
||||
switch (lptr->defn.is_global & TYPE_MASK) {
|
||||
case NOT_DEFINED_YET:
|
||||
lptr->defn.is_global = GLOBAL_PLACEHOLDER;
|
||||
lptr->defn.special = special ? perm_copy(special, "") : NULL;
|
||||
break;
|
||||
case GLOBAL_PLACEHOLDER: /* already done: silently ignore */
|
||||
case GLOBAL_SYMBOL:
|
||||
break;
|
||||
case LOCAL_SYMBOL:
|
||||
error(ERR_NONFATAL, "symbol `%s': [GLOBAL] directive must"
|
||||
" appear before symbol definition", label);
|
||||
if (!lptr->defn.is_global & EXTERN_BIT)
|
||||
error(ERR_NONFATAL, "symbol `%s': GLOBAL directive must"
|
||||
" appear before symbol definition", label);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -241,12 +258,16 @@ int init_labels (void) {
|
|||
|
||||
prevlabel = "";
|
||||
|
||||
initialised = TRUE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cleanup_labels (void) {
|
||||
int i;
|
||||
|
||||
initialised = FALSE;
|
||||
|
||||
for (i=0; i<LABEL_HASHES; i++) {
|
||||
union label *lptr, *lhold;
|
||||
|
||||
|
|
|
|||
9
labels.h
9
labels.h
|
|
@ -7,11 +7,12 @@
|
|||
*/
|
||||
|
||||
int lookup_label (char *label, long *segment, long *offset);
|
||||
void define_label (char *label, long segment, long offset,
|
||||
struct ofmt *ofmt, efunc error);
|
||||
void define_common (char *label, long segment, long size,
|
||||
int is_extern (char *label);
|
||||
void define_label (char *label, long segment, long offset, char *special,
|
||||
int is_norm, int isextrn, struct ofmt *ofmt, efunc error);
|
||||
void define_common (char *label, long segment, long size, char *special,
|
||||
struct ofmt *ofmt, efunc error);
|
||||
void define_label_stub (char *label, efunc error);
|
||||
void declare_as_global (char *label, efunc error);
|
||||
void declare_as_global (char *label, char *special, efunc error);
|
||||
int init_labels (void);
|
||||
void cleanup_labels (void);
|
||||
|
|
|
|||
175
macros.bas
Normal file
175
macros.bas
Normal file
|
|
@ -0,0 +1,175 @@
|
|||
' INFO_1: Converter for STANDARD.MAC to MACRO.C
|
||||
'
|
||||
' INFO_2: Written by Mark Junker in 1997
|
||||
' InterNet: mjs@prg.hannover.sgh-net.de
|
||||
' FIDO: Mark Junker@2:2437/47.21
|
||||
'
|
||||
' COMMENT: To start the program press SHIFT+F5 within the QBasic IDE
|
||||
' or start it from the command-line with QBASIC /RUN MACROS
|
||||
'
|
||||
|
||||
DEFINT A-Z
|
||||
|
||||
DECLARE FUNCTION StrTrimLeft$ (a$, b$)
|
||||
DECLARE FUNCTION StrTrimRight$ (a$, b$)
|
||||
DECLARE FUNCTION StrTrim$ (a$, b$)
|
||||
DECLARE SUB StrSplitString (SplitString$, SplitChars$, SplitField$(), SplitCount%)
|
||||
DECLARE FUNCTION Min% (a%, b%)
|
||||
DECLARE FUNCTION StrInstrLeft% (SearchStart%, SearchIn$, SearchFor$)
|
||||
DECLARE FUNCTION StrAscii% (a$)
|
||||
|
||||
|
||||
CLS
|
||||
DIM LineData$(1 TO 2)
|
||||
|
||||
OPEN "I", 1, "STANDARD.MAC"
|
||||
OPEN "O", 2, "macros.c"
|
||||
|
||||
PRINT #2, "/* This file auto-generated from standard.mac by macros.bas - don't edit it */"
|
||||
PRINT #2, ""
|
||||
PRINT #2, "static char *stdmac[] = {"
|
||||
|
||||
WHILE NOT EOF(1)
|
||||
LINE INPUT #1, l$
|
||||
CALL StrSplitString(l$, ";", LineData$(), SplitCount)
|
||||
IF SplitCount THEN
|
||||
LineData$(1) = StrTrim$(LineData$(1), CHR$(9) + " ")
|
||||
IF LEN(LineData$(1)) THEN
|
||||
PRINT #2, " " + CHR$(34) + LineData$(1) + CHR$(34) + ","
|
||||
END IF
|
||||
END IF
|
||||
WEND
|
||||
PRINT #2, " NULL"
|
||||
PRINT #2, "};"
|
||||
|
||||
CLOSE 2
|
||||
CLOSE 1
|
||||
SYSTEM
|
||||
|
||||
FUNCTION Min% (a%, b%)
|
||||
IF a% < b% THEN Min% = a% ELSE Min% = b%
|
||||
END FUNCTION
|
||||
|
||||
FUNCTION StrAscii (a$)
|
||||
IF LEN(a$) = 0 THEN
|
||||
StrAscii = -1
|
||||
ELSE
|
||||
StrAscii = ASC(a$)
|
||||
END IF
|
||||
END FUNCTION
|
||||
|
||||
' same as =INSTR(SearchStart, SearchIn, ANY SearchFor$) in PowerBASIC(tm)
|
||||
'
|
||||
FUNCTION StrInstrLeft (SearchStart, SearchIn$, SearchFor$)
|
||||
ValuesCount = LEN(SearchFor$)
|
||||
MaxValue = LEN(SearchIn$) + 1
|
||||
MinValue = MaxValue
|
||||
FOR Counter1 = 1 TO ValuesCount
|
||||
SearchChar$ = MID$(SearchFor$, Counter1, 1)
|
||||
hVal2 = INSTR(SearchStart, SearchIn$, SearchChar$)
|
||||
IF hVal2 > 0 THEN MinValue = Min%(hVal2, MinValue)
|
||||
NEXT
|
||||
IF MinValue = MaxValue THEN MinValue = 0
|
||||
StrInstrLeft = MinValue
|
||||
END FUNCTION
|
||||
|
||||
'
|
||||
' This is a very damn fuckin' shit version of this splitting routine.
|
||||
' At this time, it's not very useful :]
|
||||
'
|
||||
SUB StrSplitString (SplitString$, SplitChars$, SplitField$(), SplitCount)
|
||||
StartIndex = LBOUND(SplitField$)
|
||||
LastIndex = UBOUND(SplitField$)
|
||||
ActualIndex& = StartIndex
|
||||
SplitCount = 0
|
||||
|
||||
LastPos = 1
|
||||
FoundPos = StrInstrLeft(LastPos, SplitString$, SplitChars$ + CHR$(34))
|
||||
GetDirect = 0
|
||||
EndLoop = 0
|
||||
TempString$ = ""
|
||||
DO WHILE FoundPos > 0
|
||||
FoundCharVal = StrAscii(MID$(SplitString$, FoundPos, 1))
|
||||
PosDiff = (FoundPos - LastPos) + 1
|
||||
SELECT CASE FoundCharVal
|
||||
CASE 34
|
||||
TempString$ = TempString$ + MID$(SplitString$, LastPos, PosDiff - 1)
|
||||
SELECT CASE EndLoop
|
||||
CASE 0
|
||||
EndLoop = 2
|
||||
CASE 3
|
||||
EndLoop = 0
|
||||
END SELECT
|
||||
CASE ELSE
|
||||
TempString$ = TempString$ + MID$(SplitString$, LastPos, PosDiff - 1)
|
||||
SplitField$(ActualIndex&) = TempString$
|
||||
TempString$ = ""
|
||||
ActualIndex& = ActualIndex& + 1
|
||||
IF ActualIndex& > LastIndex THEN
|
||||
ActualIndex& = LastIndex
|
||||
EndLoop = 1
|
||||
END IF
|
||||
END SELECT
|
||||
SELECT CASE EndLoop
|
||||
CASE 0
|
||||
DO
|
||||
LastPos = FoundPos + 1
|
||||
FoundPos = StrInstrLeft(LastPos, SplitString$, SplitChars$)
|
||||
LOOP WHILE LastPos = FoundPos
|
||||
FoundPos = StrInstrLeft(LastPos, SplitString$, SplitChars$ + CHR$(34))
|
||||
CASE 1
|
||||
FoundPos = 0
|
||||
LastPos = LEN(SplitString$) + 1
|
||||
CASE 2
|
||||
EndLoop = 3
|
||||
LastPos = FoundPos + 1
|
||||
FoundPos = StrInstrLeft(LastPos, SplitString$, CHR$(34))
|
||||
IF FoundPos = 0 THEN
|
||||
SplitString$ = SplitString$ + CHR$(34)
|
||||
FoundPos = LEN(SplitString$)
|
||||
END IF
|
||||
END SELECT
|
||||
LOOP
|
||||
IF EndLoop = 0 THEN
|
||||
IF LEN(TempString$) > 0 THEN
|
||||
SplitField$(ActualIndex&) = TempString$
|
||||
ELSEIF LastPos <= LEN(SplitString$) THEN
|
||||
SplitField$(ActualIndex&) = MID$(SplitString$, LastPos)
|
||||
ELSE
|
||||
ActualIndex& = ActualIndex& - 1
|
||||
END IF
|
||||
END IF
|
||||
FOR a = ActualIndex& + 1 TO LastIndex
|
||||
SplitField$(a) = ""
|
||||
NEXT
|
||||
SplitCount = (ActualIndex& - StartIndex) + 1
|
||||
END SUB
|
||||
|
||||
FUNCTION StrTrim$ (a$, b$)
|
||||
StrTrim$ = StrTrimRight$(StrTrimLeft$(a$, b$), b$)
|
||||
END FUNCTION
|
||||
|
||||
FUNCTION StrTrimLeft$ (a$, b$) 'public
|
||||
p = 0
|
||||
l = LEN(a$)
|
||||
DO
|
||||
p = p + 1
|
||||
t$ = MID$(a$, p, 1)
|
||||
LOOP WHILE (p < l) AND (INSTR(b$, t$) > 0)
|
||||
StrTrimLeft$ = MID$(a$, p)
|
||||
END FUNCTION
|
||||
|
||||
FUNCTION StrTrimRight$ (a$, b$) 'public
|
||||
l = LEN(a$)
|
||||
p = l + 1
|
||||
DO
|
||||
p = p - 1
|
||||
IF p > 0 THEN
|
||||
t$ = MID$(a$, p, 1)
|
||||
ELSE
|
||||
t$ = ""
|
||||
END IF
|
||||
LOOP WHILE (p > 0) AND (INSTR(b$, t$) > 0)
|
||||
StrTrimRight$ = LEFT$(a$, p)
|
||||
END FUNCTION
|
||||
|
||||
38
macros.c
38
macros.c
|
|
@ -2,7 +2,9 @@
|
|||
|
||||
static char *stdmac[] = {
|
||||
"%define __NASM_MAJOR__ 0",
|
||||
"%define __NASM_MINOR__ 95",
|
||||
"%define __NASM_MINOR__ 96",
|
||||
"%define __FILE__",
|
||||
"%define __LINE__",
|
||||
"%define __SECT__",
|
||||
"%imacro section 1+.nolist",
|
||||
"%define __SECT__ [section %1]",
|
||||
|
|
@ -20,6 +22,7 @@ static char *stdmac[] = {
|
|||
"%push struc",
|
||||
"%define %$strucname %1",
|
||||
"[absolute 0]",
|
||||
"%$strucname:",
|
||||
"%endmacro",
|
||||
"%imacro endstruc 0.nolist",
|
||||
"%{$strucname}_size:",
|
||||
|
|
@ -39,29 +42,32 @@ static char *stdmac[] = {
|
|||
"times %{$strucname}_size-($-%$strucstart) db 0",
|
||||
"%pop",
|
||||
"%endmacro",
|
||||
"%imacro extern 1+.nolist",
|
||||
"%imacro align 1-2+.nolist nop",
|
||||
"times ($$-$) & ((%1)-1) %2",
|
||||
"%endmacro",
|
||||
"%imacro alignb 1-2+.nolist resb 1",
|
||||
"times ($$-$) & ((%1)-1) %2",
|
||||
"%endmacro",
|
||||
"%imacro extern 1-*.nolist",
|
||||
"%rep %0",
|
||||
"[extern %1]",
|
||||
"%rotate 1",
|
||||
"%endrep",
|
||||
"%endmacro",
|
||||
"%imacro bits 1+.nolist",
|
||||
"[bits %1]",
|
||||
"%endmacro",
|
||||
"%imacro global 1+.nolist",
|
||||
"%imacro global 1-*.nolist",
|
||||
"%rep %0",
|
||||
"[global %1]",
|
||||
"%rotate 1",
|
||||
"%endrep",
|
||||
"%endmacro",
|
||||
"%imacro common 1+.nolist",
|
||||
"%imacro common 1-*.nolist",
|
||||
"%rep %0",
|
||||
"[common %1]",
|
||||
"%endmacro",
|
||||
"%imacro org 1+.nolist",
|
||||
"[org %1]",
|
||||
"%endmacro",
|
||||
"%imacro group 1+.nolist",
|
||||
"[group %1]",
|
||||
"%endmacro",
|
||||
"%imacro uppercase 1+.nolist",
|
||||
"[uppercase %1]",
|
||||
"%endmacro",
|
||||
"%imacro library 1+.nolist",
|
||||
"[library %1]",
|
||||
"%rotate 1",
|
||||
"%endrep",
|
||||
"%endmacro",
|
||||
NULL
|
||||
};
|
||||
|
|
|
|||
|
|
@ -7,7 +7,8 @@
|
|||
# redistributable under the licence given in the file "Licence"
|
||||
# distributed in the NASM archive.
|
||||
|
||||
open INPUT,"standard.mac" || die "unable to open standard.mac\n";
|
||||
$fname = "standard.mac" unless $fname = $ARGV[0];
|
||||
open INPUT,$fname || die "unable to open $fname\n";
|
||||
open OUTPUT,">macros.c" || die "unable to open macros.c\n";
|
||||
|
||||
print OUTPUT "/* This file auto-generated from standard.mac by macros.pl" .
|
||||
|
|
|
|||
37
misc/c16.mac
Normal file
37
misc/c16.mac
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
; NASM macro set to make interfacing to 16-bit programs easier -*- nasm -*-
|
||||
|
||||
%imacro proc 1 ; begin a procedure definition
|
||||
%push proc
|
||||
global %1
|
||||
%1: push bp
|
||||
mov bp,sp
|
||||
%ifdef FARCODE PASCAL ; arguments may start at bp+4 or bp+6
|
||||
%assign %$arg 6
|
||||
%else
|
||||
%assign %$arg 4
|
||||
%endif
|
||||
%define %$procname %1
|
||||
%endmacro
|
||||
|
||||
%imacro arg 0-1 2 ; used with the argument name as a label
|
||||
equ %$arg
|
||||
%assign %$arg %1+%$arg
|
||||
%endmacro
|
||||
|
||||
%imacro endproc 0
|
||||
%ifnctx proc
|
||||
%error Mismatched `endproc'/`proc'
|
||||
%else
|
||||
mov sp,bp
|
||||
pop bp
|
||||
%ifdef PASCAL
|
||||
retf %$arg
|
||||
%elifdef FARCODE
|
||||
retf
|
||||
%else
|
||||
retn
|
||||
%endif
|
||||
__end_%$procname: ; useful for calculating function size
|
||||
%pop
|
||||
%endif
|
||||
%endmacro
|
||||
26
misc/c32.mac
Normal file
26
misc/c32.mac
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
; NASM macro set to make interfacing to 32-bit programs easier -*- nasm -*-
|
||||
|
||||
%imacro proc 1 ; begin a procedure definition
|
||||
%push proc
|
||||
global %1
|
||||
%1: push ebp
|
||||
mov ebp,esp
|
||||
%assign %$arg 8
|
||||
%define %$procname %1
|
||||
%endmacro
|
||||
|
||||
%imacro arg 0-1 4 ; used with the argument name as a label
|
||||
equ %$arg
|
||||
%assign %$arg %1+%$arg
|
||||
%endmacro
|
||||
|
||||
%imacro endproc 0
|
||||
%ifnctx proc
|
||||
%error Mismatched `endproc'/`proc'
|
||||
%else
|
||||
leave
|
||||
ret
|
||||
__end_%$procname: ; useful for calculating function size
|
||||
%pop
|
||||
%endif
|
||||
%endmacro
|
||||
BIN
misc/exasm.zip
Normal file
BIN
misc/exasm.zip
Normal file
Binary file not shown.
57
misc/exebin.mac
Normal file
57
misc/exebin.mac
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
; -*- nasm -*-
|
||||
; NASM macro file to allow the `bin' output format to generate
|
||||
; simple .EXE files by constructing the EXE header by hand.
|
||||
; Adapted from a contribution by Yann Guidon <whygee_corp@hol.fr>
|
||||
|
||||
%define EXE_stack_size EXE_realstacksize
|
||||
|
||||
%macro EXE_begin 0
|
||||
ORG 0E0h
|
||||
section .text
|
||||
|
||||
header_start:
|
||||
db 4Dh,5Ah ; EXE file signature
|
||||
dw EXE_allocsize % 512
|
||||
dw (EXE_allocsize + 511) / 512
|
||||
dw 0 ; relocation information: none
|
||||
dw (header_end-header_start)/16 ; header size in paragraphs
|
||||
dw (EXE_absssize + EXE_realstacksize) / 16 ; min extra mem
|
||||
dw (EXE_absssize + EXE_realstacksize) / 16 ; max extra mem
|
||||
dw -10h ; Initial SS (before fixup)
|
||||
dw EXE_endbss + EXE_realstacksize ; Initial SP (1K DPMI+1K STACK)
|
||||
dw 0 ; (no) Checksum
|
||||
dw 100h ; Initial IP - start just after the header
|
||||
dw -10h ; Initial CS (before fixup)
|
||||
dw 0 ; file offset to relocation table: none
|
||||
dw 0 ; (no overlay)
|
||||
align 16,db 0
|
||||
header_end:
|
||||
|
||||
EXE_startcode:
|
||||
section .data
|
||||
EXE_startdata:
|
||||
section .bss
|
||||
EXE_startbss:
|
||||
%endmacro
|
||||
|
||||
%macro EXE_stack 1
|
||||
EXE_realstacksize equ %1
|
||||
%define EXE_stack_size EXE_bogusstacksize ; defeat EQU in EXE_end
|
||||
%endmacro
|
||||
|
||||
%macro EXE_end 0
|
||||
section .text
|
||||
EXE_endcode:
|
||||
section .data
|
||||
EXE_enddata:
|
||||
section .bss
|
||||
alignb 4
|
||||
EXE_endbss:
|
||||
|
||||
EXE_acodesize equ (EXE_endcode-EXE_startcode+3) & (~3)
|
||||
EXE_datasize equ EXE_enddata-EXE_startdata
|
||||
EXE_absssize equ (EXE_endbss-EXE_startbss+3) & (~3)
|
||||
EXE_allocsize equ EXE_acodesize + EXE_datasize
|
||||
|
||||
EXE_stack_size equ 0x800 ; default if nothing else was used
|
||||
%endmacro
|
||||
|
|
@ -294,6 +294,14 @@ define_keywords_n($1, nasm_kw_8, 8, 0);
|
|||
define_keywords_n($1, nasm_kw_9, 9, 0);
|
||||
define_keywords_n($1, nasm_kw_10, 10, 0);
|
||||
|
||||
define_keywords_n($1, "org", 3, 1);
|
||||
define_keywords_n($1, "bitsiend", 4, 1);
|
||||
define_keywords_n($1, "aligngroupstruc", 5, 1);
|
||||
define_keywords_n($1, "alignbcommonexternglobalistruc", 6, 1);
|
||||
define_keywords_n($1, "sectionsegmentlibrary", 7, 1);
|
||||
define_keywords_n($1, "absoluteendstruc", 8, 1);
|
||||
define_keywords_n($1, "uppercase", 9, 1);
|
||||
|
||||
!if (keymap_p ($1)) make_keymap ($1);
|
||||
definekey("nasm_bol_self_ins", ";", $1);
|
||||
definekey("nasm_bol_self_ins", "#", $1);
|
||||
|
|
|
|||
68
names.c
68
names.c
|
|
@ -8,7 +8,7 @@
|
|||
*/
|
||||
|
||||
static char *reg_names[] = { /* register names, as strings */
|
||||
"\0", "ah", "al", "ax", "bh", "bl", "bp", "bx", "ch", "cl",
|
||||
"ah", "al", "ax", "bh", "bl", "bp", "bx", "ch", "cl",
|
||||
"cr0", "cr2", "cr3", "cr4", "cs", "cx", "dh", "di", "dl", "dr0",
|
||||
"dr1", "dr2", "dr3", "dr6", "dr7", "ds", "dx", "eax", "ebp",
|
||||
"ebx", "ecx", "edi", "edx", "es", "esi", "esp", "fs", "gs",
|
||||
|
|
@ -32,37 +32,41 @@ static char *insn_names[] = { /* instruction names, as strings */
|
|||
"fidivr", "fild", "fimul", "fincstp", "finit", "fist", "fistp",
|
||||
"fisub", "fisubr", "fld", "fld1", "fldcw", "fldenv", "fldl2e",
|
||||
"fldl2t", "fldlg2", "fldln2", "fldpi", "fldz", "fmul", "fmulp",
|
||||
"fnop", "fpatan", "fprem", "fprem1", "fptan", "frndint",
|
||||
"frstor", "fsave", "fscale", "fsetpm", "fsin", "fsincos",
|
||||
"fsqrt", "fst", "fstcw", "fstenv", "fstp", "fstsw", "fsub",
|
||||
"fsubp", "fsubr", "fsubrp", "ftst", "fucom", "fucomi",
|
||||
"fucomip", "fucomp", "fucompp", "fxam", "fxch", "fxtract",
|
||||
"fyl2x", "fyl2xp1", "hlt", "ibts", "icebp", "idiv", "imul",
|
||||
"in", "inc", "incbin", "insb", "insd", "insw", "int", "int1",
|
||||
"int01", "int3", "into", "invd", "invlpg", "iret", "iretd",
|
||||
"iretw", "jcxz", "jecxz", "jmp", "lahf", "lar", "lds", "lea",
|
||||
"leave", "les", "lfs", "lgdt", "lgs", "lidt", "lldt", "lmsw",
|
||||
"loadall", "loadall286", "lodsb", "lodsd", "lodsw", "loop",
|
||||
"loope", "loopne", "loopnz", "loopz", "lsl", "lss", "ltr",
|
||||
"mov", "movd", "movq", "movsb", "movsd", "movsw", "movsx",
|
||||
"movzx", "mul", "neg", "nop", "not", "or", "out", "outsb",
|
||||
"outsd", "outsw", "packssdw", "packsswb", "packuswb", "paddb",
|
||||
"paddd", "paddsb", "paddsw", "paddusb", "paddusw", "paddw",
|
||||
"pand", "pandn", "pcmpeqb", "pcmpeqd", "pcmpeqw", "pcmpgtb",
|
||||
"pcmpgtd", "pcmpgtw", "pmaddwd", "pmulhw", "pmullw", "pop",
|
||||
"popa", "popad", "popaw", "popf", "popfd", "popfw", "por",
|
||||
"pslld", "psllq", "psllw", "psrad", "psraw", "psrld", "psrlq",
|
||||
"psrlw", "psubb", "psubd", "psubsb", "psubsw", "psubusb",
|
||||
"psubusw", "psubw", "punpckhbw", "punpckhdq", "punpckhwd",
|
||||
"punpcklbw", "punpckldq", "punpcklwd", "push", "pusha",
|
||||
"pushad", "pushaw", "pushf", "pushfd", "pushfw", "pxor", "rcl",
|
||||
"rcr", "rdmsr", "rdpmc", "rdtsc", "resb", "resd", "resq",
|
||||
"rest", "resw", "ret", "retf", "retn", "rol", "ror", "rsm",
|
||||
"sahf", "sal", "salc", "sar", "sbb", "scasb", "scasd", "scasw",
|
||||
"sgdt", "shl", "shld", "shr", "shrd", "sidt", "sldt", "smi",
|
||||
"smsw", "stc", "std", "sti", "stosb", "stosd", "stosw", "str",
|
||||
"sub", "test", "umov", "verr", "verw", "wait", "wbinvd",
|
||||
"wrmsr", "xadd", "xbts", "xchg", "xlatb", "xor"
|
||||
"fnclex", "fndisi", "fneni", "fninit", "fnop", "fnsave",
|
||||
"fnstcw", "fnstenv", "fnstsw", "fpatan", "fprem", "fprem1",
|
||||
"fptan", "frndint", "frstor", "fsave", "fscale", "fsetpm",
|
||||
"fsin", "fsincos", "fsqrt", "fst", "fstcw", "fstenv", "fstp",
|
||||
"fstsw", "fsub", "fsubp", "fsubr", "fsubrp", "ftst", "fucom",
|
||||
"fucomi", "fucomip", "fucomp", "fucompp", "fxam", "fxch",
|
||||
"fxtract", "fyl2x", "fyl2xp1", "hlt", "ibts", "icebp", "idiv",
|
||||
"imul", "in", "inc", "incbin", "insb", "insd", "insw", "int",
|
||||
"int1", "int01", "int3", "into", "invd", "invlpg", "iret",
|
||||
"iretd", "iretw", "jcxz", "jecxz", "jmp", "lahf", "lar", "lds",
|
||||
"lea", "leave", "les", "lfs", "lgdt", "lgs", "lidt", "lldt",
|
||||
"lmsw", "loadall", "loadall286", "lodsb", "lodsd", "lodsw",
|
||||
"loop", "loope", "loopne", "loopnz", "loopz", "lsl", "lss",
|
||||
"ltr", "mov", "movd", "movq", "movsb", "movsd", "movsw",
|
||||
"movsx", "movzx", "mul", "neg", "nop", "not", "or", "out",
|
||||
"outsb", "outsd", "outsw", "packssdw", "packsswb", "packuswb",
|
||||
"paddb", "paddd", "paddsb", "paddsiw", "paddsw", "paddusb",
|
||||
"paddusw", "paddw", "pand", "pandn", "paveb", "pcmpeqb",
|
||||
"pcmpeqd", "pcmpeqw", "pcmpgtb", "pcmpgtd", "pcmpgtw",
|
||||
"pdistib", "pmachriw", "pmaddwd", "pmagw", "pmulhrw",
|
||||
"pmulhriw", "pmulhw", "pmullw", "pmvgezb", "pmvlzb", "pmvnzb",
|
||||
"pmvzb", "pop", "popa", "popad", "popaw", "popf", "popfd",
|
||||
"popfw", "por", "pslld", "psllq", "psllw", "psrad", "psraw",
|
||||
"psrld", "psrlq", "psrlw", "psubb", "psubd", "psubsb",
|
||||
"psubsiw", "psubsw", "psubusb", "psubusw", "psubw", "punpckhbw",
|
||||
"punpckhdq", "punpckhwd", "punpcklbw", "punpckldq", "punpcklwd",
|
||||
"push", "pusha", "pushad", "pushaw", "pushf", "pushfd",
|
||||
"pushfw", "pxor", "rcl", "rcr", "rdmsr", "rdpmc", "rdtsc",
|
||||
"resb", "resd", "resq", "rest", "resw", "ret", "retf", "retn",
|
||||
"rol", "ror", "rsm", "sahf", "sal", "salc", "sar", "sbb",
|
||||
"scasb", "scasd", "scasw", "sgdt", "shl", "shld", "shr", "shrd",
|
||||
"sidt", "sldt", "smi", "smsw", "stc", "std", "sti", "stosb",
|
||||
"stosd", "stosw", "str", "sub", "test", "umov", "verr", "verw",
|
||||
"wait", "wbinvd", "wrmsr", "xadd", "xbts", "xchg", "xlatb",
|
||||
"xor"
|
||||
};
|
||||
|
||||
static char *icn[] = { /* conditional instructions */
|
||||
|
|
|
|||
423
nasm.1
Normal file
423
nasm.1
Normal file
|
|
@ -0,0 +1,423 @@
|
|||
.TH NASM 1 "The Netwide Assembler Project"
|
||||
.SH NAME
|
||||
nasm \- the Netwide Assembler \- portable 80x86 assembler
|
||||
.SH SYNOPSIS
|
||||
.B nasm
|
||||
[
|
||||
.B \-f
|
||||
format
|
||||
] [
|
||||
.B \-o
|
||||
outfile
|
||||
] [
|
||||
.IR options ...
|
||||
] infile
|
||||
.br
|
||||
.B nasm \-h
|
||||
.br
|
||||
.B nasm \-r
|
||||
.SH DESCRIPTION
|
||||
The
|
||||
.B nasm
|
||||
command assembles the file
|
||||
.I infile
|
||||
and directs output to the file
|
||||
.I outfile
|
||||
if specified. If
|
||||
.I outfile
|
||||
is not specified,
|
||||
.B nasm
|
||||
will derive a default output file name from the name of its input
|
||||
file, usually by appending `.o' or `.obj', or by removing all
|
||||
extensions for a raw binary file. Failing that, the output file name
|
||||
will be `nasm.out'.
|
||||
.SS OPTIONS
|
||||
.TP
|
||||
.B \-h
|
||||
Causes
|
||||
.B nasm
|
||||
to exit immediately, after giving a summary of its invocation
|
||||
options, and listing all its supported output file formats.
|
||||
.TP
|
||||
.B \-a
|
||||
Causes
|
||||
.B nasm
|
||||
to assemble the given input file without first applying the macro
|
||||
preprocessor.
|
||||
.TP
|
||||
.B \-e
|
||||
Causes
|
||||
.B nasm
|
||||
to preprocess the given input file, and write the output to
|
||||
.I stdout
|
||||
(or the specified output file name), and not actually assemble
|
||||
anything.
|
||||
.TP
|
||||
.BI \-r
|
||||
Causes
|
||||
.B nasm
|
||||
to exit immediately, after displaying its version number.
|
||||
.TP
|
||||
.BI \-f " format"
|
||||
Specifies the output file format. Formats include
|
||||
.IR bin ,
|
||||
to produce flat-form binary files, and
|
||||
.I aout
|
||||
and
|
||||
.I elf
|
||||
to produce Linux a.out and ELF object files, respectively.
|
||||
.TP
|
||||
.BI \-o " outfile"
|
||||
Specifies a precise name for the output file, overriding
|
||||
.BR nasm 's
|
||||
default means of determining it.
|
||||
.TP
|
||||
.BI \-l " listfile"
|
||||
Causes an assembly listing to be directed to the given file, in
|
||||
which the original source is displayed on the right hand side (plus
|
||||
the source for included files and the expansions of multi-line
|
||||
macros) and the generated code is shown in hex on the left.
|
||||
.TP
|
||||
.B \-s
|
||||
Causes
|
||||
.B nasm
|
||||
to send its error messages and/or help text to
|
||||
.I stdout
|
||||
instead of
|
||||
.IR stderr .
|
||||
.TP
|
||||
.BI \-w [+-]foo
|
||||
Causes
|
||||
.B nasm
|
||||
to enable or disable certain classes of warning messages, for
|
||||
example
|
||||
.B \-w+orphan-labels
|
||||
or
|
||||
.B \-w-macro-params
|
||||
to, respectively, enable warnings about labels alone on lines or
|
||||
disable warnings about incorrect numbers of parameters in macro
|
||||
calls.
|
||||
.TP
|
||||
.BI \-i " directory"
|
||||
Adds a directory to the search path for include files. The directory
|
||||
specification must include the trailing slash, as it will be
|
||||
directly prepended to the name of the include file.
|
||||
.TP
|
||||
.BI \-p " file"
|
||||
Specifies a file to be pre-included, before the main source file
|
||||
starts to be processed.
|
||||
.TP
|
||||
.BI \-d " macro[=value]"
|
||||
Pre-defines a single-line macro.
|
||||
.PP
|
||||
.RE
|
||||
.SS SYNTAX
|
||||
This man page does not fully describe the syntax of
|
||||
.BR nasm 's
|
||||
assembly language, but does give a summary of the differences from
|
||||
other assemblers.
|
||||
.PP
|
||||
.I Registers
|
||||
have no leading `%' sign, unlike
|
||||
.BR gas ,
|
||||
and floating-point stack registers are referred to as
|
||||
.IR st0 ,
|
||||
.IR st1 ,
|
||||
and so on.
|
||||
.PP
|
||||
.I Floating-point instructions
|
||||
may use either the single-operand form or the double. A
|
||||
.I TO
|
||||
keyword is provided; thus, one could either write
|
||||
.PP
|
||||
.ti +15n
|
||||
fadd st0,st1
|
||||
.br
|
||||
.ti +15n
|
||||
fadd st1,st0
|
||||
.PP
|
||||
or one could use the alternative single-operand forms
|
||||
.PP
|
||||
.ti +15n
|
||||
fadd st1
|
||||
.br
|
||||
.ti +15n
|
||||
fadd to st1
|
||||
.PP
|
||||
.I Uninitialised storage
|
||||
is reserved using the
|
||||
.IR RESB ,
|
||||
.IR RESW ,
|
||||
.IR RESD ,
|
||||
.I RESQ
|
||||
and
|
||||
.I REST
|
||||
pseudo-opcodes, each taking one parameter which gives the number of
|
||||
bytes, words, doublewords, quadwords or ten-byte words to reserve.
|
||||
.PP
|
||||
.I Repetition
|
||||
of data items is not done by the
|
||||
.I DUP
|
||||
keyword as seen in DOS assemblers, but by the use of the
|
||||
.I TIMES
|
||||
prefix, like this:
|
||||
.PP
|
||||
.ti +6n
|
||||
.ta 9n
|
||||
message: times 3 db 'abc'
|
||||
.br
|
||||
.ti +15n
|
||||
times 64-$+message db 0
|
||||
.PP
|
||||
which defines the string `abcabcabc', followed by the right number
|
||||
of zero bytes to make the total length up to 64 bytes.
|
||||
.PP
|
||||
.I Symbol references
|
||||
are always understood to be immediate (i.e. the address of the
|
||||
symbol), unless square brackets are used, in which case the contents
|
||||
of the memory location are used. Thus:
|
||||
.PP
|
||||
.ti +15n
|
||||
mov ax,wordvar
|
||||
.PP
|
||||
loads AX with the address of the variable `wordvar', whereas
|
||||
.PP
|
||||
.ti +15n
|
||||
mov ax,[wordvar]
|
||||
.br
|
||||
.ti +15n
|
||||
mov ax,[wordvar+1]
|
||||
.br
|
||||
.ti +15n
|
||||
mov ax,[es:wordvar+bx]
|
||||
.PP
|
||||
all refer to the
|
||||
.I contents
|
||||
of memory locations. The syntaxes
|
||||
.PP
|
||||
.ti +15n
|
||||
mov ax,es:wordvar[bx]
|
||||
.br
|
||||
.ti +15n
|
||||
es mov ax,wordvar[1]
|
||||
.PP
|
||||
are not legal at all, although the use of a segment register name as
|
||||
an instruction prefix is valid, and can be used with instructions
|
||||
such as
|
||||
.I LODSB
|
||||
which can't be overridden any other way.
|
||||
.PP
|
||||
.I Constants
|
||||
may be expressed numerically in most formats: a trailing H, Q or B
|
||||
denotes hex, octal or binary respectively, and a leading `0x' or `$'
|
||||
denotes hex as well. Leading zeros are not treated specially at all.
|
||||
Character constants may be enclosed in single or double quotes;
|
||||
there is no escape character. The ordering is little-endian
|
||||
(reversed), so that the character constant
|
||||
.I 'abcd'
|
||||
denotes 0x64636261 and not 0x61626364.
|
||||
.PP
|
||||
.I Local labels
|
||||
begin with a period, and their `locality' is granted by the
|
||||
assembler prepending the name of the previous non-local symbol. Thus
|
||||
declaring a label `.loop' after a label `label' has actually defined
|
||||
a symbol called `label.loop'.
|
||||
.SS DIRECTIVES
|
||||
.I SECTION name
|
||||
or
|
||||
.I SEGMENT name
|
||||
causes
|
||||
.B nasm
|
||||
to direct all following code to the named section. Section names
|
||||
vary with output file format, although most formats support the
|
||||
names
|
||||
.IR .text ,
|
||||
.I .data
|
||||
and
|
||||
.IR .bss .
|
||||
(The exception is the
|
||||
.I obj
|
||||
format, in which all segments are user-definable.)
|
||||
.PP
|
||||
.I ABSOLUTE address
|
||||
causes
|
||||
.B nasm
|
||||
to position its notional assembly point at an absolute address: so
|
||||
no code or data may be generated, but you can use
|
||||
.IR RESB ,
|
||||
.I RESW
|
||||
and
|
||||
.I RESD
|
||||
to move the assembly point further on, and you can define labels. So
|
||||
this directive may be used to define data structures. When you have
|
||||
finished doing absolute assembly, you must issue another
|
||||
.I SECTION
|
||||
directive to return to normal assembly.
|
||||
.PP
|
||||
.I BITS 16
|
||||
or
|
||||
.I BITS 32
|
||||
switches the default processor mode for which
|
||||
.B nasm
|
||||
is generating code: it is equivalent to
|
||||
.I USE16
|
||||
or
|
||||
.I USE32
|
||||
in DOS assemblers.
|
||||
.PP
|
||||
.I EXTERN symbol
|
||||
and
|
||||
.I GLOBAL symbol
|
||||
import and export symbol definitions, respectively, from and to
|
||||
other modules. Note that the
|
||||
.I GLOBAL
|
||||
directive must appear before the definition of the symbol it refers
|
||||
to.
|
||||
.PP
|
||||
.I STRUC strucname
|
||||
and
|
||||
.IR ENDSTRUC ,
|
||||
when used to bracket a number of
|
||||
.IR RESB ,
|
||||
.I RESW
|
||||
or similar instructions, define a data structure. In addition to
|
||||
defining the offsets of the structure members, the construct also
|
||||
defines a symbol for the size of the structure, which is simply the
|
||||
structure name with
|
||||
.I _size
|
||||
tacked on to the end.
|
||||
.SS FORMAT-SPECIFIC DIRECTIVES
|
||||
.I ORG address
|
||||
is used by the
|
||||
.I bin
|
||||
flat-form binary output format, and specifies the address at which
|
||||
the output code will eventually be loaded.
|
||||
.PP
|
||||
.I GROUP grpname seg1 seg2...
|
||||
is used by the
|
||||
.I obj
|
||||
(Microsoft 16-bit) output format, and defines segment groups. This
|
||||
format also uses
|
||||
.IR UPPERCASE ,
|
||||
which directs that all segment, group and symbol names output to the
|
||||
object file should be in uppercase. Note that the actual assembly is
|
||||
still case sensitive.
|
||||
.PP
|
||||
.I LIBRARY libname
|
||||
is used by the
|
||||
.I rdf
|
||||
output format, and causes a dependency record to be written to the
|
||||
output file which indicates that the program requires a certain
|
||||
library in order to run.
|
||||
.SS MACRO PREPROCESSOR
|
||||
Single-line macros are defined using the
|
||||
.I %define
|
||||
or
|
||||
.I %idefine
|
||||
commands, in a similar fashion to the C preprocessor. They can be
|
||||
overloaded with respect to number of parameters, although defining a
|
||||
macro with no parameters prevents the definition of any macro with
|
||||
the same name taking parameters, and vice versa.
|
||||
.I %define
|
||||
defines macros whose names match case-sensitively, whereas
|
||||
.I %idefine
|
||||
defines case-insensitive macros.
|
||||
.PP
|
||||
Multi-line macros are defined using
|
||||
.I %macro
|
||||
and
|
||||
.I %imacro
|
||||
(the distinction is the same as that between
|
||||
.I %define
|
||||
and
|
||||
.IR %idefine ),
|
||||
whose syntax is as follows:
|
||||
.PP
|
||||
.ti +6n
|
||||
%macro
|
||||
.I name
|
||||
.IR minprm [- maxprm "][+][.nolist] [" defaults ]
|
||||
.br
|
||||
.ti +15n
|
||||
<some lines of macro expansion text>
|
||||
.br
|
||||
.ti +6n
|
||||
%endmacro
|
||||
.PP
|
||||
Again, these macros may be overloaded. The trailing plus sign
|
||||
indicates that any parameters after the last one get subsumed, with
|
||||
their separating commas, into the last parameter. The
|
||||
.I defaults
|
||||
part can be used to specify defaults for unspecified macro
|
||||
parameters after
|
||||
.IR minparam .
|
||||
.I %endm
|
||||
is a valid synonym for
|
||||
.IR %endmacro .
|
||||
.PP
|
||||
To refer to the macro parameters within a macro expansion, you use
|
||||
.IR %1 ,
|
||||
.I %2
|
||||
and so on. You can also enforce that a macro parameter should
|
||||
contain a condition code by using
|
||||
.IR %+1 ,
|
||||
and you can invert the condition code by using
|
||||
.IR %-1 .
|
||||
You can also define a label specific to a macro invocation by
|
||||
prefixing it with a double % sign.
|
||||
.PP
|
||||
Files can be included using the
|
||||
.I %include
|
||||
directive, which works like C.
|
||||
.PP
|
||||
The preprocessor has a `context stack', which may be used by one
|
||||
macro to store information that a later one will retrieve. You can
|
||||
push a context on the stack using
|
||||
.IR %push ,
|
||||
remove one using
|
||||
.IR %pop ,
|
||||
and change the name of the top context (without disturbing any
|
||||
associated definitions) using
|
||||
.IR %repl .
|
||||
Labels and
|
||||
.I %define
|
||||
macros specific to the top context may be defined by prefixing their
|
||||
names with %$, and things specific to the next context down with
|
||||
%$$, and so on.
|
||||
.PP
|
||||
Conditional assembly is done by means of
|
||||
.IR %ifdef ,
|
||||
.IR %ifndef ,
|
||||
.I %else
|
||||
and
|
||||
.I %endif
|
||||
as in C. (Except that
|
||||
.I %ifdef
|
||||
can accept several putative macro names, and will evaluate TRUE if
|
||||
any of them is defined.) In addition, the directives
|
||||
.I %ifctx
|
||||
and
|
||||
.I %ifnctx
|
||||
can be used to condition on the name of the top context on the
|
||||
context stack. The obvious set of `else-if' directives,
|
||||
.IR %elifdef ,
|
||||
.IR %elifndef ,
|
||||
.IR %elifctx
|
||||
and
|
||||
.IR %elifnctx
|
||||
are also supported.
|
||||
.SH BUGS
|
||||
There is a reported seg-fault on some (Linux) systems with some
|
||||
large source files. This appears to be very hard to reproduce. All
|
||||
other
|
||||
.I known
|
||||
bugs have been fixed...
|
||||
.SH RESTRICTIONS
|
||||
There is no support for listing files, symbol maps, or debugging
|
||||
object-file records. The advanced features of the ELF and Win32
|
||||
object file formats are not supported, and there is no means for
|
||||
warning the programmer against using an instruction beyond the
|
||||
capability of the target processor.
|
||||
.SH SEE ALSO
|
||||
.BR as "(" 1 "),"
|
||||
.BR ld "(" 1 ")."
|
||||
251
nasm.c
251
nasm.c
|
|
@ -16,6 +16,7 @@
|
|||
#include "nasmlib.h"
|
||||
#include "preproc.h"
|
||||
#include "parser.h"
|
||||
#include "eval.h"
|
||||
#include "assemble.h"
|
||||
#include "labels.h"
|
||||
#include "outform.h"
|
||||
|
|
@ -32,7 +33,6 @@ static char *obuf;
|
|||
static char inname[FILENAME_MAX];
|
||||
static char outname[FILENAME_MAX];
|
||||
static char listname[FILENAME_MAX];
|
||||
static char realout[FILENAME_MAX];
|
||||
static int lineno; /* for error reporting */
|
||||
static int lineinc; /* set by [LINE] or [ONELINE] */
|
||||
static int globallineno; /* for forward-reference tracking */
|
||||
|
|
@ -44,7 +44,7 @@ static int sb = 16; /* by default */
|
|||
|
||||
static int use_stdout = FALSE; /* by default, errors to stderr */
|
||||
|
||||
static long current_seg;
|
||||
static long current_seg, abs_seg;
|
||||
static struct RAA *offsets;
|
||||
static long abs_offset;
|
||||
|
||||
|
|
@ -62,7 +62,7 @@ static char currentfile[FILENAME_MAX];
|
|||
* doesn't do anything. Initial defaults are given here.
|
||||
*/
|
||||
static char suppressed[1+ERR_WARN_MAX] = {
|
||||
0, FALSE, TRUE
|
||||
0, FALSE, TRUE, FALSE
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
@ -70,7 +70,7 @@ static char suppressed[1+ERR_WARN_MAX] = {
|
|||
* zero does nothing.
|
||||
*/
|
||||
static char *suppressed_names[1+ERR_WARN_MAX] = {
|
||||
NULL, "macro-params", "orphan-labels"
|
||||
NULL, "macro-params", "orphan-labels", "number-overflow"
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
@ -79,7 +79,8 @@ static char *suppressed_names[1+ERR_WARN_MAX] = {
|
|||
*/
|
||||
static char *suppressed_what[1+ERR_WARN_MAX] = {
|
||||
NULL, "macro calls with wrong no. of params",
|
||||
"labels alone on lines without trailing `:'"
|
||||
"labels alone on lines without trailing `:'",
|
||||
"numeric constants greater than 0xFFFFFFFF"
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
@ -88,7 +89,7 @@ static char *suppressed_what[1+ERR_WARN_MAX] = {
|
|||
* not preprocess their source file.
|
||||
*/
|
||||
|
||||
static void no_pp_reset (char *, efunc, ListGen *);
|
||||
static void no_pp_reset (char *, int, efunc, evalfunc, ListGen *);
|
||||
static char *no_pp_getline (void);
|
||||
static void no_pp_cleanup (void);
|
||||
static Preproc no_pp = {
|
||||
|
|
@ -130,6 +131,10 @@ int main(int argc, char **argv) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
if (ofmt->stdmac)
|
||||
pp_extra_stdmac (ofmt->stdmac);
|
||||
eval_global_info (ofmt, lookup_label);
|
||||
|
||||
if (preprocess_only) {
|
||||
char *line;
|
||||
|
||||
|
|
@ -140,12 +145,29 @@ int main(int argc, char **argv) {
|
|||
"unable to open output file `%s'", outname);
|
||||
} else
|
||||
ofile = NULL;
|
||||
preproc->reset (inname, report_error, &nasmlist);
|
||||
|
||||
eval_info ("%", 0L, 0L); /* disallow labels, $ or $$ in exprs */
|
||||
|
||||
preproc->reset (inname, 2, report_error, evaluate, &nasmlist);
|
||||
strcpy(currentfile,inname);
|
||||
lineno = 0;
|
||||
lineinc = 1;
|
||||
while ( (line = preproc->getline()) ) {
|
||||
int ln, li;
|
||||
char buf[FILENAME_MAX];
|
||||
|
||||
lineno += lineinc;
|
||||
/*
|
||||
* We must still check for %line directives, so that we
|
||||
* can report errors accurately.
|
||||
*/
|
||||
if (!strncmp(line, "%line", 5) &&
|
||||
sscanf(line, "%%line %d+%d %s", &ln, &li, buf) == 3) {
|
||||
lineno = ln - li;
|
||||
lineinc = li;
|
||||
strncpy (currentfile, buf, FILENAME_MAX-1);
|
||||
currentfile[FILENAME_MAX-1] = '\0';
|
||||
}
|
||||
if (ofile) {
|
||||
fputs(line, ofile);
|
||||
fputc('\n', ofile);
|
||||
|
|
@ -166,10 +188,7 @@ int main(int argc, char **argv) {
|
|||
* the name of the input file and then put that inside the
|
||||
* file.
|
||||
*/
|
||||
ofmt->filename (inname, realout, report_error);
|
||||
if (!*outname) {
|
||||
strcpy(outname, realout);
|
||||
}
|
||||
ofmt->filename (inname, outname, report_error);
|
||||
|
||||
ofile = fopen(outname, "wb");
|
||||
if (!ofile) {
|
||||
|
|
@ -182,7 +201,7 @@ int main(int argc, char **argv) {
|
|||
* init routines. (eg OS/2 defines the FLAT group)
|
||||
*/
|
||||
init_labels ();
|
||||
ofmt->init (ofile, report_error, define_label);
|
||||
ofmt->init (ofile, report_error, define_label, evaluate);
|
||||
assemble_file (inname);
|
||||
if (!terminate_after_phase) {
|
||||
ofmt->cleanup ();
|
||||
|
|
@ -377,19 +396,23 @@ static void parse_cmdline(int argc, char **argv) {
|
|||
}
|
||||
|
||||
static void assemble_file (char *fname) {
|
||||
char *value, *p, *line;
|
||||
char *value, *p, *q, *special, *line;
|
||||
insn output_ins;
|
||||
int i, rn_error;
|
||||
long seg;
|
||||
int i, rn_error, validid;
|
||||
long seg, offs;
|
||||
struct tokenval tokval;
|
||||
expr *e;
|
||||
|
||||
/* pass one */
|
||||
pass = 1;
|
||||
current_seg = ofmt->section(NULL, pass, &sb);
|
||||
preproc->reset(fname, report_error, &nasmlist);
|
||||
preproc->reset(fname, 1, report_error, evaluate, &nasmlist);
|
||||
strcpy(currentfile,fname);
|
||||
lineno = 0;
|
||||
lineinc = 1;
|
||||
globallineno = 0;
|
||||
offs = get_curr_ofs;
|
||||
eval_info (NULL, current_seg, offs); /* set $ */
|
||||
while ( (line = preproc->getline()) ) {
|
||||
lineno += lineinc;
|
||||
globallineno++;
|
||||
|
|
@ -433,11 +456,33 @@ static void assemble_file (char *fname) {
|
|||
current_seg = seg;
|
||||
}
|
||||
break;
|
||||
case 2: /* [EXTERN label] */
|
||||
case 2: /* [EXTERN label:special] */
|
||||
if (*value == '$')
|
||||
value++; /* skip initial $ if present */
|
||||
declare_as_global (value, report_error);
|
||||
define_label (value, seg_alloc(), 0L, ofmt, report_error);
|
||||
q = value;
|
||||
validid = TRUE;
|
||||
if (!isidstart(*q))
|
||||
validid = FALSE;
|
||||
while (*q && *q != ':') {
|
||||
if (!isidchar(*q))
|
||||
validid = FALSE;
|
||||
q++;
|
||||
}
|
||||
if (!validid) {
|
||||
report_error (ERR_NONFATAL,
|
||||
"identifier expected after EXTERN");
|
||||
break;
|
||||
}
|
||||
if (*q == ':') {
|
||||
*q++ = '\0';
|
||||
special = q;
|
||||
} else
|
||||
special = NULL;
|
||||
if (!is_extern(value)) { /* allow re-EXTERN to be ignored */
|
||||
declare_as_global (value, special, report_error);
|
||||
define_label (value, seg_alloc(), 0L, NULL, FALSE, TRUE,
|
||||
ofmt, report_error);
|
||||
}
|
||||
break;
|
||||
case 3: /* [BITS bits] */
|
||||
switch (atoi(value)) {
|
||||
|
|
@ -452,39 +497,87 @@ static void assemble_file (char *fname) {
|
|||
break;
|
||||
}
|
||||
break;
|
||||
case 4: /* [GLOBAL symbol] */
|
||||
case 4: /* [GLOBAL symbol:special] */
|
||||
if (*value == '$')
|
||||
value++; /* skip initial $ if present */
|
||||
declare_as_global (value, report_error);
|
||||
q = value;
|
||||
validid = TRUE;
|
||||
if (!isidstart(*q))
|
||||
validid = FALSE;
|
||||
while (*q && *q != ':') {
|
||||
if (!isidchar(*q))
|
||||
validid = FALSE;
|
||||
q++;
|
||||
}
|
||||
if (!validid) {
|
||||
report_error (ERR_NONFATAL,
|
||||
"identifier expected after GLOBAL");
|
||||
break;
|
||||
}
|
||||
if (*q == ':') {
|
||||
*q++ = '\0';
|
||||
special = q;
|
||||
} else
|
||||
special = NULL;
|
||||
declare_as_global (value, special, report_error);
|
||||
break;
|
||||
case 5: /* [COMMON symbol size] */
|
||||
case 5: /* [COMMON symbol size:special] */
|
||||
p = value;
|
||||
while (*p && !isspace(*p))
|
||||
validid = TRUE;
|
||||
if (!isidstart(*p))
|
||||
validid = FALSE;
|
||||
while (*p && !isspace(*p)) {
|
||||
if (!isidchar(*p))
|
||||
validid = FALSE;
|
||||
p++;
|
||||
}
|
||||
if (!validid) {
|
||||
report_error (ERR_NONFATAL,
|
||||
"identifier expected after COMMON");
|
||||
break;
|
||||
}
|
||||
if (*p) {
|
||||
long size;
|
||||
|
||||
while (*p && isspace(*p))
|
||||
*p++ = '\0';
|
||||
q = p;
|
||||
while (*q && *q != ':')
|
||||
q++;
|
||||
if (*q == ':') {
|
||||
*q++ = '\0';
|
||||
special = q;
|
||||
} else
|
||||
special = NULL;
|
||||
size = readnum (p, &rn_error);
|
||||
if (rn_error)
|
||||
report_error (ERR_NONFATAL, "invalid size specified"
|
||||
" in COMMON declaration");
|
||||
else
|
||||
define_common (value, seg_alloc(), size,
|
||||
ofmt, report_error);
|
||||
special, ofmt, report_error);
|
||||
} else
|
||||
report_error (ERR_NONFATAL, "no size specified in"
|
||||
" COMMON declaration");
|
||||
break;
|
||||
case 6: /* [ABSOLUTE address] */
|
||||
current_seg = NO_SEG;
|
||||
abs_offset = readnum(value, &rn_error);
|
||||
if (rn_error) {
|
||||
report_error (ERR_NONFATAL, "invalid address specified"
|
||||
" for ABSOLUTE directive");
|
||||
stdscan_reset();
|
||||
stdscan_bufptr = value;
|
||||
tokval.t_type = TOKEN_INVALID;
|
||||
e = evaluate(stdscan, NULL, &tokval, NULL, 1, report_error,
|
||||
NULL);
|
||||
if (e) {
|
||||
if (!is_reloc(e))
|
||||
report_error (ERR_NONFATAL, "cannot use non-"
|
||||
"relocatable expression as ABSOLUTE"
|
||||
" address");
|
||||
else {
|
||||
abs_seg = reloc_seg(e);
|
||||
abs_offset = reloc_value(e);
|
||||
}
|
||||
} else
|
||||
abs_offset = 0x100;/* don't go near zero in case of / */
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (!ofmt->directive (line+1, value, 1))
|
||||
|
|
@ -493,9 +586,8 @@ static void assemble_file (char *fname) {
|
|||
break;
|
||||
}
|
||||
} else {
|
||||
long offs = get_curr_ofs;
|
||||
parse_line (current_seg, offs, lookup_label,
|
||||
1, line, &output_ins, ofmt, report_error);
|
||||
parse_line (1, line, &output_ins,
|
||||
report_error, evaluate, eval_info);
|
||||
if (output_ins.forw_ref)
|
||||
*(int *)saa_wstruct(forwrefs) = globallineno;
|
||||
|
||||
|
|
@ -535,7 +627,7 @@ static void assemble_file (char *fname) {
|
|||
define_label (output_ins.label,
|
||||
output_ins.oprs[0].segment,
|
||||
output_ins.oprs[0].offset,
|
||||
ofmt, report_error);
|
||||
NULL, FALSE, FALSE, ofmt, report_error);
|
||||
} else if (output_ins.operands == 2 &&
|
||||
(output_ins.oprs[0].type & IMMEDIATE) &&
|
||||
(output_ins.oprs[0].type & COLON) &&
|
||||
|
|
@ -547,15 +639,15 @@ static void assemble_file (char *fname) {
|
|||
define_label (output_ins.label,
|
||||
output_ins.oprs[0].offset | SEG_ABS,
|
||||
output_ins.oprs[1].offset,
|
||||
ofmt, report_error);
|
||||
NULL, FALSE, FALSE, ofmt, report_error);
|
||||
} else
|
||||
report_error(ERR_NONFATAL, "bad syntax for EQU");
|
||||
}
|
||||
} else {
|
||||
if (output_ins.label)
|
||||
define_label (output_ins.label,
|
||||
current_seg, offs,
|
||||
ofmt, report_error);
|
||||
current_seg==NO_SEG ? abs_seg : current_seg,
|
||||
offs, NULL, TRUE, FALSE, ofmt, report_error);
|
||||
offs += insn_size (current_seg, offs, sb,
|
||||
&output_ins, report_error);
|
||||
set_curr_ofs (offs);
|
||||
|
|
@ -563,6 +655,8 @@ static void assemble_file (char *fname) {
|
|||
cleanup_insn (&output_ins);
|
||||
}
|
||||
nasm_free (line);
|
||||
offs = get_curr_ofs;
|
||||
eval_info (NULL, current_seg, offs); /* set $ */
|
||||
}
|
||||
preproc->cleanup();
|
||||
|
||||
|
|
@ -589,11 +683,13 @@ static void assemble_file (char *fname) {
|
|||
current_seg = ofmt->section(NULL, pass, &sb);
|
||||
raa_free (offsets);
|
||||
offsets = raa_init();
|
||||
preproc->reset(fname, report_error, &nasmlist);
|
||||
preproc->reset(fname, 2, report_error, evaluate, &nasmlist);
|
||||
strcpy(currentfile,fname);
|
||||
lineno = 0;
|
||||
lineinc = 1;
|
||||
globallineno = 0;
|
||||
offs = get_curr_ofs;
|
||||
eval_info (NULL, current_seg, offs); /* set $ */
|
||||
while ( (line = preproc->getline()) ) {
|
||||
lineno += lineinc;
|
||||
globallineno++;
|
||||
|
|
@ -619,7 +715,6 @@ static void assemble_file (char *fname) {
|
|||
|
||||
/* here we parse our directives; this is not handled by
|
||||
* the 'real' parser. */
|
||||
|
||||
if ( (i = getkw (line, &value)) ) {
|
||||
switch (i) {
|
||||
case 1: /* [SEGMENT n] */
|
||||
|
|
@ -631,6 +726,13 @@ static void assemble_file (char *fname) {
|
|||
current_seg = seg;
|
||||
break;
|
||||
case 2: /* [EXTERN label] */
|
||||
q = value;
|
||||
while (*q && *q != ':')
|
||||
q++;
|
||||
if (*q == ':') {
|
||||
*q++ = '\0';
|
||||
ofmt->symdef(value, 0L, 0L, 3, q);
|
||||
}
|
||||
break;
|
||||
case 3: /* [BITS bits] */
|
||||
switch (atoi(value)) {
|
||||
|
|
@ -646,13 +748,42 @@ static void assemble_file (char *fname) {
|
|||
}
|
||||
break;
|
||||
case 4: /* [GLOBAL symbol] */
|
||||
q = value;
|
||||
while (*q && *q != ':')
|
||||
q++;
|
||||
if (*q == ':') {
|
||||
*q++ = '\0';
|
||||
ofmt->symdef(value, 0L, 0L, 3, q);
|
||||
}
|
||||
break;
|
||||
case 5: /* [COMMON symbol size] */
|
||||
q = value;
|
||||
while (*q && *q != ':') {
|
||||
if (isspace(*q))
|
||||
*q = '\0';
|
||||
q++;
|
||||
}
|
||||
if (*q == ':') {
|
||||
*q++ = '\0';
|
||||
ofmt->symdef(value, 0L, 0L, 3, q);
|
||||
}
|
||||
break;
|
||||
case 6: /* [ABSOLUTE addr] */
|
||||
current_seg = NO_SEG;
|
||||
abs_offset = readnum(value, &rn_error);
|
||||
if (rn_error)
|
||||
stdscan_reset();
|
||||
stdscan_bufptr = value;
|
||||
tokval.t_type = TOKEN_INVALID;
|
||||
e = evaluate(stdscan, NULL, &tokval, NULL, 2, report_error,
|
||||
NULL);
|
||||
if (e) {
|
||||
if (!is_reloc(e))
|
||||
report_error (ERR_PANIC, "non-reloc ABSOLUTE address"
|
||||
" in pass two");
|
||||
else {
|
||||
abs_seg = reloc_seg(e);
|
||||
abs_offset = reloc_value(e);
|
||||
}
|
||||
} else
|
||||
report_error (ERR_PANIC, "invalid ABSOLUTE address "
|
||||
"in pass two");
|
||||
break;
|
||||
|
|
@ -662,9 +793,8 @@ static void assemble_file (char *fname) {
|
|||
break;
|
||||
}
|
||||
} else {
|
||||
long offs = get_curr_ofs;
|
||||
parse_line (current_seg, offs, lookup_label, 2,
|
||||
line, &output_ins, ofmt, report_error);
|
||||
parse_line (2, line, &output_ins,
|
||||
report_error, evaluate, eval_info);
|
||||
if (globallineno == forwline) {
|
||||
int *p = saa_rstruct (forwrefs);
|
||||
if (p)
|
||||
|
|
@ -702,7 +832,7 @@ static void assemble_file (char *fname) {
|
|||
define_label (output_ins.label,
|
||||
output_ins.oprs[0].segment,
|
||||
output_ins.oprs[0].offset,
|
||||
ofmt, report_error);
|
||||
NULL, FALSE, FALSE, ofmt, report_error);
|
||||
} else if (output_ins.operands == 2 &&
|
||||
(output_ins.oprs[0].type & IMMEDIATE) &&
|
||||
(output_ins.oprs[0].type & COLON) &&
|
||||
|
|
@ -712,7 +842,7 @@ static void assemble_file (char *fname) {
|
|||
define_label (output_ins.label,
|
||||
output_ins.oprs[0].offset | SEG_ABS,
|
||||
output_ins.oprs[1].offset,
|
||||
ofmt, report_error);
|
||||
NULL, FALSE, FALSE, ofmt, report_error);
|
||||
} else
|
||||
report_error(ERR_NONFATAL, "bad syntax for EQU");
|
||||
}
|
||||
|
|
@ -723,6 +853,9 @@ static void assemble_file (char *fname) {
|
|||
set_curr_ofs (offs);
|
||||
}
|
||||
nasm_free (line);
|
||||
|
||||
offs = get_curr_ofs;
|
||||
eval_info (NULL, current_seg, offs); /* set $ */
|
||||
}
|
||||
preproc->cleanup();
|
||||
nasmlist.cleanup();
|
||||
|
|
@ -786,6 +919,12 @@ static void report_error (int severity, char *fmt, ...) {
|
|||
suppressed[ (severity & ERR_WARN_MASK) >> ERR_WARN_SHR ])
|
||||
return; /* and bail out if so */
|
||||
|
||||
/*
|
||||
* See if it's a pass-one only warning and we're not in pass one.
|
||||
*/
|
||||
if ((severity & ERR_PASS1) && pass != 1)
|
||||
return;
|
||||
|
||||
if (severity & ERR_NOFILE)
|
||||
fputs ("nasm: ", use_stdout ? stdout : stderr);
|
||||
else
|
||||
|
|
@ -839,6 +978,9 @@ static void register_output_formats(void) {
|
|||
#ifdef OF_AOUT
|
||||
extern struct ofmt of_aout;
|
||||
#endif
|
||||
#ifdef OF_AOUTB
|
||||
extern struct ofmt of_aoutb;
|
||||
#endif
|
||||
#ifdef OF_COFF
|
||||
extern struct ofmt of_coff;
|
||||
#endif
|
||||
|
|
@ -856,9 +998,6 @@ static void register_output_formats(void) {
|
|||
#ifdef OF_WIN32
|
||||
extern struct ofmt of_win32;
|
||||
#endif
|
||||
#ifdef OF_OS2
|
||||
extern struct ofmt of_os2;
|
||||
#endif
|
||||
#ifdef OF_RDF
|
||||
extern struct ofmt of_rdf;
|
||||
#endif
|
||||
|
|
@ -872,6 +1011,9 @@ static void register_output_formats(void) {
|
|||
#ifdef OF_AOUT
|
||||
ofmt_register (&of_aout);
|
||||
#endif
|
||||
#ifdef OF_AOUTB
|
||||
ofmt_register (&of_aoutb);
|
||||
#endif
|
||||
#ifdef OF_COFF
|
||||
ofmt_register (&of_coff);
|
||||
#endif
|
||||
|
|
@ -887,9 +1029,6 @@ static void register_output_formats(void) {
|
|||
#ifdef OF_WIN32
|
||||
ofmt_register (&of_win32);
|
||||
#endif
|
||||
#ifdef OF_OS2
|
||||
ofmt_register (&of_os2);
|
||||
#endif
|
||||
#ifdef OF_RDF
|
||||
ofmt_register (&of_rdf);
|
||||
#endif
|
||||
|
|
@ -906,14 +1045,18 @@ static void register_output_formats(void) {
|
|||
|
||||
static FILE *no_pp_fp;
|
||||
static efunc no_pp_err;
|
||||
static ListGen *no_pp_list;
|
||||
|
||||
static void no_pp_reset (char *file, efunc error, ListGen *listgen) {
|
||||
static void no_pp_reset (char *file, int pass, efunc error, evalfunc eval,
|
||||
ListGen *listgen) {
|
||||
no_pp_err = error;
|
||||
no_pp_fp = fopen(file, "r");
|
||||
if (!no_pp_fp)
|
||||
no_pp_err (ERR_FATAL | ERR_NOFILE,
|
||||
"unable to open input file `%s'", file);
|
||||
(void) listgen; /* placate compilers */
|
||||
no_pp_list = listgen;
|
||||
(void) pass; /* placate compilers */
|
||||
(void) eval; /* placate compilers */
|
||||
}
|
||||
|
||||
static char *no_pp_getline (void) {
|
||||
|
|
@ -954,6 +1097,8 @@ static char *no_pp_getline (void) {
|
|||
*/
|
||||
buffer[strcspn(buffer, "\032")] = '\0';
|
||||
|
||||
no_pp_list->line (LIST_READ, buffer);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
|
|
|||
277
nasm.h
277
nasm.h
|
|
@ -12,8 +12,8 @@
|
|||
#define NASM_NASM_H
|
||||
|
||||
#define NASM_MAJOR_VER 0
|
||||
#define NASM_MINOR_VER 95
|
||||
#define NASM_VER "0.95"
|
||||
#define NASM_MINOR_VER 96
|
||||
#define NASM_VER "0.96"
|
||||
|
||||
#ifndef NULL
|
||||
#define NULL 0
|
||||
|
|
@ -33,6 +33,15 @@
|
|||
#define FILENAME_MAX 256
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Name pollution problems: <time.h> on Digital UNIX pulls in some
|
||||
* strange hardware header file which sees fit to define R_SP. We
|
||||
* undefine it here so as not to break the enum below.
|
||||
*/
|
||||
#ifdef R_SP
|
||||
#undef R_SP
|
||||
#endif
|
||||
|
||||
/*
|
||||
* We must declare the existence of this structure type up here,
|
||||
* since we have to reference it before we define it...
|
||||
|
|
@ -66,15 +75,18 @@ typedef void (*efunc) (int severity, char *fmt, ...);
|
|||
#define ERR_OFFBY1 0x40 /* report error as being on the line
|
||||
* we're just _about_ to read, not
|
||||
* the one we've just read */
|
||||
#define ERR_PASS1 0x80 /* only print this error on pass one */
|
||||
|
||||
/*
|
||||
* These codes define specific types of suppressible warning.
|
||||
*/
|
||||
#define ERR_WARN_MNP 0x0100 /* macro-num-parameters warning */
|
||||
#define ERR_WARN_OL 0x0200 /* orphan label (no colon, and
|
||||
* alone on line) */
|
||||
#define ERR_WARN_NOV 0x0300 /* numeric overflow */
|
||||
#define ERR_WARN_MASK 0xFF00 /* the mask for this feature */
|
||||
#define ERR_WARN_SHR 8 /* how far to shift right */
|
||||
#define ERR_WARN_MAX 2 /* the highest numbered one */
|
||||
#define ERR_WARN_MAX 3 /* the highest numbered one */
|
||||
|
||||
/*
|
||||
* -----------------------
|
||||
|
|
@ -88,10 +100,14 @@ typedef void (*efunc) (int severity, char *fmt, ...);
|
|||
typedef int (*lfunc) (char *label, long *segment, long *offset);
|
||||
|
||||
/*
|
||||
* And a label-definition function like this.
|
||||
* And a label-definition function like this. The boolean parameter
|
||||
* `is_norm' states whether the label is a `normal' label (which
|
||||
* should affect the local-label system), or something odder like
|
||||
* an EQU or a segment-base symbol, which shouldn't.
|
||||
*/
|
||||
typedef void (*ldfunc) (char *label, long segment, long offset,
|
||||
struct ofmt *ofmt, efunc error);
|
||||
typedef void (*ldfunc) (char *label, long segment, long offset, char *special,
|
||||
int is_norm, int isextrn, struct ofmt *ofmt,
|
||||
efunc error);
|
||||
|
||||
/*
|
||||
* List-file generators should look like this:
|
||||
|
|
@ -152,15 +168,128 @@ typedef struct {
|
|||
void (*downlevel) (int);
|
||||
} ListGen;
|
||||
|
||||
/*
|
||||
* The expression evaluator must be passed a scanner function; a
|
||||
* standard scanner is provided as part of nasmlib.c. The
|
||||
* preprocessor will use a different one. Scanners, and the
|
||||
* token-value structures they return, look like this.
|
||||
*
|
||||
* The return value from the scanner is always a copy of the
|
||||
* `t_type' field in the structure.
|
||||
*/
|
||||
struct tokenval {
|
||||
int t_type;
|
||||
long t_integer, t_inttwo;
|
||||
char *t_charptr;
|
||||
};
|
||||
typedef int (*scanner) (void *private_data, struct tokenval *tv);
|
||||
|
||||
/*
|
||||
* Token types returned by the scanner, in addition to ordinary
|
||||
* ASCII character values, and zero for end-of-string.
|
||||
*/
|
||||
enum { /* token types, other than chars */
|
||||
TOKEN_INVALID = -1, /* a placeholder value */
|
||||
TOKEN_EOS = 0, /* end of string */
|
||||
TOKEN_EQ = '=', TOKEN_GT = '>', TOKEN_LT = '<', /* aliases */
|
||||
TOKEN_ID = 256, TOKEN_NUM, TOKEN_REG, TOKEN_INSN, /* major token types */
|
||||
TOKEN_ERRNUM, /* numeric constant with error in */
|
||||
TOKEN_HERE, TOKEN_BASE, /* $ and $$ */
|
||||
TOKEN_SPECIAL, /* BYTE, WORD, DWORD, FAR, NEAR, etc */
|
||||
TOKEN_PREFIX, /* A32, O16, LOCK, REPNZ, TIMES, etc */
|
||||
TOKEN_SHL, TOKEN_SHR, /* << and >> */
|
||||
TOKEN_SDIV, TOKEN_SMOD, /* // and %% */
|
||||
TOKEN_GE, TOKEN_LE, TOKEN_NE, /* >=, <= and <> (!= is same as <>) */
|
||||
TOKEN_DBL_AND, TOKEN_DBL_OR, TOKEN_DBL_XOR, /* &&, || and ^^ */
|
||||
TOKEN_SEG, TOKEN_WRT, /* SEG and WRT */
|
||||
TOKEN_FLOAT /* floating-point constant */
|
||||
};
|
||||
|
||||
/*
|
||||
* Expression-evaluator datatype. Expressions, within the
|
||||
* evaluator, are stored as an array of these beasts, terminated by
|
||||
* a record with type==0. Mostly, it's a vector type: each type
|
||||
* denotes some kind of a component, and the value denotes the
|
||||
* multiple of that component present in the expression. The
|
||||
* exception is the WRT type, whose `value' field denotes the
|
||||
* segment to which the expression is relative. These segments will
|
||||
* be segment-base types, i.e. either odd segment values or SEG_ABS
|
||||
* types. So it is still valid to assume that anything with a
|
||||
* `value' field of zero is insignificant.
|
||||
*/
|
||||
typedef struct {
|
||||
long type; /* a register, or EXPR_xxx */
|
||||
long value; /* must be >= 32 bits */
|
||||
} expr;
|
||||
|
||||
/*
|
||||
* The evaluator can also return hints about which of two registers
|
||||
* used in an expression should be the base register. See also the
|
||||
* `operand' structure.
|
||||
*/
|
||||
struct eval_hints {
|
||||
int base;
|
||||
int type;
|
||||
};
|
||||
|
||||
/*
|
||||
* The actual expression evaluator function looks like this. When
|
||||
* called, it expects the first token of its expression to already
|
||||
* be in `*tv'; if it is not, set tv->t_type to TOKEN_INVALID and
|
||||
* it will start by calling the scanner.
|
||||
*
|
||||
* If a forward reference happens during evaluation, the evaluator
|
||||
* must set `*fwref' to TRUE if `fwref' is non-NULL.
|
||||
*
|
||||
* `critical' is non-zero if the expression may not contain forward
|
||||
* references. The evaluator will report its own error if this
|
||||
* occurs; if `critical' is 1, the error will be "symbol not
|
||||
* defined before use", whereas if `critical' is 2, the error will
|
||||
* be "symbol undefined".
|
||||
*
|
||||
* If `critical' has bit 4 set (in addition to its main value: 0x11
|
||||
* and 0x12 correspond to 1 and 2) then an extended expression
|
||||
* syntax is recognised, in which relational operators such as =, <
|
||||
* and >= are accepted, as well as low-precedence logical operators
|
||||
* &&, ^^ and ||.
|
||||
*
|
||||
* If `hints' is non-NULL, it gets filled in with some hints as to
|
||||
* the base register in complex effective addresses.
|
||||
*/
|
||||
typedef expr *(*evalfunc) (scanner sc, void *scprivate, struct tokenval *tv,
|
||||
int *fwref, int critical, efunc error,
|
||||
struct eval_hints *hints);
|
||||
|
||||
/*
|
||||
* There's also an auxiliary routine through which the evaluator
|
||||
* needs to hear about the value of $ and the label (if any)
|
||||
* defined on the current line.
|
||||
*/
|
||||
typedef void (*evalinfofunc) (char *labelname, long segment, long offset);
|
||||
|
||||
/*
|
||||
* Special values for expr->type. ASSUMPTION MADE HERE: the number
|
||||
* of distinct register names (i.e. possible "type" fields for an
|
||||
* expr structure) does not exceed 124 (EXPR_REG_START through
|
||||
* EXPR_REG_END).
|
||||
*/
|
||||
#define EXPR_REG_START 1
|
||||
#define EXPR_REG_END 124
|
||||
#define EXPR_UNKNOWN 125L /* for forward references */
|
||||
#define EXPR_SIMPLE 126L
|
||||
#define EXPR_WRT 127L
|
||||
#define EXPR_SEGBASE 128L
|
||||
|
||||
/*
|
||||
* Preprocessors ought to look like this:
|
||||
*/
|
||||
typedef struct {
|
||||
/*
|
||||
* Called at the start of a pass; given a file name, an error
|
||||
* reporting function and a listing generator to talk to.
|
||||
* Called at the start of a pass; given a file name, the number
|
||||
* of the pass, an error reporting function, an evaluator
|
||||
* function, and a listing generator to talk to.
|
||||
*/
|
||||
void (*reset) (char *, efunc, ListGen *);
|
||||
void (*reset) (char *, int, efunc, evalfunc, ListGen *);
|
||||
|
||||
/*
|
||||
* Called to fetch a line of preprocessed source. The line
|
||||
|
|
@ -252,9 +381,9 @@ enum {
|
|||
#define REG8 0x00201001L
|
||||
#define REG16 0x00201002L
|
||||
#define REG32 0x00201004L
|
||||
#define MMXREG 0x00201008L /* MMX registers */
|
||||
#define FPUREG 0x01000000L /* floating point stack registers */
|
||||
#define FPU0 0x01000800L /* FPU stack register zero */
|
||||
#define MMXREG 0x00001008L /* MMX registers */
|
||||
|
||||
/* special register operands: these may be treated differently */
|
||||
#define REG_SMASK 0x00070000L /* a mask for the following */
|
||||
|
|
@ -290,13 +419,13 @@ enum {
|
|||
*/
|
||||
|
||||
enum { /* register names */
|
||||
R_AH = 1, R_AL, R_AX, R_BH, R_BL, R_BP, R_BX, R_CH, R_CL, R_CR0,
|
||||
R_CR2, R_CR3, R_CR4, R_CS, R_CX, R_DH, R_DI, R_DL, R_DR0, R_DR1,
|
||||
R_DR2, R_DR3, R_DR6, R_DR7, R_DS, R_DX, R_EAX, R_EBP, R_EBX,
|
||||
R_ECX, R_EDI, R_EDX, R_ES, R_ESI, R_ESP, R_FS, R_GS, R_MM0,
|
||||
R_MM1, R_MM2, R_MM3, R_MM4, R_MM5, R_MM6, R_MM7, R_SI, R_SP,
|
||||
R_SS, R_ST0, R_ST1, R_ST2, R_ST3, R_ST4, R_ST5, R_ST6, R_ST7,
|
||||
R_TR3, R_TR4, R_TR5, R_TR6, R_TR7, REG_ENUM_LIMIT
|
||||
R_AH = EXPR_REG_START, R_AL, R_AX, R_BH, R_BL, R_BP, R_BX, R_CH,
|
||||
R_CL, R_CR0, R_CR2, R_CR3, R_CR4, R_CS, R_CX, R_DH, R_DI, R_DL,
|
||||
R_DR0, R_DR1, R_DR2, R_DR3, R_DR6, R_DR7, R_DS, R_DX, R_EAX,
|
||||
R_EBP, R_EBX, R_ECX, R_EDI, R_EDX, R_ES, R_ESI, R_ESP, R_FS,
|
||||
R_GS, R_MM0, R_MM1, R_MM2, R_MM3, R_MM4, R_MM5, R_MM6, R_MM7,
|
||||
R_SI, R_SP, R_SS, R_ST0, R_ST1, R_ST2, R_ST3, R_ST4, R_ST5,
|
||||
R_ST6, R_ST7, R_TR3, R_TR4, R_TR5, R_TR6, R_TR7, REG_ENUM_LIMIT
|
||||
};
|
||||
|
||||
enum { /* instruction names */
|
||||
|
|
@ -314,38 +443,41 @@ enum { /* instruction names */
|
|||
I_FIDIVR, I_FILD, I_FIMUL, I_FINCSTP, I_FINIT, I_FIST, I_FISTP,
|
||||
I_FISUB, I_FISUBR, I_FLD, I_FLD1, I_FLDCW, I_FLDENV, I_FLDL2E,
|
||||
I_FLDL2T, I_FLDLG2, I_FLDLN2, I_FLDPI, I_FLDZ, I_FMUL, I_FMULP,
|
||||
I_FNOP, I_FPATAN, I_FPREM, I_FPREM1, I_FPTAN, I_FRNDINT,
|
||||
I_FRSTOR, I_FSAVE, I_FSCALE, I_FSETPM, I_FSIN, I_FSINCOS,
|
||||
I_FSQRT, I_FST, I_FSTCW, I_FSTENV, I_FSTP, I_FSTSW, I_FSUB,
|
||||
I_FSUBP, I_FSUBR, I_FSUBRP, I_FTST, I_FUCOM, I_FUCOMI,
|
||||
I_FUCOMIP, I_FUCOMP, I_FUCOMPP, I_FXAM, I_FXCH, I_FXTRACT,
|
||||
I_FYL2X, I_FYL2XP1, I_HLT, I_IBTS, I_ICEBP, I_IDIV, I_IMUL,
|
||||
I_IN, I_INC, I_INCBIN, I_INSB, I_INSD, I_INSW, I_INT, I_INT1,
|
||||
I_INT01, I_INT3, I_INTO, I_INVD, I_INVLPG, I_IRET, I_IRETD,
|
||||
I_IRETW, I_JCXZ, I_JECXZ, I_JMP, I_LAHF, I_LAR, I_LDS, I_LEA,
|
||||
I_LEAVE, I_LES, I_LFS, I_LGDT, I_LGS, I_LIDT, I_LLDT, I_LMSW,
|
||||
I_LOADALL, I_LOADALL286, I_LODSB, I_LODSD, I_LODSW, I_LOOP,
|
||||
I_LOOPE, I_LOOPNE, I_LOOPNZ, I_LOOPZ, I_LSL, I_LSS, I_LTR,
|
||||
I_MOV, I_MOVD, I_MOVQ, I_MOVSB, I_MOVSD, I_MOVSW, I_MOVSX,
|
||||
I_MOVZX, I_MUL, I_NEG, I_NOP, I_NOT, I_OR, I_OUT, I_OUTSB,
|
||||
I_OUTSD, I_OUTSW, I_PACKSSDW, I_PACKSSWB, I_PACKUSWB, I_PADDB,
|
||||
I_PADDD, I_PADDSB, I_PADDSW, I_PADDUSB, I_PADDUSW, I_PADDW,
|
||||
I_PAND, I_PANDN, I_PCMPEQB, I_PCMPEQD, I_PCMPEQW, I_PCMPGTB,
|
||||
I_PCMPGTD, I_PCMPGTW, I_PMADDWD, I_PMULHW, I_PMULLW, I_POP,
|
||||
I_POPA, I_POPAD, I_POPAW, I_POPF, I_POPFD, I_POPFW, I_POR,
|
||||
I_PSLLD, I_PSLLQ, I_PSLLW, I_PSRAD, I_PSRAW, I_PSRLD, I_PSRLQ,
|
||||
I_PSRLW, I_PSUBB, I_PSUBD, I_PSUBSB, I_PSUBSW, I_PSUBUSB,
|
||||
I_PSUBUSW, I_PSUBW, I_PUNPCKHBW, I_PUNPCKHDQ, I_PUNPCKHWD,
|
||||
I_PUNPCKLBW, I_PUNPCKLDQ, I_PUNPCKLWD, I_PUSH, I_PUSHA,
|
||||
I_PUSHAD, I_PUSHAW, I_PUSHF, I_PUSHFD, I_PUSHFW, I_PXOR, I_RCL,
|
||||
I_RCR, I_RDMSR, I_RDPMC, I_RDTSC, I_RESB, I_RESD, I_RESQ,
|
||||
I_REST, I_RESW, I_RET, I_RETF, I_RETN, I_ROL, I_ROR, I_RSM,
|
||||
I_SAHF, I_SAL, I_SALC, I_SAR, I_SBB, I_SCASB, I_SCASD, I_SCASW,
|
||||
I_SGDT, I_SHL, I_SHLD, I_SHR, I_SHRD, I_SIDT, I_SLDT, I_SMI,
|
||||
I_SMSW, I_STC, I_STD, I_STI, I_STOSB, I_STOSD, I_STOSW, I_STR,
|
||||
I_SUB, I_TEST, I_UMOV, I_VERR, I_VERW, I_WAIT, I_WBINVD,
|
||||
I_WRMSR, I_XADD, I_XBTS, I_XCHG, I_XLATB, I_XOR, I_CMOVcc,
|
||||
I_Jcc, I_SETcc
|
||||
I_FNCLEX, I_FNDISI, I_FNENI, I_FNINIT, I_FNOP, I_FNSAVE,
|
||||
I_FNSTCW, I_FNSTENV, I_FNSTSW, I_FPATAN, I_FPREM, I_FPREM1,
|
||||
I_FPTAN, I_FRNDINT, I_FRSTOR, I_FSAVE, I_FSCALE, I_FSETPM,
|
||||
I_FSIN, I_FSINCOS, I_FSQRT, I_FST, I_FSTCW, I_FSTENV, I_FSTP,
|
||||
I_FSTSW, I_FSUB, I_FSUBP, I_FSUBR, I_FSUBRP, I_FTST, I_FUCOM,
|
||||
I_FUCOMI, I_FUCOMIP, I_FUCOMP, I_FUCOMPP, I_FXAM, I_FXCH,
|
||||
I_FXTRACT, I_FYL2X, I_FYL2XP1, I_HLT, I_IBTS, I_ICEBP, I_IDIV,
|
||||
I_IMUL, I_IN, I_INC, I_INCBIN, I_INSB, I_INSD, I_INSW, I_INT,
|
||||
I_INT1, I_INT01, I_INT3, I_INTO, I_INVD, I_INVLPG, I_IRET,
|
||||
I_IRETD, I_IRETW, I_JCXZ, I_JECXZ, I_JMP, I_LAHF, I_LAR, I_LDS,
|
||||
I_LEA, I_LEAVE, I_LES, I_LFS, I_LGDT, I_LGS, I_LIDT, I_LLDT,
|
||||
I_LMSW, I_LOADALL, I_LOADALL286, I_LODSB, I_LODSD, I_LODSW,
|
||||
I_LOOP, I_LOOPE, I_LOOPNE, I_LOOPNZ, I_LOOPZ, I_LSL, I_LSS,
|
||||
I_LTR, I_MOV, I_MOVD, I_MOVQ, I_MOVSB, I_MOVSD, I_MOVSW,
|
||||
I_MOVSX, I_MOVZX, I_MUL, I_NEG, I_NOP, I_NOT, I_OR, I_OUT,
|
||||
I_OUTSB, I_OUTSD, I_OUTSW, I_PACKSSDW, I_PACKSSWB, I_PACKUSWB,
|
||||
I_PADDB, I_PADDD, I_PADDSB, I_PADDSIW, I_PADDSW, I_PADDUSB,
|
||||
I_PADDUSW, I_PADDW, I_PAND, I_PANDN, I_PAVEB, I_PCMPEQB,
|
||||
I_PCMPEQD, I_PCMPEQW, I_PCMPGTB, I_PCMPGTD, I_PCMPGTW,
|
||||
I_PDISTIB, I_PMACHRIW, I_PMADDWD, I_PMAGW, I_PMULHRW,
|
||||
I_PMULHRIW, I_PMULHW, I_PMULLW, I_PMVGEZB, I_PMVLZB, I_PMVNZB,
|
||||
I_PMVZB, I_POP, I_POPA, I_POPAD, I_POPAW, I_POPF, I_POPFD,
|
||||
I_POPFW, I_POR, I_PSLLD, I_PSLLQ, I_PSLLW, I_PSRAD, I_PSRAW,
|
||||
I_PSRLD, I_PSRLQ, I_PSRLW, I_PSUBB, I_PSUBD, I_PSUBSB,
|
||||
I_PSUBSIW, I_PSUBSW, I_PSUBUSB, I_PSUBUSW, I_PSUBW, I_PUNPCKHBW,
|
||||
I_PUNPCKHDQ, I_PUNPCKHWD, I_PUNPCKLBW, I_PUNPCKLDQ, I_PUNPCKLWD,
|
||||
I_PUSH, I_PUSHA, I_PUSHAD, I_PUSHAW, I_PUSHF, I_PUSHFD,
|
||||
I_PUSHFW, I_PXOR, I_RCL, I_RCR, I_RDMSR, I_RDPMC, I_RDTSC,
|
||||
I_RESB, I_RESD, I_RESQ, I_REST, I_RESW, I_RET, I_RETF, I_RETN,
|
||||
I_ROL, I_ROR, I_RSM, I_SAHF, I_SAL, I_SALC, I_SAR, I_SBB,
|
||||
I_SCASB, I_SCASD, I_SCASW, I_SGDT, I_SHL, I_SHLD, I_SHR, I_SHRD,
|
||||
I_SIDT, I_SLDT, I_SMI, I_SMSW, I_STC, I_STD, I_STI, I_STOSB,
|
||||
I_STOSD, I_STOSW, I_STR, I_SUB, I_TEST, I_UMOV, I_VERR, I_VERW,
|
||||
I_WAIT, I_WBINVD, I_WRMSR, I_XADD, I_XBTS, I_XCHG, I_XLATB,
|
||||
I_XOR, I_CMOVcc, I_Jcc, I_SETcc
|
||||
};
|
||||
|
||||
enum { /* condition code names */
|
||||
|
|
@ -369,13 +501,27 @@ enum { /* extended operand types */
|
|||
EOT_NOTHING, EOT_DB_STRING, EOT_DB_NUMBER
|
||||
};
|
||||
|
||||
enum { /* special EA flags */
|
||||
EAF_BYTEOFFS = 1, /* force offset part to byte size */
|
||||
EAF_WORDOFFS = 2, /* force offset part to [d]word size */
|
||||
EAF_TIMESTWO = 4 /* really do EAX*2 not EAX+EAX */
|
||||
};
|
||||
|
||||
enum { /* values for `hinttype' */
|
||||
EAH_NOHINT = 0, /* no hint at all - our discretion */
|
||||
EAH_MAKEBASE = 1, /* try to make given reg the base */
|
||||
EAH_NOTBASE = 2 /* try _not_ to make reg the base */
|
||||
};
|
||||
|
||||
typedef struct { /* operand to an instruction */
|
||||
long type; /* type of operand */
|
||||
int addr_size; /* 0 means default; 16; 32 */
|
||||
int basereg, indexreg, scale; /* registers and scale involved */
|
||||
int hintbase, hinttype; /* hint as to real base register */
|
||||
long segment; /* immediate segment, if needed */
|
||||
long offset; /* any immediate number */
|
||||
long wrt; /* segment base it's relative to */
|
||||
int eaflags; /* special EA flags */
|
||||
} operand;
|
||||
|
||||
typedef struct extop { /* extended operand */
|
||||
|
|
@ -422,14 +568,23 @@ struct ofmt {
|
|||
*/
|
||||
char *shortname;
|
||||
|
||||
/*
|
||||
* This, if non-NULL, is a NULL-terminated list of `char *'s
|
||||
* pointing to extra standard macros supplied by the object
|
||||
* format (e.g. a sensible initial default value of __SECT__,
|
||||
* and user-level equivalents for any format-specific
|
||||
* directives).
|
||||
*/
|
||||
char **stdmac;
|
||||
|
||||
/*
|
||||
* This procedure is called at the start of an output session.
|
||||
* It tells the output format what file it will be writing to,
|
||||
* what routine to report errors through, and how to interface
|
||||
* to the label manager if necessary. It also gives it a chance
|
||||
* to do other initialisation.
|
||||
* to the label manager and expression evaluator if necessary.
|
||||
* It also gives it a chance to do other initialisation.
|
||||
*/
|
||||
void (*init) (FILE *fp, efunc error, ldfunc ldef);
|
||||
void (*init) (FILE *fp, efunc error, ldfunc ldef, evalfunc eval);
|
||||
|
||||
/*
|
||||
* This procedure is called by assemble() to write actual
|
||||
|
|
@ -465,8 +620,14 @@ struct ofmt {
|
|||
* re-entrancy is guaranteed in the label manager. However, the
|
||||
* label manager will in turn call this routine, so it should
|
||||
* be prepared to be re-entrant itself.
|
||||
*
|
||||
* The `special' parameter contains special information passed
|
||||
* through from the command that defined the label: it may have
|
||||
* been an EXTERN, a COMMON or a GLOBAL. The distinction should
|
||||
* be obvious to the output format from the other parameters.
|
||||
*/
|
||||
void (*symdef) (char *name, long segment, long offset, int is_global);
|
||||
void (*symdef) (char *name, long segment, long offset, int is_global,
|
||||
char *special);
|
||||
|
||||
/*
|
||||
* This procedure is called when the source code requests a
|
||||
|
|
@ -492,6 +653,11 @@ struct ofmt {
|
|||
* required to produce in return a segment value which may be
|
||||
* different. It can map segment bases to absolute numbers by
|
||||
* means of returning SEG_ABS types.
|
||||
*
|
||||
* It should return NO_SEG if the segment base cannot be
|
||||
* determined; the evaluator (which calls this routine) is
|
||||
* responsible for throwing an error condition if that occurs
|
||||
* in pass two or in a critical expression.
|
||||
*/
|
||||
long (*segbase) (long segment);
|
||||
|
||||
|
|
@ -516,8 +682,9 @@ struct ofmt {
|
|||
* the "init" routine - and is passed the name of the input
|
||||
* file from which this output file is being generated. It
|
||||
* should return its preferred name for the output file in
|
||||
* `outfunc'. Since it is called before the driver is properly
|
||||
* initialised, it has to be passed its error handler
|
||||
* `outname', if outname[0] is not '\0', and do nothing to
|
||||
* `outname' otherwise. Since it is called before the driver is
|
||||
* properly initialised, it has to be passed its error handler
|
||||
* separately.
|
||||
*
|
||||
* This procedure may also take its own copy of the input file
|
||||
|
|
|
|||
422
nasmlib.c
422
nasmlib.c
|
|
@ -102,6 +102,28 @@ char *nasm_strdup (char *s)
|
|||
return p;
|
||||
}
|
||||
|
||||
#ifdef LOGALLOC
|
||||
char *nasm_strndup_log (char *file, int line, char *s, size_t len)
|
||||
#else
|
||||
char *nasm_strndup (char *s, size_t len)
|
||||
#endif
|
||||
{
|
||||
char *p;
|
||||
int size = len+1;
|
||||
|
||||
p = malloc(size);
|
||||
if (!p)
|
||||
nasm_malloc_error (ERR_FATAL | ERR_NOFILE, "out of memory");
|
||||
#ifdef LOGALLOC
|
||||
else
|
||||
fprintf(logfp, "%s %d strndup(%ld) returns %p\n",
|
||||
file, line, (long)size, p);
|
||||
#endif
|
||||
strncpy (p, s, len);
|
||||
p[len] = '\0';
|
||||
return p;
|
||||
}
|
||||
|
||||
int nasm_stricmp (char *s1, char *s2) {
|
||||
while (*s1 && toupper(*s1) == toupper(*s2))
|
||||
s1++, s2++;
|
||||
|
|
@ -130,7 +152,8 @@ int nasm_strnicmp (char *s1, char *s2, int n) {
|
|||
long readnum (char *str, int *error) {
|
||||
char *r = str, *q;
|
||||
long radix;
|
||||
long result;
|
||||
unsigned long result, checklimit;
|
||||
int warn = FALSE;
|
||||
|
||||
*error = FALSE;
|
||||
|
||||
|
|
@ -157,15 +180,42 @@ long readnum (char *str, int *error) {
|
|||
else
|
||||
radix = 10;
|
||||
|
||||
/*
|
||||
* If this number has been found for us by something other than
|
||||
* the ordinary scanners, then it might be malformed by having
|
||||
* nothing between the prefix and the suffix. Check this case
|
||||
* now.
|
||||
*/
|
||||
if (r >= q) {
|
||||
*error = TRUE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* `checklimit' must be 2**32 / radix. We can't do that in
|
||||
* 32-bit arithmetic, which we're (probably) using, so we
|
||||
* cheat: since we know that all radices we use are even, we
|
||||
* can divide 2**31 by radix/2 instead.
|
||||
*/
|
||||
checklimit = 0x80000000UL / (radix>>1);
|
||||
|
||||
result = 0;
|
||||
while (*r && r < q) {
|
||||
if (*r<'0' || (*r>'9' && *r<'A') || numvalue(*r)>=radix) {
|
||||
*error = TRUE;
|
||||
return 0;
|
||||
}
|
||||
if (result >= checklimit)
|
||||
warn = TRUE;
|
||||
result = radix * result + numvalue(*r);
|
||||
r++;
|
||||
}
|
||||
|
||||
if (warn)
|
||||
nasm_malloc_error (ERR_WARNING | ERR_PASS1 | ERR_WARN_NOV,
|
||||
"numeric constant %s does not fit in 32 bits",
|
||||
str);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
@ -195,6 +245,8 @@ void standard_extension (char *inname, char *outname, char *extension,
|
|||
efunc error) {
|
||||
char *p, *q;
|
||||
|
||||
if (*outname) /* file name already exists, */
|
||||
return; /* so do nothing */
|
||||
q = inname;
|
||||
p = outname;
|
||||
while (*q) *p++ = *q++; /* copy, and find end of string */
|
||||
|
|
@ -225,7 +277,21 @@ typedef struct RAA_LEAF RAA_LEAF;
|
|||
typedef struct RAA_BRANCH RAA_BRANCH;
|
||||
|
||||
struct RAA {
|
||||
/*
|
||||
* Number of layers below this one to get to the real data. 0
|
||||
* means this structure is a leaf, holding RAA_BLKSIZE real
|
||||
* data items; 1 and above mean it's a branch, holding
|
||||
* RAA_LAYERSIZE pointers to the next level branch or leaf
|
||||
* structures.
|
||||
*/
|
||||
int layers;
|
||||
/*
|
||||
* Number of real data items spanned by one position in the
|
||||
* `data' array at this level. This number is 1, trivially, for
|
||||
* a leaf (level 0): for a level 1 branch it should be
|
||||
* RAA_BLKSIZE, and for a level 2 branch it's
|
||||
* RAA_LAYERSIZE*RAA_BLKSIZE.
|
||||
*/
|
||||
long stepsize;
|
||||
union RAA_UNION {
|
||||
struct RAA_LEAF {
|
||||
|
|
@ -254,8 +320,8 @@ static struct RAA *real_raa_init (int layers) {
|
|||
r = nasm_malloc (BRANCHSIZ);
|
||||
memset (r->u.b.data, 0, sizeof(r->u.b.data));
|
||||
r->layers = layers;
|
||||
r->stepsize = 1L;
|
||||
while (layers--)
|
||||
r->stepsize = RAA_BLKSIZE;
|
||||
while (--layers)
|
||||
r->stepsize *= RAA_LAYERSIZE;
|
||||
}
|
||||
return r;
|
||||
|
|
@ -541,3 +607,353 @@ void saa_fpwrite (struct SAA *s, FILE *fp) {
|
|||
while ( (data = saa_rbytes (s, &len)) )
|
||||
fwrite (data, 1, len, fp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Register, instruction, condition-code and prefix keywords used
|
||||
* by the scanner.
|
||||
*/
|
||||
#include "names.c"
|
||||
static char *special_names[] = {
|
||||
"byte", "dword", "far", "long", "near", "nosplit", "qword",
|
||||
"short", "to", "tword", "word"
|
||||
};
|
||||
static char *prefix_names[] = {
|
||||
"a16", "a32", "lock", "o16", "o32", "rep", "repe", "repne",
|
||||
"repnz", "repz", "times"
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Standard scanner routine used by parser.c and some output
|
||||
* formats. It keeps a succession of temporary-storage strings in
|
||||
* stdscan_tempstorage, which can be cleared using stdscan_reset.
|
||||
*/
|
||||
static char **stdscan_tempstorage = NULL;
|
||||
static int stdscan_tempsize = 0, stdscan_templen = 0;
|
||||
#define STDSCAN_TEMP_DELTA 256
|
||||
|
||||
static void stdscan_pop(void) {
|
||||
nasm_free (stdscan_tempstorage[--stdscan_templen]);
|
||||
}
|
||||
|
||||
void stdscan_reset(void) {
|
||||
while (stdscan_templen > 0)
|
||||
stdscan_pop();
|
||||
}
|
||||
|
||||
static char *stdscan_copy(char *p, int len) {
|
||||
char *text;
|
||||
|
||||
text = nasm_malloc(len+1);
|
||||
strncpy (text, p, len);
|
||||
text[len] = '\0';
|
||||
|
||||
if (stdscan_templen >= stdscan_tempsize) {
|
||||
stdscan_tempsize += STDSCAN_TEMP_DELTA;
|
||||
stdscan_tempstorage = nasm_realloc(stdscan_tempstorage,
|
||||
stdscan_tempsize*sizeof(char *));
|
||||
}
|
||||
stdscan_tempstorage[stdscan_templen++] = text;
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
char *stdscan_bufptr = NULL;
|
||||
int stdscan (void *private_data, struct tokenval *tv) {
|
||||
char ourcopy[256], *r, *s;
|
||||
|
||||
while (isspace(*stdscan_bufptr)) stdscan_bufptr++;
|
||||
if (!*stdscan_bufptr)
|
||||
return tv->t_type = 0;
|
||||
|
||||
/* we have a token; either an id, a number or a char */
|
||||
if (isidstart(*stdscan_bufptr) ||
|
||||
(*stdscan_bufptr == '$' && isidstart(stdscan_bufptr[1]))) {
|
||||
/* now we've got an identifier */
|
||||
int i;
|
||||
int is_sym = FALSE;
|
||||
|
||||
if (*stdscan_bufptr == '$') {
|
||||
is_sym = TRUE;
|
||||
stdscan_bufptr++;
|
||||
}
|
||||
|
||||
r = stdscan_bufptr++;
|
||||
while (isidchar(*stdscan_bufptr)) stdscan_bufptr++;
|
||||
tv->t_charptr = stdscan_copy(r, stdscan_bufptr - r);
|
||||
|
||||
for (s=tv->t_charptr, r=ourcopy; *s; s++)
|
||||
*r++ = tolower (*s);
|
||||
*r = '\0';
|
||||
if (is_sym)
|
||||
return tv->t_type = TOKEN_ID;/* bypass all other checks */
|
||||
/* right, so we have an identifier sitting in temp storage. now,
|
||||
* is it actually a register or instruction name, or what? */
|
||||
if ((tv->t_integer=bsi(ourcopy, reg_names,
|
||||
elements(reg_names)))>=0) {
|
||||
tv->t_integer += EXPR_REG_START;
|
||||
return tv->t_type = TOKEN_REG;
|
||||
} else if ((tv->t_integer=bsi(ourcopy, insn_names,
|
||||
elements(insn_names)))>=0) {
|
||||
return tv->t_type = TOKEN_INSN;
|
||||
}
|
||||
for (i=0; i<elements(icn); i++)
|
||||
if (!strncmp(ourcopy, icn[i], strlen(icn[i]))) {
|
||||
char *p = ourcopy + strlen(icn[i]);
|
||||
tv->t_integer = ico[i];
|
||||
if ((tv->t_inttwo=bsi(p, conditions,
|
||||
elements(conditions)))>=0)
|
||||
return tv->t_type = TOKEN_INSN;
|
||||
}
|
||||
if ((tv->t_integer=bsi(ourcopy, prefix_names,
|
||||
elements(prefix_names)))>=0) {
|
||||
tv->t_integer += PREFIX_ENUM_START;
|
||||
return tv->t_type = TOKEN_PREFIX;
|
||||
}
|
||||
if ((tv->t_integer=bsi(ourcopy, special_names,
|
||||
elements(special_names)))>=0)
|
||||
return tv->t_type = TOKEN_SPECIAL;
|
||||
if (!strcmp(ourcopy, "seg"))
|
||||
return tv->t_type = TOKEN_SEG;
|
||||
if (!strcmp(ourcopy, "wrt"))
|
||||
return tv->t_type = TOKEN_WRT;
|
||||
return tv->t_type = TOKEN_ID;
|
||||
} else if (*stdscan_bufptr == '$' && !isnumchar(stdscan_bufptr[1])) {
|
||||
/*
|
||||
* It's a $ sign with no following hex number; this must
|
||||
* mean it's a Here token ($), evaluating to the current
|
||||
* assembly location, or a Base token ($$), evaluating to
|
||||
* the base of the current segment.
|
||||
*/
|
||||
stdscan_bufptr++;
|
||||
if (*stdscan_bufptr == '$') {
|
||||
stdscan_bufptr++;
|
||||
return tv->t_type = TOKEN_BASE;
|
||||
}
|
||||
return tv->t_type = TOKEN_HERE;
|
||||
} else if (isnumstart(*stdscan_bufptr)) { /* now we've got a number */
|
||||
int rn_error;
|
||||
|
||||
r = stdscan_bufptr++;
|
||||
while (isnumchar(*stdscan_bufptr))
|
||||
stdscan_bufptr++;
|
||||
|
||||
if (*stdscan_bufptr == '.') {
|
||||
/*
|
||||
* a floating point constant
|
||||
*/
|
||||
stdscan_bufptr++;
|
||||
while (isnumchar(*stdscan_bufptr)) {
|
||||
stdscan_bufptr++;
|
||||
}
|
||||
tv->t_charptr = stdscan_copy(r, stdscan_bufptr - r);
|
||||
return tv->t_type = TOKEN_FLOAT;
|
||||
}
|
||||
r = stdscan_copy(r, stdscan_bufptr - r);
|
||||
tv->t_integer = readnum(r, &rn_error);
|
||||
stdscan_pop();
|
||||
if (rn_error)
|
||||
return tv->t_type = TOKEN_ERRNUM;/* some malformation occurred */
|
||||
tv->t_charptr = NULL;
|
||||
return tv->t_type = TOKEN_NUM;
|
||||
} else if (*stdscan_bufptr == '\'' ||
|
||||
*stdscan_bufptr == '"') {/* a char constant */
|
||||
char quote = *stdscan_bufptr++, *r;
|
||||
r = tv->t_charptr = stdscan_bufptr;
|
||||
while (*stdscan_bufptr && *stdscan_bufptr != quote) stdscan_bufptr++;
|
||||
tv->t_inttwo = stdscan_bufptr - r; /* store full version */
|
||||
if (!*stdscan_bufptr)
|
||||
return tv->t_type = TOKEN_ERRNUM; /* unmatched quotes */
|
||||
tv->t_integer = 0;
|
||||
r = stdscan_bufptr++; /* skip over final quote */
|
||||
while (quote != *--r) {
|
||||
tv->t_integer = (tv->t_integer<<8) + (unsigned char) *r;
|
||||
}
|
||||
return tv->t_type = TOKEN_NUM;
|
||||
} else if (*stdscan_bufptr == ';') { /* a comment has happened - stay */
|
||||
return tv->t_type = 0;
|
||||
} else if (stdscan_bufptr[0] == '>' && stdscan_bufptr[1] == '>') {
|
||||
stdscan_bufptr += 2;
|
||||
return tv->t_type = TOKEN_SHR;
|
||||
} else if (stdscan_bufptr[0] == '<' && stdscan_bufptr[1] == '<') {
|
||||
stdscan_bufptr += 2;
|
||||
return tv->t_type = TOKEN_SHL;
|
||||
} else if (stdscan_bufptr[0] == '/' && stdscan_bufptr[1] == '/') {
|
||||
stdscan_bufptr += 2;
|
||||
return tv->t_type = TOKEN_SDIV;
|
||||
} else if (stdscan_bufptr[0] == '%' && stdscan_bufptr[1] == '%') {
|
||||
stdscan_bufptr += 2;
|
||||
return tv->t_type = TOKEN_SMOD;
|
||||
} else if (stdscan_bufptr[0] == '=' && stdscan_bufptr[1] == '=') {
|
||||
stdscan_bufptr += 2;
|
||||
return tv->t_type = TOKEN_EQ;
|
||||
} else if (stdscan_bufptr[0] == '<' && stdscan_bufptr[1] == '>') {
|
||||
stdscan_bufptr += 2;
|
||||
return tv->t_type = TOKEN_NE;
|
||||
} else if (stdscan_bufptr[0] == '!' && stdscan_bufptr[1] == '=') {
|
||||
stdscan_bufptr += 2;
|
||||
return tv->t_type = TOKEN_NE;
|
||||
} else if (stdscan_bufptr[0] == '<' && stdscan_bufptr[1] == '=') {
|
||||
stdscan_bufptr += 2;
|
||||
return tv->t_type = TOKEN_LE;
|
||||
} else if (stdscan_bufptr[0] == '>' && stdscan_bufptr[1] == '=') {
|
||||
stdscan_bufptr += 2;
|
||||
return tv->t_type = TOKEN_GE;
|
||||
} else if (stdscan_bufptr[0] == '&' && stdscan_bufptr[1] == '&') {
|
||||
stdscan_bufptr += 2;
|
||||
return tv->t_type = TOKEN_DBL_AND;
|
||||
} else if (stdscan_bufptr[0] == '^' && stdscan_bufptr[1] == '^') {
|
||||
stdscan_bufptr += 2;
|
||||
return tv->t_type = TOKEN_DBL_XOR;
|
||||
} else if (stdscan_bufptr[0] == '|' && stdscan_bufptr[1] == '|') {
|
||||
stdscan_bufptr += 2;
|
||||
return tv->t_type = TOKEN_DBL_OR;
|
||||
} else /* just an ordinary char */
|
||||
return tv->t_type = (unsigned char) (*stdscan_bufptr++);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return TRUE if the argument is a simple scalar. (Or a far-
|
||||
* absolute, which counts.)
|
||||
*/
|
||||
int is_simple (expr *vect) {
|
||||
while (vect->type && !vect->value)
|
||||
vect++;
|
||||
if (!vect->type)
|
||||
return 1;
|
||||
if (vect->type != EXPR_SIMPLE)
|
||||
return 0;
|
||||
do {
|
||||
vect++;
|
||||
} while (vect->type && !vect->value);
|
||||
if (vect->type && vect->type < EXPR_SEGBASE+SEG_ABS) return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return TRUE if the argument is a simple scalar, _NOT_ a far-
|
||||
* absolute.
|
||||
*/
|
||||
int is_really_simple (expr *vect) {
|
||||
while (vect->type && !vect->value)
|
||||
vect++;
|
||||
if (!vect->type)
|
||||
return 1;
|
||||
if (vect->type != EXPR_SIMPLE)
|
||||
return 0;
|
||||
do {
|
||||
vect++;
|
||||
} while (vect->type && !vect->value);
|
||||
if (vect->type) return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return TRUE if the argument is relocatable (i.e. a simple
|
||||
* scalar, plus at most one segment-base, plus possibly a WRT).
|
||||
*/
|
||||
int is_reloc (expr *vect) {
|
||||
while (vect->type && !vect->value)
|
||||
vect++;
|
||||
if (!vect->type)
|
||||
return 1;
|
||||
if (vect->type < EXPR_SIMPLE)
|
||||
return 0;
|
||||
if (vect->type == EXPR_SIMPLE) {
|
||||
do {
|
||||
vect++;
|
||||
} while (vect->type && !vect->value);
|
||||
if (!vect->type)
|
||||
return 1;
|
||||
}
|
||||
if (vect->type != EXPR_WRT && vect->value != 0 && vect->value != 1)
|
||||
return 0; /* segment base multiplier non-unity */
|
||||
do {
|
||||
vect++;
|
||||
} while (vect->type && (vect->type == EXPR_WRT || !vect->value));
|
||||
if (!vect->type)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return TRUE if the argument contains an `unknown' part.
|
||||
*/
|
||||
int is_unknown(expr *vect) {
|
||||
while (vect->type && vect->type < EXPR_UNKNOWN)
|
||||
vect++;
|
||||
return (vect->type == EXPR_UNKNOWN);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return TRUE if the argument contains nothing but an `unknown'
|
||||
* part.
|
||||
*/
|
||||
int is_just_unknown(expr *vect) {
|
||||
while (vect->type && !vect->value)
|
||||
vect++;
|
||||
return (vect->type == EXPR_UNKNOWN);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the scalar part of a relocatable vector. (Including
|
||||
* simple scalar vectors - those qualify as relocatable.)
|
||||
*/
|
||||
long reloc_value (expr *vect) {
|
||||
while (vect->type && !vect->value)
|
||||
vect++;
|
||||
if (!vect->type) return 0;
|
||||
if (vect->type == EXPR_SIMPLE)
|
||||
return vect->value;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the segment number of a relocatable vector, or NO_SEG for
|
||||
* simple scalars.
|
||||
*/
|
||||
long reloc_seg (expr *vect) {
|
||||
while (vect->type && (vect->type == EXPR_WRT || !vect->value))
|
||||
vect++;
|
||||
if (vect->type == EXPR_SIMPLE) {
|
||||
do {
|
||||
vect++;
|
||||
} while (vect->type && (vect->type == EXPR_WRT || !vect->value));
|
||||
}
|
||||
if (!vect->type)
|
||||
return NO_SEG;
|
||||
else
|
||||
return vect->type - EXPR_SEGBASE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the WRT segment number of a relocatable vector, or NO_SEG
|
||||
* if no WRT part is present.
|
||||
*/
|
||||
long reloc_wrt (expr *vect) {
|
||||
while (vect->type && vect->type < EXPR_WRT)
|
||||
vect++;
|
||||
if (vect->type == EXPR_WRT) {
|
||||
return vect->value;
|
||||
} else
|
||||
return NO_SEG;
|
||||
}
|
||||
|
||||
/*
|
||||
* Binary search.
|
||||
*/
|
||||
int bsi (char *string, char **array, int size) {
|
||||
int i = -1, j = size; /* always, i < index < j */
|
||||
while (j-i >= 2) {
|
||||
int k = (i+j)/2;
|
||||
int l = strcmp(string, array[k]);
|
||||
if (l<0) /* it's in the first half */
|
||||
j = k;
|
||||
else if (l>0) /* it's in the second half */
|
||||
i = k;
|
||||
else /* we've got it :) */
|
||||
return k;
|
||||
}
|
||||
return -1; /* we haven't got it :( */
|
||||
}
|
||||
|
|
|
|||
33
nasmlib.h
33
nasmlib.h
|
|
@ -32,15 +32,18 @@ void *nasm_malloc (size_t);
|
|||
void *nasm_realloc (void *, size_t);
|
||||
void nasm_free (void *);
|
||||
char *nasm_strdup (char *);
|
||||
char *nasm_strndup (char *, size_t);
|
||||
#else
|
||||
void *nasm_malloc_log (char *, int, size_t);
|
||||
void *nasm_realloc_log (char *, int, void *, size_t);
|
||||
void nasm_free_log (char *, int, void *);
|
||||
char *nasm_strdup_log (char *, int, char *);
|
||||
char *nasm_strndup_log (char *, int, char *, size_t);
|
||||
#define nasm_malloc(x) nasm_malloc_log(__FILE__,__LINE__,x)
|
||||
#define nasm_realloc(x,y) nasm_realloc_log(__FILE__,__LINE__,x,y)
|
||||
#define nasm_free(x) nasm_free_log(__FILE__,__LINE__,x)
|
||||
#define nasm_strdup(x) nasm_strdup_log(__FILE__,__LINE__,x)
|
||||
#define nasm_strndup(x,y) nasm_strndup_log(__FILE__,__LINE__,x,y)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
|
@ -136,4 +139,34 @@ void saa_fread (struct SAA *s, long posn, void *p, long len); /* fixup */
|
|||
void saa_fwrite (struct SAA *s, long posn, void *p, long len); /* fixup */
|
||||
void saa_fpwrite (struct SAA *, FILE *);
|
||||
|
||||
#ifdef NASM_NASM_H
|
||||
/*
|
||||
* Standard scanner.
|
||||
*/
|
||||
extern char *stdscan_bufptr;
|
||||
void stdscan_reset(void);
|
||||
int stdscan (void *private_data, struct tokenval *tv);
|
||||
#endif
|
||||
|
||||
#ifdef NASM_NASM_H
|
||||
/*
|
||||
* Library routines to manipulate expression data types.
|
||||
*/
|
||||
int is_reloc(expr *);
|
||||
int is_simple(expr *);
|
||||
int is_really_simple (expr *);
|
||||
int is_unknown(expr *);
|
||||
int is_just_unknown(expr *);
|
||||
long reloc_value(expr *);
|
||||
long reloc_seg(expr *);
|
||||
long reloc_wrt(expr *);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Binary search routine. Returns index into `array' of an entry
|
||||
* matching `string', or <0 if no match. `array' is taken to
|
||||
* contain `size' elements.
|
||||
*/
|
||||
int bsi (char *string, char **array, int size);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
117
ndisasm.1
Normal file
117
ndisasm.1
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
.TH NDISASM 1 "The Netwide Assembler Project"
|
||||
.SH NAME
|
||||
ndisasm \- the Netwide Disassembler \- 80x86 binary file disassembler
|
||||
.SH SYNOPSIS
|
||||
.B ndisasm
|
||||
[
|
||||
.B \-o
|
||||
origin
|
||||
] [
|
||||
.B \-s
|
||||
sync-point [...]]
|
||||
[
|
||||
.B \-a
|
||||
|
|
||||
.B \-i
|
||||
] [
|
||||
.B \-b
|
||||
bits
|
||||
] [
|
||||
.B -u
|
||||
] [
|
||||
.B \-e
|
||||
hdrlen
|
||||
] [
|
||||
.B \-k
|
||||
offset,length [...]]
|
||||
infile
|
||||
.br
|
||||
.B ndisasm \-h
|
||||
.br
|
||||
.B ndisasm \-r
|
||||
.SH DESCRIPTION
|
||||
The
|
||||
.B ndisasm
|
||||
command generates a disassembly listing of the binary file
|
||||
.I infile
|
||||
and directs it to stdout.
|
||||
.SS OPTIONS
|
||||
.TP
|
||||
.B \-h
|
||||
Causes
|
||||
.B ndisasm
|
||||
to exit immediately, after giving a summary of its invocation
|
||||
options.
|
||||
.TP
|
||||
.BI \-r
|
||||
Causes
|
||||
.B ndisasm
|
||||
to exit immediately, after displaying its version number.
|
||||
.TP
|
||||
.BI \-o " origin"
|
||||
Specifies the notional load address for the file. This option causes
|
||||
.B ndisasm
|
||||
to get the addresses it lists down the left hand margin, and the
|
||||
target addresses of PC-relative jumps and calls, right.
|
||||
.TP
|
||||
.BI \-s " sync-point"
|
||||
Manually specifies a synchronisation address, such that
|
||||
.B ndisasm
|
||||
will not output any machine instruction which encompasses bytes on
|
||||
both sides of the address. Hence the instruction which
|
||||
.I starts
|
||||
at that address will be correctly disassembled.
|
||||
.TP
|
||||
.BI \-e " hdrlen"
|
||||
Specifies a number of bytes to discard from the beginning of the
|
||||
file before starting disassembly. This does not count towards the
|
||||
calculation of the disassembly offset: the first
|
||||
.I disassembled
|
||||
instruction will be shown starting at the given load address.
|
||||
.TP
|
||||
.BI \-k " offset,length"
|
||||
Specifies that
|
||||
.I length
|
||||
bytes, starting from disassembly offset
|
||||
.IR offset ,
|
||||
should be skipped over without generating any output. The skipped
|
||||
bytes still count towards the calculation of the disassembly offset.
|
||||
.TP
|
||||
.BR \-a " or " \-i
|
||||
Enables automatic (or intelligent) sync mode, in which
|
||||
.B ndisasm
|
||||
will attempt to guess where synchronisation should be performed, by
|
||||
means of examining the target addresses of the relative jumps and
|
||||
calls it disassembles.
|
||||
.TP
|
||||
.BI \-b " bits"
|
||||
Specifies either 16-bit or 32-bit mode. The default is 16-bit mode.
|
||||
.TP
|
||||
.B \-u
|
||||
Specifies 32-bit mode, more compactly than using `-b 32'.
|
||||
.PP
|
||||
.RE
|
||||
.SH RESTRICTIONS
|
||||
.B ndisasm
|
||||
only disassembles binary files: it has no understanding of the
|
||||
header information present in object or executable files. If you
|
||||
want to disassemble an object file, you should probably be using
|
||||
.BR objdump "(" 1 ")."
|
||||
.PP
|
||||
Auto-sync mode won't necessarily cure all your synchronisation
|
||||
problems: a sync marker can only be placed automatically if a jump
|
||||
or call instruction is found to refer to it
|
||||
.I before
|
||||
.B ndisasm
|
||||
actually disassembles that part of the code. Also, if spurious jumps
|
||||
or calls result from disassembling non-machine-code data, sync
|
||||
markers may get placed in strange places. Feel free to turn
|
||||
auto-sync off and go back to doing it manually if necessary.
|
||||
.PP
|
||||
.B ndisasm
|
||||
can only keep track of 8192 sync markers internally at once: this is
|
||||
to do with portability, since DOS machines don't take kindly to more
|
||||
than 64K being allocated at a time.
|
||||
.PP
|
||||
.SH SEE ALSO
|
||||
.BR objdump "(" 1 ")."
|
||||
|
|
@ -10,6 +10,7 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "nasm.h"
|
||||
#include "nasmlib.h"
|
||||
|
|
@ -169,6 +170,11 @@ int main(int argc, char **argv) {
|
|||
}
|
||||
|
||||
fp = fopen(filename, "rb");
|
||||
if (!fp) {
|
||||
fprintf(stderr, "%s: unable to open `%s': %s\n",
|
||||
pname, filename, strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
if (initskip > 0)
|
||||
skip (initskip, fp);
|
||||
|
||||
|
|
|
|||
535
outaout.c
535
outaout.c
|
|
@ -16,20 +16,34 @@
|
|||
#include "nasmlib.h"
|
||||
#include "outform.h"
|
||||
|
||||
#ifdef OF_AOUT
|
||||
#if defined OF_AOUT || defined OF_AOUTB
|
||||
|
||||
#define RELTYPE_ABSOLUTE 0x00
|
||||
#define RELTYPE_RELATIVE 0x01
|
||||
#define RELTYPE_GOTPC 0x01 /* no explicit GOTPC in a.out */
|
||||
#define RELTYPE_GOTOFF 0x10
|
||||
#define RELTYPE_GOT 0x10 /* distinct from GOTOFF bcos sym not sect */
|
||||
#define RELTYPE_PLT 0x21
|
||||
#define RELTYPE_SYMFLAG 0x08
|
||||
|
||||
struct Reloc {
|
||||
struct Reloc *next;
|
||||
long address; /* relative to _start_ of section */
|
||||
long symbol; /* symbol number or -ve section id */
|
||||
int bytes; /* 2 or 4 */
|
||||
int relative; /* TRUE or FALSE */
|
||||
int reltype; /* see above */
|
||||
};
|
||||
|
||||
struct Symbol {
|
||||
long strpos; /* string table position of name */
|
||||
int type; /* symbol type - see flags below */
|
||||
long value; /* address, or COMMON variable size */
|
||||
long size; /* size for data or function exports */
|
||||
long segment; /* back-reference used by gsym_reloc */
|
||||
struct Symbol *next; /* list of globals in each section */
|
||||
struct Symbol *nextfwd; /* list of unresolved-size symbols */
|
||||
char *name; /* for unresolved-size symbols */
|
||||
long symnum; /* index into symbol table */
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
@ -43,9 +57,12 @@ struct Symbol {
|
|||
#define SECT_MASK 0xE /* mask out any of the above */
|
||||
|
||||
/*
|
||||
* Another flag used in Symbol.type.
|
||||
* More flags used in Symbol.type.
|
||||
*/
|
||||
#define SYM_GLOBAL 1 /* it's a global symbol */
|
||||
#define SYM_DATA 0x100 /* used for shared libs */
|
||||
#define SYM_FUNCTION 0x200 /* used for shared libs */
|
||||
#define SYM_WITH_SIZE 0x4000 /* not output; internal only */
|
||||
|
||||
/*
|
||||
* Bit more explanation of symbol types: SECT_xxx denotes a local
|
||||
|
|
@ -61,11 +78,10 @@ struct Section {
|
|||
unsigned long len, size, nrelocs;
|
||||
long index;
|
||||
struct Reloc *head, **tail;
|
||||
struct Symbol *gsyms, *asym;
|
||||
};
|
||||
|
||||
static struct Section stext, sdata;
|
||||
static unsigned long bsslen;
|
||||
static long bssindex;
|
||||
static struct Section stext, sdata, sbss;
|
||||
|
||||
static struct SAA *syms;
|
||||
static unsigned long nsyms;
|
||||
|
|
@ -75,8 +91,14 @@ static struct RAA *bsym;
|
|||
static struct SAA *strs;
|
||||
static unsigned long strslen;
|
||||
|
||||
static struct Symbol *fwds;
|
||||
|
||||
static FILE *aoutfp;
|
||||
static efunc error;
|
||||
static evalfunc evaluate;
|
||||
|
||||
static int bsd;
|
||||
static int is_pic;
|
||||
|
||||
static void aout_write(void);
|
||||
static void aout_write_relocs(struct Reloc *);
|
||||
|
|
@ -85,24 +107,73 @@ static void aout_sect_write(struct Section *, unsigned char *, unsigned long);
|
|||
static void aout_pad_sections(void);
|
||||
static void aout_fixup_relocs(struct Section *);
|
||||
|
||||
static void aout_init(FILE *fp, efunc errfunc, ldfunc ldef) {
|
||||
/*
|
||||
* Special section numbers which are used to define special
|
||||
* symbols, which can be used with WRT to provide PIC relocation
|
||||
* types.
|
||||
*/
|
||||
static long aout_gotpc_sect, aout_gotoff_sect;
|
||||
static long aout_got_sect, aout_plt_sect;
|
||||
static long aout_sym_sect;
|
||||
|
||||
static void aoutg_init(FILE *fp, efunc errfunc, ldfunc ldef, evalfunc eval) {
|
||||
aoutfp = fp;
|
||||
error = errfunc;
|
||||
evaluate = eval;
|
||||
(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.len = stext.size = sdata.len = sdata.size = sbss.len = 0;
|
||||
stext.nrelocs = sdata.nrelocs = 0;
|
||||
stext.gsyms = sdata.gsyms = sbss.gsyms = NULL;
|
||||
stext.index = seg_alloc();
|
||||
sdata.index = seg_alloc();
|
||||
bssindex = seg_alloc();
|
||||
sbss.index = seg_alloc();
|
||||
stext.asym = sdata.asym = sbss.asym = NULL;
|
||||
syms = saa_init((long)sizeof(struct Symbol));
|
||||
nsyms = 0;
|
||||
bsym = raa_init();
|
||||
strs = saa_init(1L);
|
||||
strslen = 0;
|
||||
fwds = NULL;
|
||||
}
|
||||
|
||||
#ifdef OF_AOUT
|
||||
|
||||
static void aout_init(FILE *fp, efunc errfunc, ldfunc ldef, evalfunc eval) {
|
||||
bsd = FALSE;
|
||||
aoutg_init (fp, errfunc, ldef, eval);
|
||||
|
||||
aout_gotpc_sect = aout_gotoff_sect = aout_got_sect =
|
||||
aout_plt_sect = aout_sym_sect = NO_SEG;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef OF_AOUTB
|
||||
|
||||
extern struct ofmt of_aoutb;
|
||||
|
||||
static void aoutb_init(FILE *fp, efunc errfunc, ldfunc ldef, evalfunc eval) {
|
||||
bsd = TRUE;
|
||||
aoutg_init (fp, errfunc, ldef, eval);
|
||||
|
||||
is_pic = 0x00; /* may become 0x40 */
|
||||
|
||||
aout_gotpc_sect = seg_alloc();
|
||||
ldef("..gotpc", aout_gotpc_sect+1, 0L, NULL, FALSE,FALSE,&of_aoutb,error);
|
||||
aout_gotoff_sect = seg_alloc();
|
||||
ldef("..gotoff", aout_gotoff_sect+1, 0L,NULL,FALSE,FALSE,&of_aoutb,error);
|
||||
aout_got_sect = seg_alloc();
|
||||
ldef("..got", aout_got_sect+1, 0L, NULL, FALSE,FALSE,&of_aoutb,error);
|
||||
aout_plt_sect = seg_alloc();
|
||||
ldef("..plt", aout_plt_sect+1, 0L, NULL, FALSE,FALSE,&of_aoutb,error);
|
||||
aout_sym_sect = seg_alloc();
|
||||
ldef("..sym", aout_sym_sect+1, 0L, NULL, FALSE,FALSE,&of_aoutb,error);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static void aout_cleanup(void) {
|
||||
struct Reloc *r;
|
||||
|
||||
|
|
@ -143,21 +214,66 @@ static long aout_section_names (char *name, int pass, int *bits) {
|
|||
else if (!strcmp(name, ".data"))
|
||||
return sdata.index;
|
||||
else if (!strcmp(name, ".bss"))
|
||||
return bssindex;
|
||||
return sbss.index;
|
||||
else
|
||||
return NO_SEG;
|
||||
}
|
||||
|
||||
static void aout_deflabel (char *name, long segment, long offset,
|
||||
int is_global) {
|
||||
int is_global, char *special) {
|
||||
int pos = strslen+4;
|
||||
struct Symbol *sym;
|
||||
int special_used = FALSE;
|
||||
|
||||
if (name[0] == '.' && name[1] == '.' && name[2] != '@') {
|
||||
error (ERR_NONFATAL, "unrecognised special symbol `%s'", name);
|
||||
/*
|
||||
* This is a NASM special symbol. We never allow it into
|
||||
* the a.out symbol table, even if it's a valid one. If it
|
||||
* _isn't_ a valid one, we should barf immediately.
|
||||
*/
|
||||
if (strcmp(name, "..gotpc") && strcmp(name, "..gotoff") &&
|
||||
strcmp(name, "..got") && strcmp(name, "..plt") &&
|
||||
strcmp(name, "..sym"))
|
||||
error (ERR_NONFATAL, "unrecognised special symbol `%s'", name);
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_global == 3) {
|
||||
struct Symbol **s;
|
||||
/*
|
||||
* Fix up a forward-reference symbol size from the first
|
||||
* pass.
|
||||
*/
|
||||
for (s = &fwds; *s; s = &(*s)->nextfwd)
|
||||
if (!strcmp((*s)->name, name)) {
|
||||
struct tokenval tokval;
|
||||
expr *e;
|
||||
char *p = special;
|
||||
|
||||
while (*p && !isspace(*p)) p++;
|
||||
while (*p && isspace(*p)) p++;
|
||||
stdscan_reset();
|
||||
stdscan_bufptr = p;
|
||||
tokval.t_type = TOKEN_INVALID;
|
||||
e = evaluate(stdscan, NULL, &tokval, NULL, 1, error, NULL);
|
||||
if (e) {
|
||||
if (!is_simple(e))
|
||||
error (ERR_NONFATAL, "cannot use relocatable"
|
||||
" expression as symbol size");
|
||||
else
|
||||
(*s)->size = reloc_value(e);
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove it from the list of unresolved sizes.
|
||||
*/
|
||||
nasm_free ((*s)->name);
|
||||
*s = (*s)->nextfwd;
|
||||
return;
|
||||
}
|
||||
return; /* it wasn't an important one */
|
||||
}
|
||||
|
||||
saa_wbytes (strs, name, (long)(1+strlen(name)));
|
||||
strslen += 1+strlen(name);
|
||||
|
||||
|
|
@ -165,34 +281,110 @@ static void aout_deflabel (char *name, long segment, long offset,
|
|||
|
||||
sym->strpos = pos;
|
||||
sym->type = is_global ? SYM_GLOBAL : 0;
|
||||
sym->segment = segment;
|
||||
if (segment == NO_SEG)
|
||||
sym->type |= SECT_ABS;
|
||||
else if (segment == stext.index)
|
||||
else if (segment == stext.index) {
|
||||
sym->type |= SECT_TEXT;
|
||||
else if (segment == sdata.index)
|
||||
if (is_global) {
|
||||
sym->next = stext.gsyms;
|
||||
stext.gsyms = sym;
|
||||
} else if (!stext.asym)
|
||||
stext.asym = sym;
|
||||
} else if (segment == sdata.index) {
|
||||
sym->type |= SECT_DATA;
|
||||
else if (segment == bssindex)
|
||||
if (is_global) {
|
||||
sym->next = sdata.gsyms;
|
||||
sdata.gsyms = sym;
|
||||
} else if (!sdata.asym)
|
||||
sdata.asym = sym;
|
||||
} else if (segment == sbss.index) {
|
||||
sym->type |= SECT_BSS;
|
||||
else
|
||||
if (is_global) {
|
||||
sym->next = sbss.gsyms;
|
||||
sbss.gsyms = sym;
|
||||
} else if (!sbss.asym)
|
||||
sbss.asym = sym;
|
||||
} else
|
||||
sym->type = SYM_GLOBAL;
|
||||
if (is_global == 2)
|
||||
sym->value = offset;
|
||||
else
|
||||
sym->value = (sym->type == SYM_GLOBAL ? 0 : offset);
|
||||
|
||||
if (is_global && sym->type != SYM_GLOBAL) {
|
||||
/*
|
||||
* Global symbol exported _from_ this module. We must check
|
||||
* the special text for type information.
|
||||
*/
|
||||
|
||||
if (special) {
|
||||
int n = strcspn(special, " ");
|
||||
|
||||
if (!nasm_strnicmp(special, "function", n))
|
||||
sym->type |= SYM_FUNCTION;
|
||||
else if (!nasm_strnicmp(special, "data", n) ||
|
||||
!nasm_strnicmp(special, "object", n))
|
||||
sym->type |= SYM_DATA;
|
||||
else
|
||||
error(ERR_NONFATAL, "unrecognised symbol type `%.*s'",
|
||||
n, special);
|
||||
if (special[n]) {
|
||||
struct tokenval tokval;
|
||||
expr *e;
|
||||
int fwd = FALSE;
|
||||
|
||||
if (!bsd) {
|
||||
error(ERR_NONFATAL, "Linux a.out does not support"
|
||||
" symbol size information");
|
||||
} else {
|
||||
while (special[n] && isspace(special[n]))
|
||||
n++;
|
||||
/*
|
||||
* We have a size expression; attempt to
|
||||
* evaluate it.
|
||||
*/
|
||||
sym->type |= SYM_WITH_SIZE;
|
||||
stdscan_reset();
|
||||
stdscan_bufptr = special+n;
|
||||
tokval.t_type = TOKEN_INVALID;
|
||||
e = evaluate(stdscan, NULL, &tokval, &fwd, 0, error, NULL);
|
||||
if (fwd) {
|
||||
sym->nextfwd = fwds;
|
||||
fwds = sym;
|
||||
sym->name = nasm_strdup(name);
|
||||
} else if (e) {
|
||||
if (!is_simple(e))
|
||||
error (ERR_NONFATAL, "cannot use relocatable"
|
||||
" expression as symbol size");
|
||||
else
|
||||
sym->size = reloc_value(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
special_used = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* define the references from external-symbol segment numbers
|
||||
* to these symbol records.
|
||||
*/
|
||||
if (segment != NO_SEG && segment != stext.index &&
|
||||
segment != sdata.index && segment != bssindex)
|
||||
segment != sdata.index && segment != sbss.index)
|
||||
bsym = raa_write (bsym, segment, nsyms);
|
||||
sym->symnum = nsyms;
|
||||
|
||||
nsyms++;
|
||||
if (sym->type & SYM_WITH_SIZE)
|
||||
nsyms++; /* and another for the size */
|
||||
|
||||
if (special && !special_used)
|
||||
error(ERR_NONFATAL, "no special symbol features supported here");
|
||||
}
|
||||
|
||||
static void aout_add_reloc (struct Section *sect, long segment,
|
||||
int relative, int bytes) {
|
||||
int reltype, int bytes) {
|
||||
struct Reloc *r;
|
||||
|
||||
r = *sect->tail = nasm_malloc(sizeof(struct Reloc));
|
||||
|
|
@ -203,25 +395,151 @@ static void aout_add_reloc (struct Section *sect, long segment,
|
|||
r->symbol = (segment == NO_SEG ? -SECT_ABS :
|
||||
segment == stext.index ? -SECT_TEXT :
|
||||
segment == sdata.index ? -SECT_DATA :
|
||||
segment == bssindex ? -SECT_BSS :
|
||||
segment == sbss.index ? -SECT_BSS :
|
||||
raa_read(bsym, segment));
|
||||
r->relative = relative;
|
||||
r->reltype = reltype;
|
||||
if (r->symbol >= 0)
|
||||
r->reltype |= RELTYPE_SYMFLAG;
|
||||
r->bytes = bytes;
|
||||
|
||||
sect->nrelocs++;
|
||||
}
|
||||
|
||||
/*
|
||||
* This routine deals with ..got and ..sym relocations: the more
|
||||
* complicated kinds. In shared-library writing, some relocations
|
||||
* with respect to global symbols must refer to the precise symbol
|
||||
* rather than referring to an offset from the base of the section
|
||||
* _containing_ the symbol. Such relocations call to this routine,
|
||||
* which searches the symbol list for the symbol in question.
|
||||
*
|
||||
* RELTYPE_GOT references require the _exact_ symbol address to be
|
||||
* used; RELTYPE_ABSOLUTE references can be at an offset from the
|
||||
* symbol. The boolean argument `exact' tells us this.
|
||||
*
|
||||
* Return value is the adjusted value of `addr', having become an
|
||||
* offset from the symbol rather than the section. Should always be
|
||||
* zero when returning from an exact call.
|
||||
*
|
||||
* Limitation: if you define two symbols at the same place,
|
||||
* confusion will occur.
|
||||
*
|
||||
* Inefficiency: we search, currently, using a linked list which
|
||||
* isn't even necessarily sorted.
|
||||
*/
|
||||
static long aout_add_gsym_reloc (struct Section *sect,
|
||||
long segment, long offset,
|
||||
int type, int bytes, int exact) {
|
||||
struct Symbol *sym, *sm, *shead;
|
||||
struct Reloc *r;
|
||||
|
||||
/*
|
||||
* First look up the segment to find whether it's text, data,
|
||||
* bss or an external symbol.
|
||||
*/
|
||||
shead = NULL;
|
||||
if (segment == stext.index)
|
||||
shead = stext.gsyms;
|
||||
else if (segment == sdata.index)
|
||||
shead = sdata.gsyms;
|
||||
else if (segment == sbss.index)
|
||||
shead = sbss.gsyms;
|
||||
if (!shead) {
|
||||
if (exact && offset != 0)
|
||||
error (ERR_NONFATAL, "unable to find a suitable global symbol"
|
||||
" for this reference");
|
||||
else
|
||||
aout_add_reloc (sect, segment, type, bytes);
|
||||
return offset;
|
||||
}
|
||||
|
||||
if (exact) {
|
||||
/*
|
||||
* Find a symbol pointing _exactly_ at this one.
|
||||
*/
|
||||
for (sym = shead; sym; sym = sym->next)
|
||||
if (sym->value == offset)
|
||||
break;
|
||||
} else {
|
||||
/*
|
||||
* Find the nearest symbol below this one.
|
||||
*/
|
||||
sym = NULL;
|
||||
for (sm = shead; sm; sm = sm->next)
|
||||
if (sm->value <= offset && (!sym || sm->value > sym->value))
|
||||
sym = sm;
|
||||
}
|
||||
if (!sym && exact) {
|
||||
error (ERR_NONFATAL, "unable to find a suitable global symbol"
|
||||
" for this reference");
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = *sect->tail = nasm_malloc(sizeof(struct Reloc));
|
||||
sect->tail = &r->next;
|
||||
r->next = NULL;
|
||||
|
||||
r->address = sect->len;
|
||||
r->symbol = sym->symnum;
|
||||
r->reltype = type | RELTYPE_SYMFLAG;
|
||||
r->bytes = bytes;
|
||||
|
||||
sect->nrelocs++;
|
||||
|
||||
return offset - sym->value;
|
||||
}
|
||||
|
||||
/*
|
||||
* This routine deals with ..gotoff relocations. These _must_ refer
|
||||
* to a symbol, due to a perversity of *BSD's PIC implementation,
|
||||
* and it must be a non-global one as well; so we store `asym', the
|
||||
* first nonglobal symbol defined in each section, and always work
|
||||
* from that. Relocation type is always RELTYPE_GOTOFF.
|
||||
*
|
||||
* Return value is the adjusted value of `addr', having become an
|
||||
* offset from the `asym' symbol rather than the section.
|
||||
*/
|
||||
static long aout_add_gotoff_reloc (struct Section *sect, long segment,
|
||||
long offset, int bytes) {
|
||||
struct Reloc *r;
|
||||
struct Symbol *asym;
|
||||
|
||||
/*
|
||||
* First look up the segment to find whether it's text, data,
|
||||
* bss or an external symbol.
|
||||
*/
|
||||
asym = NULL;
|
||||
if (segment == stext.index)
|
||||
asym = stext.asym;
|
||||
else if (segment == sdata.index)
|
||||
asym = sdata.asym;
|
||||
else if (segment == sbss.index)
|
||||
asym = sbss.asym;
|
||||
if (!asym)
|
||||
error (ERR_NONFATAL, "`..gotoff' relocations require a non-global"
|
||||
" symbol in the section");
|
||||
|
||||
r = *sect->tail = nasm_malloc(sizeof(struct Reloc));
|
||||
sect->tail = &r->next;
|
||||
r->next = NULL;
|
||||
|
||||
r->address = sect->len;
|
||||
r->symbol = asym->symnum;
|
||||
r->reltype = RELTYPE_GOTOFF;
|
||||
r->bytes = bytes;
|
||||
|
||||
sect->nrelocs++;
|
||||
|
||||
return offset - asym->value;
|
||||
}
|
||||
|
||||
static void aout_out (long segto, void *data, unsigned long type,
|
||||
long segment, long wrt) {
|
||||
struct Section *s;
|
||||
long realbytes = type & OUT_SIZMASK;
|
||||
long addr;
|
||||
unsigned char mydata[4], *p;
|
||||
|
||||
if (wrt != NO_SEG) {
|
||||
wrt = NO_SEG; /* continue to do _something_ */
|
||||
error (ERR_NONFATAL, "WRT not supported by a.out output format");
|
||||
}
|
||||
|
||||
type &= OUT_TYPMASK;
|
||||
|
||||
/*
|
||||
|
|
@ -238,7 +556,7 @@ static void aout_out (long segto, void *data, unsigned long type,
|
|||
s = &stext;
|
||||
else if (segto == sdata.index)
|
||||
s = &sdata;
|
||||
else if (segto == bssindex)
|
||||
else if (segto == sbss.index)
|
||||
s = NULL;
|
||||
else {
|
||||
error(ERR_WARNING, "attempt to assemble code in"
|
||||
|
|
@ -253,7 +571,7 @@ static void aout_out (long segto, void *data, unsigned long type,
|
|||
realbytes = 2;
|
||||
else if (type == OUT_REL4ADR)
|
||||
realbytes = 4;
|
||||
bsslen += realbytes;
|
||||
sbss.len += realbytes;
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -264,24 +582,55 @@ static void aout_out (long segto, void *data, unsigned long type,
|
|||
(segto == stext.index ? "code" : "data"));
|
||||
aout_sect_write (s, NULL, realbytes);
|
||||
} else
|
||||
bsslen += realbytes;
|
||||
sbss.len += realbytes;
|
||||
} else if (type == OUT_RAWDATA) {
|
||||
if (segment != NO_SEG)
|
||||
error(ERR_PANIC, "OUT_RAWDATA with other than NO_SEG");
|
||||
aout_sect_write (s, data, realbytes);
|
||||
} else if (type == OUT_ADDRESS) {
|
||||
addr = *(long *)data;
|
||||
if (segment != NO_SEG) {
|
||||
if (segment % 2) {
|
||||
error(ERR_NONFATAL, "a.out format does not support"
|
||||
" segment base references");
|
||||
} else
|
||||
aout_add_reloc (s, segment, FALSE, realbytes);
|
||||
} else {
|
||||
if (wrt == NO_SEG) {
|
||||
aout_add_reloc (s, segment, RELTYPE_ABSOLUTE, realbytes);
|
||||
} else if (!bsd) {
|
||||
error (ERR_NONFATAL, "Linux a.out format does not support"
|
||||
" any use of WRT");
|
||||
wrt = NO_SEG; /* we can at least _try_ to continue */
|
||||
} else if (wrt == aout_gotpc_sect+1) {
|
||||
is_pic = 0x40;
|
||||
aout_add_reloc (s, segment, RELTYPE_GOTPC, realbytes);
|
||||
} else if (wrt == aout_gotoff_sect+1) {
|
||||
is_pic = 0x40;
|
||||
addr = aout_add_gotoff_reloc (s, segment,
|
||||
addr, realbytes);
|
||||
} else if (wrt == aout_got_sect+1) {
|
||||
is_pic = 0x40;
|
||||
addr = aout_add_gsym_reloc (s, segment, addr, RELTYPE_GOT,
|
||||
realbytes, TRUE);
|
||||
} else if (wrt == aout_sym_sect+1) {
|
||||
addr = aout_add_gsym_reloc (s, segment, addr,
|
||||
RELTYPE_ABSOLUTE, realbytes,
|
||||
FALSE);
|
||||
} else if (wrt == aout_plt_sect+1) {
|
||||
is_pic = 0x40;
|
||||
error(ERR_NONFATAL, "a.out format cannot produce non-PC-"
|
||||
"relative PLT references");
|
||||
} else {
|
||||
error (ERR_NONFATAL, "a.out format does not support this"
|
||||
" use of WRT");
|
||||
wrt = NO_SEG; /* we can at least _try_ to continue */
|
||||
}
|
||||
}
|
||||
}
|
||||
p = mydata;
|
||||
if (realbytes == 2)
|
||||
WRITESHORT (p, *(long *)data);
|
||||
WRITESHORT (p, addr);
|
||||
else
|
||||
WRITELONG (p, *(long *)data);
|
||||
WRITELONG (p, addr);
|
||||
aout_sect_write (s, mydata, realbytes);
|
||||
} else if (type == OUT_REL2ADR) {
|
||||
if (segment == segto)
|
||||
|
|
@ -289,8 +638,27 @@ static void aout_out (long segto, void *data, unsigned long type,
|
|||
if (segment != NO_SEG && segment % 2) {
|
||||
error(ERR_NONFATAL, "a.out format does not support"
|
||||
" segment base references");
|
||||
} else
|
||||
aout_add_reloc (s, segment, TRUE, 2);
|
||||
} else {
|
||||
if (wrt == NO_SEG) {
|
||||
aout_add_reloc (s, segment, RELTYPE_RELATIVE, 2);
|
||||
} else if (!bsd) {
|
||||
error (ERR_NONFATAL, "Linux a.out format does not support"
|
||||
" any use of WRT");
|
||||
wrt = NO_SEG; /* we can at least _try_ to continue */
|
||||
} else if (wrt == aout_plt_sect+1) {
|
||||
is_pic = 0x40;
|
||||
aout_add_reloc (s, segment, RELTYPE_PLT, 2);
|
||||
} else if (wrt == aout_gotpc_sect+1 ||
|
||||
wrt == aout_gotoff_sect+1 ||
|
||||
wrt == aout_got_sect+1) {
|
||||
error(ERR_NONFATAL, "a.out format cannot produce PC-"
|
||||
"relative GOT references");
|
||||
} else {
|
||||
error (ERR_NONFATAL, "a.out format does not support this"
|
||||
" use of WRT");
|
||||
wrt = NO_SEG; /* we can at least _try_ to continue */
|
||||
}
|
||||
}
|
||||
p = mydata;
|
||||
WRITESHORT (p, *(long*)data-(realbytes + s->len));
|
||||
aout_sect_write (s, mydata, 2L);
|
||||
|
|
@ -300,8 +668,27 @@ static void aout_out (long segto, void *data, unsigned long type,
|
|||
if (segment != NO_SEG && segment % 2) {
|
||||
error(ERR_NONFATAL, "a.out format does not support"
|
||||
" segment base references");
|
||||
} else
|
||||
aout_add_reloc (s, segment, TRUE, 4);
|
||||
} else {
|
||||
if (wrt == NO_SEG) {
|
||||
aout_add_reloc (s, segment, RELTYPE_RELATIVE, 4);
|
||||
} else if (!bsd) {
|
||||
error (ERR_NONFATAL, "Linux a.out format does not support"
|
||||
" any use of WRT");
|
||||
wrt = NO_SEG; /* we can at least _try_ to continue */
|
||||
} else if (wrt == aout_plt_sect+1) {
|
||||
is_pic = 0x40;
|
||||
aout_add_reloc (s, segment, RELTYPE_PLT, 4);
|
||||
} else if (wrt == aout_gotpc_sect+1 ||
|
||||
wrt == aout_gotoff_sect+1 ||
|
||||
wrt == aout_got_sect+1) {
|
||||
error(ERR_NONFATAL, "a.out format cannot produce PC-"
|
||||
"relative GOT references");
|
||||
} else {
|
||||
error (ERR_NONFATAL, "a.out format does not support this"
|
||||
" use of WRT");
|
||||
wrt = NO_SEG; /* we can at least _try_ to continue */
|
||||
}
|
||||
}
|
||||
p = mydata;
|
||||
WRITELONG (p, *(long*)data-(realbytes + s->len));
|
||||
aout_sect_write (s, mydata, 4L);
|
||||
|
|
@ -315,9 +702,9 @@ static void aout_pad_sections(void) {
|
|||
* length is a multiple of four. (NOP == 0x90.) Also increase
|
||||
* the length of the BSS section similarly.
|
||||
*/
|
||||
aout_sect_write (&stext, pad, (-stext.len) & 3);
|
||||
aout_sect_write (&sdata, pad, (-sdata.len) & 3);
|
||||
bsslen = (bsslen + 3) & ~3;
|
||||
aout_sect_write (&stext, pad, (-(long)stext.len) & 3);
|
||||
aout_sect_write (&sdata, pad, (-(long)sdata.len) & 3);
|
||||
sbss.len = (sbss.len + 3) & ~3;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -340,10 +727,12 @@ static void aout_fixup_relocs(struct Section *sect) {
|
|||
saa_fread (sect->data, r->address, blk, (long)r->bytes);
|
||||
p = q = blk;
|
||||
l = *p++;
|
||||
l += ((long)*p++) << 8;
|
||||
if (r->bytes == 4) {
|
||||
l += ((long)*p++) << 16;
|
||||
l += ((long)*p++) << 24;
|
||||
if (r->bytes > 1) {
|
||||
l += ((long)*p++) << 8;
|
||||
if (r->bytes == 4) {
|
||||
l += ((long)*p++) << 16;
|
||||
l += ((long)*p++) << 24;
|
||||
}
|
||||
}
|
||||
if (r->symbol == -SECT_DATA)
|
||||
l += stext.len;
|
||||
|
|
@ -351,8 +740,10 @@ static void aout_fixup_relocs(struct Section *sect) {
|
|||
l += stext.len + sdata.len;
|
||||
if (r->bytes == 4)
|
||||
WRITELONG(q, l);
|
||||
else
|
||||
else if (r->bytes == 2)
|
||||
WRITESHORT(q, l);
|
||||
else
|
||||
*q++ = l & 0xFF;
|
||||
saa_fwrite (sect->data, r->address, blk, (long)r->bytes);
|
||||
}
|
||||
}
|
||||
|
|
@ -361,10 +752,11 @@ static void aout_write(void) {
|
|||
/*
|
||||
* Emit the a.out header.
|
||||
*/
|
||||
fwritelong (0x640107L, aoutfp); /* OMAGIC, M_386, no flags */
|
||||
/* OMAGIC, M_386 or MID_I386, no flags */
|
||||
fwritelong (bsd ? 0x07018600 | is_pic : 0x640107L, aoutfp);
|
||||
fwritelong (stext.len, aoutfp);
|
||||
fwritelong (sdata.len, aoutfp);
|
||||
fwritelong (bsslen, aoutfp);
|
||||
fwritelong (sbss.len, aoutfp);
|
||||
fwritelong (nsyms * 12, aoutfp); /* length of symbol table */
|
||||
fwritelong (0L, aoutfp); /* object files have no entry point */
|
||||
fwritelong (stext.nrelocs * 8, aoutfp); /* size of text relocs */
|
||||
|
|
@ -401,12 +793,12 @@ static void aout_write_relocs (struct Reloc *r) {
|
|||
fwritelong (r->address, aoutfp);
|
||||
|
||||
if (r->symbol >= 0)
|
||||
word2 = r->symbol | 0x8000000L;
|
||||
word2 = r->symbol;
|
||||
else
|
||||
word2 = -r->symbol;
|
||||
if (r->relative)
|
||||
word2 |= 0x1000000L;
|
||||
word2 |= (r->bytes == 2 ? 0x2000000L : 0x4000000L);
|
||||
word2 |= r->reltype << 24;
|
||||
word2 |= (r->bytes == 1 ? 0 :
|
||||
r->bytes == 2 ? 0x2000000L : 0x4000000L);
|
||||
fwritelong (word2, aoutfp);
|
||||
|
||||
r = r->next;
|
||||
|
|
@ -420,7 +812,7 @@ static void aout_write_syms (void) {
|
|||
for (i=0; i<nsyms; i++) {
|
||||
struct Symbol *sym = saa_rstruct(syms);
|
||||
fwritelong (sym->strpos, aoutfp);
|
||||
fwritelong ((long)sym->type, aoutfp);
|
||||
fwritelong ((long)sym->type & ~SYM_WITH_SIZE, aoutfp);
|
||||
/*
|
||||
* Fix up the symbol value now we know the final section
|
||||
* sizes.
|
||||
|
|
@ -430,6 +822,15 @@ static void aout_write_syms (void) {
|
|||
if ((sym->type & SECT_MASK) == SECT_BSS)
|
||||
sym->value += stext.len + sdata.len;
|
||||
fwritelong (sym->value, aoutfp);
|
||||
/*
|
||||
* Output a size record if necessary.
|
||||
*/
|
||||
if (sym->type & SYM_WITH_SIZE) {
|
||||
fwritelong(sym->strpos, aoutfp);
|
||||
fwritelong(0x0DL, aoutfp); /* special value: means size */
|
||||
fwritelong(sym->size, aoutfp);
|
||||
i++; /* use up another of `nsyms' */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -451,9 +852,19 @@ static void aout_filename (char *inname, char *outname, efunc error) {
|
|||
standard_extension (inname, outname, ".o", error);
|
||||
}
|
||||
|
||||
static char *aout_stdmac[] = {
|
||||
"%define __SECT__ [section .text]",
|
||||
NULL
|
||||
};
|
||||
|
||||
#endif /* OF_AOUT || OF_AOUTB */
|
||||
|
||||
#ifdef OF_AOUT
|
||||
|
||||
struct ofmt of_aout = {
|
||||
"GNU a.out (i386) object files (e.g. Linux)",
|
||||
"Linux a.out object files",
|
||||
"aout",
|
||||
aout_stdmac,
|
||||
aout_init,
|
||||
aout_out,
|
||||
aout_deflabel,
|
||||
|
|
@ -464,4 +875,22 @@ struct ofmt of_aout = {
|
|||
aout_cleanup
|
||||
};
|
||||
|
||||
#endif /* OF_AOUT */
|
||||
#endif
|
||||
|
||||
#ifdef OF_AOUTB
|
||||
|
||||
struct ofmt of_aoutb = {
|
||||
"NetBSD/FreeBSD a.out object files",
|
||||
"aoutb",
|
||||
aout_stdmac,
|
||||
aoutb_init,
|
||||
aout_out,
|
||||
aout_deflabel,
|
||||
aout_section_names,
|
||||
aout_segbase,
|
||||
aout_directive,
|
||||
aout_filename,
|
||||
aout_cleanup
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
16
outas86.c
16
outas86.c
|
|
@ -80,7 +80,7 @@ static void as86_write_section (struct Section *, int);
|
|||
static int as86_add_string (char *name);
|
||||
static void as86_sect_write(struct Section *, unsigned char *, unsigned long);
|
||||
|
||||
static void as86_init(FILE *fp, efunc errfunc, ldfunc ldef) {
|
||||
static void as86_init(FILE *fp, efunc errfunc, ldfunc ldef, evalfunc eval) {
|
||||
as86fp = fp;
|
||||
error = errfunc;
|
||||
(void) ldef; /* placate optimisers */
|
||||
|
|
@ -158,9 +158,13 @@ static int as86_add_string (char *name) {
|
|||
}
|
||||
|
||||
static void as86_deflabel (char *name, long segment, long offset,
|
||||
int is_global) {
|
||||
int is_global, char *special) {
|
||||
struct Symbol *sym;
|
||||
|
||||
if (special)
|
||||
error (ERR_NONFATAL, "as86 format does not support any"
|
||||
" special symbol types");
|
||||
|
||||
if (name[0] == '.' && name[1] == '.' && name[2] != '@') {
|
||||
error (ERR_NONFATAL, "unrecognised special symbol `%s'", name);
|
||||
return;
|
||||
|
|
@ -429,7 +433,7 @@ static void as86_write(void) {
|
|||
static void as86_set_rsize (int size) {
|
||||
if (as86_reloc_size != size) {
|
||||
switch (as86_reloc_size = size) {
|
||||
case 1: fputc (0x01, as86fp); break; /* shouldn't happen */
|
||||
case 1: fputc (0x01, as86fp); break;
|
||||
case 2: fputc (0x02, as86fp); break;
|
||||
case 4: fputc (0x03, as86fp); break;
|
||||
default: error (ERR_PANIC, "bizarre relocation size %d", size);
|
||||
|
|
@ -533,9 +537,15 @@ static void as86_filename (char *inname, char *outname, efunc error) {
|
|||
standard_extension (inname, outname, ".o", error);
|
||||
}
|
||||
|
||||
static char *as86_stdmac[] = {
|
||||
"%define __SECT__ [section .text]",
|
||||
NULL
|
||||
};
|
||||
|
||||
struct ofmt of_as86 = {
|
||||
"Linux as86 (bin86 version 0.3) object files",
|
||||
"as86",
|
||||
as86_stdmac,
|
||||
as86_init,
|
||||
as86_out,
|
||||
as86_deflabel,
|
||||
|
|
|
|||
95
outbin.c
95
outbin.c
|
|
@ -10,6 +10,8 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "nasm.h"
|
||||
#include "nasmlib.h"
|
||||
#include "outform.h"
|
||||
|
|
@ -35,6 +37,8 @@ static struct Reloc {
|
|||
struct Section *target;
|
||||
} *relocs, **reloctail;
|
||||
|
||||
static long data_align, bss_align;
|
||||
|
||||
static long start_point;
|
||||
|
||||
static void add_reloc (struct Section *s, long bytes, long secref,
|
||||
|
|
@ -51,7 +55,7 @@ static void add_reloc (struct Section *s, long bytes, long secref,
|
|||
r->target = s;
|
||||
}
|
||||
|
||||
static void bin_init (FILE *afp, efunc errfunc, ldfunc ldef) {
|
||||
static void bin_init (FILE *afp, efunc errfunc, ldfunc ldef, evalfunc eval) {
|
||||
fp = afp;
|
||||
|
||||
error = errfunc;
|
||||
|
|
@ -67,20 +71,22 @@ static void bin_init (FILE *afp, efunc errfunc, ldfunc ldef) {
|
|||
bssindex = seg_alloc();
|
||||
relocs = NULL;
|
||||
reloctail = &relocs;
|
||||
data_align = bss_align = 4;
|
||||
}
|
||||
|
||||
static void bin_cleanup (void) {
|
||||
struct Reloc *r;
|
||||
long datapos, dataalign, bsspos;
|
||||
long datapos, datagap, bsspos;
|
||||
|
||||
datapos = (start_point + textsect.length + 3) & ~3;/* align on 4 bytes */
|
||||
dataalign = datapos - (start_point + textsect.length);
|
||||
datapos = start_point + textsect.length;
|
||||
datapos = (datapos + data_align-1) & ~(data_align-1);
|
||||
datagap = datapos - (start_point + textsect.length);
|
||||
bsspos = datapos + datasect.length;
|
||||
bsspos = (bsspos + bss_align-1) & ~(bss_align-1);
|
||||
|
||||
saa_rewind (textsect.contents);
|
||||
saa_rewind (datasect.contents);
|
||||
|
||||
bsspos = (datapos + datasect.length + 3) & ~3;
|
||||
|
||||
for (r = relocs; r; r = r->next) {
|
||||
unsigned char *p, *q, mydata[4];
|
||||
long l;
|
||||
|
|
@ -88,10 +94,12 @@ static void bin_cleanup (void) {
|
|||
saa_fread (r->target->contents, r->posn, mydata, r->bytes);
|
||||
p = q = mydata;
|
||||
l = *p++;
|
||||
l += ((long)*p++) << 8;
|
||||
if (r->bytes == 4) {
|
||||
l += ((long)*p++) << 16;
|
||||
l += ((long)*p++) << 24;
|
||||
if (r->bytes > 1) {
|
||||
l += ((long)*p++) << 8;
|
||||
if (r->bytes == 4) {
|
||||
l += ((long)*p++) << 16;
|
||||
l += ((long)*p++) << 24;
|
||||
}
|
||||
}
|
||||
|
||||
if (r->secref == textsect.index)
|
||||
|
|
@ -110,13 +118,16 @@ static void bin_cleanup (void) {
|
|||
|
||||
if (r->bytes == 4)
|
||||
WRITELONG(q, l);
|
||||
else
|
||||
else if (r->bytes == 2)
|
||||
WRITESHORT(q, l);
|
||||
else
|
||||
*q++ = l & 0xFF;
|
||||
saa_fwrite (r->target->contents, r->posn, mydata, r->bytes);
|
||||
}
|
||||
saa_fpwrite (textsect.contents, fp);
|
||||
if (datasect.length > 0) {
|
||||
fwrite ("\0\0\0\0", dataalign, 1, fp);
|
||||
while (datagap--)
|
||||
fputc('\0', fp);
|
||||
saa_fpwrite (datasect.contents, fp);
|
||||
}
|
||||
fclose (fp);
|
||||
|
|
@ -240,7 +251,12 @@ static void bin_out (long segto, void *data, unsigned long type,
|
|||
}
|
||||
|
||||
static void bin_deflabel (char *name, long segment, long offset,
|
||||
int is_global) {
|
||||
int is_global, char *special) {
|
||||
|
||||
if (special)
|
||||
error (ERR_NONFATAL, "binary format does not support any"
|
||||
" special symbol types");
|
||||
|
||||
if (name[0] == '.' && name[1] == '.' && name[2] != '@') {
|
||||
error (ERR_NONFATAL, "unrecognised special symbol `%s'", name);
|
||||
return;
|
||||
|
|
@ -253,6 +269,10 @@ static void bin_deflabel (char *name, long segment, long offset,
|
|||
}
|
||||
|
||||
static long bin_secname (char *name, int pass, int *bits) {
|
||||
int sec_index;
|
||||
long *sec_align;
|
||||
char *p;
|
||||
|
||||
/*
|
||||
* Default is 16 bits.
|
||||
*/
|
||||
|
|
@ -262,14 +282,40 @@ static long bin_secname (char *name, int pass, int *bits) {
|
|||
if (!name)
|
||||
return textsect.index;
|
||||
|
||||
if (!strcmp(name, ".text"))
|
||||
return textsect.index;
|
||||
else if (!strcmp(name, ".data"))
|
||||
return datasect.index;
|
||||
else if (!strcmp(name, ".bss"))
|
||||
return bssindex;
|
||||
else
|
||||
p = name;
|
||||
while (*p && !isspace(*p)) p++;
|
||||
if (*p) *p++ = '\0';
|
||||
if (!strcmp(name, ".text")) {
|
||||
sec_index = textsect.index;
|
||||
sec_align = NULL;
|
||||
} else if (!strcmp(name, ".data")) {
|
||||
sec_index = datasect.index;
|
||||
sec_align = &data_align;
|
||||
} else if (!strcmp(name, ".bss")) {
|
||||
sec_index = bssindex;
|
||||
sec_align = &bss_align;
|
||||
} else
|
||||
return NO_SEG;
|
||||
|
||||
if (*p) {
|
||||
if (!nasm_strnicmp(p,"align=",6)) {
|
||||
if (sec_align == NULL)
|
||||
error(ERR_NONFATAL, "cannot specify an alignment to"
|
||||
" the `.text' section");
|
||||
else if (p[6+strspn(p+6,"0123456789")])
|
||||
error(ERR_NONFATAL, "argument to `align' is not numeric");
|
||||
else {
|
||||
unsigned int align = atoi(p+6);
|
||||
if (!align || ((align-1) & align))
|
||||
error(ERR_NONFATAL, "argument to `align' is not a"
|
||||
" power of two");
|
||||
else
|
||||
*sec_align = align;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return sec_index;
|
||||
}
|
||||
|
||||
static long bin_segbase (long segment) {
|
||||
|
|
@ -292,9 +338,18 @@ static void bin_filename (char *inname, char *outname, efunc error) {
|
|||
standard_extension (inname, outname, "", error);
|
||||
}
|
||||
|
||||
static char *bin_stdmac[] = {
|
||||
"%define __SECT__ [section .text]",
|
||||
"%imacro org 1+.nolist",
|
||||
"[org %1]",
|
||||
"%endmacro",
|
||||
NULL
|
||||
};
|
||||
|
||||
struct ofmt of_bin = {
|
||||
"flat-form binary files (e.g. DOS .COM, .SYS)",
|
||||
"bin",
|
||||
bin_stdmac,
|
||||
bin_init,
|
||||
bin_out,
|
||||
bin_deflabel,
|
||||
|
|
|
|||
92
outcoff.c
92
outcoff.c
|
|
@ -37,14 +37,11 @@
|
|||
* (2) Win32 doesn't bother putting any flags in the header flags
|
||||
* field (at offset 0x12 into the file).
|
||||
*
|
||||
* (3) Win32 puts some weird flags into the section header table.
|
||||
* It uses flags 0x80000000 (writable), 0x40000000 (readable) and
|
||||
* 0x20000000 (executable) in the expected combinations, which
|
||||
* standard COFF doesn't seem to bother with, but it also does
|
||||
* something else strange: it also flags code sections as
|
||||
* 0x00500000 and data/bss as 0x00300000. Even Microsoft's
|
||||
* documentation doesn't explain what these things mean. I just go
|
||||
* ahead and use them anyway - it seems to work.
|
||||
* (3) Win32 uses some extra flags into the section header table:
|
||||
* it defines flags 0x80000000 (writable), 0x40000000 (readable)
|
||||
* and 0x20000000 (executable), and uses them in the expected
|
||||
* combinations. It also defines 0x00100000 through 0x00700000 for
|
||||
* section alignments of 1 through 64 bytes.
|
||||
*
|
||||
* (4) Both standard COFF and Win32 COFF seem to use the DWORD
|
||||
* field directly after the section name in the section header
|
||||
|
|
@ -53,8 +50,7 @@
|
|||
* to end starting at zero. Dunno why. Microsoft's documentation
|
||||
* lists this field as "Virtual Size of Section", which doesn't
|
||||
* seem to fit at all. In fact, Win32 even includes non-linked
|
||||
* sections such as .drectve in this calculation. Not that I can be
|
||||
* bothered with those things anyway.
|
||||
* sections such as .drectve in this calculation.
|
||||
*
|
||||
* (5) Standard COFF does something very strange to common
|
||||
* variables: the relocation point for a common variable is as far
|
||||
|
|
@ -131,13 +127,15 @@ static void coff_section_header (char *, long, long, long, long, int, long);
|
|||
static void coff_write_relocs (struct Section *);
|
||||
static void coff_write_symbols (void);
|
||||
|
||||
static void coff_win32_init(FILE *fp, efunc errfunc, ldfunc ldef) {
|
||||
static void coff_win32_init(FILE *fp, efunc errfunc,
|
||||
ldfunc ldef, evalfunc eval) {
|
||||
win32 = TRUE;
|
||||
(void) ldef; /* placate optimisers */
|
||||
coff_gen_init(fp, errfunc);
|
||||
}
|
||||
|
||||
static void coff_std_init(FILE *fp, efunc errfunc, ldfunc ldef) {
|
||||
static void coff_std_init(FILE *fp, efunc errfunc,
|
||||
ldfunc ldef, evalfunc eval) {
|
||||
win32 = FALSE;
|
||||
(void) ldef; /* placate optimisers */
|
||||
coff_gen_init(fp, errfunc);
|
||||
|
|
@ -209,7 +207,7 @@ static int coff_make_section (char *name, unsigned long flags) {
|
|||
|
||||
static long coff_section_names (char *name, int pass, int *bits) {
|
||||
char *p;
|
||||
unsigned long flags;
|
||||
unsigned long flags, align_and = ~0L, align_or = 0L;
|
||||
int i;
|
||||
|
||||
/*
|
||||
|
|
@ -224,7 +222,7 @@ static long coff_section_names (char *name, int pass, int *bits) {
|
|||
p = name;
|
||||
while (*p && !isspace(*p)) p++;
|
||||
if (*p) *p++ = '\0';
|
||||
if (strlen(p) > 8) {
|
||||
if (strlen(name) > 8) {
|
||||
error (ERR_WARNING, "COFF section names limited to 8 characters:"
|
||||
" truncating");
|
||||
p[8] = '\0';
|
||||
|
|
@ -237,7 +235,7 @@ static long coff_section_names (char *name, int pass, int *bits) {
|
|||
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")) {
|
||||
|
|
@ -252,6 +250,32 @@ static long coff_section_names (char *name, int pass, int *bits) {
|
|||
error (ERR_NONFATAL, "standard COFF does not support"
|
||||
" informational sections");
|
||||
}
|
||||
} else if (!nasm_strnicmp(q,"align=",6)) {
|
||||
if (!win32)
|
||||
error (ERR_NONFATAL, "standard COFF does not support"
|
||||
" section alignment specification");
|
||||
else {
|
||||
if (q[6+strspn(q+6,"0123456789")])
|
||||
error(ERR_NONFATAL, "argument to `align' is not numeric");
|
||||
else {
|
||||
unsigned int align = atoi(q+6);
|
||||
if (!align || ((align-1) & align))
|
||||
error(ERR_NONFATAL, "argument to `align' is not a"
|
||||
" power of two");
|
||||
else if (align > 64)
|
||||
error(ERR_NONFATAL, "Win32 cannot align sections"
|
||||
" to better than 64-byte boundaries");
|
||||
else {
|
||||
align_and = ~0x00F00000L;
|
||||
align_or = (align == 1 ? 0x00100000L :
|
||||
align == 2 ? 0x00200000L :
|
||||
align == 4 ? 0x00300000L :
|
||||
align == 8 ? 0x00400000L :
|
||||
align == 16 ? 0x00500000L :
|
||||
align == 32 ? 0x00600000L : 0x00700000L);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -259,18 +283,19 @@ static long coff_section_names (char *name, int pass, int *bits) {
|
|||
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) {
|
||||
if (!strcmp(name, ".data"))
|
||||
flags = DATA_FLAGS;
|
||||
else if (!strcmp(name, ".bss"))
|
||||
flags = BSS_FLAGS;
|
||||
else
|
||||
flags = TEXT_FLAGS;
|
||||
}
|
||||
i = coff_make_section (name, flags);
|
||||
if (flags)
|
||||
sects[i]->flags = flags;
|
||||
sects[i]->flags &= align_and;
|
||||
sects[i]->flags |= align_or;
|
||||
} else if (pass == 1) {
|
||||
if (flags)
|
||||
error (ERR_WARNING, "section attributes ignored on"
|
||||
|
|
@ -281,10 +306,14 @@ static long coff_section_names (char *name, int pass, int *bits) {
|
|||
}
|
||||
|
||||
static void coff_deflabel (char *name, long segment, long offset,
|
||||
int is_global) {
|
||||
int is_global, char *special) {
|
||||
int pos = strslen+4;
|
||||
struct Symbol *sym;
|
||||
|
||||
if (special)
|
||||
error (ERR_NONFATAL, "binary format does not support any"
|
||||
" special symbol types");
|
||||
|
||||
if (name[0] == '.' && name[1] == '.' && name[2] != '@') {
|
||||
error (ERR_NONFATAL, "unrecognised special symbol `%s'", name);
|
||||
return;
|
||||
|
|
@ -430,8 +459,8 @@ static void coff_out (long segto, void *data, unsigned long type,
|
|||
error(ERR_PANIC, "OUT_RAWDATA with other than NO_SEG");
|
||||
coff_sect_write (s, data, realbytes);
|
||||
} else if (type == OUT_ADDRESS) {
|
||||
if (realbytes == 2 && (segment != NO_SEG || wrt != NO_SEG))
|
||||
error(ERR_NONFATAL, "COFF format does not support 16-bit"
|
||||
if (realbytes != 4 && (segment != NO_SEG || wrt != NO_SEG))
|
||||
error(ERR_NONFATAL, "COFF format does not support non-32-bit"
|
||||
" relocations");
|
||||
else {
|
||||
long fix = 0;
|
||||
|
|
@ -661,11 +690,17 @@ static void coff_win32_filename (char *inname, char *outname, efunc error) {
|
|||
|
||||
#endif /* defined(OF_COFF) || defined(OF_WIN32) */
|
||||
|
||||
static char *coff_stdmac[] = {
|
||||
"%define __SECT__ [section .text]",
|
||||
NULL
|
||||
};
|
||||
|
||||
#ifdef OF_COFF
|
||||
|
||||
struct ofmt of_coff = {
|
||||
"COFF (i386) object files (e.g. DJGPP for DOS)",
|
||||
"coff",
|
||||
coff_stdmac,
|
||||
coff_std_init,
|
||||
coff_out,
|
||||
coff_deflabel,
|
||||
|
|
@ -683,6 +718,7 @@ struct ofmt of_coff = {
|
|||
struct ofmt of_win32 = {
|
||||
"Microsoft Win32 (i386) object files",
|
||||
"win32",
|
||||
coff_stdmac,
|
||||
coff_win32_init,
|
||||
coff_out,
|
||||
coff_deflabel,
|
||||
|
|
|
|||
152
outdbg.c
152
outdbg.c
|
|
@ -18,30 +18,39 @@
|
|||
|
||||
#ifdef OF_DBG
|
||||
|
||||
struct Section {
|
||||
struct Section *next;
|
||||
long number;
|
||||
char *name;
|
||||
} *dbgsect;
|
||||
|
||||
FILE *dbgf;
|
||||
efunc dbgef;
|
||||
|
||||
int segcode,segdata,segbss;
|
||||
|
||||
static void dbg_init(FILE *fp, efunc errfunc, ldfunc ldef)
|
||||
static void dbg_init(FILE *fp, efunc errfunc, ldfunc ldef, evalfunc eval)
|
||||
{
|
||||
dbgf = fp;
|
||||
dbgef = errfunc;
|
||||
(void) ldef;
|
||||
segcode = seg_alloc();
|
||||
segdata = seg_alloc();
|
||||
segbss = seg_alloc();
|
||||
fprintf(fp,"NASM Output format debug dump - code=%d,data=%d,bss=%d\n",
|
||||
segcode,segdata,segbss);
|
||||
dbgf = fp;
|
||||
dbgef = errfunc;
|
||||
dbgsect = NULL;
|
||||
(void) ldef;
|
||||
fprintf(fp,"NASM Output format debug dump\n");
|
||||
}
|
||||
|
||||
static void dbg_cleanup(void)
|
||||
{
|
||||
fclose(dbgf);
|
||||
while (dbgsect) {
|
||||
struct Section *tmp = dbgsect;
|
||||
dbgsect = dbgsect->next;
|
||||
nasm_free (tmp->name);
|
||||
nasm_free (tmp);
|
||||
}
|
||||
fclose(dbgf);
|
||||
}
|
||||
|
||||
static long dbg_section_names (char *name, int pass, int *bits)
|
||||
{
|
||||
int seg;
|
||||
|
||||
/*
|
||||
* We must have an initial default: let's make it 16.
|
||||
*/
|
||||
|
|
@ -49,73 +58,91 @@ static long dbg_section_names (char *name, int pass, int *bits)
|
|||
*bits = 16;
|
||||
|
||||
if (!name)
|
||||
return 0;
|
||||
fprintf(dbgf, "section_name on init: returning %d\n",
|
||||
seg = seg_alloc());
|
||||
else {
|
||||
int n = strcspn(name, " \t");
|
||||
char *sname = nasm_strndup(name, n);
|
||||
struct Section *s;
|
||||
|
||||
if (!strcmp(name, ".text"))
|
||||
return segcode;
|
||||
else if (!strcmp(name, ".data"))
|
||||
return segdata;
|
||||
else if (!strcmp(name, ".bss"))
|
||||
return segbss;
|
||||
else
|
||||
return NO_SEG;
|
||||
seg = NO_SEG;
|
||||
for (s = dbgsect; s; s = s->next)
|
||||
if (!strcmp(s->name, sname))
|
||||
seg = s->number;
|
||||
|
||||
if (seg == NO_SEG) {
|
||||
s = nasm_malloc(sizeof(*s));
|
||||
s->name = sname;
|
||||
s->number = seg = seg_alloc();
|
||||
s->next = dbgsect;
|
||||
dbgsect = s;
|
||||
fprintf(dbgf, "section_name %s (pass %d): returning %d\n",
|
||||
name, pass, seg);
|
||||
}
|
||||
}
|
||||
return seg;
|
||||
}
|
||||
|
||||
static void dbg_deflabel (char *name, long segment, long offset,
|
||||
int is_global) {
|
||||
fprintf(dbgf,"deflabel %s := %08lx:%08lx %s (%d)\n",name,segment,offset,
|
||||
is_global ? "global" : "local", is_global);
|
||||
int is_global, char *special) {
|
||||
fprintf(dbgf,"deflabel %s := %08lx:%08lx %s (%d)%s%s\n",
|
||||
name, segment, offset,
|
||||
is_global == 2 ? "common" : is_global ? "global" : "local",
|
||||
is_global,
|
||||
special ? ": " : "", special);
|
||||
}
|
||||
|
||||
static void dbg_out (long segto, void *data, unsigned long type,
|
||||
long segment, long wrt) {
|
||||
long realbytes = type & OUT_SIZMASK;
|
||||
long ldata;
|
||||
int id;
|
||||
long segment, long wrt) {
|
||||
long realbytes = type & OUT_SIZMASK;
|
||||
long ldata;
|
||||
int id;
|
||||
|
||||
type &= OUT_TYPMASK;
|
||||
type &= OUT_TYPMASK;
|
||||
|
||||
fprintf(dbgf,"out to %lx, len = %ld: ",segto,realbytes);
|
||||
fprintf(dbgf,"out to %lx, len = %ld: ",segto,realbytes);
|
||||
|
||||
switch(type) {
|
||||
case OUT_RESERVE:
|
||||
fprintf(dbgf,"reserved.\n"); break;
|
||||
case OUT_RAWDATA:
|
||||
fprintf(dbgf,"raw data = ");
|
||||
while (realbytes--) {
|
||||
id = *(unsigned char *)data;
|
||||
data = (char *)data + 1;
|
||||
fprintf(dbgf,"%02x ",id);
|
||||
switch(type) {
|
||||
case OUT_RESERVE:
|
||||
fprintf(dbgf,"reserved.\n"); break;
|
||||
case OUT_RAWDATA:
|
||||
fprintf(dbgf,"raw data = ");
|
||||
while (realbytes--) {
|
||||
id = *(unsigned char *)data;
|
||||
data = (char *)data + 1;
|
||||
fprintf(dbgf,"%02x ",id);
|
||||
}
|
||||
fprintf(dbgf,"\n"); break;
|
||||
case OUT_ADDRESS:
|
||||
ldata = 0; /* placate gcc */
|
||||
if (realbytes == 1)
|
||||
ldata = *((char *)data);
|
||||
else if (realbytes == 2)
|
||||
ldata = *((short *)data);
|
||||
else if (realbytes == 4)
|
||||
ldata = *((long *)data);
|
||||
fprintf(dbgf,"addr %08lx (seg %08lx, wrt %08lx)\n",ldata,
|
||||
segment,wrt);break;
|
||||
case OUT_REL2ADR:
|
||||
fprintf(dbgf,"rel2adr %04x (seg %08lx)\n",(int)*(short *)data,segment);
|
||||
break;
|
||||
case OUT_REL4ADR:
|
||||
fprintf(dbgf,"rel4adr %08lx (seg %08lx)\n",*(long *)data,segment);
|
||||
break;
|
||||
default:
|
||||
fprintf(dbgf,"unknown\n");
|
||||
break;
|
||||
}
|
||||
fprintf(dbgf,"\n"); break;
|
||||
case OUT_ADDRESS:
|
||||
ldata = 0; /* placate gcc */
|
||||
if (realbytes == 1)
|
||||
ldata = *((char *)data);
|
||||
else if (realbytes == 2)
|
||||
ldata = *((short *)data);
|
||||
else if (realbytes == 4)
|
||||
ldata = *((long *)data);
|
||||
fprintf(dbgf,"addr %08lx (seg %08lx, wrt %08lx)\n",ldata,
|
||||
segment,wrt);break;
|
||||
case OUT_REL2ADR:
|
||||
fprintf(dbgf,"rel2adr %04x (seg %08lx)\n",(int)*(short *)data,segment);
|
||||
break;
|
||||
case OUT_REL4ADR:
|
||||
fprintf(dbgf,"rel4adr %08lx (seg %08lx)\n",*(long *)data,segment);
|
||||
break;
|
||||
default:
|
||||
fprintf(dbgf,"unknown\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static long dbg_segbase(long segment) {
|
||||
return segment;
|
||||
return segment;
|
||||
}
|
||||
|
||||
static int dbg_directive (char *directive, char *value, int pass) {
|
||||
return 0;
|
||||
fprintf(dbgf, "directive [%s] value [%s] (pass %d)\n",
|
||||
directive, value, pass);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void dbg_filename (char *inname, char *outname, efunc error) {
|
||||
|
|
@ -125,6 +152,7 @@ static void dbg_filename (char *inname, char *outname, efunc error) {
|
|||
struct ofmt of_dbg = {
|
||||
"Trace of all info passed to output stage",
|
||||
"dbg",
|
||||
NULL,
|
||||
dbg_init,
|
||||
dbg_out,
|
||||
dbg_deflabel,
|
||||
|
|
|
|||
363
outelf.c
363
outelf.c
|
|
@ -18,18 +18,33 @@
|
|||
|
||||
#ifdef OF_ELF
|
||||
|
||||
/*
|
||||
* Relocation types.
|
||||
*/
|
||||
#define R_386_32 1 /* ordinary absolute relocation */
|
||||
#define R_386_PC32 2 /* PC-relative relocation */
|
||||
#define R_386_GOT32 3 /* an offset into GOT */
|
||||
#define R_386_PLT32 4 /* a PC-relative offset into PLT */
|
||||
#define R_386_GOTOFF 9 /* an offset from GOT base */
|
||||
#define R_386_GOTPC 10 /* a PC-relative offset _to_ GOT */
|
||||
|
||||
struct Reloc {
|
||||
struct Reloc *next;
|
||||
long address; /* relative to _start_ of section */
|
||||
long symbol; /* ELF symbol info thingy */
|
||||
int relative; /* TRUE or FALSE */
|
||||
int type; /* type of relocation */
|
||||
};
|
||||
|
||||
struct Symbol {
|
||||
long strpos; /* string table position of name */
|
||||
long section; /* section ID of the symbol */
|
||||
int type; /* TRUE or FALSE */
|
||||
long value; /* address, or COMMON variable size */
|
||||
int type; /* symbol type */
|
||||
long value; /* address, or COMMON variable align */
|
||||
long size; /* size of symbol */
|
||||
long globnum; /* symbol table offset if global */
|
||||
struct Symbol *next; /* list of globals in each section */
|
||||
struct Symbol *nextfwd; /* list of unresolved-size symbols */
|
||||
char *name; /* used temporarily if in above list */
|
||||
};
|
||||
|
||||
#define SHT_PROGBITS 1
|
||||
|
|
@ -50,6 +65,7 @@ struct Section {
|
|||
struct SAA *rel;
|
||||
long rellen;
|
||||
struct Reloc *head, **tail;
|
||||
struct Symbol *gsyms; /* global symbols in section */
|
||||
};
|
||||
|
||||
#define SECT_DELTA 32
|
||||
|
|
@ -72,15 +88,22 @@ static unsigned long strslen;
|
|||
|
||||
static FILE *elffp;
|
||||
static efunc error;
|
||||
static evalfunc evaluate;
|
||||
|
||||
static struct Symbol *fwds;
|
||||
|
||||
static char elf_module[FILENAME_MAX];
|
||||
|
||||
extern struct ofmt of_elf;
|
||||
|
||||
#define SHN_ABS 0xFFF1
|
||||
#define SHN_COMMON 0xFFF2
|
||||
#define SHN_UNDEF 0
|
||||
|
||||
#define SYM_SECTION 0x04
|
||||
#define SYM_GLOBAL 0x10
|
||||
#define SYM_DATA 0x01
|
||||
#define SYM_FUNCTION 0x02
|
||||
|
||||
#define GLOBAL_TEMP_BASE 6 /* bigger than any constant sym id */
|
||||
|
||||
|
|
@ -107,9 +130,19 @@ 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) {
|
||||
/*
|
||||
* Special section numbers which are used to define ELF special
|
||||
* symbols, which can be used with WRT to provide PIC relocation
|
||||
* types.
|
||||
*/
|
||||
static long elf_gotpc_sect, elf_gotoff_sect;
|
||||
static long elf_got_sect, elf_plt_sect;
|
||||
static long elf_sym_sect;
|
||||
|
||||
static void elf_init(FILE *fp, efunc errfunc, ldfunc ldef, evalfunc eval) {
|
||||
elffp = fp;
|
||||
error = errfunc;
|
||||
evaluate = eval;
|
||||
(void) ldef; /* placate optimisers */
|
||||
sects = NULL;
|
||||
nsects = sectlen = 0;
|
||||
|
|
@ -123,6 +156,20 @@ static void elf_init(FILE *fp, efunc errfunc, ldfunc ldef) {
|
|||
shstrtab = NULL;
|
||||
shstrtablen = shstrtabsize = 0;;
|
||||
add_sectname ("", "");
|
||||
|
||||
fwds = NULL;
|
||||
|
||||
elf_gotpc_sect = seg_alloc();
|
||||
ldef("..gotpc", elf_gotpc_sect+1, 0L, NULL, FALSE, FALSE, &of_elf, error);
|
||||
elf_gotoff_sect = seg_alloc();
|
||||
ldef("..gotoff", elf_gotoff_sect+1, 0L, NULL, FALSE, FALSE,&of_elf,error);
|
||||
elf_got_sect = seg_alloc();
|
||||
ldef("..got", elf_got_sect+1, 0L, NULL, FALSE, FALSE, &of_elf, error);
|
||||
elf_plt_sect = seg_alloc();
|
||||
ldef("..plt", elf_plt_sect+1, 0L, NULL, FALSE, FALSE, &of_elf, error);
|
||||
elf_sym_sect = seg_alloc();
|
||||
ldef("..sym", elf_sym_sect+1, 0L, NULL, FALSE, FALSE, &of_elf, error);
|
||||
|
||||
def_seg = seg_alloc();
|
||||
}
|
||||
|
||||
|
|
@ -179,6 +226,7 @@ static int elf_make_section (char *name, int type, int flags, int align) {
|
|||
s->type = type;
|
||||
s->flags = flags;
|
||||
s->align = align;
|
||||
s->gsyms = NULL;
|
||||
|
||||
if (nsects >= sectlen)
|
||||
sects = nasm_realloc (sects, (sectlen += SECT_DELTA)*sizeof(*sects));
|
||||
|
|
@ -286,15 +334,60 @@ static long elf_section_names (char *name, int pass, int *bits) {
|
|||
}
|
||||
|
||||
static void elf_deflabel (char *name, long segment, long offset,
|
||||
int is_global) {
|
||||
int is_global, char *special) {
|
||||
int pos = strslen;
|
||||
struct Symbol *sym;
|
||||
int special_used = FALSE;
|
||||
|
||||
if (name[0] == '.' && name[1] == '.' && name[2] != '@') {
|
||||
error (ERR_NONFATAL, "unrecognised special symbol `%s'", name);
|
||||
/*
|
||||
* This is a NASM special symbol. We never allow it into
|
||||
* the ELF symbol table, even if it's a valid one. If it
|
||||
* _isn't_ a valid one, we should barf immediately.
|
||||
*/
|
||||
if (strcmp(name, "..gotpc") && strcmp(name, "..gotoff") &&
|
||||
strcmp(name, "..got") && strcmp(name, "..plt") &&
|
||||
strcmp(name, "..sym"))
|
||||
error (ERR_NONFATAL, "unrecognised special symbol `%s'", name);
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_global == 3) {
|
||||
struct Symbol **s;
|
||||
/*
|
||||
* Fix up a forward-reference symbol size from the first
|
||||
* pass.
|
||||
*/
|
||||
for (s = &fwds; *s; s = &(*s)->nextfwd)
|
||||
if (!strcmp((*s)->name, name)) {
|
||||
struct tokenval tokval;
|
||||
expr *e;
|
||||
char *p = special;
|
||||
|
||||
while (*p && !isspace(*p)) p++;
|
||||
while (*p && isspace(*p)) p++;
|
||||
stdscan_reset();
|
||||
stdscan_bufptr = p;
|
||||
tokval.t_type = TOKEN_INVALID;
|
||||
e = evaluate(stdscan, NULL, &tokval, NULL, 1, error, NULL);
|
||||
if (e) {
|
||||
if (!is_simple(e))
|
||||
error (ERR_NONFATAL, "cannot use relocatable"
|
||||
" expression as symbol size");
|
||||
else
|
||||
(*s)->size = reloc_value(e);
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove it from the list of unresolved sizes.
|
||||
*/
|
||||
nasm_free ((*s)->name);
|
||||
*s = (*s)->nextfwd;
|
||||
return;
|
||||
}
|
||||
return; /* it wasn't an important one */
|
||||
}
|
||||
|
||||
saa_wbytes (strs, name, (long)(1+strlen(name)));
|
||||
strslen += 1+strlen(name);
|
||||
|
||||
|
|
@ -302,6 +395,7 @@ static void elf_deflabel (char *name, long segment, long offset,
|
|||
|
||||
sym->strpos = pos;
|
||||
sym->type = is_global ? SYM_GLOBAL : 0;
|
||||
sym->size = 0;
|
||||
if (segment == NO_SEG)
|
||||
sym->section = SHN_ABS;
|
||||
else {
|
||||
|
|
@ -322,21 +416,96 @@ static void elf_deflabel (char *name, long segment, long offset,
|
|||
}
|
||||
|
||||
if (is_global == 2) {
|
||||
sym->value = offset;
|
||||
sym->size = offset;
|
||||
sym->value = 0;
|
||||
sym->section = SHN_COMMON;
|
||||
/*
|
||||
* We have a common variable. Check the special text to see
|
||||
* if it's a valid number and power of two; if so, store it
|
||||
* as the alignment for the common variable.
|
||||
*/
|
||||
if (special) {
|
||||
int err;
|
||||
sym->value = readnum (special, &err);
|
||||
if (err)
|
||||
error(ERR_NONFATAL, "alignment constraint `%s' is not a"
|
||||
" valid number", special);
|
||||
else if ( (sym->value | (sym->value-1)) != 2*sym->value - 1)
|
||||
error(ERR_NONFATAL, "alignment constraint `%s' is not a"
|
||||
" power of two", special);
|
||||
}
|
||||
special_used = TRUE;
|
||||
} else
|
||||
sym->value = (sym->section == SHN_UNDEF ? 0 : offset);
|
||||
|
||||
if (sym->type == SYM_GLOBAL) {
|
||||
if (sym->section == SHN_UNDEF || sym->section == SHN_COMMON)
|
||||
bsym = raa_write (bsym, segment, nglobs);
|
||||
else {
|
||||
/*
|
||||
* This is a global symbol; so we must add it to the linked
|
||||
* list of global symbols in its section. We'll push it on
|
||||
* the beginning of the list, because it doesn't matter
|
||||
* much which end we put it on and it's easier like this.
|
||||
*
|
||||
* In addition, we check the special text for symbol
|
||||
* type and size information.
|
||||
*/
|
||||
sym->next = sects[sym->section-1]->gsyms;
|
||||
sects[sym->section-1]->gsyms = sym;
|
||||
|
||||
if (special) {
|
||||
int n = strcspn(special, " ");
|
||||
|
||||
if (!nasm_strnicmp(special, "function", n))
|
||||
sym->type |= SYM_FUNCTION;
|
||||
else if (!nasm_strnicmp(special, "data", n) ||
|
||||
!nasm_strnicmp(special, "object", n))
|
||||
sym->type |= SYM_DATA;
|
||||
else
|
||||
error(ERR_NONFATAL, "unrecognised symbol type `%.*s'",
|
||||
n, special);
|
||||
if (special[n]) {
|
||||
struct tokenval tokval;
|
||||
expr *e;
|
||||
int fwd = FALSE;
|
||||
|
||||
while (special[n] && isspace(special[n]))
|
||||
n++;
|
||||
/*
|
||||
* We have a size expression; attempt to
|
||||
* evaluate it.
|
||||
*/
|
||||
stdscan_reset();
|
||||
stdscan_bufptr = special+n;
|
||||
tokval.t_type = TOKEN_INVALID;
|
||||
e = evaluate(stdscan, NULL, &tokval, &fwd, 0, error, NULL);
|
||||
if (fwd) {
|
||||
sym->nextfwd = fwds;
|
||||
fwds = sym;
|
||||
sym->name = nasm_strdup(name);
|
||||
} else if (e) {
|
||||
if (!is_simple(e))
|
||||
error (ERR_NONFATAL, "cannot use relocatable"
|
||||
" expression as symbol size");
|
||||
else
|
||||
sym->size = reloc_value(e);
|
||||
}
|
||||
}
|
||||
special_used = TRUE;
|
||||
}
|
||||
}
|
||||
sym->globnum = nglobs;
|
||||
nglobs++;
|
||||
} else
|
||||
nlocals++;
|
||||
|
||||
if (special && !special_used)
|
||||
error(ERR_NONFATAL, "no special symbol features supported here");
|
||||
}
|
||||
|
||||
static void elf_add_reloc (struct Section *sect, long segment,
|
||||
int relative) {
|
||||
int type) {
|
||||
struct Reloc *r;
|
||||
|
||||
r = *sect->tail = nasm_malloc(sizeof(struct Reloc));
|
||||
|
|
@ -355,23 +524,106 @@ static void elf_add_reloc (struct Section *sect, long segment,
|
|||
if (!r->symbol)
|
||||
r->symbol = GLOBAL_TEMP_BASE + raa_read(bsym, segment);
|
||||
}
|
||||
r->relative = relative;
|
||||
r->type = type;
|
||||
|
||||
sect->nrelocs++;
|
||||
}
|
||||
|
||||
/*
|
||||
* This routine deals with ..got and ..sym relocations: the more
|
||||
* complicated kinds. In shared-library writing, some relocations
|
||||
* with respect to global symbols must refer to the precise symbol
|
||||
* rather than referring to an offset from the base of the section
|
||||
* _containing_ the symbol. Such relocations call to this routine,
|
||||
* which searches the symbol list for the symbol in question.
|
||||
*
|
||||
* R_386_GOT32 references require the _exact_ symbol address to be
|
||||
* used; R_386_32 references can be at an offset from the symbol.
|
||||
* The boolean argument `exact' tells us this.
|
||||
*
|
||||
* Return value is the adjusted value of `addr', having become an
|
||||
* offset from the symbol rather than the section. Should always be
|
||||
* zero when returning from an exact call.
|
||||
*
|
||||
* Limitation: if you define two symbols at the same place,
|
||||
* confusion will occur.
|
||||
*
|
||||
* Inefficiency: we search, currently, using a linked list which
|
||||
* isn't even necessarily sorted.
|
||||
*/
|
||||
static long elf_add_gsym_reloc (struct Section *sect,
|
||||
long segment, long offset,
|
||||
int type, int exact) {
|
||||
struct Reloc *r;
|
||||
struct Section *s;
|
||||
struct Symbol *sym, *sm;
|
||||
int i;
|
||||
|
||||
/*
|
||||
* First look up the segment/offset pair and find a global
|
||||
* symbol corresponding to it. If it's not one of our segments,
|
||||
* then it must be an external symbol, in which case we're fine
|
||||
* doing a normal elf_add_reloc after first sanity-checking
|
||||
* that the offset from the symbol is zero.
|
||||
*/
|
||||
s = NULL;
|
||||
for (i=0; i<nsects; i++)
|
||||
if (segment == sects[i]->index) {
|
||||
s = sects[i];
|
||||
break;
|
||||
}
|
||||
if (!s) {
|
||||
if (exact && offset != 0)
|
||||
error (ERR_NONFATAL, "unable to find a suitable global symbol"
|
||||
" for this reference");
|
||||
else
|
||||
elf_add_reloc (sect, segment, type);
|
||||
return offset;
|
||||
}
|
||||
|
||||
if (exact) {
|
||||
/*
|
||||
* Find a symbol pointing _exactly_ at this one.
|
||||
*/
|
||||
for (sym = s->gsyms; sym; sym = sym->next)
|
||||
if (sym->value == offset)
|
||||
break;
|
||||
} else {
|
||||
/*
|
||||
* Find the nearest symbol below this one.
|
||||
*/
|
||||
sym = NULL;
|
||||
for (sm = s->gsyms; sm; sm = sm->next)
|
||||
if (sm->value <= offset && (!sym || sm->value > sym->value))
|
||||
sym = sm;
|
||||
}
|
||||
if (!sym && exact) {
|
||||
error (ERR_NONFATAL, "unable to find a suitable global symbol"
|
||||
" for this reference");
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = *sect->tail = nasm_malloc(sizeof(struct Reloc));
|
||||
sect->tail = &r->next;
|
||||
r->next = NULL;
|
||||
|
||||
r->address = sect->len;
|
||||
r->symbol = GLOBAL_TEMP_BASE + sym->globnum;
|
||||
r->type = type;
|
||||
|
||||
sect->nrelocs++;
|
||||
|
||||
return offset - sym->value;
|
||||
}
|
||||
|
||||
static void elf_out (long segto, void *data, unsigned long type,
|
||||
long segment, long wrt) {
|
||||
struct Section *s;
|
||||
long realbytes = type & OUT_SIZMASK;
|
||||
long addr;
|
||||
unsigned char mydata[4], *p;
|
||||
int i;
|
||||
|
||||
if (wrt != NO_SEG) {
|
||||
wrt = NO_SEG; /* continue to do _something_ */
|
||||
error (ERR_NONFATAL, "WRT not supported by ELF output format");
|
||||
}
|
||||
|
||||
type &= OUT_TYPMASK;
|
||||
|
||||
/*
|
||||
|
|
@ -421,20 +673,45 @@ static void elf_out (long segto, void *data, unsigned long type,
|
|||
error(ERR_PANIC, "OUT_RAWDATA with other than NO_SEG");
|
||||
elf_sect_write (s, data, realbytes);
|
||||
} else if (type == OUT_ADDRESS) {
|
||||
if (wrt != NO_SEG)
|
||||
error(ERR_NONFATAL, "ELF format does not support WRT types");
|
||||
addr = *(long *)data;
|
||||
if (segment != NO_SEG) {
|
||||
if (segment % 2) {
|
||||
error(ERR_NONFATAL, "ELF format does not support"
|
||||
" segment base references");
|
||||
} else
|
||||
elf_add_reloc (s, segment, FALSE);
|
||||
} else {
|
||||
if (wrt == NO_SEG) {
|
||||
elf_add_reloc (s, segment, R_386_32);
|
||||
} else if (wrt == elf_gotpc_sect+1) {
|
||||
/*
|
||||
* The user will supply GOT relative to $$. ELF
|
||||
* will let us have GOT relative to $. So we
|
||||
* need to fix up the data item by $-$$.
|
||||
*/
|
||||
addr += s->len;
|
||||
elf_add_reloc (s, segment, R_386_GOTPC);
|
||||
} else if (wrt == elf_gotoff_sect+1) {
|
||||
elf_add_reloc (s, segment, R_386_GOTOFF);
|
||||
} else if (wrt == elf_got_sect+1) {
|
||||
addr = elf_add_gsym_reloc (s, segment, addr,
|
||||
R_386_GOT32, TRUE);
|
||||
} else if (wrt == elf_sym_sect+1) {
|
||||
addr = elf_add_gsym_reloc (s, segment, addr,
|
||||
R_386_32, FALSE);
|
||||
} else if (wrt == elf_plt_sect+1) {
|
||||
error(ERR_NONFATAL, "ELF format cannot produce non-PC-"
|
||||
"relative PLT references");
|
||||
} else {
|
||||
error (ERR_NONFATAL, "ELF format does not support this"
|
||||
" use of WRT");
|
||||
wrt = NO_SEG; /* we can at least _try_ to continue */
|
||||
}
|
||||
}
|
||||
}
|
||||
p = mydata;
|
||||
if (realbytes == 2 && segment != NO_SEG)
|
||||
error (ERR_NONFATAL, "ELF format does not support 16-bit"
|
||||
if (realbytes != 4 && segment != NO_SEG)
|
||||
error (ERR_NONFATAL, "ELF format does not support non-32-bit"
|
||||
" relocations");
|
||||
WRITELONG (p, *(long *)data);
|
||||
WRITELONG (p, addr);
|
||||
elf_sect_write (s, mydata, realbytes);
|
||||
} else if (type == OUT_REL2ADR) {
|
||||
error (ERR_NONFATAL, "ELF format does not support 16-bit"
|
||||
|
|
@ -445,8 +722,22 @@ static void elf_out (long segto, void *data, unsigned long type,
|
|||
if (segment != NO_SEG && segment % 2) {
|
||||
error(ERR_NONFATAL, "ELF format does not support"
|
||||
" segment base references");
|
||||
} else
|
||||
elf_add_reloc (s, segment, TRUE);
|
||||
} else {
|
||||
if (wrt == NO_SEG) {
|
||||
elf_add_reloc (s, segment, R_386_PC32);
|
||||
} else if (wrt == elf_plt_sect+1) {
|
||||
elf_add_reloc (s, segment, R_386_PLT32);
|
||||
} else if (wrt == elf_gotpc_sect+1 ||
|
||||
wrt == elf_gotoff_sect+1 ||
|
||||
wrt == elf_got_sect+1) {
|
||||
error(ERR_NONFATAL, "ELF format cannot produce PC-"
|
||||
"relative GOT references");
|
||||
} else {
|
||||
error (ERR_NONFATAL, "ELF format does not support this"
|
||||
" use of WRT");
|
||||
wrt = NO_SEG; /* we can at least _try_ to continue */
|
||||
}
|
||||
}
|
||||
p = mydata;
|
||||
WRITELONG (p, *(long*)data - realbytes);
|
||||
elf_sect_write (s, mydata, 4L);
|
||||
|
|
@ -614,16 +905,13 @@ static struct SAA *elf_build_symtab (long *len, long *local) {
|
|||
*/
|
||||
saa_rewind (syms);
|
||||
while ( (sym = saa_rstruct (syms)) ) {
|
||||
if (sym->type == SYM_GLOBAL)
|
||||
if (sym->type & SYM_GLOBAL)
|
||||
continue;
|
||||
p = entry;
|
||||
WRITELONG (p, sym->strpos);
|
||||
WRITELONG (p, sym->value);
|
||||
if (sym->section == SHN_COMMON)
|
||||
WRITELONG (p, sym->value);
|
||||
else
|
||||
WRITELONG (p, 0);
|
||||
WRITESHORT (p, 0); /* local non-typed thing */
|
||||
WRITELONG (p, sym->size);
|
||||
WRITESHORT (p, sym->type); /* local non-typed thing */
|
||||
WRITESHORT (p, sym->section);
|
||||
saa_wbytes (s, entry, 16L);
|
||||
*len += 16;
|
||||
|
|
@ -635,16 +923,13 @@ static struct SAA *elf_build_symtab (long *len, long *local) {
|
|||
*/
|
||||
saa_rewind (syms);
|
||||
while ( (sym = saa_rstruct (syms)) ) {
|
||||
if (sym->type != SYM_GLOBAL)
|
||||
if (!(sym->type & SYM_GLOBAL))
|
||||
continue;
|
||||
p = entry;
|
||||
WRITELONG (p, sym->strpos);
|
||||
WRITELONG (p, sym->value);
|
||||
if (sym->section == SHN_COMMON)
|
||||
WRITELONG (p, sym->value);
|
||||
else
|
||||
WRITELONG (p, 0);
|
||||
WRITESHORT (p, SYM_GLOBAL); /* global non-typed thing */
|
||||
WRITELONG (p, sym->size);
|
||||
WRITESHORT (p, sym->type); /* global non-typed thing */
|
||||
WRITESHORT (p, sym->section);
|
||||
saa_wbytes (s, entry, 16L);
|
||||
*len += 16;
|
||||
|
|
@ -671,7 +956,7 @@ static struct SAA *elf_build_reltab (long *len, struct Reloc *r) {
|
|||
|
||||
p = entry;
|
||||
WRITELONG (p, r->address);
|
||||
WRITELONG (p, (sym << 8) + (r->relative ? 2 : 1));
|
||||
WRITELONG (p, (sym << 8) + r->type);
|
||||
saa_wbytes (s, entry, 8L);
|
||||
*len += 8;
|
||||
|
||||
|
|
@ -737,9 +1022,15 @@ static void elf_filename (char *inname, char *outname, efunc error) {
|
|||
standard_extension (inname, outname, ".o", error);
|
||||
}
|
||||
|
||||
static char *elf_stdmac[] = {
|
||||
"%define __SECT__ [section .text]",
|
||||
NULL
|
||||
};
|
||||
|
||||
struct ofmt of_elf = {
|
||||
"ELF32 (i386) object files (e.g. Linux)",
|
||||
"elf",
|
||||
elf_stdmac,
|
||||
elf_init,
|
||||
elf_out,
|
||||
elf_deflabel,
|
||||
|
|
|
|||
24
outform.h
24
outform.h
|
|
@ -17,8 +17,8 @@
|
|||
* OF_name -- ensure that output format 'name' is included
|
||||
* OF_NO_name -- remove output format 'name'
|
||||
* OF_DOS -- ensure that 'obj', 'bin' & 'win32' are included.
|
||||
* OF_UNIX -- ensure that 'aout', 'coff' and 'elf' are in.
|
||||
* OF_OTHERS -- ensure that 'bin', 'as86', 'os2' & 'rdf' are in.
|
||||
* OF_UNIX -- ensure that 'aout', 'aoutb', 'coff', 'elf' are in.
|
||||
* OF_OTHERS -- ensure that 'bin', 'as86' & 'rdf' are in.
|
||||
* OF_ALL -- ensure that all formats are included.
|
||||
*
|
||||
* OF_DEFAULT=of_name -- ensure that 'name' is the default format.
|
||||
|
|
@ -60,7 +60,7 @@ void ofmt_register (struct ofmt *);
|
|||
|
||||
/* ====configurable info begins here==== */
|
||||
/* formats configurable:
|
||||
* bin,obj,elf,aout,coff,win32,as86,rdf */
|
||||
* bin,obj,elf,aout,aoutb,coff,win32,as86,rdf */
|
||||
|
||||
/* process options... */
|
||||
|
||||
|
|
@ -77,9 +77,6 @@ void ofmt_register (struct ofmt *);
|
|||
#ifndef OF_OBJ
|
||||
#define OF_OBJ
|
||||
#endif
|
||||
#ifndef OF_OS2
|
||||
#define OF_OS2
|
||||
#endif
|
||||
#ifndef OF_ELF
|
||||
#define OF_ELF
|
||||
#endif
|
||||
|
|
@ -89,6 +86,9 @@ void ofmt_register (struct ofmt *);
|
|||
#ifndef OF_AOUT
|
||||
#define OF_AOUT
|
||||
#endif
|
||||
#ifndef OF_AOUTB
|
||||
#define OF_AOUTB
|
||||
#endif
|
||||
#ifndef OF_WIN32
|
||||
#define OF_WIN32
|
||||
#endif
|
||||
|
|
@ -117,6 +117,9 @@ void ofmt_register (struct ofmt *);
|
|||
#ifndef OF_AOUT
|
||||
#define OF_AOUT
|
||||
#endif
|
||||
#ifndef OF_AOUTB
|
||||
#define OF_AOUTB
|
||||
#endif
|
||||
#ifndef OF_COFF
|
||||
#define OF_COFF
|
||||
#endif
|
||||
|
|
@ -135,9 +138,6 @@ void ofmt_register (struct ofmt *);
|
|||
#ifndef OF_RDF
|
||||
#define OF_RDF
|
||||
#endif
|
||||
#ifndef OF_OS2
|
||||
#define OF_OS2
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* finally... override any format specifically specifed to be off */
|
||||
|
|
@ -153,6 +153,9 @@ void ofmt_register (struct ofmt *);
|
|||
#ifdef OF_NO_AOUT
|
||||
#undef OF_AOUT
|
||||
#endif
|
||||
#ifdef OF_NO_AOUTB
|
||||
#undef OF_AOUTB
|
||||
#endif
|
||||
#ifdef OF_NO_COFF
|
||||
#undef OF_COFF
|
||||
#endif
|
||||
|
|
@ -165,9 +168,6 @@ void ofmt_register (struct ofmt *);
|
|||
#ifdef OF_NO_RDF
|
||||
#undef OF_RDF
|
||||
#endif
|
||||
#ifdef OF_NO_OS2
|
||||
#undef OF_OS2
|
||||
#endif
|
||||
|
||||
#ifndef OF_DEFAULT
|
||||
#define OF_DEFAULT of_bin
|
||||
|
|
|
|||
648
outobj.c
648
outobj.c
|
|
@ -22,6 +22,7 @@ static char obj_infile[FILENAME_MAX];
|
|||
static int obj_uppercase;
|
||||
|
||||
static efunc error;
|
||||
static evalfunc evaluate;
|
||||
static ldfunc deflabel;
|
||||
static FILE *ofp;
|
||||
static long first_seg;
|
||||
|
|
@ -35,6 +36,9 @@ static int any_segs;
|
|||
|
||||
static unsigned char record[RECORD_MAX], *recptr;
|
||||
|
||||
struct Segment; /* need to know these structs exist */
|
||||
struct Group;
|
||||
|
||||
static struct Public {
|
||||
struct Public *next;
|
||||
char *name;
|
||||
|
|
@ -46,13 +50,27 @@ static struct External {
|
|||
struct External *next;
|
||||
char *name;
|
||||
long commonsize;
|
||||
} *exthead, **exttail;
|
||||
long commonelem; /* element size if FAR, else zero */
|
||||
int index; /* OBJ-file external index */
|
||||
enum {
|
||||
DEFWRT_NONE, /* no unusual default-WRT */
|
||||
DEFWRT_STRING, /* a string we don't yet understand */
|
||||
DEFWRT_SEGMENT, /* a segment */
|
||||
DEFWRT_GROUP /* a group */
|
||||
} defwrt_type;
|
||||
union {
|
||||
char *string;
|
||||
struct Segment *seg;
|
||||
struct Group *grp;
|
||||
} defwrt_ptr;
|
||||
struct External *next_dws; /* next with DEFWRT_STRING */
|
||||
} *exthead, **exttail, *dws;
|
||||
|
||||
static int externals;
|
||||
|
||||
static struct ExtBack {
|
||||
struct ExtBack *next;
|
||||
int index[EXT_BLKSIZ];
|
||||
struct External *exts[EXT_BLKSIZ];
|
||||
} *ebhead, **ebtail;
|
||||
|
||||
static struct Segment {
|
||||
|
|
@ -85,7 +103,7 @@ static struct Group {
|
|||
long index;
|
||||
char *name;
|
||||
} segs[GROUP_MAX]; /* ...in this */
|
||||
} *grphead, **grptail, *obj_grp_needs_update, *defgrp;
|
||||
} *grphead, **grptail, *obj_grp_needs_update;
|
||||
|
||||
static struct ObjData {
|
||||
struct ObjData *next;
|
||||
|
|
@ -97,9 +115,28 @@ static struct ObjData {
|
|||
unsigned char fixupp[RECORD_MAX], *fptr;
|
||||
} *datahead, *datacurr, **datatail;
|
||||
|
||||
static long obj_entry_seg, obj_entry_ofs;
|
||||
static struct ImpDef {
|
||||
struct ImpDef *next;
|
||||
char *extname;
|
||||
char *libname;
|
||||
unsigned int impindex;
|
||||
char *impname;
|
||||
} *imphead, **imptail;
|
||||
|
||||
static int os2;
|
||||
static struct ExpDef {
|
||||
struct ExpDef *next;
|
||||
char *intname;
|
||||
char *extname;
|
||||
unsigned int ordinal;
|
||||
int flags;
|
||||
} *exphead, **exptail;
|
||||
|
||||
#define EXPDEF_FLAG_ORDINAL 0x80
|
||||
#define EXPDEF_FLAG_RESIDENT 0x40
|
||||
#define EXPDEF_FLAG_NODATA 0x20
|
||||
#define EXPDEF_MASK_PARMCNT 0x1F
|
||||
|
||||
static long obj_entry_seg, obj_entry_ofs;
|
||||
|
||||
enum RecordID { /* record ID codes */
|
||||
|
||||
|
|
@ -140,9 +177,10 @@ static unsigned char *obj_write_value(unsigned char *, unsigned long);
|
|||
static void obj_record(int, unsigned char *, unsigned char *);
|
||||
static int obj_directive (char *, char *, int);
|
||||
|
||||
static void obj_init (FILE *fp, efunc errfunc, ldfunc ldef) {
|
||||
static void obj_init (FILE *fp, efunc errfunc, ldfunc ldef, evalfunc eval) {
|
||||
ofp = fp;
|
||||
error = errfunc;
|
||||
evaluate = eval;
|
||||
deflabel = ldef;
|
||||
first_seg = seg_alloc();
|
||||
any_segs = FALSE;
|
||||
|
|
@ -150,6 +188,11 @@ static void obj_init (FILE *fp, efunc errfunc, ldfunc ldef) {
|
|||
fpubtail = &fpubhead;
|
||||
exthead = NULL;
|
||||
exttail = &exthead;
|
||||
imphead = NULL;
|
||||
imptail = &imphead;
|
||||
exphead = NULL;
|
||||
exptail = &exphead;
|
||||
dws = NULL;
|
||||
externals = 0;
|
||||
ebhead = NULL;
|
||||
ebtail = &ebhead;
|
||||
|
|
@ -161,22 +204,6 @@ static void obj_init (FILE *fp, efunc errfunc, ldfunc ldef) {
|
|||
datatail = &datahead;
|
||||
obj_entry_seg = NO_SEG;
|
||||
obj_uppercase = FALSE;
|
||||
|
||||
if (os2) {
|
||||
obj_directive ("group", "FLAT", 1);
|
||||
defgrp = grphead;
|
||||
} else
|
||||
defgrp = NULL;
|
||||
}
|
||||
|
||||
static void dos_init (FILE *fp, efunc errfunc, ldfunc ldef) {
|
||||
os2 = FALSE;
|
||||
obj_init (fp, errfunc, ldef);
|
||||
}
|
||||
|
||||
static void os2_init (FILE *fp, efunc errfunc, ldfunc ldef) {
|
||||
os2 = TRUE;
|
||||
obj_init (fp, errfunc, ldef);
|
||||
}
|
||||
|
||||
static void obj_cleanup (void) {
|
||||
|
|
@ -188,6 +215,7 @@ static void obj_cleanup (void) {
|
|||
while (segtmp->pubhead) {
|
||||
struct Public *pubtmp = segtmp->pubhead;
|
||||
segtmp->pubhead = pubtmp->next;
|
||||
nasm_free (pubtmp->name);
|
||||
nasm_free (pubtmp);
|
||||
}
|
||||
nasm_free (segtmp);
|
||||
|
|
@ -195,6 +223,7 @@ static void obj_cleanup (void) {
|
|||
while (fpubhead) {
|
||||
struct Public *pubtmp = fpubhead;
|
||||
fpubhead = fpubhead->next;
|
||||
nasm_free (pubtmp->name);
|
||||
nasm_free (pubtmp);
|
||||
}
|
||||
while (exthead) {
|
||||
|
|
@ -202,6 +231,21 @@ static void obj_cleanup (void) {
|
|||
exthead = exthead->next;
|
||||
nasm_free (exttmp);
|
||||
}
|
||||
while (imphead) {
|
||||
struct ImpDef *imptmp = imphead;
|
||||
imphead = imphead->next;
|
||||
nasm_free (imptmp->extname);
|
||||
nasm_free (imptmp->libname);
|
||||
nasm_free (imptmp->impname); /* nasm_free won't mind if it's NULL */
|
||||
nasm_free (imptmp);
|
||||
}
|
||||
while (exphead) {
|
||||
struct ExpDef *exptmp = exphead;
|
||||
exphead = exphead->next;
|
||||
nasm_free (exptmp->extname);
|
||||
nasm_free (exptmp->intname);
|
||||
nasm_free (exptmp);
|
||||
}
|
||||
while (ebhead) {
|
||||
struct ExtBack *ebtmp = ebhead;
|
||||
ebhead = ebhead->next;
|
||||
|
|
@ -219,8 +263,34 @@ static void obj_cleanup (void) {
|
|||
}
|
||||
}
|
||||
|
||||
static void obj_ext_set_defwrt (struct External *ext, char *id) {
|
||||
struct Segment *seg;
|
||||
struct Group *grp;
|
||||
|
||||
for (seg = seghead; seg; seg = seg->next)
|
||||
if (!strcmp(seg->name, id)) {
|
||||
ext->defwrt_type = DEFWRT_SEGMENT;
|
||||
ext->defwrt_ptr.seg = seg;
|
||||
nasm_free (id);
|
||||
return;
|
||||
}
|
||||
|
||||
for (grp = grphead; grp; grp = grp->next)
|
||||
if (!strcmp(grp->name, id)) {
|
||||
ext->defwrt_type = DEFWRT_GROUP;
|
||||
ext->defwrt_ptr.grp = grp;
|
||||
nasm_free (id);
|
||||
return;
|
||||
}
|
||||
|
||||
ext->defwrt_type = DEFWRT_STRING;
|
||||
ext->defwrt_ptr.string = id;
|
||||
ext->next_dws = dws;
|
||||
dws = ext;
|
||||
}
|
||||
|
||||
static void obj_deflabel (char *name, long segment,
|
||||
long offset, int is_global) {
|
||||
long offset, int is_global, char *special) {
|
||||
/*
|
||||
* We have three cases:
|
||||
*
|
||||
|
|
@ -241,6 +311,13 @@ static void obj_deflabel (char *name, long segment,
|
|||
struct ExtBack *eb;
|
||||
struct Segment *seg;
|
||||
int i;
|
||||
int used_special = FALSE; /* have we used the special text? */
|
||||
|
||||
/*
|
||||
* If it's a special-retry from pass two, discard it.
|
||||
*/
|
||||
if (is_global == 3)
|
||||
return;
|
||||
|
||||
/*
|
||||
* First check for the double-period, signifying something
|
||||
|
|
@ -278,10 +355,13 @@ static void obj_deflabel (char *name, long segment,
|
|||
pub = *fpubtail = nasm_malloc(sizeof(*pub));
|
||||
fpubtail = &pub->next;
|
||||
pub->next = NULL;
|
||||
pub->name = name;
|
||||
pub->name = nasm_strdup(name);
|
||||
pub->offset = offset;
|
||||
pub->segment = (segment == NO_SEG ? 0 : segment & ~SEG_ABS);
|
||||
}
|
||||
if (special)
|
||||
error(ERR_NONFATAL, "OBJ supports no special symbol features"
|
||||
" for this symbol type");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -306,9 +386,12 @@ static void obj_deflabel (char *name, long segment,
|
|||
pub = *seg->pubtail = nasm_malloc(sizeof(*pub));
|
||||
seg->pubtail = &pub->next;
|
||||
pub->next = NULL;
|
||||
pub->name = name;
|
||||
pub->name = nasm_strdup(name);
|
||||
pub->offset = offset;
|
||||
}
|
||||
if (special)
|
||||
error(ERR_NONFATAL, "OBJ supports no special symbol features"
|
||||
" for this symbol type");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -319,11 +402,97 @@ static void obj_deflabel (char *name, long segment,
|
|||
ext->next = NULL;
|
||||
exttail = &ext->next;
|
||||
ext->name = name;
|
||||
if (is_global == 2)
|
||||
ext->defwrt_type = DEFWRT_NONE;
|
||||
if (is_global == 2) {
|
||||
ext->commonsize = offset;
|
||||
else
|
||||
ext->commonelem = 1; /* default FAR */
|
||||
} else
|
||||
ext->commonsize = 0;
|
||||
|
||||
/*
|
||||
* Now process the special text, if any, to find default-WRT
|
||||
* specifications and common-variable element-size and near/far
|
||||
* specifications.
|
||||
*/
|
||||
while (special && *special) {
|
||||
used_special = TRUE;
|
||||
|
||||
/*
|
||||
* We might have a default-WRT specification.
|
||||
*/
|
||||
if (!nasm_strnicmp(special, "wrt", 3)) {
|
||||
char *p;
|
||||
int len;
|
||||
special += 3;
|
||||
special += strspn(special, " \t");
|
||||
p = nasm_strndup(special, len = strcspn(special, ":"));
|
||||
obj_ext_set_defwrt (ext, p);
|
||||
special += len;
|
||||
if (*special && *special != ':')
|
||||
error(ERR_NONFATAL, "`:' expected in special symbol"
|
||||
" text for `%s'", ext->name);
|
||||
else if (*special == ':')
|
||||
special++;
|
||||
}
|
||||
|
||||
/*
|
||||
* The NEAR or FAR keywords specify nearness or
|
||||
* farness. FAR gives default element size 1.
|
||||
*/
|
||||
if (!nasm_strnicmp(special, "far", 3)) {
|
||||
if (ext->commonsize)
|
||||
ext->commonelem = 1;
|
||||
else
|
||||
error(ERR_NONFATAL, "`%s': `far' keyword may only be applied"
|
||||
" to common variables\n", ext->name);
|
||||
special += 3;
|
||||
special += strspn(special, " \t");
|
||||
} else if (!nasm_strnicmp(special, "near", 4)) {
|
||||
if (ext->commonsize)
|
||||
ext->commonelem = 0;
|
||||
else
|
||||
error(ERR_NONFATAL, "`%s': `far' keyword may only be applied"
|
||||
" to common variables\n", ext->name);
|
||||
special += 4;
|
||||
special += strspn(special, " \t");
|
||||
}
|
||||
|
||||
/*
|
||||
* If it's a common, and anything else remains on the line
|
||||
* before a further colon, evaluate it as an expression and
|
||||
* use that as the element size. Forward references aren't
|
||||
* allowed.
|
||||
*/
|
||||
if (*special == ':')
|
||||
special++;
|
||||
else if (*special) {
|
||||
if (ext->commonsize) {
|
||||
expr *e;
|
||||
struct tokenval tokval;
|
||||
|
||||
stdscan_reset();
|
||||
stdscan_bufptr = special;
|
||||
tokval.t_type = TOKEN_INVALID;
|
||||
e = evaluate(stdscan, NULL, &tokval, NULL, 1, error, NULL);
|
||||
if (e) {
|
||||
if (!is_simple(e))
|
||||
error (ERR_NONFATAL, "cannot use relocatable"
|
||||
" expression as common-variable element size");
|
||||
else
|
||||
ext->commonelem = reloc_value(e);
|
||||
}
|
||||
special = stdscan_bufptr;
|
||||
} else {
|
||||
error (ERR_NONFATAL, "`%s': element-size specifications only"
|
||||
" apply to common variables", ext->name);
|
||||
while (*special && *special != ':')
|
||||
special++;
|
||||
if (*special == ':')
|
||||
special++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
i = segment/2;
|
||||
eb = ebhead;
|
||||
if (!eb) {
|
||||
|
|
@ -341,7 +510,12 @@ static void obj_deflabel (char *name, long segment,
|
|||
}
|
||||
i -= EXT_BLKSIZ;
|
||||
}
|
||||
eb->index[i] = ++externals;
|
||||
eb->exts[i] = ext;
|
||||
ext->index = ++externals;
|
||||
|
||||
if (special && !used_special)
|
||||
error(ERR_NONFATAL, "OBJ supports no special symbol features"
|
||||
" for this symbol type");
|
||||
}
|
||||
|
||||
static void obj_out (long segto, void *data, unsigned long type,
|
||||
|
|
@ -400,6 +574,8 @@ static void obj_out (long segto, void *data, unsigned long type,
|
|||
}
|
||||
} else if (realtype == OUT_ADDRESS || realtype == OUT_REL2ADR ||
|
||||
realtype == OUT_REL4ADR) {
|
||||
int rsize;
|
||||
|
||||
if (segment == NO_SEG && realtype != OUT_ADDRESS)
|
||||
error(ERR_NONFATAL, "relative call to absolute address not"
|
||||
" supported by OBJ format");
|
||||
|
|
@ -407,10 +583,14 @@ static void obj_out (long segto, void *data, unsigned long type,
|
|||
error(ERR_NONFATAL, "far-absolute relocations not supported"
|
||||
" by OBJ format");
|
||||
ldata = *(long *)data;
|
||||
if (realtype == OUT_REL2ADR)
|
||||
if (realtype == OUT_REL2ADR) {
|
||||
ldata += (size-2);
|
||||
if (realtype == OUT_REL4ADR)
|
||||
size = 2;
|
||||
}
|
||||
if (realtype == OUT_REL4ADR) {
|
||||
ldata += (size-4);
|
||||
size = 4;
|
||||
}
|
||||
if (obj_ledata_space(seg) < 4 || !obj_fixup_free(seg))
|
||||
obj_ledata_new(seg);
|
||||
if (size == 2)
|
||||
|
|
@ -418,8 +598,22 @@ static void obj_out (long segto, void *data, unsigned long type,
|
|||
else
|
||||
datacurr->lptr = obj_write_dword (datacurr->lptr, ldata);
|
||||
datacurr->nonempty = TRUE;
|
||||
rsize = size;
|
||||
if (segment < SEG_ABS && segment % 2 && size == 4) {
|
||||
/*
|
||||
* This is a 4-byte segment-base relocation such as
|
||||
* `MOV EAX,SEG foo'. OBJ format can't actually handle
|
||||
* these, but if the constant term has the 16 low bits
|
||||
* zero, we can just apply a 2-byte segment-base
|
||||
* relocation to the low word instead.
|
||||
*/
|
||||
rsize = 2;
|
||||
if (ldata & 0xFFFF)
|
||||
error(ERR_NONFATAL, "OBJ format cannot handle complex"
|
||||
" dword-size segment base references");
|
||||
}
|
||||
if (segment != NO_SEG)
|
||||
obj_write_fixup (datacurr, size,
|
||||
obj_write_fixup (datacurr, rsize,
|
||||
(realtype == OUT_REL2ADR ||
|
||||
realtype == OUT_REL4ADR ? 0 : 0x4000),
|
||||
segment, wrt,
|
||||
|
|
@ -479,6 +673,13 @@ static void obj_write_fixup (struct ObjData *data, int bytes,
|
|||
long tidx, fidx;
|
||||
struct Segment *s = NULL;
|
||||
struct Group *g = NULL;
|
||||
struct External *e = NULL;
|
||||
|
||||
if (bytes == 1) {
|
||||
error(ERR_NONFATAL, "`obj' output driver does not support"
|
||||
" one-byte relocations");
|
||||
return;
|
||||
}
|
||||
|
||||
locat = 0x8000 | segrel | offset;
|
||||
if (seg % 2) {
|
||||
|
|
@ -486,8 +687,8 @@ static void obj_write_fixup (struct ObjData *data, int bytes,
|
|||
locat |= 0x800;
|
||||
seg--;
|
||||
if (bytes != 2)
|
||||
error(ERR_NONFATAL, "OBJ format can only handle 2-byte"
|
||||
" segment base references");
|
||||
error(ERR_PANIC, "OBJ: 4-byte segment base fixup got"
|
||||
" through sanity check");
|
||||
} else {
|
||||
base = FALSE;
|
||||
if (bytes == 2)
|
||||
|
|
@ -527,7 +728,7 @@ static void obj_write_fixup (struct ObjData *data, int bytes,
|
|||
i -= EXT_BLKSIZ;
|
||||
}
|
||||
if (eb)
|
||||
method = 6, tidx = eb->index[i];
|
||||
method = 6, e = eb->exts[i], tidx = e->index;
|
||||
else
|
||||
error(ERR_PANIC,
|
||||
"unrecognised segment value in obj_write_fixup");
|
||||
|
|
@ -536,17 +737,28 @@ static void obj_write_fixup (struct ObjData *data, int bytes,
|
|||
|
||||
/*
|
||||
* If no WRT given, assume the natural default, which is method
|
||||
* F5 unless we are doing an OFFSET fixup for a grouped
|
||||
* segment, in which case we require F1 (group). Oh, and in
|
||||
* OS/2 mode we're in F1 (group) on `defgrp' _always_, by
|
||||
* default.
|
||||
* F5 unless:
|
||||
*
|
||||
* - we are doing an OFFSET fixup for a grouped segment, in
|
||||
* which case we require F1 (group).
|
||||
*
|
||||
* - we are doing an OFFSET fixup for an external with a
|
||||
* default WRT, in which case we must honour the default WRT.
|
||||
*/
|
||||
if (wrt == NO_SEG) {
|
||||
if (os2)
|
||||
method |= 0x10, fidx = defgrp->obj_index;
|
||||
else if (!base && s && s->grp)
|
||||
if (!base && s && s->grp)
|
||||
method |= 0x10, fidx = s->grp->obj_index;
|
||||
else
|
||||
else if (!base && e && e->defwrt_type != DEFWRT_NONE) {
|
||||
if (e->defwrt_type == DEFWRT_SEGMENT)
|
||||
method |= 0x00, fidx = e->defwrt_ptr.seg->obj_index;
|
||||
else if (e->defwrt_type == DEFWRT_GROUP)
|
||||
method |= 0x10, fidx = e->defwrt_ptr.grp->obj_index;
|
||||
else {
|
||||
error(ERR_NONFATAL, "default WRT specification for"
|
||||
" external `%s' unresolved", e->name);
|
||||
method |= 0x50, fidx = -1; /* got to do _something_ */
|
||||
}
|
||||
} else
|
||||
method |= 0x50, fidx = -1;
|
||||
} else {
|
||||
/*
|
||||
|
|
@ -575,7 +787,7 @@ static void obj_write_fixup (struct ObjData *data, int bytes,
|
|||
i -= EXT_BLKSIZ;
|
||||
}
|
||||
if (eb)
|
||||
method |= 0x20, fidx = eb->index[i];
|
||||
method |= 0x20, fidx = eb->exts[i]->index;
|
||||
else
|
||||
error(ERR_PANIC,
|
||||
"unrecognised WRT value in obj_write_fixup");
|
||||
|
|
@ -603,6 +815,7 @@ static long obj_segment (char *name, int pass, int *bits) {
|
|||
} else {
|
||||
struct Segment *seg;
|
||||
struct Group *grp;
|
||||
struct External **extp;
|
||||
int obj_idx, i, attrs, rn_error;
|
||||
char *p;
|
||||
|
||||
|
|
@ -686,7 +899,32 @@ static long obj_segment (char *name, int pass, int *bits) {
|
|||
seg->use32 = FALSE;
|
||||
else if (!nasm_stricmp(p, "use32"))
|
||||
seg->use32 = TRUE;
|
||||
else if (!nasm_strnicmp(p, "class=", 6))
|
||||
else if (!nasm_stricmp(p, "flat")) {
|
||||
/*
|
||||
* This segment is an OS/2 FLAT segment. That means
|
||||
* that its default group is group FLAT, even if
|
||||
* the group FLAT does not explicitly _contain_ the
|
||||
* segment.
|
||||
*
|
||||
* When we see this, we must create the group
|
||||
* `FLAT', containing no segments, if it does not
|
||||
* already exist; then we must set the default
|
||||
* group of this segment to be the FLAT group.
|
||||
*/
|
||||
struct Group *grp;
|
||||
for (grp = grphead; grp; grp = grp->next)
|
||||
if (!strcmp(grp->name, "FLAT"))
|
||||
break;
|
||||
if (!grp) {
|
||||
obj_directive ("group", "FLAT", 1);
|
||||
for (grp = grphead; grp; grp = grp->next)
|
||||
if (!strcmp(grp->name, "FLAT"))
|
||||
break;
|
||||
if (!grp)
|
||||
error (ERR_PANIC, "failure to define FLAT?!");
|
||||
}
|
||||
seg->grp = grp;
|
||||
} else if (!nasm_strnicmp(p, "class=", 6))
|
||||
seg->segclass = nasm_strdup(p+6);
|
||||
else if (!nasm_strnicmp(p, "overlay=", 8))
|
||||
seg->overlay = nasm_strdup(p+8);
|
||||
|
|
@ -703,6 +941,7 @@ static long obj_segment (char *name, int pass, int *bits) {
|
|||
case 4: /* DWORD */
|
||||
case 16: /* PARA */
|
||||
case 256: /* PAGE */
|
||||
case 4096: /* PharLap extension */
|
||||
break;
|
||||
case 8:
|
||||
error(ERR_WARNING, "OBJ format does not support alignment"
|
||||
|
|
@ -716,6 +955,13 @@ static long obj_segment (char *name, int pass, int *bits) {
|
|||
" of %d: rounding up to 256", seg->align);
|
||||
seg->align = 256;
|
||||
break;
|
||||
case 512:
|
||||
case 1024:
|
||||
case 2048:
|
||||
error(ERR_WARNING, "OBJ format does not support alignment"
|
||||
" of %d: rounding up to 4096", seg->align);
|
||||
seg->align = 4096;
|
||||
break;
|
||||
default:
|
||||
error(ERR_NONFATAL, "invalid alignment value %d",
|
||||
seg->align);
|
||||
|
|
@ -732,9 +978,11 @@ static long obj_segment (char *name, int pass, int *bits) {
|
|||
|
||||
obj_seg_needs_update = seg;
|
||||
if (seg->align >= SEG_ABS)
|
||||
deflabel (name, NO_SEG, seg->align - SEG_ABS, &of_obj, error);
|
||||
deflabel (name, NO_SEG, seg->align - SEG_ABS,
|
||||
NULL, FALSE, FALSE, &of_obj, error);
|
||||
else
|
||||
deflabel (name, seg->index+1, 0L, &of_obj, error);
|
||||
deflabel (name, seg->index+1, 0L,
|
||||
NULL, FALSE, FALSE, &of_obj, error);
|
||||
obj_seg_needs_update = NULL;
|
||||
|
||||
/*
|
||||
|
|
@ -756,6 +1004,22 @@ static long obj_segment (char *name, int pass, int *bits) {
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Walk through the list of externals with unresolved
|
||||
* default-WRT clauses, and resolve any that point at this
|
||||
* segment.
|
||||
*/
|
||||
extp = &dws;
|
||||
while (*extp) {
|
||||
if ((*extp)->defwrt_type == DEFWRT_STRING &&
|
||||
!strcmp((*extp)->defwrt_ptr.string, seg->name)) {
|
||||
(*extp)->defwrt_type = DEFWRT_SEGMENT;
|
||||
(*extp)->defwrt_ptr.seg = seg;
|
||||
*extp = (*extp)->next_dws;
|
||||
} else
|
||||
extp = &(*extp)->next_dws;
|
||||
}
|
||||
|
||||
if (seg->use32)
|
||||
*bits = 32;
|
||||
else
|
||||
|
|
@ -770,6 +1034,7 @@ static int obj_directive (char *directive, char *value, int pass) {
|
|||
if (pass == 1) {
|
||||
struct Group *grp;
|
||||
struct Segment *seg;
|
||||
struct External **extp;
|
||||
int obj_idx;
|
||||
|
||||
q = value;
|
||||
|
|
@ -813,7 +1078,8 @@ static int obj_directive (char *directive, char *value, int pass) {
|
|||
grp->name = NULL;
|
||||
|
||||
obj_grp_needs_update = grp;
|
||||
deflabel (v, grp->index+1, 0L, &of_obj, error);
|
||||
deflabel (v, grp->index+1, 0L,
|
||||
NULL, FALSE, FALSE, &of_obj, error);
|
||||
obj_grp_needs_update = NULL;
|
||||
|
||||
while (*q) {
|
||||
|
|
@ -852,6 +1118,22 @@ static int obj_directive (char *directive, char *value, int pass) {
|
|||
grp->segs[grp->nentries++].name = nasm_strdup(p);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Walk through the list of externals with unresolved
|
||||
* default-WRT clauses, and resolve any that point at
|
||||
* this group.
|
||||
*/
|
||||
extp = &dws;
|
||||
while (*extp) {
|
||||
if ((*extp)->defwrt_type == DEFWRT_STRING &&
|
||||
!strcmp((*extp)->defwrt_ptr.string, grp->name)) {
|
||||
(*extp)->defwrt_type = DEFWRT_GROUP;
|
||||
(*extp)->defwrt_ptr.grp = grp;
|
||||
*extp = (*extp)->next_dws;
|
||||
} else
|
||||
extp = &(*extp)->next_dws;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
|
@ -859,6 +1141,129 @@ static int obj_directive (char *directive, char *value, int pass) {
|
|||
obj_uppercase = TRUE;
|
||||
return 1;
|
||||
}
|
||||
if (!strcmp(directive, "import")) {
|
||||
char *q, *extname, *libname, *impname;
|
||||
|
||||
if (pass == 2)
|
||||
return 1; /* ignore in pass two */
|
||||
extname = q = value;
|
||||
while (*q && !isspace(*q))
|
||||
q++;
|
||||
if (isspace(*q)) {
|
||||
*q++ = '\0';
|
||||
while (*q && isspace(*q))
|
||||
q++;
|
||||
}
|
||||
|
||||
libname = q;
|
||||
while (*q && !isspace(*q))
|
||||
q++;
|
||||
if (isspace(*q)) {
|
||||
*q++ = '\0';
|
||||
while (*q && isspace(*q))
|
||||
q++;
|
||||
}
|
||||
|
||||
impname = q;
|
||||
|
||||
if (!*extname || !*libname)
|
||||
error(ERR_NONFATAL, "`import' directive requires symbol name"
|
||||
" and library name");
|
||||
else {
|
||||
struct ImpDef *imp;
|
||||
int err = FALSE;
|
||||
|
||||
imp = *imptail = nasm_malloc(sizeof(struct ImpDef));
|
||||
imptail = &imp->next;
|
||||
imp->next = NULL;
|
||||
imp->extname = nasm_strdup(extname);
|
||||
imp->libname = nasm_strdup(libname);
|
||||
imp->impindex = readnum(impname, &err);
|
||||
if (!*impname || err)
|
||||
imp->impname = nasm_strdup(impname);
|
||||
else
|
||||
imp->impname = NULL;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
if (!strcmp(directive, "export")) {
|
||||
char *q, *extname, *intname, *v;
|
||||
struct ExpDef *export;
|
||||
int flags = 0;
|
||||
unsigned int ordinal = 0;
|
||||
|
||||
if (pass == 2)
|
||||
return 1; /* ignore in pass two */
|
||||
intname = q = value;
|
||||
while (*q && !isspace(*q))
|
||||
q++;
|
||||
if (isspace(*q)) {
|
||||
*q++ = '\0';
|
||||
while (*q && isspace(*q))
|
||||
q++;
|
||||
}
|
||||
|
||||
extname = q;
|
||||
while (*q && !isspace(*q))
|
||||
q++;
|
||||
if (isspace(*q)) {
|
||||
*q++ = '\0';
|
||||
while (*q && isspace(*q))
|
||||
q++;
|
||||
}
|
||||
|
||||
if (!*intname) {
|
||||
error(ERR_NONFATAL, "`export' directive requires export name");
|
||||
return 1;
|
||||
}
|
||||
if (!*extname) {
|
||||
extname = intname;
|
||||
intname = "";
|
||||
}
|
||||
while (*q) {
|
||||
v = q;
|
||||
while (*q && !isspace(*q))
|
||||
q++;
|
||||
if (isspace(*q)) {
|
||||
*q++ = '\0';
|
||||
while (*q && isspace(*q))
|
||||
q++;
|
||||
}
|
||||
if (!nasm_stricmp(v, "resident"))
|
||||
flags |= EXPDEF_FLAG_RESIDENT;
|
||||
else if (!nasm_stricmp(v, "nodata"))
|
||||
flags |= EXPDEF_FLAG_NODATA;
|
||||
else if (!nasm_strnicmp(v, "parm=", 5)) {
|
||||
int err = FALSE;
|
||||
flags |= EXPDEF_MASK_PARMCNT & readnum(v+5, &err);
|
||||
if (err) {
|
||||
error(ERR_NONFATAL,
|
||||
"value `%s' for `parm' is non-numeric", v+5);
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
int err = FALSE;
|
||||
ordinal = readnum(v, &err);
|
||||
if (err) {
|
||||
error(ERR_NONFATAL, "unrecognised export qualifier `%s'",
|
||||
v);
|
||||
return 1;
|
||||
}
|
||||
flags |= EXPDEF_FLAG_ORDINAL;
|
||||
}
|
||||
}
|
||||
|
||||
export = *exptail = nasm_malloc(sizeof(struct ExpDef));
|
||||
exptail = &export->next;
|
||||
export->next = NULL;
|
||||
export->extname = nasm_strdup(extname);
|
||||
export->intname = nasm_strdup(intname);
|
||||
export->ordinal = ordinal;
|
||||
export->flags = flags;
|
||||
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -872,8 +1277,35 @@ static long obj_segbase (long segment) {
|
|||
if (seg->index == segment-1)
|
||||
break;
|
||||
|
||||
if (!seg)
|
||||
if (!seg) {
|
||||
/*
|
||||
* Might be an external with a default WRT.
|
||||
*/
|
||||
long i = segment/2;
|
||||
struct ExtBack *eb = ebhead;
|
||||
struct External *e;
|
||||
|
||||
while (i > EXT_BLKSIZ) {
|
||||
if (eb)
|
||||
eb = eb->next;
|
||||
else
|
||||
break;
|
||||
i -= EXT_BLKSIZ;
|
||||
}
|
||||
if (eb) {
|
||||
e = eb->exts[i];
|
||||
if (e->defwrt_type == DEFWRT_NONE)
|
||||
return segment; /* fine */
|
||||
else if (e->defwrt_type == DEFWRT_SEGMENT)
|
||||
return e->defwrt_ptr.seg->index+1;
|
||||
else if (e->defwrt_type == DEFWRT_GROUP)
|
||||
return e->defwrt_ptr.grp->index+1;
|
||||
else if (e->defwrt_type == DEFWRT_STRING)
|
||||
return NO_SEG; /* can't tell what it is */
|
||||
}
|
||||
|
||||
return segment; /* not one of ours - leave it alone */
|
||||
}
|
||||
|
||||
if (seg->align >= SEG_ABS)
|
||||
return seg->align; /* absolute segment */
|
||||
|
|
@ -894,6 +1326,8 @@ static void obj_write_file (void) {
|
|||
struct Public *pub;
|
||||
struct External *ext;
|
||||
struct ObjData *data;
|
||||
struct ImpDef *imp;
|
||||
struct ExpDef *export;
|
||||
static char boast[] = "The Netwide Assembler " NASM_VER;
|
||||
int lname_idx, rectype;
|
||||
|
||||
|
|
@ -912,6 +1346,41 @@ static void obj_write_file (void) {
|
|||
recptr = obj_write_name (recptr, boast);
|
||||
obj_record (COMENT, record, recptr);
|
||||
|
||||
/*
|
||||
* Write the IMPDEF records, if any.
|
||||
*/
|
||||
for (imp = imphead; imp; imp = imp->next) {
|
||||
recptr = record;
|
||||
recptr = obj_write_rword (recptr, 0xA0); /* comment class A0 */
|
||||
recptr = obj_write_byte (recptr, 1); /* subfunction 1: IMPDEF */
|
||||
if (imp->impname)
|
||||
recptr = obj_write_byte (recptr, 0); /* import by name */
|
||||
else
|
||||
recptr = obj_write_byte (recptr, 1); /* import by ordinal */
|
||||
recptr = obj_write_name (recptr, imp->extname);
|
||||
recptr = obj_write_name (recptr, imp->libname);
|
||||
if (imp->impname)
|
||||
recptr = obj_write_name (recptr, imp->impname);
|
||||
else
|
||||
recptr = obj_write_word (recptr, imp->impindex);
|
||||
obj_record (COMENT, record, recptr);
|
||||
}
|
||||
|
||||
/*
|
||||
* Write the EXPDEF records, if any.
|
||||
*/
|
||||
for (export = exphead; export; export = export->next) {
|
||||
recptr = record;
|
||||
recptr = obj_write_rword (recptr, 0xA0); /* comment class A0 */
|
||||
recptr = obj_write_byte (recptr, 2); /* subfunction 1: EXPDEF */
|
||||
recptr = obj_write_byte (recptr, export->flags);
|
||||
recptr = obj_write_name (recptr, export->extname);
|
||||
recptr = obj_write_name (recptr, export->intname);
|
||||
if (export->flags & EXPDEF_FLAG_ORDINAL)
|
||||
recptr = obj_write_word (recptr, export->ordinal);
|
||||
obj_record (COMENT, record, recptr);
|
||||
}
|
||||
|
||||
/*
|
||||
* Write the first LNAMES record, containing LNAME one, which
|
||||
* is null. Also initialise the LNAME counter.
|
||||
|
|
@ -961,10 +1430,12 @@ static void obj_write_file (void) {
|
|||
/* A field */
|
||||
if (seg->align >= SEG_ABS)
|
||||
acbp |= 0x00;
|
||||
else if (seg->align >= 256) {
|
||||
if (seg->align > 256)
|
||||
else if (seg->align >= 4096) {
|
||||
if (seg->align > 4096)
|
||||
error(ERR_NONFATAL, "segment `%s' requires more alignment"
|
||||
" than OBJ format supports", seg->name);
|
||||
acbp |= 0xC0; /* PharLap extension */
|
||||
} else if (seg->align >= 256) {
|
||||
acbp |= 0x80;
|
||||
} else if (seg->align >= 16) {
|
||||
acbp |= 0x60;
|
||||
|
|
@ -1000,11 +1471,11 @@ static void obj_write_file (void) {
|
|||
*/
|
||||
recptr = record;
|
||||
for (grp = grphead; grp; grp = grp->next) {
|
||||
recptr = obj_write_name (recptr, grp->name);
|
||||
if (recptr - record > 1024) {
|
||||
if (recptr - record + strlen(grp->name)+2 > 1024) {
|
||||
obj_record (LNAMES, record, recptr);
|
||||
recptr = record;
|
||||
}
|
||||
recptr = obj_write_name (recptr, grp->name);
|
||||
}
|
||||
if (recptr > record)
|
||||
obj_record (LNAMES, record, recptr);
|
||||
|
|
@ -1083,28 +1554,29 @@ static void obj_write_file (void) {
|
|||
recptr = record;
|
||||
for (ext = exthead; ext; ext = ext->next) {
|
||||
if (ext->commonsize == 0) {
|
||||
recptr = obj_write_name (recptr, ext->name);
|
||||
recptr = obj_write_index (recptr, 0);
|
||||
if (recptr - record > 1024) {
|
||||
/* dj@delorie.com: check for buffer overrun before we overrun it */
|
||||
if (recptr - record + strlen(ext->name)+2 > RECORD_MAX) {
|
||||
obj_record (EXTDEF, record, recptr);
|
||||
recptr = record;
|
||||
}
|
||||
recptr = obj_write_name (recptr, ext->name);
|
||||
recptr = obj_write_index (recptr, 0);
|
||||
} else {
|
||||
if (recptr > record)
|
||||
obj_record (EXTDEF, record, recptr);
|
||||
recptr = record;
|
||||
if (ext->commonsize > 0) {
|
||||
if (ext->commonsize) {
|
||||
recptr = obj_write_name (recptr, ext->name);
|
||||
recptr = obj_write_index (recptr, 0);
|
||||
recptr = obj_write_byte (recptr, 0x61);/* far communal */
|
||||
recptr = obj_write_value (recptr, 1L);
|
||||
recptr = obj_write_value (recptr, ext->commonsize);
|
||||
obj_record (COMDEF, record, recptr);
|
||||
} else if (ext->commonsize < 0) {
|
||||
recptr = obj_write_name (recptr, ext->name);
|
||||
recptr = obj_write_index (recptr, 0);
|
||||
recptr = obj_write_byte (recptr, 0x62);/* near communal */
|
||||
recptr = obj_write_value (recptr, ext->commonsize);
|
||||
if (ext->commonelem) {
|
||||
recptr = obj_write_byte (recptr, 0x61);/* far communal */
|
||||
recptr = obj_write_value (recptr, (ext->commonsize /
|
||||
ext->commonelem));
|
||||
recptr = obj_write_value (recptr, ext->commonelem);
|
||||
} else {
|
||||
recptr = obj_write_byte (recptr, 0x62);/* near communal */
|
||||
recptr = obj_write_value (recptr, ext->commonsize);
|
||||
}
|
||||
obj_record (COMDEF, record, recptr);
|
||||
}
|
||||
recptr = record;
|
||||
|
|
@ -1115,12 +1587,12 @@ static void obj_write_file (void) {
|
|||
|
||||
/*
|
||||
* Write a COMENT record stating that the linker's first pass
|
||||
* may stop processing at this point. Exception is if we're in
|
||||
* OS/2 mode and our MODEND record specifies a start point, in
|
||||
* which case, according to the OS/2 documentation, this COMENT
|
||||
* should be omitted.
|
||||
* may stop processing at this point. Exception is if our
|
||||
* MODEND record specifies a start point, in which case,
|
||||
* according to some variants of the documentation, this COMENT
|
||||
* should be omitted. So we'll omit it just in case.
|
||||
*/
|
||||
if (!os2 || obj_entry_seg == NO_SEG) {
|
||||
if (obj_entry_seg == NO_SEG) {
|
||||
recptr = record;
|
||||
recptr = obj_write_rword (recptr, 0x40A2);
|
||||
recptr = obj_write_byte (recptr, 1);
|
||||
|
|
@ -1262,13 +1734,31 @@ static void obj_record(int type, unsigned char *start, unsigned char *end) {
|
|||
fwrite (start, 1, end-start, ofp);
|
||||
while (start < end)
|
||||
cksum += *start++;
|
||||
fputc ( (-cksum) & 0xFF, ofp);
|
||||
fputc ( (-(long)cksum) & 0xFF, ofp);
|
||||
}
|
||||
|
||||
static char *obj_stdmac[] = {
|
||||
"%define __SECT__ [section .text]",
|
||||
"%imacro group 1+.nolist",
|
||||
"[group %1]",
|
||||
"%endmacro",
|
||||
"%imacro uppercase 1+.nolist",
|
||||
"[uppercase %1]",
|
||||
"%endmacro",
|
||||
"%imacro export 1+.nolist",
|
||||
"[export %1]",
|
||||
"%endmacro",
|
||||
"%imacro import 1+.nolist",
|
||||
"[import %1]",
|
||||
"%endmacro",
|
||||
NULL
|
||||
};
|
||||
|
||||
struct ofmt of_obj = {
|
||||
"Microsoft MS-DOS 16-bit OMF object files",
|
||||
"obj",
|
||||
dos_init,
|
||||
obj_stdmac,
|
||||
obj_init,
|
||||
obj_out,
|
||||
obj_deflabel,
|
||||
obj_segment,
|
||||
|
|
@ -1277,18 +1767,4 @@ struct ofmt of_obj = {
|
|||
obj_filename,
|
||||
obj_cleanup
|
||||
};
|
||||
|
||||
struct ofmt of_os2 = {
|
||||
"OS/2 object files (variant of OMF)",
|
||||
"os2",
|
||||
os2_init,
|
||||
obj_out,
|
||||
obj_deflabel,
|
||||
obj_segment,
|
||||
obj_segbase,
|
||||
obj_directive,
|
||||
obj_filename,
|
||||
obj_cleanup
|
||||
};
|
||||
|
||||
#endif /* OF_OBJ */
|
||||
|
|
|
|||
42
outrdf.c
42
outrdf.c
|
|
@ -187,7 +187,7 @@ static efunc error;
|
|||
static int segtext,segdata,segbss;
|
||||
static long bsslength;
|
||||
|
||||
static void rdf_init(FILE *fp, efunc errfunc, ldfunc ldef)
|
||||
static void rdf_init(FILE *fp, efunc errfunc, ldfunc ldef, evalfunc eval)
|
||||
{
|
||||
ofile = fp;
|
||||
error = errfunc;
|
||||
|
|
@ -261,7 +261,8 @@ static void write_dll_rec(struct DLLRec *r)
|
|||
membufwrite(header,r->libname,strlen(r->libname) + 1);
|
||||
}
|
||||
|
||||
static void rdf_deflabel(char *name, long segment, long offset, int is_global)
|
||||
static void rdf_deflabel(char *name, long segment, long offset,
|
||||
int is_global, char *special)
|
||||
{
|
||||
struct ExportRec r;
|
||||
struct ImportRec ri;
|
||||
|
|
@ -269,28 +270,23 @@ static void rdf_deflabel(char *name, long segment, long offset, int is_global)
|
|||
static int warned_common = 0;
|
||||
#endif
|
||||
|
||||
if (special)
|
||||
error (ERR_NONFATAL, "RDOFF format does not support any"
|
||||
" special symbol types");
|
||||
|
||||
if (name[0] == '.' && name[1] == '.' && name[2] != '@') {
|
||||
error (ERR_NONFATAL, "unrecognised special symbol `%s'", name);
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_global && segment > 4) {
|
||||
if (is_global == 2) {
|
||||
#ifdef VERBOSE_WARNINGS
|
||||
if (! warned_common) {
|
||||
error(ERR_WARNING,"common declarations not supported... using extern");
|
||||
if (!warned_common) {
|
||||
error(ERR_WARNING,"common declarations not supported: using extern");
|
||||
warned_common = 1;
|
||||
}
|
||||
#endif
|
||||
is_global = 0;
|
||||
}
|
||||
|
||||
if (is_global) {
|
||||
r.type = 3;
|
||||
r.segment = segment;
|
||||
r.offset = offset;
|
||||
strncpy(r.label,name,32);
|
||||
r.label[32] = 0;
|
||||
write_export_rec(&r);
|
||||
is_global = 1;
|
||||
}
|
||||
|
||||
if (segment > 4) { /* EXTERN declaration */
|
||||
|
|
@ -299,6 +295,13 @@ static void rdf_deflabel(char *name, long segment, long offset, int is_global)
|
|||
strncpy(ri.label,name,32);
|
||||
ri.label[32] = 0;
|
||||
write_import_rec(&ri);
|
||||
} else if (is_global) {
|
||||
r.type = 3;
|
||||
r.segment = segment;
|
||||
r.offset = offset;
|
||||
strncpy(r.label,name,32);
|
||||
r.label[32] = 0;
|
||||
write_export_rec(&r);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -484,9 +487,18 @@ static void rdf_filename (char *inname, char *outname, efunc error) {
|
|||
standard_extension(inname,outname,".rdf",error);
|
||||
}
|
||||
|
||||
static char *rdf_stdmac[] = {
|
||||
"%define __SECT__ [section .text]",
|
||||
"%imacro library 1+.nolist",
|
||||
"[library %1]",
|
||||
"%endmacro",
|
||||
NULL
|
||||
};
|
||||
|
||||
struct ofmt of_rdf = {
|
||||
"Relocatable Dynamic Object File Format v1.1",
|
||||
"rdf",
|
||||
rdf_stdmac,
|
||||
rdf_init,
|
||||
rdf_out,
|
||||
rdf_deflabel,
|
||||
|
|
|
|||
5
parser.h
5
parser.h
|
|
@ -10,9 +10,8 @@
|
|||
#ifndef NASM_PARSER_H
|
||||
#define NASM_PARSER_H
|
||||
|
||||
insn *parse_line (long segment, long offset, lfunc lookup_label, int pass,
|
||||
char *buffer, insn *result, struct ofmt *output,
|
||||
efunc error);
|
||||
insn *parse_line (int pass, char *buffer, insn *result,
|
||||
efunc error, evalfunc evaluate, evalinfofunc einfo);
|
||||
void cleanup_insn (insn *instruction);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
void pp_include_path (char *);
|
||||
void pp_pre_include (char *);
|
||||
void pp_pre_define (char *);
|
||||
void pp_extra_stdmac (char **);
|
||||
|
||||
extern Preproc nasmpp;
|
||||
|
||||
|
|
|
|||
74
rdoff/Makefile.in
Normal file
74
rdoff/Makefile.in
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
#
|
||||
# Auto-configuring Makefile for RDOFF object file utils; part of the
|
||||
# Netwide Assembler
|
||||
#
|
||||
# The Netwide Assembler is copyright (C) 1996 Simon Tatham and
|
||||
# Julian Hall. All rights reserved. The software is
|
||||
# redistributable under the licence given in the file "Licence"
|
||||
# distributed in the NASM archive.
|
||||
|
||||
top_srcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
prefix = @prefix@
|
||||
exec_prefix = @exec_prefix@
|
||||
bindir = @bindir@
|
||||
mandir = @mandir@
|
||||
|
||||
CC = @CC@
|
||||
CFLAGS = @CFLAGS@ @GCCFLAGS@ -I$(top_srcdir)
|
||||
|
||||
INSTALL = @INSTALL@
|
||||
INSTALL_PROGRAM = @INSTALL_PROGRAM@
|
||||
INSTALL_DATA = @INSTALL_DATA@
|
||||
LN_S = @LN_S@
|
||||
|
||||
LDRDFLIBS = rdoff.o nasmlib.o symtab.o collectn.o rdlib.o
|
||||
RDXLIBS = rdoff.o rdfload.o symtab.o collectn.o
|
||||
|
||||
.c.o:
|
||||
$(CC) -c $(CFLAGS) $<
|
||||
|
||||
all: rdfdump ldrdf rdx rdflib rdf2bin rdf2com
|
||||
|
||||
rdfdump: rdfdump.o
|
||||
$(CC) -o rdfdump rdfdump.o
|
||||
|
||||
ldrdf: ldrdf.o $(LDRDFLIBS)
|
||||
$(CC) -o ldrdf ldrdf.o $(LDRDFLIBS)
|
||||
rdx: rdx.o $(RDXLIBS)
|
||||
$(CC) -o rdx rdx.o $(RDXLIBS)
|
||||
rdflib: rdflib.o
|
||||
$(CC) -o rdflib rdflib.o
|
||||
rdf2bin: rdf2bin.o $(RDXLIBS) nasmlib.o
|
||||
$(CC) -o rdf2bin rdf2bin.o $(RDXLIBS) nasmlib.o
|
||||
rdf2com:
|
||||
$(LN_S) rdf2bin rdf2com
|
||||
|
||||
rdf2bin.o: rdf2bin.c
|
||||
rdfdump.o: rdfdump.c
|
||||
rdoff.o: rdoff.c rdoff.h
|
||||
ldrdf.o: ldrdf.c rdoff.h $(top_srcdir)/nasmlib.h symtab.h collectn.h rdlib.h
|
||||
symtab.o: symtab.c symtab.h
|
||||
collectn.o: collectn.c collectn.h
|
||||
rdx.o: rdx.c rdoff.h rdfload.h symtab.h
|
||||
rdfload.o: rdfload.c rdfload.h rdoff.h collectn.h symtab.h
|
||||
rdlib.o: rdlib.c rdlib.h
|
||||
rdflib.o: rdflib.c
|
||||
|
||||
nasmlib.o: $(top_srcdir)/nasmlib.c
|
||||
$(CC) -c $(CFLAGS) $(top_srcdir)/nasmlib.c
|
||||
|
||||
clean:
|
||||
rm -f *.o rdfdump ldrdf rdx rdflib rdf2bin rdf2com
|
||||
|
||||
spotless: clean
|
||||
rm -f Makefile
|
||||
|
||||
install: rdfdump ldrdf rdx rdflib rdf2bin rdf2com
|
||||
$(INSTALL_PROGRAM) rdfdump $(bindir)/rdfdump
|
||||
$(INSTALL_PROGRAM) ldrdf $(bindir)/ldrdf
|
||||
$(INSTALL_PROGRAM) rdx $(bindir)/rdx
|
||||
$(INSTALL_PROGRAM) rdflib $(bindir)/rdflib
|
||||
$(INSTALL_PROGRAM) rdf2bin $(bindir)/rdf2bin
|
||||
cd $(bindir); $(LN_S) rdf2bin rdf2com
|
||||
73
rdoff/Makefile.unx
Normal file
73
rdoff/Makefile.unx
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
# Generated automatically from Makefile.in by configure.
|
||||
#
|
||||
# Auto-configuring Makefile for RDOFF object file utils; part of the
|
||||
# Netwide Assembler
|
||||
#
|
||||
# The Netwide Assembler is copyright (C) 1996 Simon Tatham and
|
||||
# Julian Hall. All rights reserved. The software is
|
||||
# redistributable under the licence given in the file "Licence"
|
||||
# distributed in the NASM archive.
|
||||
|
||||
# You may need to adjust these values.
|
||||
|
||||
prefix = /usr/local
|
||||
CC = cc
|
||||
CFLAGS = -O -I..
|
||||
|
||||
# You _shouldn't_ need to adjust anything below this line.
|
||||
|
||||
exec_prefix = ${prefix}
|
||||
bindir = ${exec_prefix}/bin
|
||||
mandir = ${prefix}/man
|
||||
|
||||
INSTALL = /usr/bin/install -c
|
||||
INSTALL_PROGRAM = ${INSTALL}
|
||||
INSTALL_DATA = ${INSTALL} -m 644
|
||||
LN_S = ln -s
|
||||
|
||||
LDRDFLIBS = rdoff.o nasmlib.o symtab.o collectn.o rdlib.o
|
||||
RDXLIBS = rdoff.o rdfload.o symtab.o collectn.o
|
||||
|
||||
.c.o:
|
||||
$(CC) -c $(CFLAGS) $*.c
|
||||
|
||||
all: rdfdump ldrdf rdx rdflib rdf2bin rdf2com
|
||||
|
||||
rdfdump: rdfdump.o
|
||||
$(CC) -o rdfdump rdfdump.o
|
||||
|
||||
ldrdf: ldrdf.o $(LDRDFLIBS)
|
||||
$(CC) -o ldrdf ldrdf.o $(LDRDFLIBS)
|
||||
rdx: rdx.o $(RDXLIBS)
|
||||
$(CC) -o rdx rdx.o $(RDXLIBS)
|
||||
rdflib: rdflib.o
|
||||
$(CC) -o rdflib rdflib.o
|
||||
rdf2bin: rdf2bin.o $(RDXLIBS) nasmlib.o
|
||||
$(CC) -o rdf2bin rdf2bin.o $(RDXLIBS) nasmlib.o
|
||||
rdf2com:
|
||||
$(LN_S) rdf2bin rdf2com
|
||||
|
||||
rdf2bin.o: rdf2bin.c
|
||||
rdfdump.o: rdfdump.c
|
||||
rdoff.o: rdoff.c rdoff.h
|
||||
ldrdf.o: ldrdf.c rdoff.h ../nasmlib.h symtab.h collectn.h rdlib.h
|
||||
symtab.o: symtab.c symtab.h
|
||||
collectn.o: collectn.c collectn.h
|
||||
rdx.o: rdx.c rdoff.h rdfload.h symtab.h
|
||||
rdfload.o: rdfload.c rdfload.h rdoff.h collectn.h symtab.h
|
||||
rdlib.o: rdlib.c rdlib.h
|
||||
rdflib.o: rdflib.c
|
||||
|
||||
nasmlib.o: ../nasmlib.c ../nasmlib.h ../names.c ../nasm.h
|
||||
$(CC) -c $(CFLAGS) ../nasmlib.c
|
||||
|
||||
clean:
|
||||
rm -f *.o rdfdump ldrdf rdx rdflib rdf2bin rdf2com
|
||||
|
||||
install: rdfdump ldrdf rdx rdflib rdf2bin rdf2com
|
||||
$(INSTALL_PROGRAM) rdfdump $(bindir)/rdfdump
|
||||
$(INSTALL_PROGRAM) ldrdf $(bindir)/ldrdf
|
||||
$(INSTALL_PROGRAM) rdx $(bindir)/rdx
|
||||
$(INSTALL_PROGRAM) rdflib $(bindir)/rdflib
|
||||
$(INSTALL_PROGRAM) rdf2bin $(bindir)/rdf2bin
|
||||
cd $(bindir); $(LN_S) rdf2bin rdf2com
|
||||
|
|
@ -24,7 +24,6 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "nasm.h"
|
||||
#include "rdoff.h"
|
||||
#include "nasmlib.h"
|
||||
#include "symtab.h"
|
||||
|
|
@ -419,8 +418,11 @@ void link_segments(void)
|
|||
relto = r->r.segment == 0 ? mod->coderel : mod->datarel;
|
||||
}
|
||||
else
|
||||
{
|
||||
bRelative = 0; /* non-relative - need to relocate
|
||||
* at load time */
|
||||
relto = 0; /* placate optimiser warnings */
|
||||
}
|
||||
|
||||
/* calculate absolute offset of reference, not rel to beginning of
|
||||
segment */
|
||||
|
|
|
|||
99
rdoff/rdf.doc
Normal file
99
rdoff/rdf.doc
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
RDOFF: Relocatable Dynamically-linked Object File Format
|
||||
========================================================
|
||||
|
||||
RDOFF was designed initially to test the object-file production
|
||||
interface to NASM. It soon became apparent that it could be enhanced
|
||||
for use in serious applications due to its simplicity; code to load
|
||||
and execute an RDOFF object module is very simple. It also contains
|
||||
enhancements to allow it to be linked with a dynamic link library at
|
||||
either run- or load- time, depending on how complex you wish to make
|
||||
your loader.
|
||||
|
||||
The RDOFF format (version 1.1, as produced by NASM v0.91) is defined
|
||||
as follows:
|
||||
|
||||
The first six bytes of the file contain the string 'RDOFF1'. Other
|
||||
versions of the format may contain other last characters other than
|
||||
'1' - all little endian versions of the file will always contain an
|
||||
ASCII character with value greater than 32. If RDOFF is used on a
|
||||
big-endian machine at some point in the future, the version will be
|
||||
encoded in decimal rather than ASCII, so will be below 32.
|
||||
|
||||
All multi-byte fields follwing this are encoded in either little- or
|
||||
big-endian format depending on the system described by this version
|
||||
information. Object files should be encoded in the endianness of
|
||||
their target machine; files of incorrect endianness will be rejected
|
||||
by the loader - this means that loaders do not need to convert
|
||||
endianness, as RDOFF has been designed with simplicity of loading at
|
||||
the forefront of the design requirements.
|
||||
|
||||
The next 4 byte field is the length of the header in bytes. The
|
||||
header consists of a sequence of variable length records. Each
|
||||
record's type is identified by the first byte of the record. Record
|
||||
types 1-4 are currently supported. Record type 5 will be added in
|
||||
the near future, when I implement BSS segments. Record type 6 may be
|
||||
to do with debugging, when I get debugging implemented.
|
||||
|
||||
Type 1: Relocation
|
||||
==================
|
||||
|
||||
Offset Length Description
|
||||
0 1 Type (contains 1)
|
||||
1 1 Segment that contains reference (0 = text, 1 = data)
|
||||
Add 64 to this number to indicate a relative linkage
|
||||
to an external symbol (see notes)
|
||||
2 4 Offset of reference
|
||||
6 1 Length of reference (1,2 or 4 bytes)
|
||||
7 2 Segment to which reference is made (0 = text, 1 =
|
||||
data, 2 = BSS [when implemented]) others are external
|
||||
symbols.
|
||||
|
||||
Total length = 9 bytes
|
||||
|
||||
Type 2: Symbol Import
|
||||
=====================
|
||||
|
||||
0 1 Type (2)
|
||||
1 2 Segment number that will be used in references to this
|
||||
symbol.
|
||||
3 ? Null terminated string containing label (up to 32
|
||||
chars) to match against exports in linkage.
|
||||
|
||||
Type 3: Symbol Export
|
||||
=====================
|
||||
|
||||
0 1 Type (3)
|
||||
1 1 Segment containing object to be exported (0/1/2)
|
||||
2 4 Offset within segment
|
||||
6 ? Null terminate string containing label to export (32
|
||||
char maximum length)
|
||||
|
||||
Type 4: Dynamic Link Library
|
||||
============================
|
||||
|
||||
0 1 Type (4)
|
||||
1 ? Library name (up to 128 chars)
|
||||
|
||||
Type 5: Reserve BSS
|
||||
===================
|
||||
|
||||
0 1 Type (5)
|
||||
1 4 Amount of BSS space to reserve in bytes
|
||||
|
||||
Total length: 5 bytes
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
Following the header is the text (code) segment. This is preceded by
|
||||
a 4-byte integer, which is its length in bytes. This is followed by
|
||||
the length of the data segment (also 4 bytes), and finally the data
|
||||
segment.
|
||||
|
||||
Notes
|
||||
=====
|
||||
|
||||
Relative linking: The number stored at the address is offset
|
||||
required from the imported symbol, with the address of the end of
|
||||
the instruction subtracted from it. This means that the linker can
|
||||
simply add the address of the label relative to the beginning of the
|
||||
current segment to it.
|
||||
|
|
@ -57,7 +57,7 @@ void print_header(long length) {
|
|||
case 3: /* export record */
|
||||
fread(&s,1,1,infile);
|
||||
fread(&o,4,1,infile);
|
||||
l = 0;
|
||||
ll = 0;
|
||||
do {
|
||||
fread(&buf[ll],1,1,infile);
|
||||
} while (buf[ll++]);
|
||||
|
|
@ -65,7 +65,7 @@ void print_header(long length) {
|
|||
length -= ll + 6;
|
||||
break;
|
||||
case 4: /* DLL record */
|
||||
l = 0;
|
||||
ll = 0;
|
||||
do {
|
||||
fread(&buf[ll],1,1,infile);
|
||||
} while (buf[ll++]);
|
||||
|
|
@ -88,6 +88,7 @@ int main(int argc,char **argv) {
|
|||
char id[7];
|
||||
long l;
|
||||
int verbose = 0;
|
||||
long offset;
|
||||
|
||||
puts("RDOFF Dump utility v1.1 (C) Copyright 1996 Julian R Hall");
|
||||
|
||||
|
|
@ -133,9 +134,15 @@ int main(int argc,char **argv) {
|
|||
fread(&l,4,1,infile);
|
||||
l = translatelong(l);
|
||||
printf("\nText segment length = %ld bytes\n",l);
|
||||
offset = 0;
|
||||
while(l--) {
|
||||
fread(id,1,1,infile);
|
||||
if (verbose) printf(" %02x",(int) (unsigned char)id[0]);
|
||||
if (verbose) {
|
||||
if (offset % 16 == 0)
|
||||
printf("\n%08lx ", offset);
|
||||
printf(" %02x",(int) (unsigned char)id[0]);
|
||||
offset++;
|
||||
}
|
||||
}
|
||||
if (verbose) printf("\n\n");
|
||||
|
||||
|
|
@ -145,9 +152,13 @@ int main(int argc,char **argv) {
|
|||
|
||||
if (verbose)
|
||||
{
|
||||
offset = 0;
|
||||
while (l--) {
|
||||
fread(id,1,1,infile);
|
||||
printf(" %02x",(int) (unsigned char) id[0]);
|
||||
if (offset % 16 == 0)
|
||||
printf("\n%08lx ", offset);
|
||||
printf(" %02x",(int) (unsigned char) id[0]);
|
||||
offset++;
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
|
|
|||
2
rdoff/test/Makefile
Normal file
2
rdoff/test/Makefile
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
clean:
|
||||
rm -f *.rdf *.rdx
|
||||
14
rdoff/test/makelib
Normal file
14
rdoff/test/makelib
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
|
||||
LIBNAME=$1;
|
||||
shift;
|
||||
|
||||
if [ "$LIBNAME" = "" ]; then
|
||||
echo 'Usage: makelib <library name> <module> [...]'
|
||||
fi
|
||||
|
||||
rdflib c $LIBNAME
|
||||
|
||||
for FILE in $*; do
|
||||
rdflib a $LIBNAME $FILE $FILE
|
||||
done
|
||||
|
||||
54
rdoff/test/rdftest1.asm
Normal file
54
rdoff/test/rdftest1.asm
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
;; program to test RDOFF production and linkage
|
||||
|
||||
;; items to test include:
|
||||
;; [1] relocation within the same segment in each module
|
||||
;; [2] relocation to different segments in same module
|
||||
;; [3] relocation to same segment in different module
|
||||
;; [4] relocation to different segment in different module
|
||||
;; [5] relative relocation to same module
|
||||
;; [6] relative relocation to different module
|
||||
;; [7] correct generation of BSS addresses
|
||||
|
||||
[SECTION .text]
|
||||
[BITS 32]
|
||||
|
||||
_main:
|
||||
mov ax,localdata ; [2] (16 bit) => 66 b8 0000
|
||||
mov eax,localdata2 ; [2] (32 bit) => b8 0000000a
|
||||
|
||||
[EXTERN _fardata]
|
||||
|
||||
mov eax,[_fardata] ; [4] => a1 00000000 (+20)
|
||||
mov cx,next ; [1] => 66 b9 0012
|
||||
next:
|
||||
call localproc ; [5] => e8 00000019
|
||||
|
||||
[EXTERN _farproc]
|
||||
mov eax,_farproc ; [3] => b8 00000000 (+40+0)
|
||||
call _farproc ; [6] => e8 -$ (-0+40+0) (=1f)
|
||||
|
||||
mov eax,localbss ; [7] => b8 00000000
|
||||
|
||||
[GLOBAL _term]
|
||||
_term: xor ax,ax ; => 66 31 c0
|
||||
int 21h ; => cd 21
|
||||
jmp _term ; => e9 -0a (=fffffff6)
|
||||
|
||||
localproc:
|
||||
ret ; => c3
|
||||
|
||||
[GLOBAL _test1proc]
|
||||
_test1proc:
|
||||
call localproc ; [5] => e8 -$ (-0+0+?) (=-6=fffffffa)
|
||||
ret ; => c3
|
||||
|
||||
[SECTION .data]
|
||||
[GLOBAL localdata2]
|
||||
localdata: db 'localdata',0
|
||||
localdata2: db 'localdata2',0
|
||||
farref: dd _fardata ; [3] => 0 (+20)
|
||||
localref: dd _main ; [2] => 0 (+0)
|
||||
|
||||
[SECTION .bss]
|
||||
localbss: resw 4 ; reserve 8 bytes BSS
|
||||
|
||||
33
rdoff/test/rdftest2.asm
Normal file
33
rdoff/test/rdftest2.asm
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
;; rdftest2.asm - test linkage and generation of RDOFF files
|
||||
|
||||
[SECTION .text]
|
||||
[BITS 32]
|
||||
|
||||
[GLOBAL _farproc]
|
||||
[EXTERN _test1proc]
|
||||
[EXTERN localdata2]
|
||||
[EXTERN _term]
|
||||
_farproc:
|
||||
|
||||
mov bx,localdata2 ; [4] 0 => 66 bb 000a(+0)
|
||||
mov eax,_term ; [3] 5 => b8 00000000(+26+0)
|
||||
call _test1proc ; [6] A => e8 fffffff2(-40+0+31)(=ffffffe3)
|
||||
|
||||
mov eax,_farproc ; [1] => b8 00000000(+40)
|
||||
add eax,[_fardata] ; [2] => 03 05 00000000(+20)
|
||||
|
||||
mov ebx,mybssdata ; [7] => bb 00000000(+08)
|
||||
call myproc ; [5] => e8 00000001
|
||||
ret
|
||||
|
||||
myproc:
|
||||
add eax,ebx
|
||||
ret
|
||||
|
||||
[SECTION .data]
|
||||
[GLOBAL _fardata]
|
||||
_fardata: dw _term ; [4]
|
||||
_localref: dd _farproc ; [2]
|
||||
|
||||
[SECTION .bss]
|
||||
mybssdata: resw 1
|
||||
48
rdoff/test/rdtlib.asm
Normal file
48
rdoff/test/rdtlib.asm
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
;; library functions for rdtmain - test of rdx linking and execution
|
||||
|
||||
;; library function = _strcmp, defined as in C
|
||||
|
||||
[SECTION .text]
|
||||
[BITS 32]
|
||||
|
||||
[GLOBAL _strcmp]
|
||||
_strcmp:
|
||||
push ebp
|
||||
mov ebp,esp
|
||||
|
||||
;; ebp+8 = first paramater, ebp+12 = second
|
||||
|
||||
mov esi,[ebp+8]
|
||||
mov edi,[ebp+12]
|
||||
|
||||
.loop:
|
||||
mov cl,byte [esi]
|
||||
mov dl,byte [edi]
|
||||
cmp cl,dl
|
||||
jb .below
|
||||
ja .above
|
||||
or cl,cl
|
||||
jz .match
|
||||
inc esi
|
||||
inc edi
|
||||
jmp .loop
|
||||
|
||||
.below:
|
||||
mov eax,-1
|
||||
pop ebp
|
||||
ret
|
||||
|
||||
.above:
|
||||
mov eax,1
|
||||
pop ebp
|
||||
ret
|
||||
|
||||
.match:
|
||||
xor eax,eax
|
||||
pop ebp
|
||||
ret
|
||||
|
||||
[SECTION .data]
|
||||
[GLOBAL _message]
|
||||
|
||||
_message: db 'hello',0
|
||||
47
rdoff/test/rdtmain.asm
Normal file
47
rdoff/test/rdtmain.asm
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
;; rdtmain - main part of test program for RDX execution.
|
||||
;; returns true (0) if its parameter equals the phrase "hello"
|
||||
;; "hello" is stored in the library part, to complicate the
|
||||
;; linkage.
|
||||
|
||||
;; assemble and link with the following commands:
|
||||
;; nasm -f rdf rdtmain.asm
|
||||
;; nasm -f rdf rdtlib.asm
|
||||
;; ldrdf rdtmain.rdf rdtlib.rdf -o rdxtest.rdx
|
||||
|
||||
;; run with 'rdx rdxtest.rdx [parameters]' on a Linux (or possibly
|
||||
;; other 32 bit OS) systems (x86 architectures only!)
|
||||
;; try using '&& echo Yes' afterwards to find out when it returns 0.
|
||||
|
||||
[EXTERN _strcmp] ; strcmp is an imported function
|
||||
[EXTERN _message] ; imported data
|
||||
[SECTION .text]
|
||||
[BITS 32]
|
||||
|
||||
;; main(int argc,char **argv)
|
||||
[GLOBAL _main]
|
||||
_main:
|
||||
push ebp
|
||||
mov ebp,esp
|
||||
|
||||
;; ebp+8 = argc, ebp+12 = argv
|
||||
|
||||
cmp dword [ebp+8],2
|
||||
jb error ; cause error if < 1 parameters
|
||||
|
||||
mov eax, [ebp+12] ; eax = argv
|
||||
|
||||
mov ebx, [eax+4] ; ebx = argv[1]
|
||||
mov ecx, _message ; ecx = "hello"
|
||||
|
||||
push ecx
|
||||
push ebx
|
||||
call _strcmp ; compare strings
|
||||
add esp,8 ; caller clears stack
|
||||
|
||||
pop ebp
|
||||
ret ; return return value of _strcmp
|
||||
|
||||
error:
|
||||
mov eax,2 ; return 2 on error
|
||||
pop ebp
|
||||
ret
|
||||
18
rdoff/test/testlib.asm
Normal file
18
rdoff/test/testlib.asm
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
; program to test retrieval of and linkage to modules in libraries by
|
||||
; ldrdf
|
||||
|
||||
[SECTION .text]
|
||||
[GLOBAL _main]
|
||||
[EXTERN _strcmp]
|
||||
|
||||
_main:
|
||||
push dword string1
|
||||
push dword string2
|
||||
call _strcmp
|
||||
add esp,8 ; doh! clear up stack ;-)
|
||||
ret
|
||||
|
||||
[SECTION .data]
|
||||
|
||||
string1: db 'abc',0 ; try changing these strings and see
|
||||
string2: db 'abd',0 ; what happens!
|
||||
51
standard.mac
51
standard.mac
|
|
@ -1,7 +1,15 @@
|
|||
; Standard macro set for NASM 0.95
|
||||
; Standard macro set for NASM 0.96 -*- nasm -*-
|
||||
; Note that although some user-level forms of directives are defined
|
||||
; here, not all of them are: the user-level form of a format-specific
|
||||
; directive should be defined in the module for that directive.
|
||||
|
||||
%define __NASM_MAJOR__ 0
|
||||
%define __NASM_MINOR__ 95
|
||||
%define __NASM_MINOR__ 96
|
||||
|
||||
; These two need to be defined, though the actual definitions will
|
||||
; be constantly updated during preprocessing.
|
||||
%define __FILE__
|
||||
%define __LINE__
|
||||
|
||||
%define __SECT__ ; it ought to be defined, even if as nothing
|
||||
|
||||
|
|
@ -23,6 +31,7 @@
|
|||
%push struc
|
||||
%define %$strucname %1
|
||||
[absolute 0]
|
||||
%$strucname: ; allow definition of `.member' to work sanely
|
||||
%endmacro
|
||||
%imacro endstruc 0.nolist
|
||||
%{$strucname}_size:
|
||||
|
|
@ -44,34 +53,34 @@ __SECT__
|
|||
%pop
|
||||
%endmacro
|
||||
|
||||
%imacro extern 1+.nolist
|
||||
%imacro align 1-2+.nolist nop
|
||||
times ($$-$) & ((%1)-1) %2
|
||||
%endmacro
|
||||
%imacro alignb 1-2+.nolist resb 1
|
||||
times ($$-$) & ((%1)-1) %2
|
||||
%endmacro
|
||||
|
||||
%imacro extern 1-*.nolist
|
||||
%rep %0
|
||||
[extern %1]
|
||||
%rotate 1
|
||||
%endrep
|
||||
%endmacro
|
||||
|
||||
%imacro bits 1+.nolist
|
||||
[bits %1]
|
||||
%endmacro
|
||||
|
||||
%imacro global 1+.nolist
|
||||
%imacro global 1-*.nolist
|
||||
%rep %0
|
||||
[global %1]
|
||||
%rotate 1
|
||||
%endrep
|
||||
%endmacro
|
||||
|
||||
%imacro common 1+.nolist
|
||||
%imacro common 1-*.nolist
|
||||
%rep %0
|
||||
[common %1]
|
||||
%endmacro
|
||||
|
||||
%imacro org 1+.nolist
|
||||
[org %1]
|
||||
%endmacro
|
||||
|
||||
%imacro group 1+.nolist
|
||||
[group %1]
|
||||
%endmacro
|
||||
|
||||
%imacro uppercase 1+.nolist
|
||||
[uppercase %1]
|
||||
%endmacro
|
||||
|
||||
%imacro library 1+.nolist
|
||||
[library %1]
|
||||
%rotate 1
|
||||
%endrep
|
||||
%endmacro
|
||||
|
|
|
|||
|
|
@ -1,2 +1,2 @@
|
|||
clean:
|
||||
rm -f *.o *.obj *.com bintest inctest
|
||||
rm -f *test *.com *.o *.obj *so *.exe
|
||||
|
|
|
|||
96
test/aoutso.asm
Normal file
96
test/aoutso.asm
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
; test source file for assembling to NetBSD/FreeBSD a.out shared library
|
||||
; build with:
|
||||
; nasm -f aoutb aoutso.asm
|
||||
; ld -Bshareable -o aoutso.so aoutso.o
|
||||
; test with:
|
||||
; cc -o aoutso aouttest.c aoutso.so
|
||||
; ./aoutso
|
||||
|
||||
; This file should test the following:
|
||||
; [1] Define and export a global text-section symbol
|
||||
; [2] Define and export a global data-section symbol
|
||||
; [3] Define and export a global BSS-section symbol
|
||||
; [4] Define a non-global text-section symbol
|
||||
; [5] Define a non-global data-section symbol
|
||||
; [6] Define a non-global BSS-section symbol
|
||||
; [7] Define a COMMON symbol
|
||||
; [8] Define a NASM local label
|
||||
; [9] Reference a NASM local label
|
||||
; [10] Import an external symbol
|
||||
; [11] Make a PC-relative call to an external symbol
|
||||
; [12] Reference a text-section symbol in the text section
|
||||
; [13] Reference a data-section symbol in the text section
|
||||
; [14] Reference a BSS-section symbol in the text section
|
||||
; [15] Reference a text-section symbol in the data section
|
||||
; [16] Reference a data-section symbol in the data section
|
||||
; [17] Reference a BSS-section symbol in the data section
|
||||
|
||||
BITS 32
|
||||
EXTERN __GLOBAL_OFFSET_TABLE_
|
||||
GLOBAL _lrotate:function ; [1]
|
||||
GLOBAL _greet:function ; [1]
|
||||
GLOBAL _asmstr:data _asmstr.end-_asmstr ; [2]
|
||||
GLOBAL _textptr:data 4 ; [2]
|
||||
GLOBAL _selfptr:data 4 ; [2]
|
||||
GLOBAL _integer:data 4 ; [3]
|
||||
EXTERN _printf ; [10]
|
||||
COMMON _commvar 4 ; [7]
|
||||
|
||||
SECTION .text
|
||||
|
||||
; prototype: long lrotate(long x, int num);
|
||||
_lrotate: ; [1]
|
||||
push ebp
|
||||
mov ebp,esp
|
||||
mov eax,[ebp+8]
|
||||
mov ecx,[ebp+12]
|
||||
.label rol eax,1 ; [4] [8]
|
||||
loop .label ; [9] [12]
|
||||
mov esp,ebp
|
||||
pop ebp
|
||||
ret
|
||||
|
||||
; prototype: void greet(void);
|
||||
_greet push ebx ; we'll use EBX for GOT, so save it
|
||||
call .getgot
|
||||
.getgot: pop ebx
|
||||
add ebx,__GLOBAL_OFFSET_TABLE_ + $$ - .getgot wrt ..gotpc
|
||||
mov eax,[ebx+_integer wrt ..got] ; [14]
|
||||
mov eax,[eax]
|
||||
inc eax
|
||||
mov [ebx+localint wrt ..gotoff],eax ; [14]
|
||||
mov eax,[ebx+_commvar wrt ..got]
|
||||
push dword [eax]
|
||||
mov eax,[ebx+localptr wrt ..gotoff] ; [13]
|
||||
push dword [eax]
|
||||
mov eax,[ebx+_integer wrt ..got] ; [1] [14]
|
||||
push dword [eax]
|
||||
lea eax,[ebx+_printfstr wrt ..gotoff]
|
||||
push eax ; [13]
|
||||
call _printf wrt ..plt ; [11]
|
||||
add esp,16
|
||||
pop ebx
|
||||
ret
|
||||
|
||||
SECTION .data
|
||||
|
||||
; a string
|
||||
_asmstr db 'hello, world', 0 ; [2]
|
||||
.end
|
||||
|
||||
; a string for Printf
|
||||
_printfstr db "integer==%d, localint==%d, commvar=%d"
|
||||
db 10, 0
|
||||
|
||||
; some pointers
|
||||
localptr dd localint ; [5] [17]
|
||||
_textptr dd _greet wrt ..sym ; [15]
|
||||
_selfptr dd _selfptr wrt ..sym ; [16]
|
||||
|
||||
SECTION .bss
|
||||
|
||||
; an integer
|
||||
_integer resd 1 ; [3]
|
||||
|
||||
; a local integer
|
||||
localint resd 1 ; [6]
|
||||
32
test/binexe.asm
Normal file
32
test/binexe.asm
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
; Demonstration of how to write an entire .EXE format program by using
|
||||
; the `exebin.mac' macro package.
|
||||
; To build:
|
||||
; nasm -fbin binexe.asm -o binexe.exe -ipath
|
||||
; (where `path' is such as to allow the %include directive to find
|
||||
; exebin.mac)
|
||||
; To test:
|
||||
; binexe
|
||||
; (should print `hello, world')
|
||||
|
||||
%include "exebin.mac"
|
||||
|
||||
EXE_begin
|
||||
EXE_stack 64 ; demonstrates overriding the 0x800 default
|
||||
|
||||
section .text
|
||||
|
||||
mov ax,cs
|
||||
mov ds,ax
|
||||
|
||||
mov dx,hello
|
||||
mov ah,9
|
||||
int 0x21
|
||||
|
||||
mov ax,0x4c00
|
||||
int 0x21
|
||||
|
||||
section .data
|
||||
|
||||
hello: db 'hello, world', 13, 10, '$'
|
||||
|
||||
EXE_end
|
||||
97
test/elfso.asm
Normal file
97
test/elfso.asm
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
; test source file for assembling to ELF shared library
|
||||
; build with:
|
||||
; nasm -f elf elfso.asm
|
||||
; ld -shared -o elfso.so elfso.o
|
||||
; test with:
|
||||
; gcc -o elfso elftest.c ./elfso.so
|
||||
; ./elfso
|
||||
; (assuming your gcc is ELF, and you're running bash)
|
||||
|
||||
; This file should test the following:
|
||||
; [1] Define and export a global text-section symbol
|
||||
; [2] Define and export a global data-section symbol
|
||||
; [3] Define and export a global BSS-section symbol
|
||||
; [4] Define a non-global text-section symbol
|
||||
; [5] Define a non-global data-section symbol
|
||||
; [6] Define a non-global BSS-section symbol
|
||||
; [7] Define a COMMON symbol
|
||||
; [8] Define a NASM local label
|
||||
; [9] Reference a NASM local label
|
||||
; [10] Import an external symbol
|
||||
; [11] Make a PC-relative call to an external symbol
|
||||
; [12] Reference a text-section symbol in the text section
|
||||
; [13] Reference a data-section symbol in the text section
|
||||
; [14] Reference a BSS-section symbol in the text section
|
||||
; [15] Reference a text-section symbol in the data section
|
||||
; [16] Reference a data-section symbol in the data section
|
||||
; [17] Reference a BSS-section symbol in the data section
|
||||
|
||||
BITS 32
|
||||
GLOBAL lrotate:function ; [1]
|
||||
GLOBAL greet:function ; [1]
|
||||
GLOBAL asmstr:data asmstr.end-asmstr ; [2]
|
||||
GLOBAL textptr:data 4 ; [2]
|
||||
GLOBAL selfptr:data 4 ; [2]
|
||||
GLOBAL integer:data 4 ; [3]
|
||||
EXTERN printf ; [10]
|
||||
COMMON commvar 4:4 ; [7]
|
||||
EXTERN _GLOBAL_OFFSET_TABLE_
|
||||
|
||||
SECTION .text
|
||||
|
||||
; prototype: long lrotate(long x, int num);
|
||||
lrotate: ; [1]
|
||||
push ebp
|
||||
mov ebp,esp
|
||||
mov eax,[ebp+8]
|
||||
mov ecx,[ebp+12]
|
||||
.label rol eax,1 ; [4] [8]
|
||||
loop .label ; [9] [12]
|
||||
mov esp,ebp
|
||||
pop ebp
|
||||
ret
|
||||
|
||||
; prototype: void greet(void);
|
||||
greet push ebx ; we'll use EBX for GOT, so save it
|
||||
call .getgot
|
||||
.getgot: pop ebx
|
||||
add ebx,_GLOBAL_OFFSET_TABLE_ + $$ - .getgot wrt ..gotpc
|
||||
mov eax,[ebx+integer wrt ..got] ; [14]
|
||||
mov eax,[eax]
|
||||
inc eax
|
||||
mov [ebx+localint wrt ..gotoff],eax ; [14]
|
||||
mov eax,[ebx+commvar wrt ..got]
|
||||
push dword [eax]
|
||||
mov eax,[ebx+localptr wrt ..gotoff] ; [13]
|
||||
push dword [eax]
|
||||
mov eax,[ebx+integer wrt ..got] ; [1] [14]
|
||||
push dword [eax]
|
||||
lea eax,[ebx+printfstr wrt ..gotoff]
|
||||
push eax ; [13]
|
||||
call printf wrt ..plt ; [11]
|
||||
add esp,16
|
||||
pop ebx
|
||||
ret
|
||||
|
||||
SECTION .data
|
||||
|
||||
; a string
|
||||
asmstr db 'hello, world', 0 ; [2]
|
||||
.end
|
||||
|
||||
; a string for Printf
|
||||
printfstr db "integer==%d, localint==%d, commvar=%d"
|
||||
db 10, 0
|
||||
|
||||
; some pointers
|
||||
localptr dd localint ; [5] [17]
|
||||
textptr dd greet wrt ..sym ; [15]
|
||||
selfptr dd selfptr wrt ..sym ; [16]
|
||||
|
||||
SECTION .bss
|
||||
|
||||
; an integer
|
||||
integer resd 1 ; [3]
|
||||
|
||||
; a local integer
|
||||
localint resd 1 ; [6]
|
||||
30
test/objexe.asm
Normal file
30
test/objexe.asm
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
; Demonstration of how to write an entire .EXE format program as a .OBJ
|
||||
; file to be linked. Tested with the VAL free linker.
|
||||
; To build:
|
||||
; nasm -fobj objexe.asm
|
||||
; val objexe.obj,objexe.exe;
|
||||
; To test:
|
||||
; objexe
|
||||
; (should print `hello, world')
|
||||
|
||||
segment code
|
||||
|
||||
..start: mov ax,data
|
||||
mov ds,ax
|
||||
mov ax,stack
|
||||
mov ss,ax
|
||||
mov sp,stacktop
|
||||
|
||||
mov dx,hello
|
||||
mov ah,9
|
||||
int 0x21
|
||||
|
||||
mov ax,0x4c00
|
||||
int 0x21
|
||||
|
||||
segment data
|
||||
hello: db 'hello, world', 13, 10, '$'
|
||||
|
||||
segment stack stack
|
||||
resb 64
|
||||
stacktop:
|
||||
Loading…
Add table
Add a link
Reference in a new issue