summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.in19
-rw-r--r--SubmittingPatches116
-rw-r--r--assemble.c50
-rw-r--r--configure.in9
-rwxr-xr-xdirectiv.pl2
-rw-r--r--doc/changes.src11
-rw-r--r--doc/nasmdoc.src77
-rw-r--r--eval.c2
-rw-r--r--insns.dat148
-rw-r--r--insns.h3
-rwxr-xr-xinsns.pl1040
-rw-r--r--lcc/README52
-rw-r--r--lcc/bind.c23
-rw-r--r--lcc/lin-aout.c48
-rw-r--r--lcc/lin-elf.c49
-rw-r--r--lcc/x86nasm.md703
-rwxr-xr-xmacros.pl2
-rw-r--r--opflags.h15
-rw-r--r--output/outbin.c63
-rw-r--r--output/outcoff.c7
-rw-r--r--output/outelf32.c32
-rw-r--r--output/outelf64.c30
-rw-r--r--parser.c8
-rw-r--r--perllib/phash.ph28
-rwxr-xr-xphash.pl28
-rw-r--r--pptok.dat6
-rwxr-xr-xpptok.pl2
-rw-r--r--preproc.c1913
-rw-r--r--test/align13.asm3
-rw-r--r--test/align13s.asm4
-rw-r--r--test/alonesym-obj.asm3
-rw-r--r--test/bcd.asm2
-rw-r--r--test/br2003451.asm2
-rw-r--r--test/br2030823.asm4
-rw-r--r--test/br3005117.asm2
-rw-r--r--test/br3026808.asm2
-rw-r--r--test/br3028880.asm2
-rw-r--r--test/br3058845.asm2
-rw-r--r--test/br3066383.asm2
-rw-r--r--test/br3074517.asm12
-rw-r--r--test/br3092924.asm25
-rw-r--r--test/br3104312.asm11
-rw-r--r--test/imm64.asm50
-rw-r--r--test/prefix66.asm28
-rw-r--r--test/sreg.asm65
-rwxr-xr-xtokhash.pl2
-rw-r--r--version2
47 files changed, 2209 insertions, 2500 deletions
diff --git a/Makefile.in b/Makefile.in
index ed93b440..8370d9af 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -36,6 +36,7 @@ MKDIR = mkdir
RM = rm
STRIP = strip
+FIND = find
# Binary suffixes
O = @OBJEXT@
@@ -43,8 +44,8 @@ X = @EXEEXT@
.SUFFIXES: .c .i .s .$(O) .1 .man
-.PHONY: all doc rdf install clean distclean cleaner spotless install_rdf
-.PHONY: install_doc everything install_everything strip perlreq dist
+.PHONY: all doc rdf install clean distclean cleaner spotless install_rdf test
+.PHONY: install_doc everything install_everything strip perlreq dist tags TAGS
.c.$(O):
$(CC) -c $(ALL_CFLAGS) -o $@ $<
@@ -187,6 +188,7 @@ clean:
$(RM) -f lib/*.$(O) lib/*.s lib/*.i
$(RM) -f output/*.$(O) output/*.s output/*.i
$(RM) -f nasm$(X) ndisasm$(X)
+ $(RM) -f tags TAGS
cd rdoff && $(MAKE) clean
distclean: clean
@@ -210,6 +212,19 @@ strip:
rdf:
cd rdoff && $(MAKE)
+TAGS:
+ $(RM) -f TAGS
+ $(FIND) . -name '*.[hcS]' -print | xargs etags -a
+
+tags:
+ $(RM) -f tags
+ $(FIND) . -name '*.[hcS]' -print | xargs ctags -a
+
+cscope:
+ $(RM) -f cscope.out cscope.files
+ $(FIND) . -name '*.[hcS]' -print > cscope.files
+ cscope -b -f cscope.out
+
rdf_install install_rdf:
cd rdoff && $(MAKE) install
diff --git a/SubmittingPatches b/SubmittingPatches
new file mode 100644
index 00000000..168ab640
--- /dev/null
+++ b/SubmittingPatches
@@ -0,0 +1,116 @@
+How to submit patches into the NASM
+===================================
+
+Actually the rules are pretty simple
+
+Obtaining the source code
+-------------------------
+
+The NASM sources are tracked by Git SCM at http://repo.or.cz/w/nasm.git
+repository. You either could download packed sources or use git tool itself
+
+ git clone git://repo.or.cz/nasm.git
+
+Changin the source code
+-----------------------
+
+When you change the NASM source code keep in mind -- we prefer tabs and
+indentations to be 4 characters width, space filled.
+
+Other "rules" could be learned from NASM sources -- just make your code
+to look similar.
+
+Producing patch
+---------------
+
+There are at least two ways to make it right.
+
+ 1) git format-patch
+
+ You might need to read documentation on Git SCM how to prepare patch
+ for mail submission. Take a look on http://book.git-scm.com/ and/or
+ http://git-scm.com/documentation for details. It should not be hard
+ at all.
+
+ 2) Use "diff -up"
+
+ Use "diff -up" or "diff -uprN" to create patches.
+
+Signing your work
+-----------------
+
+To improve tracking of who did what we've introduced a "sign-off" procedure
+on patches that are being emailed around.
+
+The sign-off is a simple line at the end of the explanation for the
+patch, which certifies that you wrote it or otherwise have the right to
+pass it on as a open-source patch. The rules are pretty simple: if you
+can certify the below:
+
+ Developer's Certificate of Origin 1.1
+
+ By making a contribution to this project, I certify that:
+
+ (a) The contribution was created in whole or in part by me and I
+ have the right to submit it under the open source license
+ indicated in the file; or
+
+ (b) The contribution is based upon previous work that, to the best
+ of my knowledge, is covered under an appropriate open source
+ license and I have the right under that license to submit that
+ work with modifications, whether created in whole or in part
+ by me, under the same open source license (unless I am
+ permitted to submit under a different license), as indicated
+ in the file; or
+
+ (c) The contribution was provided directly to me by some other
+ person who certified (a), (b) or (c) and I have not modified
+ it.
+
+ (d) I understand and agree that this project and the contribution
+ are public and that a record of the contribution (including all
+ personal information I submit with it, including my sign-off) is
+ maintained indefinitely and may be redistributed consistent with
+ this project or the open source license(s) involved.
+
+then you just add a line saying
+
+ Signed-off-by: Random J Developer <random@developer.example.org>
+
+using your real name (please, no pseudonyms or anonymous contributions if
+it possible)
+
+An example of patch message
+---------------------------
+
+From: Random J Developer <random@developer.example.org>
+Subject: [PATCH] Short patch description
+
+Long patch description (could be skipped if patch
+is trivial enough)
+
+Signed-off-by: Random J Developer <random@developer.example.org>
+---
+Patch body here
+
+Mailing patches
+---------------
+
+The patches should be sent to NASM development mailing list
+
+ nasm-devel@lists.sourceforge.net
+
+Please make sure the email client you're using doesn't screw
+your patch (line wrapping and so on).
+
+Wait for response
+-----------------
+
+Be patient. Most NASM developers are pretty busy people so if
+there is no immediate response on your patch -- don't
+be surprised, sometimes a patch may fly around a week(s) before
+gets reviewed. But definitely the patches will not go to /dev/null.
+
+ ---
+ With best regards,
+ NASM-team
diff --git a/assemble.c b/assemble.c
index 1ee7f7fe..a9f6eb02 100644
--- a/assemble.c
+++ b/assemble.c
@@ -976,12 +976,28 @@ static int64_t calcsize(int32_t segment, int64_t offset, int bits,
break;
case 0320:
- length += (bits != 16);
+ {
+ enum prefixes pfx = ins->prefixes[PPS_OSIZE];
+ if (pfx == P_O16)
+ break;
+ if (pfx != P_none)
+ errfunc(ERR_WARNING | ERR_PASS2, "invalid operand size prefix");
+ else
+ ins->prefixes[PPS_OSIZE] = P_O16;
break;
+ }
case 0321:
- length += (bits == 16);
+ {
+ enum prefixes pfx = ins->prefixes[PPS_OSIZE];
+ if (pfx == P_O32)
+ break;
+ if (pfx != P_none)
+ errfunc(ERR_WARNING | ERR_PASS2, "invalid operand size prefix");
+ else
+ ins->prefixes[PPS_OSIZE] = P_O32;
break;
+ }
case 0322:
break;
@@ -1636,32 +1652,8 @@ static void gencode(int32_t segment, int64_t offset, int bits,
break;
case 0320:
- {
- enum prefixes pfx = ins->prefixes[PPS_OSIZE];
- if (pfx != P_O16 && pfx != P_none)
- nasm_error(ERR_WARNING, "Invalid operand size prefix");
- if (pfx != P_O16 && bits != 16) {
- ins->prefixes[PPS_OSIZE] = P_O16;
- *bytes = 0x66;
- out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
- offset += 1;
- }
- break;
- }
-
case 0321:
- {
- enum prefixes pfx = ins->prefixes[PPS_OSIZE];
- if (pfx != P_O32 && pfx != P_none)
- nasm_error(ERR_WARNING, "Invalid operand size prefix");
- if (pfx != P_O32 && bits == 16) {
- ins->prefixes[PPS_OSIZE] = P_O32;
- *bytes = 0x66;
- out(offset, segment, bytes, OUT_RAWDATA, 1, NO_SEG, NO_SEG);
- offset += 1;
- }
break;
- }
case 0322:
case 0323:
@@ -2056,6 +2048,12 @@ static enum match_result matches(const struct itemplate *itemp,
return MERR_INVALOP;
/*
+ * Is it legal?
+ */
+ if (!(optimizing > 0) && (itemp->flags & IF_OPT))
+ return MERR_INVALOP;
+
+ /*
* Check that no spurious colons or TOs are present
*/
for (i = 0; i < itemp->operands; i++)
diff --git a/configure.in b/configure.in
index c23bac1d..8c6a4297 100644
--- a/configure.in
+++ b/configure.in
@@ -152,5 +152,14 @@ if test $ac_cv_prog_make_vpathok = no; then
done
fi
+dnl
+dnl support cchace
+dnl
+AC_ARG_WITH([ccache],
+ [AC_HELP_STRING([--with-ccache],
+ [Compile with ccache])],
+ [CC="ccache $CC"],
+ [])
+
AC_OUTPUT_COMMANDS([mkdir -p output])
AC_OUTPUT(Makefile rdoff/Makefile doc/Makefile)
diff --git a/directiv.pl b/directiv.pl
index 684f542a..0417f565 100755
--- a/directiv.pl
+++ b/directiv.pl
@@ -95,7 +95,7 @@ if ($output eq 'h') {
}
@hashinfo = gen_perfect_hash(\%directive);
- if (!defined(@hashinfo)) {
+ if (!@hashinfo) {
die "$0: no hash found\n";
}
diff --git a/doc/changes.src b/doc/changes.src
index 71953779..a3ba18c5 100644
--- a/doc/changes.src
+++ b/doc/changes.src
@@ -7,6 +7,17 @@
The NASM 2 series support x86-64, and is the production version of NASM
since 2007.
+\S{cl-2.10} Version 2.10
+
+\b When optimization is enabled, \c{mov r64,imm} now optimizes to the
+ shortest form possible between:
+
+\c mov r32,imm32 ; 5 bytes
+\c mov r64,imm32 ; 7 bytes
+\c mov r64,imm64 ; 10 bytes
+
+To force a specific form, use the \c{STRICT} keyword, see \k{strict}.
+
\S{cl-2.09.08} Version 2.09.08
diff --git a/doc/nasmdoc.src b/doc/nasmdoc.src
index 82cbf510..34e83868 100644
--- a/doc/nasmdoc.src
+++ b/doc/nasmdoc.src
@@ -2415,20 +2415,21 @@ things like
\c silly {13,10}, crlf ; crlf: db 13,10
-\#\S{mlrmacro} \i{Recursive Multi-Line Macros}: \I\c{%irmacro}\i\c{%rmacro}
-\#
-\#A multi-line macro cannot be referenced within itself, in order to
-\#prevent accidental infinite recursion.
-\#
-\#Recursive multi-line macros allow for self-referencing, with the
-\#caveat that the user is aware of the existence, use and purpose of
-\#recursive multi-line macros. There is also a generous, but sane, upper
-\#limit to the number of recursions, in order to prevent run-away memory
-\#consumption in case of accidental infinite recursion.
-\#
-\#As with non-recursive multi-line macros, recursive multi-line macros are
-\#\i{case-sensitive}, unless you define them using the alternative
-\#directive \c{%irmacro}.
+\S{mlrmacro} \i{Recursive Multi-Line Macros}: \I\c{%irmacro}\i\c{%rmacro}
+
+A multi-line macro cannot be referenced within itself, in order to
+prevent accidental infinite recursion and allow instruction overloading.
+
+Recursive multi-line macros allow for self-referencing, with the
+caveat that the user is aware of the existence, use and purpose of
+recursive multi-line macros. There is also a generous, but sane, upper
+limit to the number of recursions, in order to prevent run-away memory
+consumption in case of accidental infinite recursion.
+
+As with non-recursive multi-line macros, recursive multi-line macros are
+\i{case-sensitive}, unless you define them using the alternative
+directive \c{%irmacro}.
+
\S{mlmacover} Overloading Multi-Line Macros\I{overloading, multi-line macros}
@@ -2887,20 +2888,21 @@ does \e{not} remove the macro \c{bar}, since the argument
specification does not match exactly.
-\#\S{exitmacro} Exiting Multi-Line Macros: \i\c{%exitmacro}
-\#
-\#Multi-line macro expansions can be arbitrarily terminated with
-\#the \c{%exitmacro} directive.
-\#
-\#For example:
-\#
-\#\c %macro foo 1-3
-\#\c ; Do something
-\#\c %if<condition>
-\#\c %exitmacro
-\#\c %endif
-\#\c ; Do something
-\#\c %endmacro
+\S{exitmacro} Exiting Multi-Line Macros: \i\c{%exitmacro}
+
+Multi-line macro expansions can be arbitrarily terminated with
+the \c{%exitmacro} directive.
+
+For example:
+
+\c %macro foo 1-3
+\c ; Do something
+\c %if<condition>
+\c %exitmacro
+\c %endif
+\c ; Do something
+\c %endmacro
+
\H{condasm} \i{Conditional Assembly}\I\c{%if}
@@ -3221,6 +3223,17 @@ Note a maximum repeat count is limited by 62 bit number, though it
is hardly possible that you ever need anything bigger.
+\H{while} \i{Conditional Loops}: \i\c{%while}
+
+The directives \c{%while} and \i\c{%endwhile} combine preprocessor
+loops with conditional assembly, allowing the enclosed chunk of
+code to be replicated as long as certain conditions are met:
+
+\c %while<condition>
+\c ; some code which only repeats while <condition> is met
+\c %endwhile
+
+
\H{files} Source Files and Dependencies
These commands allow you to split your sources into multiple files.
@@ -3793,6 +3806,14 @@ variable, for example:
\c %defstr C_colon %!'C:'
+\S{final} \i\c{%final} Directive
+
+The \c{%final} directive is used to delay preprocessing of a line
+until all other "normal" preprocessing is complete. Multiple
+\c{%final} directives are processed in the opposite order of their
+declaration, last one first and first one last.
+
+
\H{stdmac} \i{Standard Macros}
NASM defines a set of standard macros, which are already defined
diff --git a/eval.c b/eval.c
index bfbf2819..e5267237 100644
--- a/eval.c
+++ b/eval.c
@@ -877,7 +877,7 @@ static expr *expr6(int critical)
return NULL;
} else {
if (opflags)
- *opflags |= 1;
+ *opflags |= OPFLAG_FORWARD;
type = EXPR_UNKNOWN;
label_seg = NO_SEG;
label_ofs = 1;
diff --git a/insns.dat b/insns.dat
index 7574dc34..41d9123c 100644
--- a/insns.dat
+++ b/insns.dat
@@ -770,12 +770,18 @@ MFENCE void \3\x0F\xAE\xF0 X64,AMD
MONITOR void \3\x0F\x01\xC8 PRESCOTT
MONITOR reg_eax,reg_ecx,reg_edx \3\x0F\x01\xC8 PRESCOTT,ND
MONITOR reg_rax,reg_ecx,reg_edx \3\x0F\x01\xC8 X64,ND
-MOV mem,reg_sreg \1\x8C\101 8086,SM
+MOV mem,reg_sreg \1\x8C\101 8086,SW
MOV reg16,reg_sreg \320\1\x8C\101 8086
MOV reg32,reg_sreg \321\1\x8C\101 386
-MOV reg_sreg,mem \1\x8E\110 8086,SM
-MOV reg_sreg,reg16 \1\x8E\110 8086
-MOV reg_sreg,reg32 \1\x8E\110 386
+MOV reg64,reg_sreg \323\1\x8C\101 X64,OPT,ND
+MOV rm64,reg_sreg \324\1\x8C\101 X64
+MOV reg_sreg,mem \1\x8E\110 8086,SW
+MOV reg_sreg,reg16 \1\x8E\110 8086,OPT,ND
+MOV reg_sreg,reg32 \1\x8E\110 386,OPT,ND
+MOV reg_sreg,reg64 \323\1\x8E\110 X64,OPT,ND
+MOV reg_sreg,reg16 \320\1\x8E\110 8086
+MOV reg_sreg,reg32 \321\1\x8E\110 386
+MOV reg_sreg,rm64 \324\1\x8E\110 X64
MOV reg_al,mem_offs \1\xA0\45 8086,SM
MOV reg_ax,mem_offs \320\1\xA1\45 8086,SM
MOV reg_eax,mem_offs \321\1\xA1\45 386,SM
@@ -813,6 +819,8 @@ MOV reg64,reg64 \324\1\x8B\110 X64
MOV reg8,imm \10\xB0\21 8086,SM
MOV reg16,imm \320\10\xB8\31 8086,SM
MOV reg32,imm \321\10\xB8\41 386,SM
+MOV reg64,udword64 \323\10\xB8\41 X64,SM,OPT,ND
+MOV reg64,sdword64 \324\1\xC7\200\255 X64,SM,OPT,ND
MOV reg64,imm \324\10\xB8\55 X64,SM
MOV rm8,imm \1\xC6\200\21 8086,SM
MOV rm16,imm \320\1\xC7\200\31 8086,SM
@@ -1423,35 +1431,35 @@ SETcc mem \1\x0F\330\x90\200 386,SB
SETcc reg8 \1\x0F\330\x90\200 386
;# Katmai Streaming SIMD instructions (SSE -- a.k.a. KNI, XMM, MMX2)
-ADDPS xmmreg,xmmrm \360\2\x0F\x58\110 KATMAI,SSE
-ADDSS xmmreg,xmmrm \363\2\x0F\x58\110 KATMAI,SSE,SD
-ANDNPS xmmreg,xmmrm \360\2\x0F\x55\110 KATMAI,SSE
-ANDPS xmmreg,xmmrm \360\2\x0F\x54\110 KATMAI,SSE
-CMPEQPS xmmreg,xmmrm \360\2\x0F\xC2\110\1\x00 KATMAI,SSE
-CMPEQSS xmmreg,xmmrm \363\2\x0F\xC2\110\1\x00 KATMAI,SSE
-CMPLEPS xmmreg,xmmrm \360\2\x0F\xC2\110\1\x02 KATMAI,SSE
-CMPLESS xmmreg,xmmrm \363\2\x0F\xC2\110\1\x02 KATMAI,SSE
-CMPLTPS xmmreg,xmmrm \360\2\x0F\xC2\110\1\x01 KATMAI,SSE
-CMPLTSS xmmreg,xmmrm \363\2\x0F\xC2\110\1\x01 KATMAI,SSE
-CMPNEQPS xmmreg,xmmrm \360\2\x0F\xC2\110\1\x04 KATMAI,SSE
-CMPNEQSS xmmreg,xmmrm \363\2\x0F\xC2\110\1\x04 KATMAI,SSE
-CMPNLEPS xmmreg,xmmrm \360\2\x0F\xC2\110\1\x06 KATMAI,SSE
-CMPNLESS xmmreg,xmmrm \363\2\x0F\xC2\110\1\x06 KATMAI,SSE
-CMPNLTPS xmmreg,xmmrm \360\2\x0F\xC2\110\1\x05 KATMAI,SSE
-CMPNLTSS xmmreg,xmmrm \363\2\x0F\xC2\110\1\x05 KATMAI,SSE
-CMPORDPS xmmreg,xmmrm \360\2\x0F\xC2\110\1\x07 KATMAI,SSE
-CMPORDSS xmmreg,xmmrm \363\2\x0F\xC2\110\1\x07 KATMAI,SSE
-CMPUNORDPS xmmreg,xmmrm \360\2\x0F\xC2\110\1\x03 KATMAI,SSE
-CMPUNORDSS xmmreg,xmmrm \363\2\x0F\xC2\110\1\x03 KATMAI,SSE
+ADDPS xmmreg,xmmrm128 \360\2\x0F\x58\110 KATMAI,SSE
+ADDSS xmmreg,xmmrm32 \363\2\x0F\x58\110 KATMAI,SSE
+ANDNPS xmmreg,xmmrm128 \360\2\x0F\x55\110 KATMAI,SSE
+ANDPS xmmreg,xmmrm128 \360\2\x0F\x54\110 KATMAI,SSE
+CMPEQPS xmmreg,xmmrm128 \360\2\x0F\xC2\110\1\x00 KATMAI,SSE
+CMPEQSS xmmreg,xmmrm32 \363\2\x0F\xC2\110\1\x00 KATMAI,SSE
+CMPLEPS xmmreg,xmmrm128 \360\2\x0F\xC2\110\1\x02 KATMAI,SSE
+CMPLESS xmmreg,xmmrm32 \363\2\x0F\xC2\110\1\x02 KATMAI,SSE
+CMPLTPS xmmreg,xmmrm128 \360\2\x0F\xC2\110\1\x01 KATMAI,SSE
+CMPLTSS xmmreg,xmmrm32 \363\2\x0F\xC2\110\1\x01 KATMAI,SSE
+CMPNEQPS xmmreg,xmmrm128 \360\2\x0F\xC2\110\1\x04 KATMAI,SSE
+CMPNEQSS xmmreg,xmmrm32 \363\2\x0F\xC2\110\1\x04 KATMAI,SSE
+CMPNLEPS xmmreg,xmmrm128 \360\2\x0F\xC2\110\1\x06 KATMAI,SSE
+CMPNLESS xmmreg,xmmrm32 \363\2\x0F\xC2\110\1\x06 KATMAI,SSE
+CMPNLTPS xmmreg,xmmrm128 \360\2\x0F\xC2\110\1\x05 KATMAI,SSE
+CMPNLTSS xmmreg,xmmrm32 \363\2\x0F\xC2\110\1\x05 KATMAI,SSE
+CMPORDPS xmmreg,xmmrm128 \360\2\x0F\xC2\110\1\x07 KATMAI,SSE
+CMPORDSS xmmreg,xmmrm32 \363\2\x0F\xC2\110\1\x07 KATMAI,SSE
+CMPUNORDPS xmmreg,xmmrm128 \360\2\x0F\xC2\110\1\x03 KATMAI,SSE
+CMPUNORDSS xmmreg,xmmrm32 \363\2\x0F\xC2\110\1\x03 KATMAI,SSE
; CMPPS/CMPSS must come after the specific ops; that way the disassembler will find the
; specific ops first and only disassemble illegal ones as cmpps/cmpss.
CMPPS xmmreg,mem,imm \360\2\x0F\xC2\110\26 KATMAI,SSE,SB,AR2
CMPPS xmmreg,xmmreg,imm \360\2\x0F\xC2\110\26 KATMAI,SSE,SB,AR2
CMPSS xmmreg,mem,imm \363\2\x0F\xC2\110\26 KATMAI,SSE,SB,AR2
CMPSS xmmreg,xmmreg,imm \363\2\x0F\xC2\110\26 KATMAI,SSE,SB,AR2
-COMISS xmmreg,xmmrm \360\2\x0F\x2F\110 KATMAI,SSE
-CVTPI2PS xmmreg,mmxrm \360\2\x0F\x2A\110 KATMAI,SSE,MMX,SQ
-CVTPS2PI mmxreg,xmmrm \360\2\x0F\x2D\110 KATMAI,SSE,MMX,SQ
+COMISS xmmreg,xmmrm32 \360\2\x0F\x2F\110 KATMAI,SSE
+CVTPI2PS xmmreg,mmxrm64 \360\2\x0F\x2A\110 KATMAI,SSE,MMX
+CVTPS2PI mmxreg,xmmrm64 \360\2\x0F\x2D\110 KATMAI,SSE,MMX
CVTSI2SS xmmreg,mem \363\2\x0F\x2A\110 KATMAI,SSE,SD,AR1,ND
CVTSI2SS xmmreg,rm32 \363\2\x0F\x2A\110 KATMAI,SSE,SD,AR1
CVTSI2SS xmmreg,rm64 \324\363\2\x0F\x2A\110 X64,SSE,SQ,AR1
@@ -1462,52 +1470,46 @@ CVTSS2SI reg64,mem \324\363\2\x0F\x2D\110 X64,SSE,SD,AR1
CVTTPS2PI mmxreg,xmmrm \360\2\x0F\x2C\110 KATMAI,SSE,MMX,SQ
CVTTSS2SI reg32,xmmrm \363\2\x0F\x2C\110 KATMAI,SSE,SD,AR1
CVTTSS2SI reg64,xmmrm \324\363\2\x0F\x2C\110 X64,SSE,SD,AR1
-DIVPS xmmreg,xmmrm \360\2\x0F\x5E\110 KATMAI,SSE
-DIVSS xmmreg,xmmrm \363\2\x0F\x5E\110 KATMAI,SSE
-LDMXCSR mem \2\x0F\xAE\202 KATMAI,SSE,SD
-MAXPS xmmreg,xmmrm \360\2\x0F\x5F\110 KATMAI,SSE
-MAXSS xmmreg,xmmrm \363\2\x0F\x5F\110 KATMAI,SSE
-MINPS xmmreg,xmmrm \360\2\x0F\x5D\110 KATMAI,SSE
-MINSS xmmreg,xmmrm \363\2\x0F\x5D\110 KATMAI,SSE
-MOVAPS xmmreg,mem \360\2\x0F\x28\110 KATMAI,SSE
-MOVAPS mem,xmmreg \360\2\x0F\x29\101 KATMAI,SSE
-MOVAPS xmmreg,xmmreg \360\2\x0F\x28\110 KATMAI,SSE
-MOVAPS xmmreg,xmmreg \360\2\x0F\x29\101 KATMAI,SSE
-MOVHPS xmmreg,mem \360\2\x0F\x16\110 KATMAI,SSE
-MOVHPS mem,xmmreg \360\2\x0F\x17\101 KATMAI,SSE
+DIVPS xmmreg,xmmrm128 \360\2\x0F\x5E\110 KATMAI,SSE
+DIVSS xmmreg,xmmrm32 \363\2\x0F\x5E\110 KATMAI,SSE
+LDMXCSR mem32 \2\x0F\xAE\202 KATMAI,SSE
+MAXPS xmmreg,xmmrm128 \360\2\x0F\x5F\110 KATMAI,SSE
+MAXSS xmmreg,xmmrm32 \363\2\x0F\x5F\110 KATMAI,SSE
+MINPS xmmreg,xmmrm128 \360\2\x0F\x5D\110 KATMAI,SSE
+MINSS xmmreg,xmmrm32 \363\2\x0F\x5D\110 KATMAI,SSE
+MOVAPS xmmreg,xmmrm128 \360\2\x0F\x28\110 KATMAI,SSE
+MOVAPS xmmrm128,xmmreg \360\2\x0F\x29\101 KATMAI,SSE
+MOVHPS xmmreg,mem64 \360\2\x0F\x16\110 KATMAI,SSE
+MOVHPS mem64,xmmreg \360\2\x0F\x17\101 KATMAI,SSE
MOVLHPS xmmreg,xmmreg \360\2\x0F\x16\110 KATMAI,SSE
-MOVLPS xmmreg,mem \360\2\x0F\x12\110 KATMAI,SSE
-MOVLPS mem,xmmreg \360\2\x0F\x13\101 KATMAI,SSE
+MOVLPS xmmreg,mem64 \360\2\x0F\x12\110 KATMAI,SSE
+MOVLPS mem64,xmmreg \360\2\x0F\x13\101 KATMAI,SSE
MOVHLPS xmmreg,xmmreg \360\2\x0F\x12\110 KATMAI,SSE
MOVMSKPS reg32,xmmreg \360\2\x0F\x50\110 KATMAI,SSE
MOVMSKPS reg64,xmmreg \360\324\2\x0F\x50\110 X64,SSE
-MOVNTPS mem,xmmreg \360\2\x0F\x2B\101 KATMAI,SSE
-MOVSS xmmreg,mem \363\2\x0F\x10\110 KATMAI,SSE
-MOVSS mem,xmmreg \363\2\x0F\x11\101 KATMAI,SSE
+MOVNTPS mem128,xmmreg \360\2\x0F\x2B\101 KATMAI,SSE
+MOVSS xmmreg,xmmrm32 \363\2\x0F\x10\110 KATMAI,SSE
+MOVSS mem32,xmmreg \363\2\x0F\x11\101 KATMAI,SSE
MOVSS xmmreg,xmmreg \363\2\x0F\x10\110 KATMAI,SSE
-MOVSS xmmreg,xmmreg \363\2\x0F\x11\101 KATMAI,SSE
-MOVUPS xmmreg,mem \360\2\x0F\x10\110 KATMAI,SSE
-MOVUPS mem,xmmreg \360\2\x0F\x11\101 KATMAI,SSE
-MOVUPS xmmreg,xmmreg \360\2\x0F\x10\110 KATMAI,SSE
-MOVUPS xmmreg,xmmreg \360\2\x0F\x11\101 KATMAI,SSE
-MULPS xmmreg,xmmrm \360\2\x0F\x59\110 KATMAI,SSE
-MULSS xmmreg,xmmrm \363\2\x0F\x59\110 KATMAI,SSE
-ORPS xmmreg,xmmrm \360\2\x0F\x56\110 KATMAI,SSE
-RCPPS xmmreg,xmmrm \360\2\x0F\x53\110 KATMAI,SSE
-RCPSS xmmreg,xmmrm \363\2\x0F\x53\110 KATMAI,SSE
-RSQRTPS xmmreg,xmmrm \360\2\x0F\x52\110 KATMAI,SSE
-RSQRTSS xmmreg,xmmrm \363\2\x0F\x52\110 KATMAI,SSE
-SHUFPS xmmreg,mem,imm \360\2\x0F\xC6\110\26 KATMAI,SSE,SB,AR2
-SHUFPS xmmreg,xmmreg,imm \360\2\x0F\xC6\110\26 KATMAI,SSE,SB,AR2
-SQRTPS xmmreg,xmmrm \360\2\x0F\x51\110 KATMAI,SSE
-SQRTSS xmmreg,xmmrm \363\2\x0F\x51\110 KATMAI,SSE
-STMXCSR mem \2\x0F\xAE\203 KATMAI,SSE,SD
-SUBPS xmmreg,xmmrm \360\2\x0F\x5C\110 KATMAI,SSE
-SUBSS xmmreg,xmmrm \363\2\x0F\x5C\110 KATMAI,SSE
-UCOMISS xmmreg,xmmrm \360\2\x0F\x2E\110 KATMAI,SSE
-UNPCKHPS xmmreg,xmmrm \360\2\x0F\x15\110 KATMAI,SSE
-UNPCKLPS xmmreg,xmmrm \360\2\x0F\x14\110 KATMAI,SSE
-XORPS xmmreg,xmmrm \360\2\x0F\x57\110 KATMAI,SSE
+MOVUPS xmmreg,xmmrm128 \360\2\x0F\x10\110 KATMAI,SSE
+MOVUPS xmmrm128,xmmreg \360\2\x0F\x11\101 KATMAI,SSE
+MULPS xmmreg,xmmrm128 \360\2\x0F\x59\110 KATMAI,SSE
+MULSS xmmreg,xmmrm32 \363\2\x0F\x59\110 KATMAI,SSE
+ORPS xmmreg,xmmrm128 \360\2\x0F\x56\110 KATMAI,SSE
+RCPPS xmmreg,xmmrm128 \360\2\x0F\x53\110 KATMAI,SSE
+RCPSS xmmreg,xmmrm32 \363\2\x0F\x53\110 KATMAI,SSE
+RSQRTPS xmmreg,xmmrm128 \360\2\x0F\x52\110 KATMAI,SSE
+RSQRTSS xmmreg,xmmrm32 \363\2\x0F\x52\110 KATMAI,SSE
+SHUFPS xmmreg,xmmrm128,imm8 \360\2\x0F\xC6\110\26 KATMAI,SSE
+SQRTPS xmmreg,xmmrm128 \360\2\x0F\x51\110 KATMAI,SSE
+SQRTSS xmmreg,xmmrm32 \363\2\x0F\x51\110 KATMAI,SSE
+STMXCSR mem32 \2\x0F\xAE\203 KATMAI,SSE
+SUBPS xmmreg,xmmrm128 \360\2\x0F\x5C\110 KATMAI,SSE
+SUBSS xmmreg,xmmrm32 \363\2\x0F\x5C\110 KATMAI,SSE
+UCOMISS xmmreg,xmmrm32 \360\2\x0F\x2E\110 KATMAI,SSE
+UNPCKHPS xmmreg,xmmrm128 \360\2\x0F\x15\110 KATMAI,SSE
+UNPCKLPS xmmreg,xmmrm128 \360\2\x0F\x14\110 KATMAI,SSE
+XORPS xmmreg,xmmrm128 \360\2\x0F\x57\110 KATMAI,SSE
;# Introduced in Deschutes but necessary for SSE support
FXRSTOR mem [m: 0f ae /1] P6,SSE,FPU
@@ -1701,8 +1703,8 @@ CMPUNORDPD xmmreg,xmmrm \361\2\x0F\xC2\110\1\x03 WILLAMETTE,SSE2,SO
CMPUNORDSD xmmreg,xmmrm \362\2\x0F\xC2\110\1\x03 WILLAMETTE,SSE2
; CMPPD/CMPSD must come after the specific ops; that way the disassembler will find the
; specific ops first and only disassemble illegal ones as cmppd/cmpsd.
-CMPPD xmmreg,xmmrm,imm \361\2\x0F\xC2\110\26 WILLAMETTE,SSE2,SM2,SB,AR2
-CMPSD xmmreg,xmmrm,imm \362\2\x0F\xC2\110\26 WILLAMETTE,SSE2,SB,AR2
+CMPPD xmmreg,xmmrm128,imm8 \361\2\x0F\xC2\110\26 WILLAMETTE,SSE2
+CMPSD xmmreg,xmmrm128,imm8 \362\2\x0F\xC2\110\26 WILLAMETTE,SSE2
COMISD xmmreg,xmmrm \361\2\x0F\x2F\110 WILLAMETTE,SSE2
CVTDQ2PD xmmreg,xmmrm \363\2\x0F\xE6\110 WILLAMETTE,SSE2,SQ
CVTDQ2PS xmmreg,xmmrm \360\2\x0F\x5B\110 WILLAMETTE,SSE2,SO
@@ -1762,9 +1764,9 @@ SQRTSD xmmreg,xmmrm \362\2\x0F\x51\110 WILLAMETTE,SSE2
SUBPD xmmreg,xmmrm \361\2\x0F\x5C\110 WILLAMETTE,SSE2,SO
SUBSD xmmreg,xmmrm \362\2\x0F\x5C\110 WILLAMETTE,SSE2
UCOMISD xmmreg,xmmrm \361\2\x0F\x2E\110 WILLAMETTE,SSE2
-UNPCKHPD xmmreg,xmmrm \361\2\x0F\x15\110 WILLAMETTE,SSE2,SO
-UNPCKLPD xmmreg,xmmrm \361\2\x0F\x14\110 WILLAMETTE,SSE2,SO
-XORPD xmmreg,xmmrm \361\2\x0F\x57\110 WILLAMETTE,SSE2,SO
+UNPCKHPD xmmreg,xmmrm128 \361\2\x0F\x15\110 WILLAMETTE,SSE2
+UNPCKLPD xmmreg,xmmrm128 \361\2\x0F\x14\110 WILLAMETTE,SSE2
+XORPD xmmreg,xmmrm128 \361\2\x0F\x57\110 WILLAMETTE,SSE2
;# Prescott New Instructions (SSE3)
ADDSUBPD xmmreg,xmmrm \361\2\x0F\xD0\110 PRESCOTT,SSE3,SO
diff --git a/insns.h b/insns.h
index 4f3dd80b..51fb5cda 100644
--- a/insns.h
+++ b/insns.h
@@ -87,6 +87,7 @@ extern const uint8_t nasm_bytecodes[];
#define IF_AR4 0x00000140UL /* SB, SW, SD applies to argument 4 */
#define IF_ARMASK 0x000001C0UL /* mask for unsized argument spec */
#define IF_ARSHFT 6 /* LSB in IF_ARMASK */
+#define IF_OPT 0x00000200UL /* optimizing assembly only */
/* The next 3 bits aren't actually used for anything */
#define IF_PRIV 0x00000000UL /* it's a privileged instruction */
#define IF_SMM 0x00000000UL /* it's only valid in SMM */
@@ -111,7 +112,7 @@ extern const uint8_t nasm_bytecodes[];
#define IF_PMASK 0xFF000000UL /* the mask for processor types */
#define IF_PLEVEL 0x0F000000UL /* the mask for processor instr. level */
/* also the highest possible processor */
-#define IF_PFMASK 0xF01FFF00UL /* the mask for disassembly "prefer" */
+#define IF_PFMASK 0xF01FF800UL /* the mask for disassembly "prefer" */
#define IF_8086 0x00000000UL /* 8086 instruction */
#define IF_186 0x01000000UL /* 186+ instruction */
#define IF_286 0x02000000UL /* 286+ instruction */
diff --git a/insns.pl b/insns.pl
index 5ffdce2f..851d2d06 100755
--- a/insns.pl
+++ b/insns.pl
@@ -1,7 +1,7 @@
#!/usr/bin/perl
## --------------------------------------------------------------------------
-##
-## Copyright 1996-2009 The NASM Authors - All Rights Reserved
+##
+## Copyright 1996-2010 The NASM Authors - All Rights Reserved
## See the file AUTHORS included with the NASM distribution for
## the specific copyright holders.
##
@@ -15,7 +15,7 @@
## copyright notice, this list of conditions and the following
## disclaimer in the documentation and/or other materials provided
## with the distribution.
-##
+##
## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
## CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
## INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
@@ -52,9 +52,9 @@ $vex_classes = scalar(@vex_class);
for ($c = 0; $c < $vex_classes; $c++) {
$vexmap{$vex_class[$c]} = $c;
for ($m = 0; $m < 32; $m++) {
- for ($p = 0; $p < 4; $p++) {
- push(@vexlist, sprintf("%s%02X%01X", $vex_class[$c], $m, $p));
- }
+ for ($p = 0; $p < 4; $p++) {
+ push(@vexlist, sprintf("%s%02X%01X", $vex_class[$c], $m, $p));
+ }
}
}
@disasm_prefixes = (@vexlist, @disasm_prefixes);
@@ -67,13 +67,13 @@ print STDERR "Reading insns.dat...\n";
undef $output;
foreach $arg ( @ARGV ) {
if ( $arg =~ /^\-/ ) {
- if ( $arg =~ /^\-([abdin])$/ ) {
- $output = $1;
- } else {
- die "$0: Unknown option: ${arg}\n";
- }
+ if ( $arg =~ /^\-([abdin])$/ ) {
+ $output = $1;
+ } else {
+ die "$0: Unknown option: ${arg}\n";
+ }
} else {
- push (@args, $arg);
+ push (@args, $arg);
}
}
@@ -91,72 +91,72 @@ while (<F>) {
next if ( /^\s*(\;.*|)$/ ); # comments or blank lines
unless (/^\s*(\S+)\s+(\S+)\s+(\S+|\[.*\])\s+(\S+)\s*$/) {
- warn "line $line does not contain four fields\n";
- next;
+ warn "line $line does not contain four fields\n";
+ next;
}
@fields = ($1, $2, $3, $4);
@field_list = ([@fields, 0]);
if ($fields[1] =~ /\*/) {
- # This instruction has relaxed form(s)
- if ($fields[2] !~ /^\[/) {
- warn "line $line has an * operand but uses raw bytecodes\n";
- next;
- }
-
- $opmask = 0;
- @ops = split(/,/, $fields[1]);
- for ($oi = 0; $oi < scalar @ops; $oi++) {
- if ($ops[$oi] =~ /\*$/) {
- if ($oi == 0) {
- warn "line $line has a first operand with a *\n";
- next;
- }
- $opmask |= 1 << $oi;
- }
- }
-
- for ($oi = 1; $oi < (1 << scalar @ops); $oi++) {
- if (($oi & ~$opmask) == 0) {
- my @xops = ();
- my $omask = ~$oi;
- for ($oj = 0; $oj < scalar(@ops); $oj++) {
- if ($omask & 1) {
- push(@xops, $ops[$oj]);
- }
- $omask >>= 1;
- }
- push(@field_list, [$fields[0], join(',', @xops),
- $fields[2], $fields[3], $oi]);
- }
- }
+ # This instruction has relaxed form(s)
+ if ($fields[2] !~ /^\[/) {
+ warn "line $line has an * operand but uses raw bytecodes\n";
+ next;
+ }
+
+ $opmask = 0;
+ @ops = split(/,/, $fields[1]);
+ for ($oi = 0; $oi < scalar @ops; $oi++) {
+ if ($ops[$oi] =~ /\*$/) {
+ if ($oi == 0) {
+ warn "line $line has a first operand with a *\n";
+ next;
+ }
+ $opmask |= 1 << $oi;
+ }
+ }
+
+ for ($oi = 1; $oi < (1 << scalar @ops); $oi++) {
+ if (($oi & ~$opmask) == 0) {
+ my @xops = ();
+ my $omask = ~$oi;
+ for ($oj = 0; $oj < scalar(@ops); $oj++) {
+ if ($omask & 1) {
+ push(@xops, $ops[$oj]);
+ }
+ $omask >>= 1;
+ }
+ push(@field_list, [$fields[0], join(',', @xops),
+ $fields[2], $fields[3], $oi]);
+ }
+ }
}
foreach $fptr (@field_list) {
- @fields = @$fptr;
- ($formatted, $nd) = format_insn(@fields);
- if ($formatted) {
- $insns++;
- $aname = "aa_$fields[0]";
- push @$aname, $formatted;
- }
- if ( $fields[0] =~ /cc$/ ) {
- # Conditional instruction
- $k_opcodes_cc{$fields[0]}++;
- } else {
- # Unconditional instruction
- $k_opcodes{$fields[0]}++;
- }
- if ($formatted && !$nd) {
- push @big, $formatted;
- my @sseq = startseq($fields[2], $fields[4]);
- foreach $i (@sseq) {
- if (!defined($dinstables{$i})) {
- $dinstables{$i} = [];
- }
- push(@{$dinstables{$i}}, $#big);
- }
- }
+ @fields = @$fptr;
+ ($formatted, $nd) = format_insn(@fields);
+ if ($formatted) {
+ $insns++;
+ $aname = "aa_$fields[0]";
+ push @$aname, $formatted;
+ }
+ if ( $fields[0] =~ /cc$/ ) {
+ # Conditional instruction
+ $k_opcodes_cc{$fields[0]}++;
+ } else {
+ # Unconditional instruction
+ $k_opcodes{$fields[0]}++;
+ }
+ if ($formatted && !$nd) {
+ push @big, $formatted;
+ my @sseq = startseq($fields[2], $fields[4]);
+ foreach $i (@sseq) {
+ if (!defined($dinstables{$i})) {
+ $dinstables{$i} = [];
+ }
+ push(@{$dinstables{$i}}, $#big);
+ }
+ }
}
}
@@ -178,9 +178,9 @@ foreach $bl (@bytecode_list) {
push(@bytecode_array, $bl);
while ($h ne '') {
- $bytecode_pos{$h} = $bytecode_next;
- $h = substr($h, 2);
- $bytecode_next++;
+ $bytecode_pos{$h} = $bytecode_next;
+ $h = substr($h, 2);
+ $bytecode_next++;
}
}
undef @bytecode_list;
@@ -203,12 +203,12 @@ if ( !defined($output) || $output eq 'b') {
$p = 0;
foreach $bl (@bytecode_array) {
- printf B " /* %5d */ ", $p;
- foreach $d (@$bl) {
- printf B "%#o,", $d;
- $p++;
- }
- printf B "\n";
+ printf B " /* %5d */ ", $p;
+ foreach $d (@$bl) {
+ printf B "%#o,", $d;
+ $p++;
+ }
+ printf B "\n";
}
print B "};\n";
@@ -217,12 +217,12 @@ if ( !defined($output) || $output eq 'b') {
print B " * Bytecode frequencies (including reuse):\n";
print B " *\n";
for ($i = 0; $i < 32; $i++) {
- print B " *";
- for ($j = 0; $j < 256; $j += 32) {
- print B " |" if ($j);
- printf B " %3o:%4d", $i+$j, $bytecode_count[$i+$j];
- }
- print B "\n";
+ print B " *";
+ for ($j = 0; $j < 256; $j += 32) {
+ print B " |" if ($j);
+ printf B " %3o:%4d", $i+$j, $bytecode_count[$i+$j];
+ }
+ print B "\n";
}
print B " */\n";
@@ -241,16 +241,16 @@ if ( !defined($output) || $output eq 'a' ) {
print A "#include \"insns.h\"\n\n";
foreach $i (@opcodes, @opcodes_cc) {
- print A "static const struct itemplate instrux_${i}[] = {\n";
- $aname = "aa_$i";
- foreach $j (@$aname) {
- print A " ", codesubst($j), "\n";
- }
- print A " ITEMPLATE_END\n};\n\n";
+ print A "static const struct itemplate instrux_${i}[] = {\n";
+ $aname = "aa_$i";
+ foreach $j (@$aname) {
+ print A " ", codesubst($j), "\n";
+ }
+ print A " ITEMPLATE_END\n};\n\n";
}
print A "const struct itemplate * const nasm_instructions[] = {\n";
foreach $i (@opcodes, @opcodes_cc) {
- print A " instrux_${i},\n";
+ print A " instrux_${i},\n";
}
print A "};\n";
@@ -271,69 +271,69 @@ if ( !defined($output) || $output eq 'd' ) {
print D "static const struct itemplate instrux[] = {\n";
$n = 0;
foreach $j (@big) {
- printf D " /* %4d */ %s\n", $n++, codesubst($j);
+ printf D " /* %4d */ %s\n", $n++, codesubst($j);
}
print D "};\n";
foreach $h (sort(keys(%dinstables))) {
- next if ($h eq ''); # Skip pseudo-instructions
- print D "\nstatic const struct itemplate * const itable_${h}[] = {\n";
- foreach $j (@{$dinstables{$h}}) {
- print D " instrux + $j,\n";
- }
- print D "};\n";
+ next if ($h eq ''); # Skip pseudo-instructions
+ print D "\nstatic const struct itemplate * const itable_${h}[] = {\n";
+ foreach $j (@{$dinstables{$h}}) {
+ print D " instrux + $j,\n";
+ }
+ print D "};\n";
}
@prefix_list = ();
foreach $h (@disasm_prefixes, '') {
- for ($c = 0; $c < 256; $c++) {
- $nn = sprintf("%s%02X", $h, $c);
- if ($is_prefix{$nn} || defined($dinstables{$nn})) {
- # At least one entry in this prefix table
- push(@prefix_list, $h);
- $is_prefix{$h} = 1;
- last;
- }
- }
+ for ($c = 0; $c < 256; $c++) {
+ $nn = sprintf("%s%02X", $h, $c);
+ if ($is_prefix{$nn} || defined($dinstables{$nn})) {
+ # At least one entry in this prefix table
+ push(@prefix_list, $h);
+ $is_prefix{$h} = 1;
+ last;
+ }
+ }
}
foreach $h (@prefix_list) {
- print D "\n";
- print D "static " unless ($h eq '');
- print D "const struct disasm_index ";
- print D ($h eq '') ? 'itable' : "itable_$h";
- print D "[256] = {\n";
- for ($c = 0; $c < 256; $c++) {
- $nn = sprintf("%s%02X", $h, $c);
- if ($is_prefix{$nn}) {
- die "$fname: ambiguous decoding of $nn\n"
- if (defined($dinstables{$nn}));
- printf D " /* 0x%02x */ { itable_%s, -1 },\n", $c, $nn;
- } elsif (defined($dinstables{$nn})) {
- printf D " /* 0x%02x */ { itable_%s, %u },\n", $c,
- $nn, scalar(@{$dinstables{$nn}});
- } else {
- printf D " /* 0x%02x */ { NULL, 0 },\n", $c;
- }
- }
- print D "};\n";
+ print D "\n";
+ print D "static " unless ($h eq '');
+ print D "const struct disasm_index ";
+ print D ($h eq '') ? 'itable' : "itable_$h";
+ print D "[256] = {\n";
+ for ($c = 0; $c < 256; $c++) {
+ $nn = sprintf("%s%02X", $h, $c);
+ if ($is_prefix{$nn}) {
+ die "$fname: ambiguous decoding of $nn\n"
+ if (defined($dinstables{$nn}));
+ printf D " /* 0x%02x */ { itable_%s, -1 },\n", $c, $nn;
+ } elsif (defined($dinstables{$nn})) {
+ printf D " /* 0x%02x */ { itable_%s, %u },\n", $c,
+ $nn, scalar(@{$dinstables{$nn}});
+ } else {
+ printf D " /* 0x%02x */ { NULL, 0 },\n", $c;
+ }
+ }
+ print D "};\n";
}
printf D "\nconst struct disasm_index * const itable_vex[%d][32][4] =\n",
$vex_classes;
print D "{\n";
for ($c = 0; $c < $vex_classes; $c++) {
- print D " {\n";
- for ($m = 0; $m < 32; $m++) {
- print D " { ";
- for ($p = 0; $p < 4; $p++) {
- $vp = sprintf("%s%02X%01X", $vex_class[$c], $m, $p);
- printf D "%-15s",
- ($is_prefix{$vp} ? sprintf("itable_%s,", $vp) : 'NULL,');
- }
- print D "},\n";
- }
- print D " },\n";
+ print D " {\n";
+ for ($m = 0; $m < 32; $m++) {
+ print D " { ";
+ for ($p = 0; $p < 4; $p++) {
+ $vp = sprintf("%s%02X%01X", $vex_class[$c], $m, $p);
+ printf D "%-15s",
+ ($is_prefix{$vp} ? sprintf("itable_%s,", $vp) : 'NULL,');
+ }
+ print D "},\n";
+ }
+ print D " },\n";
}
print D "};\n";
@@ -355,10 +355,10 @@ if ( !defined($output) || $output eq 'i' ) {
print I "enum opcode {\n";
$maxlen = 0;
foreach $i (@opcodes, @opcodes_cc) {
- print I "\tI_${i},\n";
- $len = length($i);
- $len++ if ( $i =~ /cc$/ ); # Condition codes can be 3 characters long
- $maxlen = $len if ( $len > $maxlen );
+ print I "\tI_${i},\n";
+ $len = length($i);
+ $len++ if ( $i =~ /cc$/ ); # Condition codes can be 3 characters long
+ $maxlen = $len if ( $len > $maxlen );
}
print I "\tI_none = -1\n";
print I "};\n\n";
@@ -381,12 +381,12 @@ if ( !defined($output) || $output eq 'n' ) {
print N "const char * const nasm_insn_names[] = {";
$first = 1;
foreach $i (@opcodes, @opcodes_cc) {
- print N "," if ( !$first );
- $first = 0;
- $ilower = $i;
- $ilower =~ s/cc$//; # Remove conditional cc suffix
- $ilower =~ tr/A-Z/a-z/; # Change to lower case (Perl 4 compatible)
- print N "\n\t\"${ilower}\"";
+ print N "," if ( !$first );
+ $first = 0;
+ $ilower = $i;
+ $ilower =~ s/cc$//; # Remove conditional cc suffix
+ $ilower =~ tr/A-Z/a-z/; # Change to lower case (Perl 4 compatible)
+ print N "\n\t\"${ilower}\"";
}
print N "\n};\n";
close N;
@@ -398,24 +398,24 @@ printf STDERR "Done: %d instructions\n", $insns;
sub count_bytecodes(@) {
my $skip = 0;
foreach my $bc (@_) {
- if ($skip) {
- $skip--;
- next;
- }
- $bytecode_count[$bc]++;
- if ($bc >= 01 && $bc <= 04) {
- $skip = $bc;
- } elsif (($bc & ~03) == 010) {
- $skip = 1;
- } elsif (($bc & ~013) == 0144) {
- $skip = 1;
- } elsif ($bc == 0172) {
- $skip = 1;
- } elsif ($bc >= 0260 && $bc <= 0270) {
- $skip = 2;
- } elsif ($bc == 0330) {
- $skip = 1;
- }
+ if ($skip) {
+ $skip--;
+ next;
+ }
+ $bytecode_count[$bc]++;
+ if ($bc >= 01 && $bc <= 04) {
+ $skip = $bc;
+ } elsif (($bc & ~03) == 010) {
+ $skip = 1;
+ } elsif (($bc & ~013) == 0144) {
+ $skip = 1;
+ } elsif ($bc == 0172) {
+ $skip = 1;
+ } elsif ($bc >= 0260 && $bc <= 0270) {
+ $skip = 2;
+ } elsif ($bc == 0330) {
+ $skip = 1;
+ }
}
}
@@ -432,38 +432,38 @@ sub format_insn($$$$$) {
$operands =~ s/:/|colon,/g;
@ops = ();
if ($operands ne 'void') {
- foreach $op (split(/,/, $operands)) {
- if ($op =~ /^\=([0-9]+)$/) {
- $op = "same_as|$1";
- } else {
- @opx = ();
- foreach $opp (split(/\|/, $op)) {
- @oppx = ();
- if ($opp =~ /^(.*[^\d])(8|16|32|64|80|128|256)$/) {
- my $ox = $1;
- my $on = $2;
- if ($ox !~ /^sbyte$/) {
- $opp = $ox;
- push(@oppx, "bits$on");
- }
- }
- $opp =~ s/^mem$/memory/;
- $opp =~ s/^memory_offs$/mem_offs/;
- $opp =~ s/^imm$/immediate/;
- $opp =~ s/^([a-z]+)rm$/rm_$1/;
- $opp =~ s/^rm$/rm_gpr/;
- $opp =~ s/^reg$/reg_gpr/;
- push(@opx, $opp, @oppx);
- }
- $op = join('|', @opx);
- }
- push(@ops, $op);
- }
+ foreach $op (split(/,/, $operands)) {
+ if ($op =~ /^\=([0-9]+)$/) {
+ $op = "same_as|$1";
+ } else {
+ @opx = ();
+ foreach $opp (split(/\|/, $op)) {
+ @oppx = ();
+ if ($opp =~ /^(.*[^\d])(8|16|32|64|80|128|256)$/) {
+ my $ox = $1;
+ my $on = $2;
+ if ($ox !~ /^(sbyte|sdword|udword)$/) {
+ $opp = $ox;
+ push(@oppx, "bits$on");
+ }
+ }
+ $opp =~ s/^mem$/memory/;
+ $opp =~ s/^memory_offs$/mem_offs/;
+ $opp =~ s/^imm$/immediate/;
+ $opp =~ s/^([a-z]+)rm$/rm_$1/;
+ $opp =~ s/^rm$/rm_gpr/;
+ $opp =~ s/^reg$/reg_gpr/;
+ push(@opx, $opp, @oppx);
+ }
+ $op = join('|', @opx);
+ }
+ push(@ops, $op);
+ }
}
$num = scalar(@ops);
while (scalar(@ops) < $MAX_OPERANDS) {
- push(@ops, '0');
+ push(@ops, '0');
}
$operands = join(',', @ops);
$operands =~ tr/a-z/A-Z/;
@@ -490,11 +490,11 @@ sub codesubst($) {
my $n;
while ($s =~ /\@\@CODES-([0-9A-F]+)\@\@/) {
- my $pos = $bytecode_pos{$1};
- if (!defined($pos)) {
- die "$fname: no position assigned to byte code $1\n";
- }
- $s = $` . "nasm_bytecodes+${pos}" . "$'";
+ my $pos = $bytecode_pos{$1};
+ if (!defined($pos)) {
+ die "$fname: no position assigned to byte code $1\n";
+ }
+ $s = $` . "nasm_bytecodes+${pos}" . "$'";
}
return $s;
}
@@ -505,7 +505,7 @@ sub addprefix ($@) {
my @l = ();
foreach $x (@list) {
- push(@l, sprintf("%s%02X", $prefix, $x));
+ push(@l, sprintf("%s%02X", $prefix, $x));
}
return @l;
@@ -521,24 +521,24 @@ sub decodify($$) {
my($codestr, $relax) = @_;
if ($codestr =~ /^\s*\[([^\]]*)\]\s*$/) {
- return byte_code_compile($1, $relax);
+ return byte_code_compile($1, $relax);
}
my $c = $codestr;
my @codes = ();
while ($c ne '') {
- if ($c =~ /^\\x([0-9a-f]+)(.*)$/i) {
- push(@codes, hex $1);
- $c = $2;
- next;
- } elsif ($c =~ /^\\([0-7]{1,3})(.*)$/) {
- push(@codes, oct $1);
- $c = $2;
- next;
- } else {
- die "$fname: unknown code format in \"$codestr\"\n";
- }
+ if ($c =~ /^\\x([0-9a-f]+)(.*)$/i) {
+ push(@codes, hex $1);
+ $c = $2;
+ next;
+ } elsif ($c =~ /^\\([0-7]{1,3})(.*)$/) {
+ push(@codes, oct $1);
+ $c = $2;
+ next;
+ } else {
+ die "$fname: unknown code format in \"$codestr\"\n";
+ }
}
return @codes;
@@ -550,7 +550,7 @@ sub hexstr(@) {
my $c;
foreach $c (@_) {
- $s .= sprintf("%02X", $c);
+ $s .= sprintf("%02X", $c);
}
return $s;
}
@@ -575,63 +575,63 @@ sub startseq($$) {
@codes = decodify($codestr, $relax);
while ($c0 = shift(@codes)) {
- $c1 = $codes[0];
- if ($c0 >= 01 && $c0 <= 04) {
- # Fixed byte string
- my $fbs = $prefix;
- while (1) {
- if ($c0 >= 01 && $c0 <= 04) {
- while ($c0--) {
- $fbs .= sprintf("%02X", shift(@codes));
- }
- } else {
- last;
- }
- $c0 = shift(@codes);
- }
-
- foreach $pfx (@disasm_prefixes) {
- if (substr($fbs, 0, length($pfx)) eq $pfx) {
- $prefix = $pfx;
- $fbs = substr($fbs, length($pfx));
- last;
- }
- }
-
- if ($fbs ne '') {
- return ($prefix.substr($fbs,0,2));
- }
-
- unshift(@codes, $c0);
- } elsif ($c0 >= 010 && $c0 <= 013) {
- return addprefix($prefix, $c1..($c1+7));
- } elsif (($c0 & ~013) == 0144) {
- return addprefix($prefix, $c1, $c1|2);
- } elsif ($c0 == 0330) {
- return addprefix($prefix, $c1..($c1+15));
- } elsif ($c0 == 0 || $c0 == 0340) {
- return $prefix;
- } elsif ($c0 == 0344) {
- return addprefix($prefix, 0x06, 0x0E, 0x16, 0x1E);
- } elsif ($c0 == 0345) {
- return addprefix($prefix, 0x07, 0x17, 0x1F);
- } elsif ($c0 == 0346) {
- return addprefix($prefix, 0xA0, 0xA8);
- } elsif ($c0 == 0347) {
- return addprefix($prefix, 0xA1, 0xA9);
- } elsif (($c0 & ~3) == 0260 || $c0 == 0270) {
- my $c,$m,$wlp;
- $m = shift(@codes);
- $wlp = shift(@codes);
- $c = ($m >> 6);
- $m = $m & 31;
- $prefix .= sprintf('%s%02X%01X', $vex_class[$c], $m, $wlp & 3);
- } elsif ($c0 >= 0172 && $c0 <= 174) {
- shift(@codes); # Skip is4 control byte
- } else {
- # We really need to be able to distinguish "forbidden"
- # and "ignorable" codes here
- }
+ $c1 = $codes[0];
+ if ($c0 >= 01 && $c0 <= 04) {
+ # Fixed byte string
+ my $fbs = $prefix;
+ while (1) {
+ if ($c0 >= 01 && $c0 <= 04) {
+ while ($c0--) {
+ $fbs .= sprintf("%02X", shift(@codes));
+ }
+ } else {
+ last;
+ }
+ $c0 = shift(@codes);
+ }
+
+ foreach $pfx (@disasm_prefixes) {
+ if (substr($fbs, 0, length($pfx)) eq $pfx) {
+ $prefix = $pfx;
+ $fbs = substr($fbs, length($pfx));
+ last;
+ }
+ }
+
+ if ($fbs ne '') {
+ return ($prefix.substr($fbs,0,2));
+ }
+
+ unshift(@codes, $c0);
+ } elsif ($c0 >= 010 && $c0 <= 013) {
+ return addprefix($prefix, $c1..($c1+7));
+ } elsif (($c0 & ~013) == 0144) {
+ return addprefix($prefix, $c1, $c1|2);
+ } elsif ($c0 == 0330) {
+ return addprefix($prefix, $c1..($c1+15));
+ } elsif ($c0 == 0 || $c0 == 0340) {
+ return $prefix;
+ } elsif ($c0 == 0344) {
+ return addprefix($prefix, 0x06, 0x0E, 0x16, 0x1E);
+ } elsif ($c0 == 0345) {
+ return addprefix($prefix, 0x07, 0x17, 0x1F);
+ } elsif ($c0 == 0346) {
+ return addprefix($prefix, 0xA0, 0xA8);
+ } elsif ($c0 == 0347) {
+ return addprefix($prefix, 0xA1, 0xA9);
+ } elsif (($c0 & ~3) == 0260 || $c0 == 0270) {
+ my $c,$m,$wlp;
+ $m = shift(@codes);
+ $wlp = shift(@codes);
+ $c = ($m >> 6);
+ $m = $m & 31;
+ $prefix .= sprintf('%s%02X%01X', $vex_class[$c], $m, $wlp & 3);
+ } elsif ($c0 >= 0172 && $c0 <= 174) {
+ shift(@codes); # Skip is4 control byte
+ } else {
+ # We really need to be able to distinguish "forbidden"
+ # and "ignorable" codes here
+ }
}
return $prefix;
}
@@ -669,266 +669,266 @@ sub byte_code_compile($$) {
my $opex;
unless ($str =~ /^(([^\s:]*)\:|)\s*(.*\S)\s*$/) {
- die "$fname: $line: cannot parse: [$str]\n";
+ die "$fname: $line: cannot parse: [$str]\n";
}
$opr = "\L$2";
$opc = "\L$3";
my $op = 0;
for ($i = 0; $i < length($opr); $i++) {
- my $c = substr($opr,$i,1);
- if ($c eq '+') {
- $op--;
- } else {
- if ($relax & 1) {
- $op--;
- }
- $relax >>= 1;
- $oppos{$c} = $op++;
- }
+ my $c = substr($opr,$i,1);
+ if ($c eq '+') {
+ $op--;
+ } else {
+ if ($relax & 1) {
+ $op--;
+ }
+ $relax >>= 1;
+ $oppos{$c} = $op++;
+ }
}
$prefix_ok = 1;
foreach $op (split(/\s*(?:\s|(?=[\/\\]))/, $opc)) {
- if ($op eq 'o16') {
- push(@codes, 0320);
- } elsif ($op eq 'o32') {
- push(@codes, 0321);
- } elsif ($op eq 'o64') { # 64-bit operand size requiring REX.W
- push(@codes, 0324);
- } elsif ($op eq 'o64nw') { # Implied 64-bit operand size (no REX.W)
- push(@codes, 0323);
- } elsif ($op eq 'a16') {
- push(@codes, 0310);
- } elsif ($op eq 'a32') {
- push(@codes, 0311);
- } elsif ($op eq 'a64') {
- push(@codes, 0313);
- } elsif ($op eq '!osp') {
- push(@codes, 0364);
- } elsif ($op eq '!asp') {
- push(@codes, 0365);
- } elsif ($op eq 'rex.l') {
- push(@codes, 0334);
- } elsif ($op eq 'repe') {
- push(@codes, 0335);
- } elsif ($op eq 'nohi') { # Use spl/bpl/sil/dil even without REX
- push(@codes, 0325);
- } elsif ($prefix_ok && $op =~ /^(66|f2|f3|np)$/) {
- # 66/F2/F3 prefix used as an opcode extension, or np = no prefix
- if ($op eq '66') {
- push(@codes, 0361);
- } elsif ($op eq 'f2') {
- push(@codes, 0362);
- } elsif ($op eq 'f3') {
- push(@codes, 0363);
- } else {
- push(@codes, 0360);
- }
- } elsif ($op =~ /^[0-9a-f]{2}$/) {
- if (defined($litix) && $litix+$codes[$litix]+1 == scalar @codes &&
- $codes[$litix] < 4) {
- $codes[$litix]++;
- push(@codes, hex $op);
- } else {
- $litix = scalar(@codes);
- push(@codes, 01, hex $op);
- }
- $prefix_ok = 0;
- } elsif ($op eq '/r') {
- if (!defined($oppos{'r'}) || !defined($oppos{'m'})) {
- die "$fname: $line: $op requires r and m operands\n";
- }
- $opex = (($oppos{'m'} & 4) ? 06 : 0) |
- (($oppos{'r'} & 4) ? 05 : 0);
- push(@codes, $opex) if ($opex);
- push(@codes, 0100 + (($oppos{'m'} & 3) << 3) + ($oppos{'r'} & 3));
- $prefix_ok = 0;
- } elsif ($op =~ m:^/([0-7])$:) {
- if (!defined($oppos{'m'})) {
- die "$fname: $line: $op requires m operand\n";
- }
- push(@codes, 06) if ($oppos{'m'} & 4);
- push(@codes, 0200 + (($oppos{'m'} & 3) << 3) + $1);
- $prefix_ok = 0;
- } elsif ($op =~ /^(vex|xop)(|\..*)$/) {
- my $c = $vexmap{$1};
- my ($m,$w,$l,$p) = (undef,2,undef,0);
- my $has_nds = 0;
- my @subops = split(/\./, $op);
- shift @subops; # Drop prefix
- foreach $oq (@subops) {
- if ($oq eq '128' || $oq eq 'l0' || $oq eq 'lz') {
- $l = 0;
- } elsif ($oq eq '256' || $oq eq 'l1') {
- $l = 1;
- } elsif ($oq eq 'lig') {
- $l = 2;
- } elsif ($oq eq 'w0') {
- $w = 0;
- } elsif ($oq eq 'w1') {
- $w = 1;
- } elsif ($oq eq 'wig') {
- $w = 2;
- } elsif ($oq eq 'ww') {
- $w = 3;
- } elsif ($oq eq 'p0') {
- $p = 0;
- } elsif ($oq eq '66' || $oq eq 'p1') {
- $p = 1;
- } elsif ($oq eq 'f3' || $oq eq 'p2') {
- $p = 2;
- } elsif ($oq eq 'f2' || $oq eq 'p3') {
- $p = 3;
- } elsif ($oq eq '0f') {
- $m = 1;
- } elsif ($oq eq '0f38') {
- $m = 2;
- } elsif ($oq eq '0f3a') {
- $m = 3;
- } elsif ($oq =~ /^m([0-9]+)$/) {
- $m = $1+0;
- } elsif ($oq eq 'nds' || $oq eq 'ndd' || $oq eq 'dds') {
- if (!defined($oppos{'v'})) {
- die "$fname: $line: vex.$oq without 'v' operand\n";
- }
- $has_nds = 1;
- } else {
- die "$fname: $line: undefined VEX subcode: $oq\n";
- }
- }
- if (!defined($m) || !defined($w) || !defined($l) || !defined($p)) {
- die "$fname: $line: missing fields in VEX specification\n";
- }
- if (defined($oppos{'v'}) && !$has_nds) {
- die "$fname: $line: 'v' operand without vex.nds or vex.ndd\n";
- }
- push(@codes, defined($oppos{'v'}) ? 0260+($oppos{'v'} & 3) : 0270,
- ($c << 6)+$m, ($w << 4)+($l << 2)+$p);
- $prefix_ok = 0;
- } elsif ($op =~ /^\/drex([01])$/) {
- my $oc0 = $1;
- if (!defined($oppos{'d'})) {
- die "$fname: $line: DREX without a 'd' operand\n";
- }
- # Note the use of *unshift* here, as opposed to *push*.
- # This is because NASM want this byte code at the start of
- # the instruction sequence, but the AMD documentation puts
- # this at (roughly) the position of the drex byte itself.
- # This allows us to match the AMD documentation and still
- # do the right thing.
- unshift(@codes, 0160+($oppos{'d'} & 3)+($oc0 ? 4 : 0));
- unshift(@codes, 05) if ($oppos{'d'} & 4);
- } elsif ($op =~ /^(ib\,s|ib|ibx|ib\,w|iw|iwd|id|idx|iwdq|rel|rel8|rel16|rel32|iq|seg|ibw|ibd|ibd,s)$/) {
- if (!defined($oppos{'i'})) {
- die "$fname: $line: $op without 'i' operand\n";
- }
- if ($op eq 'ib,s') { # Signed imm8
- push(@codes, 05) if ($oppos{'i'} & 4);
- push(@codes, 014+($oppos{'i'} & 3));
- } elsif ($op eq 'ib') { # imm8
- push(@codes, 05) if ($oppos{'i'} & 4);
- push(@codes, 020+($oppos{'i'} & 3));
- } elsif ($op eq 'ib,u') { # Unsigned imm8
- push(@codes, 05) if ($oppos{'i'} & 4);
- push(@codes, 024+($oppos{'i'} & 3));
- } elsif ($op eq 'iw') { # imm16
- push(@codes, 05) if ($oppos{'i'} & 4);
- push(@codes, 030+($oppos{'i'} & 3));
- } elsif ($op eq 'ibx') { # imm8 sign-extended to opsize
- push(@codes, 05) if ($oppos{'i'} & 4);
- push(@codes, 0274+($oppos{'i'} & 3));
- } elsif ($op eq 'iwd') { # imm16 or imm32, depending on opsize
- push(@codes, 05) if ($oppos{'i'} & 4);
- push(@codes, 034+($oppos{'i'} & 3));
- } elsif ($op eq 'id') { # imm32
- push(@codes, 05) if ($oppos{'i'} & 4);
- push(@codes, 040+($oppos{'i'} & 3));
- } elsif ($op eq 'idx') { # imm32 extended to 64 bits
- push(@codes, 05) if ($oppos{'i'} & 4);
- push(@codes, 0254+($oppos{'i'} & 3));
- } elsif ($op eq 'iwdq') { # imm16/32/64, depending on opsize
- push(@codes, 05) if ($oppos{'i'} & 4);
- push(@codes, 044+($oppos{'i'} & 3));
- } elsif ($op eq 'rel8') {
- push(@codes, 05) if ($oppos{'i'} & 4);
- push(@codes, 050+($oppos{'i'} & 3));
- } elsif ($op eq 'iq') {
- push(@codes, 05) if ($oppos{'i'} & 4);
- push(@codes, 054+($oppos{'i'} & 3));
- } elsif ($op eq 'rel16') {
- push(@codes, 05) if ($oppos{'i'} & 4);
- push(@codes, 060+($oppos{'i'} & 3));
- } elsif ($op eq 'rel') { # 16 or 32 bit relative operand
- push(@codes, 05) if ($oppos{'i'} & 4);
- push(@codes, 064+($oppos{'i'} & 3));
- } elsif ($op eq 'rel32') {
- push(@codes, 05) if ($oppos{'i'} & 4);
- push(@codes, 070+($oppos{'i'} & 3));
- } elsif ($op eq 'seg') {
- push(@codes, 05) if ($oppos{'i'} & 4);
- push(@codes, 074+($oppos{'i'} & 3));
- } elsif ($op eq 'ibw') { # imm16 that can be bytified
- if (!defined($s_pos)) {
- die "$fname: $line: $op without a +s byte\n";
- }
- $codes[$s_pos] += 0144;
- push(@codes, 05) if ($oppos{'i'} & 4);
- push(@codes, 0140+($oppos{'i'} & 3));
- } elsif ($op eq 'ibd') { # imm32 that can be bytified
- if (!defined($s_pos)) {
- die "$fname: $line: $op without a +s byte\n";
- }
- $codes[$s_pos] += 0154;
- push(@codes, 05) if ($oppos{'i'} & 4);
- push(@codes, 0150+($oppos{'i'} & 3));
- } elsif ($op eq 'ibd,s') {
- # imm32 that can be bytified, sign extended to 64 bits
- if (!defined($s_pos)) {
- die "$fname: $line: $op without a +s byte\n";
- }
- $codes[$s_pos] += 0154;
- push(@codes, 05) if ($oppos{'i'} & 4);
- push(@codes, 0250+($oppos{'i'} & 3));
- }
- $prefix_ok = 0;
- } elsif ($op eq '/is4') {
- if (!defined($oppos{'s'})) {
- die "$fname: $line: $op without 's' operand\n";
- }
- if (defined($oppos{'i'})) {
- push(@codes, 0172, ($oppos{'s'} << 3)+$oppos{'i'});
- } else {
- push(@codes, 0174, $oppos{'s'});
- }
- $prefix_ok = 0;
- } elsif ($op =~ /^\/is4\=([0-9]+)$/) {
- my $imm = $1;
- if (!defined($oppos{'s'})) {
- die "$fname: $line: $op without 's' operand\n";
- }
- if ($imm < 0 || $imm > 15) {
- die "$fname: $line: invalid imm4 value for $op: $imm\n";
- }
- push(@codes, 0173, ($oppos{'s'} << 4) + $imm);
- $prefix_ok = 0;
- } elsif ($op =~ /^([0-9a-f]{2})\+s$/) {
- if (!defined($oppos{'i'})) {
- die "$fname: $line: $op without 'i' operand\n";
- }
- $s_pos = scalar @codes;
- push(@codes, 05) if ($oppos{'i'} & 4);
- push(@codes, $oppos{'i'} & 3, hex $1);
- $prefix_ok = 0;
- } elsif ($op =~ /^([0-9a-f]{2})\+c$/) {
- push(@codes, 0330, hex $1);
- $prefix_ok = 0;
- } elsif ($op =~ /^\\([0-7]+|x[0-9a-f]{2})$/) {
- # Escape to enter literal bytecodes
- push(@codes, oct $1);
- } else {
- die "$fname: $line: unknown operation: $op\n";
- }
+ if ($op eq 'o16') {
+ push(@codes, 0320);
+ } elsif ($op eq 'o32') {
+ push(@codes, 0321);
+ } elsif ($op eq 'o64') { # 64-bit operand size requiring REX.W
+ push(@codes, 0324);
+ } elsif ($op eq 'o64nw') { # Implied 64-bit operand size (no REX.W)
+ push(@codes, 0323);
+ } elsif ($op eq 'a16') {
+ push(@codes, 0310);
+ } elsif ($op eq 'a32') {
+ push(@codes, 0311);
+ } elsif ($op eq 'a64') {
+ push(@codes, 0313);
+ } elsif ($op eq '!osp') {
+ push(@codes, 0364);
+ } elsif ($op eq '!asp') {
+ push(@codes, 0365);
+ } elsif ($op eq 'rex.l') {
+ push(@codes, 0334);
+ } elsif ($op eq 'repe') {
+ push(@codes, 0335);
+ } elsif ($op eq 'nohi') { # Use spl/bpl/sil/dil even without REX
+ push(@codes, 0325);
+ } elsif ($prefix_ok && $op =~ /^(66|f2|f3|np)$/) {
+ # 66/F2/F3 prefix used as an opcode extension, or np = no prefix
+ if ($op eq '66') {
+ push(@codes, 0361);
+ } elsif ($op eq 'f2') {
+ push(@codes, 0362);
+ } elsif ($op eq 'f3') {
+ push(@codes, 0363);
+ } else {
+ push(@codes, 0360);
+ }
+ } elsif ($op =~ /^[0-9a-f]{2}$/) {
+ if (defined($litix) && $litix+$codes[$litix]+1 == scalar @codes &&
+ $codes[$litix] < 4) {
+ $codes[$litix]++;
+ push(@codes, hex $op);
+ } else {
+ $litix = scalar(@codes);
+ push(@codes, 01, hex $op);
+ }
+ $prefix_ok = 0;
+ } elsif ($op eq '/r') {
+ if (!defined($oppos{'r'}) || !defined($oppos{'m'})) {
+ die "$fname: $line: $op requires r and m operands\n";
+ }
+ $opex = (($oppos{'m'} & 4) ? 06 : 0) |
+ (($oppos{'r'} & 4) ? 05 : 0);
+ push(@codes, $opex) if ($opex);
+ push(@codes, 0100 + (($oppos{'m'} & 3) << 3) + ($oppos{'r'} & 3));
+ $prefix_ok = 0;
+ } elsif ($op =~ m:^/([0-7])$:) {
+ if (!defined($oppos{'m'})) {
+ die "$fname: $line: $op requires m operand\n";
+ }
+ push(@codes, 06) if ($oppos{'m'} & 4);
+ push(@codes, 0200 + (($oppos{'m'} & 3) << 3) + $1);
+ $prefix_ok = 0;
+ } elsif ($op =~ /^(vex|xop)(|\..*)$/) {
+ my $c = $vexmap{$1};
+ my ($m,$w,$l,$p) = (undef,2,undef,0);
+ my $has_nds = 0;
+ my @subops = split(/\./, $op);
+ shift @subops; # Drop prefix
+ foreach $oq (@subops) {
+ if ($oq eq '128' || $oq eq 'l0' || $oq eq 'lz') {
+ $l = 0;
+ } elsif ($oq eq '256' || $oq eq 'l1') {
+ $l = 1;
+ } elsif ($oq eq 'lig') {
+ $l = 2;
+ } elsif ($oq eq 'w0') {
+ $w = 0;
+ } elsif ($oq eq 'w1') {
+ $w = 1;
+ } elsif ($oq eq 'wig') {
+ $w = 2;
+ } elsif ($oq eq 'ww') {
+ $w = 3;
+ } elsif ($oq eq 'p0') {
+ $p = 0;
+ } elsif ($oq eq '66' || $oq eq 'p1') {
+ $p = 1;
+ } elsif ($oq eq 'f3' || $oq eq 'p2') {
+ $p = 2;
+ } elsif ($oq eq 'f2' || $oq eq 'p3') {
+ $p = 3;
+ } elsif ($oq eq '0f') {
+ $m = 1;
+ } elsif ($oq eq '0f38') {
+ $m = 2;
+ } elsif ($oq eq '0f3a') {
+ $m = 3;
+ } elsif ($oq =~ /^m([0-9]+)$/) {
+ $m = $1+0;
+ } elsif ($oq eq 'nds' || $oq eq 'ndd' || $oq eq 'dds') {
+ if (!defined($oppos{'v'})) {
+ die "$fname: $line: vex.$oq without 'v' operand\n";
+ }
+ $has_nds = 1;
+ } else {
+ die "$fname: $line: undefined VEX subcode: $oq\n";
+ }
+ }
+ if (!defined($m) || !defined($w) || !defined($l) || !defined($p)) {
+ die "$fname: $line: missing fields in VEX specification\n";
+ }
+ if (defined($oppos{'v'}) && !$has_nds) {
+ die "$fname: $line: 'v' operand without vex.nds or vex.ndd\n";
+ }
+ push(@codes, defined($oppos{'v'}) ? 0260+($oppos{'v'} & 3) : 0270,
+ ($c << 6)+$m, ($w << 4)+($l << 2)+$p);
+ $prefix_ok = 0;
+ } elsif ($op =~ /^\/drex([01])$/) {
+ my $oc0 = $1;
+ if (!defined($oppos{'d'})) {
+ die "$fname: $line: DREX without a 'd' operand\n";
+ }
+ # Note the use of *unshift* here, as opposed to *push*.
+ # This is because NASM want this byte code at the start of
+ # the instruction sequence, but the AMD documentation puts
+ # this at (roughly) the position of the drex byte itself.
+ # This allows us to match the AMD documentation and still
+ # do the right thing.
+ unshift(@codes, 0160+($oppos{'d'} & 3)+($oc0 ? 4 : 0));
+ unshift(@codes, 05) if ($oppos{'d'} & 4);
+ } elsif ($op =~ /^(ib\,s|ib|ibx|ib\,w|iw|iwd|id|idx|iwdq|rel|rel8|rel16|rel32|iq|seg|ibw|ibd|ibd,s)$/) {
+ if (!defined($oppos{'i'})) {
+ die "$fname: $line: $op without 'i' operand\n";
+ }
+ if ($op eq 'ib,s') { # Signed imm8
+ push(@codes, 05) if ($oppos{'i'} & 4);
+ push(@codes, 014+($oppos{'i'} & 3));
+ } elsif ($op eq 'ib') { # imm8
+ push(@codes, 05) if ($oppos{'i'} & 4);
+ push(@codes, 020+($oppos{'i'} & 3));
+ } elsif ($op eq 'ib,u') { # Unsigned imm8
+ push(@codes, 05) if ($oppos{'i'} & 4);
+ push(@codes, 024+($oppos{'i'} & 3));
+ } elsif ($op eq 'iw') { # imm16
+ push(@codes, 05) if ($oppos{'i'} & 4);
+ push(@codes, 030+($oppos{'i'} & 3));
+ } elsif ($op eq 'ibx') { # imm8 sign-extended to opsize
+ push(@codes, 05) if ($oppos{'i'} & 4);
+ push(@codes, 0274+($oppos{'i'} & 3));
+ } elsif ($op eq 'iwd') { # imm16 or imm32, depending on opsize
+ push(@codes, 05) if ($oppos{'i'} & 4);
+ push(@codes, 034+($oppos{'i'} & 3));
+ } elsif ($op eq 'id') { # imm32
+ push(@codes, 05) if ($oppos{'i'} & 4);
+ push(@codes, 040+($oppos{'i'} & 3));
+ } elsif ($op eq 'idx') { # imm32 extended to 64 bits
+ push(@codes, 05) if ($oppos{'i'} & 4);
+ push(@codes, 0254+($oppos{'i'} & 3));
+ } elsif ($op eq 'iwdq') { # imm16/32/64, depending on opsize
+ push(@codes, 05) if ($oppos{'i'} & 4);
+ push(@codes, 044+($oppos{'i'} & 3));
+ } elsif ($op eq 'rel8') {
+ push(@codes, 05) if ($oppos{'i'} & 4);
+ push(@codes, 050+($oppos{'i'} & 3));
+ } elsif ($op eq 'iq') {
+ push(@codes, 05) if ($oppos{'i'} & 4);
+ push(@codes, 054+($oppos{'i'} & 3));
+ } elsif ($op eq 'rel16') {
+ push(@codes, 05) if ($oppos{'i'} & 4);
+ push(@codes, 060+($oppos{'i'} & 3));
+ } elsif ($op eq 'rel') { # 16 or 32 bit relative operand
+ push(@codes, 05) if ($oppos{'i'} & 4);
+ push(@codes, 064+($oppos{'i'} & 3));
+ } elsif ($op eq 'rel32') {
+ push(@codes, 05) if ($oppos{'i'} & 4);
+ push(@codes, 070+($oppos{'i'} & 3));
+ } elsif ($op eq 'seg') {
+ push(@codes, 05) if ($oppos{'i'} & 4);
+ push(@codes, 074+($oppos{'i'} & 3));
+ } elsif ($op eq 'ibw') { # imm16 that can be bytified
+ if (!defined($s_pos)) {
+ die "$fname: $line: $op without a +s byte\n";
+ }
+ $codes[$s_pos] += 0144;
+ push(@codes, 05) if ($oppos{'i'} & 4);
+ push(@codes, 0140+($oppos{'i'} & 3));
+ } elsif ($op eq 'ibd') { # imm32 that can be bytified
+ if (!defined($s_pos)) {
+ die "$fname: $line: $op without a +s byte\n";
+ }
+ $codes[$s_pos] += 0154;
+ push(@codes, 05) if ($oppos{'i'} & 4);
+ push(@codes, 0150+($oppos{'i'} & 3));
+ } elsif ($op eq 'ibd,s') {
+ # imm32 that can be bytified, sign extended to 64 bits
+ if (!defined($s_pos)) {
+ die "$fname: $line: $op without a +s byte\n";
+ }
+ $codes[$s_pos] += 0154;
+ push(@codes, 05) if ($oppos{'i'} & 4);
+ push(@codes, 0250+($oppos{'i'} & 3));
+ }
+ $prefix_ok = 0;
+ } elsif ($op eq '/is4') {
+ if (!defined($oppos{'s'})) {
+ die "$fname: $line: $op without 's' operand\n";
+ }
+ if (defined($oppos{'i'})) {
+ push(@codes, 0172, ($oppos{'s'} << 3)+$oppos{'i'});
+ } else {
+ push(@codes, 0174, $oppos{'s'});
+ }
+ $prefix_ok = 0;
+ } elsif ($op =~ /^\/is4\=([0-9]+)$/) {
+ my $imm = $1;
+ if (!defined($oppos{'s'})) {
+ die "$fname: $line: $op without 's' operand\n";
+ }
+ if ($imm < 0 || $imm > 15) {
+ die "$fname: $line: invalid imm4 value for $op: $imm\n";
+ }
+ push(@codes, 0173, ($oppos{'s'} << 4) + $imm);
+ $prefix_ok = 0;
+ } elsif ($op =~ /^([0-9a-f]{2})\+s$/) {
+ if (!defined($oppos{'i'})) {
+ die "$fname: $line: $op without 'i' operand\n";
+ }
+ $s_pos = scalar @codes;
+ push(@codes, 05) if ($oppos{'i'} & 4);
+ push(@codes, $oppos{'i'} & 3, hex $1);
+ $prefix_ok = 0;
+ } elsif ($op =~ /^([0-9a-f]{2})\+c$/) {
+ push(@codes, 0330, hex $1);
+ $prefix_ok = 0;
+ } elsif ($op =~ /^\\([0-7]+|x[0-9a-f]{2})$/) {
+ # Escape to enter literal bytecodes
+ push(@codes, oct $1);
+ } else {
+ die "$fname: $line: unknown operation: $op\n";
+ }
}
return @codes;
diff --git a/lcc/README b/lcc/README
deleted file mode 100644
index 569b9be7..00000000
--- a/lcc/README
+++ /dev/null
@@ -1,52 +0,0 @@
-This directory contains the necessary files to port the C compiler
-``LCC'' (available by FTP from sunsite.doc.ic.ac.uk in the directory
-/computing/programming/languages/c/lcc) to compile for Linux (a.out
-or ELF) by using NASM as a back-end code generator.
-
-This patch has been tested on lcc version 3.6.
-
-To install:
-
-- Copy `x86nasm.md' into the `src' directory of the lcc tree.
-
-- Copy either `lin-elf.c' or `lin-aout.c' into the `etc' directory.
-
-- If you're installing for a.out, edit `x86nasm.md' and change the
- conditional after the comment reading "CHANGE THIS FOR a.out" in
- the `defsymbol' function from `#if 0' to `#if 1'.
-
-- Make the following changes to `bind.c' in the `src' directory:
-
- - Near the top of the file, add a line that reads
- extern Interface x86nasmIR;
-
- - In the `bindings' array, add the lines
- "x86-nasm", &x86nasmIR,
- "x86/nasm", &x86nasmIR,
- (in sensible looking places...)
-
- A sample `bind.c' has been provided to show what the result of
- this might look like. You might be able to get away with using it
- directly...
-
-- Modify the lcc makefile to include rules for x86nasm.o: this will
- have to be done in about three places. Just copy any line with
- `x86' on it and modify it to read `x86nasm' everywhere. (Except
- that in the list of object files that rcc is made up from, do
- remember to ensure that every line but the last has a trailing
- backslash...)
-
-- You may have to modify the contents of `lin-elf.c' or `lin-aout.c'
- to reflect the true locations of files such as crt0.o, crt1.o,
- ld-linux.so and so forth. If you don't know where to find these,
- compile a short C program with `gcc -v' and see what command line
- gcc feeds to `ld'.
-
-- You should now be able to build lcc, using `lin-elf.c' or
- `lin-aout.c' as the system-dependent part of the `lcc' wrapper
- program.
-
-- Symlink x86nasm.c into the `src' directory before attempting the
- triple test, or the compile will fail.
-
-- Now it should pass the triple test, on either ELF or a.out. Voila!
diff --git a/lcc/bind.c b/lcc/bind.c
deleted file mode 100644
index 286431d7..00000000
--- a/lcc/bind.c
+++ /dev/null
@@ -1,23 +0,0 @@
-#include "c.h"
-extern Interface nullIR, symbolicIR;
-extern Interface mipsebIR, mipselIR;
-extern Interface sparcIR, solarisIR;
-extern Interface x86IR, x86nasmIR;
-Binding bindings[] = {
- "symbolic", &symbolicIR,
- "mips-irix", &mipsebIR,
- "mips-ultrix", &mipselIR,
- "sparc-sun", &sparcIR,
- "sparc-solaris", &solarisIR,
- "x86-dos", &x86IR,
- "x86-nasm", &x86nasmIR,
- "symbolic/irix", &symbolicIR, /* omit */
- "mips/irix", &mipsebIR, /* omit */
- "mips/ultrix", &mipselIR, /* omit */
- "sparc/sun", &sparcIR, /* omit */
- "sparc/solaris", &solarisIR, /* omit */
- "x86/dos", &x86IR, /* omit */
- "x86/nasm", &x86nasmIR, /* omit */
- "null", &nullIR,
- NULL, NULL
-};
diff --git a/lcc/lin-aout.c b/lcc/lin-aout.c
deleted file mode 100644
index e4ac48f2..00000000
--- a/lcc/lin-aout.c
+++ /dev/null
@@ -1,48 +0,0 @@
-/* x86 running linux and using nasm as a.out */
-
-#include <string.h>
-
-#ifndef LCCDIR
-#define LCCDIR "/usr/local/lib/lcc/"
-#endif
-
-#define NASMPATH "/usr/local/bin/nasm"
-
-char *cpp[] = { LCCDIR "cpp", "-D__STDC__=1",
- "-Di386", "-D__i386", "-D__i386__",
- "-Dlinux", "-D__linux", "-D__linux__",
- "-Dunix", "-D__unix", "-D__unix__",
- "$1", "$2", "$3", 0
-};
-char *include[] = { "-I" LCCDIR "include", "-I/usr/local/include",
- "-I/usr/include", 0
-};
-char *com[] = { LCCDIR "rcc", "-target=x86/nasm",
- "$1", "$2", "$3", 0
-};
-char *as[] = { NASMPATH, "-a", "-faout", "-o", "$3", "$1", "$2", 0 };
-char *ld[] = { "/usr/bin/ld", "-m", "i386linux",
- "-L/usr/i486-linuxaout/lib",
- "-o", "$3", "$1",
- "/usr/i486-linuxaout/lib/crt0.o",
- "$2", "", "-lc", 0
-};
-static char *bbexit = LCCDIR "bbexit.o";
-
-extern char *concat(char *, char *);
-extern int access(const char *, int);
-
-int option(char *arg)
-{
- if (strncmp(arg, "-lccdir=", 8) == 0) {
- cpp[0] = concat(&arg[8], "/cpp");
- include[0] = concat("-I", concat(&arg[8], "/include"));
- com[0] = concat(&arg[8], "/rcc");
- bbexit = concat(&arg[8], "/bbexit.o");
- } else if (strcmp(arg, "-g") == 0) ;
- else if (strcmp(arg, "-b") == 0 && access(bbexit, 4) == 0)
- ld[9] = bbexit;
- else
- return 0;
- return 1;
-}
diff --git a/lcc/lin-elf.c b/lcc/lin-elf.c
deleted file mode 100644
index 693309f9..00000000
--- a/lcc/lin-elf.c
+++ /dev/null
@@ -1,49 +0,0 @@
-/* x86 running linux and using nasm as ELF */
-
-#include <string.h>
-
-#ifndef LCCDIR
-#define LCCDIR "/usr/local/lib/lcc/"
-#endif
-
-#define NASMPATH "/usr/local/bin/nasm"
-
-char *cpp[] = { LCCDIR "cpp", "-D__STDC__=1",
- "-D__ELF__", "-Di386", "-D__i386", "-D__i386__",
- "-Dlinux", "-D__linux", "-D__linux__",
- "$1", "$2", "$3", 0
-};
-char *include[] = { "-I" LCCDIR "include", "-I/usr/local/include",
- "-I/usr/include", 0
-};
-char *com[] = { LCCDIR "rcc", "-target=x86/nasm",
- "$1", "$2", "$3", 0
-};
-char *as[] = { NASMPATH, "-a", "-felf", "-o", "$3", "$1", "$2", 0 };
-char *ld[] = { "/usr/bin/ld", "-m", "elf_i386",
- "-dynamic-linker", "/lib/ld-linux.so.1",
- "-L/usr/i486-linux/lib",
- "-o", "$3", "$1",
- "/usr/lib/crt1.o", "/usr/lib/crti.o", "/usr/lib/crtbegin.o",
- "$2", "",
- "-lc", "", "/usr/lib/crtend.o", "/usr/lib/crtn.o", 0
-};
-static char *bbexit = LCCDIR "bbexit.o";
-
-extern char *concat(char *, char *);
-extern int access(const char *, int);
-
-int option(char *arg)
-{
- if (strncmp(arg, "-lccdir=", 8) == 0) {
- cpp[0] = concat(&arg[8], "/cpp");
- include[0] = concat("-I", concat(&arg[8], "/include"));
- com[0] = concat(&arg[8], "/rcc");
- bbexit = concat(&arg[8], "/bbexit.o");
- } else if (strcmp(arg, "-g") == 0) ;
- else if (strcmp(arg, "-b") == 0 && access(bbexit, 4) == 0)
- ld[13] = bbexit;
- else
- return 0;
- return 1;
-}
diff --git a/lcc/x86nasm.md b/lcc/x86nasm.md
deleted file mode 100644
index 54d0be6c..00000000
--- a/lcc/x86nasm.md
+++ /dev/null
@@ -1,703 +0,0 @@
-%{
-enum { EAX=0, ECX=1, EDX=2, EBX=3, ESI=6, EDI=7 };
-#include "c.h"
-#define NODEPTR_TYPE Node
-#define OP_LABEL(p) ((p)->op)
-#define LEFT_CHILD(p) ((p)->kids[0])
-#define RIGHT_CHILD(p) ((p)->kids[1])
-#define STATE_LABEL(p) ((p)->x.state)
-static void address ARGS((Symbol, Symbol, int));
-static void blkfetch ARGS((int, int, int, int));
-static void blkloop ARGS((int, int, int, int, int, int[]));
-static void blkstore ARGS((int, int, int, int));
-static void defaddress ARGS((Symbol));
-static void defconst ARGS((int, Value));
-static void defstring ARGS((int, char *));
-static void defsymbol ARGS((Symbol));
-static void doarg ARGS((Node));
-static void emit2 ARGS((Node));
-static void export ARGS((Symbol));
-static void clobber ARGS((Node));
-static void function ARGS((Symbol, Symbol [], Symbol [], int));
-static void global ARGS((Symbol));
-static void import ARGS((Symbol));
-static void local ARGS((Symbol));
-static void progbeg ARGS((int, char **));
-static void progend ARGS((void));
-static void segment ARGS((int));
-static void space ARGS((int));
-static void target ARGS((Node));
-static int ckstack ARGS((Node, int));
-static int memop ARGS((Node));
-static int sametree ARGS((Node, Node));
-static Symbol charreg[32], shortreg[32], intreg[32];
-static Symbol fltreg[32];
-
-static int cseg;
-
-static Symbol quo, rem;
-
-%}
-%start stmt
-%term ADDD=306 ADDF=305 ADDI=309 ADDP=311 ADDU=310
-%term ADDRFP=279
-%term ADDRGP=263
-%term ADDRLP=295
-%term ARGB=41 ARGD=34 ARGF=33 ARGI=37 ARGP=39
-%term ASGNB=57 ASGNC=51 ASGND=50 ASGNF=49 ASGNI=53 ASGNP=55 ASGNS=52
-%term BANDU=390
-%term BCOMU=406
-%term BORU=422
-%term BXORU=438
-%term CALLB=217 CALLD=210 CALLF=209 CALLI=213 CALLV=216
-%term CNSTC=19 CNSTD=18 CNSTF=17 CNSTI=21 CNSTP=23 CNSTS=20 CNSTU=22
-%term CVCI=85 CVCU=86
-%term CVDF=97 CVDI=101
-%term CVFD=114
-%term CVIC=131 CVID=130 CVIS=132 CVIU=134
-%term CVPU=150
-%term CVSI=165 CVSU=166
-%term CVUC=179 CVUI=181 CVUP=183 CVUS=180
-%term DIVD=450 DIVF=449 DIVI=453 DIVU=454
-%term EQD=482 EQF=481 EQI=485
-%term GED=498 GEF=497 GEI=501 GEU=502
-%term GTD=514 GTF=513 GTI=517 GTU=518
-%term INDIRB=73 INDIRC=67 INDIRD=66 INDIRF=65 INDIRI=69 INDIRP=71 INDIRS=68
-%term JUMPV=584
-%term LABELV=600
-%term LED=530 LEF=529 LEI=533 LEU=534
-%term LOADB=233 LOADC=227 LOADD=226 LOADF=225 LOADI=229 LOADP=231 LOADS=228 LOADU=230
-%term LSHI=341 LSHU=342
-%term LTD=546 LTF=545 LTI=549 LTU=550
-%term MODI=357 MODU=358
-%term MULD=466 MULF=465 MULI=469 MULU=470
-%term NED=562 NEF=561 NEI=565
-%term NEGD=194 NEGF=193 NEGI=197
-%term RETD=242 RETF=241 RETI=245
-%term RSHI=373 RSHU=374
-%term SUBD=322 SUBF=321 SUBI=325 SUBP=327 SUBU=326
-%term VREGP=615
-%%
-reg: INDIRC(VREGP) "# read register\n"
-reg: INDIRD(VREGP) "# read register\n"
-reg: INDIRF(VREGP) "# read register\n"
-reg: INDIRI(VREGP) "# read register\n"
-reg: INDIRP(VREGP) "# read register\n"
-reg: INDIRS(VREGP) "# read register\n"
-stmt: ASGNC(VREGP,reg) "# write register\n"
-stmt: ASGND(VREGP,reg) "# write register\n"
-stmt: ASGNF(VREGP,reg) "# write register\n"
-stmt: ASGNI(VREGP,reg) "# write register\n"
-stmt: ASGNP(VREGP,reg) "# write register\n"
-stmt: ASGNS(VREGP,reg) "# write register\n"
-con: CNSTC "%a"
-con: CNSTI "%a"
-con: CNSTP "%a"
-con: CNSTS "%a"
-con: CNSTU "%a"
-stmt: reg ""
-reg: CVIU(reg) "%0" notarget(a)
-reg: CVPU(reg) "%0" notarget(a)
-reg: CVUI(reg) "%0" notarget(a)
-reg: CVUP(reg) "%0" notarget(a)
-acon: ADDRGP "%a"
-acon: con "%0"
-base: ADDRGP "%a"
-base: reg "%0"
-base: ADDI(reg,acon) "%0 + (%1)"
-base: ADDP(reg,acon) "%0 + (%1)"
-base: ADDU(reg,acon) "%0 + (%1)"
-base: ADDRFP "ebp + %a"
-base: ADDRLP "ebp + %a"
-index: reg "%0"
-index: LSHI(reg,con1) "%0*2"
-index: LSHI(reg,con2) "%0*4"
-index: LSHI(reg,con3) "%0*8"
-
-con1: CNSTI "1" range(a, 1, 1)
-con1: CNSTU "1" range(a, 1, 1)
-con2: CNSTI "2" range(a, 2, 2)
-con2: CNSTU "2" range(a, 2, 2)
-con3: CNSTI "3" range(a, 3, 3)
-con3: CNSTU "3" range(a, 3, 3)
-index: LSHU(reg,con1) "%0*2"
-index: LSHU(reg,con2) "%0*4"
-index: LSHU(reg,con3) "%0*8"
-addr: base "[%0]"
-addr: ADDI(index,base) "[%1 + %0]"
-addr: ADDP(index,base) "[%1 + %0]"
-addr: ADDU(index,base) "[%1 + %0]"
-addr: index "[%0]"
-mem: INDIRC(addr) "byte %0"
-mem: INDIRI(addr) "dword %0"
-mem: INDIRP(addr) "dword %0"
-mem: INDIRS(addr) "word %0"
-rc: reg "%0"
-rc: con "%0"
-
-mr: reg "%0"
-mr: mem "%0"
-
-mrc0: mem "%0"
-mrc0: rc "%0"
-mrc1: mem "%0" 1
-mrc1: rc "%0"
-
-mrc3: mem "%0" 3
-mrc3: rc "%0"
-reg: addr "lea %c,%0\n" 1
-reg: mrc0 "mov %c,%0\n" 1
-reg: LOADC(reg) "mov %c,%0\n" move(a)
-reg: LOADI(reg) "mov %c,%0\n" move(a)
-reg: LOADP(reg) "mov %c,%0\n" move(a)
-reg: LOADS(reg) "mov %c,%0\n" move(a)
-reg: LOADU(reg) "mov %c,%0\n" move(a)
-reg: ADDI(reg,mrc1) "?mov %c,%0\nadd %c,%1\n" 1
-reg: ADDP(reg,mrc1) "?mov %c,%0\nadd %c,%1\n" 1
-reg: ADDU(reg,mrc1) "?mov %c,%0\nadd %c,%1\n" 1
-reg: SUBI(reg,mrc1) "?mov %c,%0\nsub %c,%1\n" 1
-reg: SUBP(reg,mrc1) "?mov %c,%0\nsub %c,%1\n" 1
-reg: SUBU(reg,mrc1) "?mov %c,%0\nsub %c,%1\n" 1
-reg: BANDU(reg,mrc1) "?mov %c,%0\nand %c,%1\n" 1
-reg: BORU(reg,mrc1) "?mov %c,%0\nor %c,%1\n" 1
-reg: BXORU(reg,mrc1) "?mov %c,%0\nxor %c,%1\n" 1
-stmt: ASGNI(addr,ADDI(mem,con1)) "inc %1\n" memop(a)
-stmt: ASGNI(addr,ADDU(mem,con1)) "inc %1\n" memop(a)
-stmt: ASGNP(addr,ADDP(mem,con1)) "inc %1\n" memop(a)
-stmt: ASGNI(addr,SUBI(mem,con1)) "dec %1\n" memop(a)
-stmt: ASGNI(addr,SUBU(mem,con1)) "dec %1\n" memop(a)
-stmt: ASGNP(addr,SUBP(mem,con1)) "dec %1\n" memop(a)
-stmt: ASGNI(addr,ADDI(mem,rc)) "add %1,%2\n" memop(a)
-stmt: ASGNI(addr,ADDU(mem,rc)) "add %1,%2\n" memop(a)
-stmt: ASGNI(addr,SUBI(mem,rc)) "sub %1,%2\n" memop(a)
-stmt: ASGNI(addr,SUBU(mem,rc)) "sub %1,%2\n" memop(a)
-
-stmt: ASGNI(addr,BANDU(mem,rc)) "and %1,%2\n" memop(a)
-stmt: ASGNI(addr,BORU(mem,rc)) "or %1,%2\n" memop(a)
-stmt: ASGNI(addr,BXORU(mem,rc)) "xor %1,%2\n" memop(a)
-reg: BCOMU(reg) "?mov %c,%0\nnot %c\n" 2
-reg: NEGI(reg) "?mov %c,%0\nneg %c\n" 2
-
-stmt: ASGNI(addr,BCOMU(mem)) "not %1\n" memop(a)
-stmt: ASGNI(addr,NEGI(mem)) "neg %1\n" memop(a)
-reg: LSHI(reg,rc5) "?mov %c,%0\nsal %c,%1\n" 2
-reg: LSHU(reg,rc5) "?mov %c,%0\nshl %c,%1\n" 2
-reg: RSHI(reg,rc5) "?mov %c,%0\nsar %c,%1\n" 2
-reg: RSHU(reg,rc5) "?mov %c,%0\nshr %c,%1\n" 2
-
-stmt: ASGNI(addr,LSHI(mem,rc5)) "sal %1,%2\n" memop(a)
-stmt: ASGNI(addr,LSHU(mem,rc5)) "shl %1,%2\n" memop(a)
-stmt: ASGNI(addr,RSHI(mem,rc5)) "sar %1,%2\n" memop(a)
-stmt: ASGNI(addr,RSHU(mem,rc5)) "shr %1,%2\n" memop(a)
-
-rc5: CNSTI "%a" range(a, 0, 31)
-rc5: reg "cl"
-reg: MULI(reg,mrc3) "?mov %c,%0\nimul %c,%1\n" 14
-reg: MULI(con,mr) "imul %c,%1,%0\n" 13
-reg: MULU(reg,mr) "mul %1\n" 13
-reg: DIVU(reg,reg) "xor edx,edx\ndiv %1\n"
-reg: MODU(reg,reg) "xor edx,edx\ndiv %1\n"
-reg: DIVI(reg,reg) "cdq\nidiv %1\n"
-reg: MODI(reg,reg) "cdq\nidiv %1\n"
-reg: CVIU(reg) "mov %c,%0\n" move(a)
-reg: CVPU(reg) "mov %c,%0\n" move(a)
-reg: CVUI(reg) "mov %c,%0\n" move(a)
-reg: CVUP(reg) "mov %c,%0\n" move(a)
-reg: CVCI(INDIRC(addr)) "movsx %c,byte %0\n" 3
-reg: CVCU(INDIRC(addr)) "movzx %c,byte %0\n" 3
-reg: CVSI(INDIRS(addr)) "movsx %c,word %0\n" 3
-reg: CVSU(INDIRS(addr)) "movzx %c,word %0\n" 3
-reg: CVCI(reg) "# extend\n" 3
-reg: CVCU(reg) "# extend\n" 3
-reg: CVSI(reg) "# extend\n" 3
-reg: CVSU(reg) "# extend\n" 3
-
-reg: CVIC(reg) "# truncate\n" 1
-reg: CVIS(reg) "# truncate\n" 1
-reg: CVUC(reg) "# truncate\n" 1
-reg: CVUS(reg) "# truncate\n" 1
-stmt: ASGNC(addr,rc) "mov byte %0,%1\n" 1
-stmt: ASGNI(addr,rc) "mov dword %0,%1\n" 1
-stmt: ASGNP(addr,rc) "mov dword %0,%1\n" 1
-stmt: ASGNS(addr,rc) "mov word %0,%1\n" 1
-stmt: ARGI(mrc3) "push dword %0\n" 1
-stmt: ARGP(mrc3) "push dword %0\n" 1
-stmt: ASGNB(reg,INDIRB(reg)) "mov ecx,%a\nrep movsb\n"
-stmt: ARGB(INDIRB(reg)) "sub esp,%a\nmov edi,esp\nmov ecx,%a\nrep movsb\n"
-
-memf: INDIRD(addr) "qword %0"
-memf: INDIRF(addr) "dword %0"
-memf: CVFD(INDIRF(addr)) "dword %0"
-reg: memf "fld %0\n" 3
-stmt: ASGND(addr,reg) "fstp qword %0\n" 7
-stmt: ASGNF(addr,reg) "fstp dword %0\n" 7
-stmt: ASGNF(addr,CVDF(reg)) "fstp dword %0\n" 7
-stmt: ARGD(reg) "sub esp,8\nfstp qword [esp]\n"
-stmt: ARGF(reg) "sub esp,4\nfstp dword [esp]\n"
-reg: NEGD(reg) "fchs\n"
-reg: NEGF(reg) "fchs\n"
-reg: ADDD(reg,memf) "fadd %1\n"
-reg: ADDD(reg,reg) "faddp st1\n"
-reg: ADDF(reg,memf) "fadd %1\n"
-reg: ADDF(reg,reg) "faddp st1\n"
-reg: DIVD(reg,memf) "fdiv %1\n"
-reg: DIVD(reg,reg) "fdivp st1\n"
-reg: DIVF(reg,memf) "fdiv %1\n"
-reg: DIVF(reg,reg) "fdivp st1\n"
-reg: MULD(reg,memf) "fmul %1\n"
-reg: MULD(reg,reg) "fmulp st1\n"
-reg: MULF(reg,memf) "fmul %1\n"
-reg: MULF(reg,reg) "fmulp st1\n"
-reg: SUBD(reg,memf) "fsub %1\n"
-reg: SUBD(reg,reg) "fsubp st1\n"
-reg: SUBF(reg,memf) "fsub %1\n"
-reg: SUBF(reg,reg) "fsubp st1\n"
-reg: CVFD(reg) "# CVFD\n"
-reg: CVDF(reg) "sub esp,4\nfstp dword [esp]\nfld dword [esp]\nadd esp,4\n" 12
-
-stmt: ASGNI(addr,CVDI(reg)) "fistp dword %0\n" 29
-reg: CVDI(reg) "sub esp,4\nfistp dword [esp]\npop %c\n" 31
-
-reg: CVID(INDIRI(addr)) "fild dword %0\n" 10
-reg: CVID(reg) "push %0\nfild dword [esp]\nadd esp,4\n" 12
-
-addrj: ADDRGP "%a"
-addrj: reg "%0" 2
-addrj: mem "%0" 2
-
-stmt: JUMPV(addrj) "jmp %0\n" 3
-stmt: LABELV "%a:\n"
-stmt: EQI(mem,rc) "cmp %0,%1\nje near %a\n" 5
-stmt: GEI(mem,rc) "cmp %0,%1\njge near %a\n" 5
-stmt: GTI(mem,rc) "cmp %0,%1\njg near %a\n" 5
-stmt: LEI(mem,rc) "cmp %0,%1\njle near %a\n" 5
-stmt: LTI(mem,rc) "cmp %0,%1\njl near %a\n" 5
-stmt: NEI(mem,rc) "cmp %0,%1\njne near %a\n" 5
-stmt: GEU(mem,rc) "cmp %0,%1\njae near %a\n" 5
-stmt: GTU(mem,rc) "cmp %0,%1\nja near %a\n" 5
-stmt: LEU(mem,rc) "cmp %0,%1\njbe near %a\n" 5
-stmt: LTU(mem,rc) "cmp %0,%1\njb near %a\n" 5
-stmt: EQI(reg,mrc1) "cmp %0,%1\nje near %a\n" 4
-stmt: GEI(reg,mrc1) "cmp %0,%1\njge near %a\n" 4
-stmt: GTI(reg,mrc1) "cmp %0,%1\njg near %a\n" 4
-stmt: LEI(reg,mrc1) "cmp %0,%1\njle near %a\n" 4
-stmt: LTI(reg,mrc1) "cmp %0,%1\njl near %a\n" 4
-stmt: NEI(reg,mrc1) "cmp %0,%1\njne near %a\n" 4
-
-stmt: GEU(reg,mrc1) "cmp %0,%1\njae near %a\n" 4
-stmt: GTU(reg,mrc1) "cmp %0,%1\nja near %a\n" 4
-stmt: LEU(reg,mrc1) "cmp %0,%1\njbe near %a\n" 4
-stmt: LTU(reg,mrc1) "cmp %0,%1\njb near %a\n" 4
-cmpf: memf " %0"
-cmpf: reg "p"
-stmt: EQD(cmpf,reg) "fcomp%0\nfstsw ax\nsahf\nje near %a\n"
-stmt: GED(cmpf,reg) "fcomp%0\nfstsw ax\nsahf\njbe near %a\n"
-stmt: GTD(cmpf,reg) "fcomp%0\nfstsw ax\nsahf\njb near %a\n"
-stmt: LED(cmpf,reg) "fcomp%0\nfstsw ax\nsahf\njae near %a\n"
-stmt: LTD(cmpf,reg) "fcomp%0\nfstsw ax\nsahf\nja near %a\n"
-stmt: NED(cmpf,reg) "fcomp%0\nfstsw ax\nsahf\njne near %a\n"
-
-stmt: EQF(cmpf,reg) "fcomp%0\nfstsw ax\nsahf\nje near %a\n"
-stmt: GEF(cmpf,reg) "fcomp%0\nfstsw ax\nsahf\njbe near %a\n"
-stmt: GTF(cmpf,reg) "fcomp%0\nfstsw ax\nsahf\njb near %a\n"
-stmt: LEF(cmpf,reg) "fcomp%0\nfstsw ax\nsahf\njae near %a\n"
-stmt: LTF(cmpf,reg) "fcomp%0\nfstsw ax\nsahf\nja near %a\n"
-stmt: NEF(cmpf,reg) "fcomp%0\nfstsw ax\nsahf\njne near %a\n"
-reg: CALLI(addrj) "call %0\nadd esp,%a\n"
-stmt: CALLV(addrj) "call %0\nadd esp,%a\n"
-reg: CALLF(addrj) "call %0\nadd esp,%a\n"
-reg: CALLD(addrj) "call %0\nadd esp,%a\n"
-
-stmt: RETI(reg) "# ret\n"
-stmt: RETF(reg) "# ret\n"
-stmt: RETD(reg) "# ret\n"
-%%
-static void progbeg(argc, argv) int argc; char *argv[]; {
- int i;
-
- {
- union {
- char c;
- int i;
- } u;
- u.i = 0;
- u.c = 1;
- swap = (u.i == 1) != IR->little_endian;
- }
- parseflags(argc, argv);
- intreg[EAX] = mkreg("eax", EAX, 1, IREG);
- intreg[EDX] = mkreg("edx", EDX, 1, IREG);
- intreg[ECX] = mkreg("ecx", ECX, 1, IREG);
- intreg[EBX] = mkreg("ebx", EBX, 1, IREG);
- intreg[ESI] = mkreg("esi", ESI, 1, IREG);
- intreg[EDI] = mkreg("edi", EDI, 1, IREG);
- shortreg[EAX] = mkreg("ax", EAX, 1, IREG);
- shortreg[ECX] = mkreg("cx", ECX, 1, IREG);
- shortreg[EDX] = mkreg("dx", EDX, 1, IREG);
- shortreg[EBX] = mkreg("bx", EBX, 1, IREG);
- shortreg[ESI] = mkreg("si", ESI, 1, IREG);
- shortreg[EDI] = mkreg("di", EDI, 1, IREG);
-
- charreg[EAX] = mkreg("al", EAX, 1, IREG);
- charreg[ECX] = mkreg("cl", ECX, 1, IREG);
- charreg[EDX] = mkreg("dl", EDX, 1, IREG);
- charreg[EBX] = mkreg("bl", EBX, 1, IREG);
- for (i = 0; i < 8; i++)
- fltreg[i] = mkreg("%d", i, 0, FREG);
- rmap[C] = mkwildcard(charreg);
- rmap[S] = mkwildcard(shortreg);
- rmap[P] = rmap[B] = rmap[U] = rmap[I] = mkwildcard(intreg);
- rmap[F] = rmap[D] = mkwildcard(fltreg);
- tmask[IREG] = (1<<EDI) | (1<<ESI) | (1<<EBX)
- | (1<<EDX) | (1<<ECX) | (1<<EAX);
- vmask[IREG] = 0;
- tmask[FREG] = 0xff;
- vmask[FREG] = 0;
- cseg = 0;
- quo = mkreg("eax", EAX, 1, IREG);
- quo->x.regnode->mask |= 1<<EDX;
- rem = mkreg("edx", EDX, 1, IREG);
- rem->x.regnode->mask |= 1<<EAX;
-}
-static void segment(n) int n; {
- if (n == cseg)
- return;
- cseg = n;
- if (cseg == CODE)
- print("[section .text]\n");
- else if (cseg == DATA || cseg == LIT)
- print("[section .data]\n");
- else if (cseg == BSS)
- print("[section .bss]\n");
-}
-static void progend() {
-
-}
-static void target(p) Node p; {
- assert(p);
- switch (p->op) {
- case RSHI: case RSHU: case LSHI: case LSHU:
- if (generic(p->kids[1]->op) != CNST
- && !( generic(p->kids[1]->op) == INDIR
- && p->kids[1]->kids[0]->op == VREG+P
- && p->kids[1]->syms[RX]->u.t.cse
- && generic(p->kids[1]->syms[RX]->u.t.cse->op) == CNST
-)) {
- rtarget(p, 1, intreg[ECX]);
- setreg(p, intreg[EAX]);
- }
- break;
- case MULU:
- setreg(p, quo);
- rtarget(p, 0, intreg[EAX]);
- break;
- case DIVI: case DIVU:
- setreg(p, quo);
- rtarget(p, 0, intreg[EAX]);
- rtarget(p, 1, intreg[ECX]);
- break;
- case MODI: case MODU:
- setreg(p, rem);
- rtarget(p, 0, intreg[EAX]);
- rtarget(p, 1, intreg[ECX]);
- break;
- case ASGNB:
- rtarget(p, 0, intreg[EDI]);
- rtarget(p->kids[1], 0, intreg[ESI]);
- break;
- case ARGB:
- rtarget(p->kids[0], 0, intreg[ESI]);
- break;
- case CALLI: case CALLV:
- setreg(p, intreg[EAX]);
- break;
- case RETI:
- rtarget(p, 0, intreg[EAX]);
- break;
- }
-}
-
-static void clobber(p) Node p; {
- static int nstack = 0;
-
- assert(p);
- nstack = ckstack(p, nstack);
- assert(p->count > 0 || nstack == 0);
- switch (p->op) {
- case ASGNB: case ARGB:
- spill(1<<ECX | 1<<ESI | 1<<EDI, IREG, p);
- break;
- case EQD: case LED: case GED: case LTD: case GTD: case NED:
- case EQF: case LEF: case GEF: case LTF: case GTF: case NEF:
- spill(1<<EAX, IREG, p);
- break;
- case CALLD: case CALLF:
- spill(1<<EDX | 1<<EAX, IREG, p);
- break;
- }
-}
-#define isfp(p) (optype((p)->op)==F || optype((p)->op)==D)
-
-static int ckstack(p, n) Node p; int n; {
- int i;
-
- for (i = 0; i < NELEMS(p->x.kids) && p->x.kids[i]; i++)
- if (isfp(p->x.kids[i]))
- n--;
- if (isfp(p) && p->count > 0)
- n++;
- if (n > 8)
- error("expression too complicated\n");
- debug(fprint(2, "(ckstack(%x)=%d)\n", p, n));
- assert(n >= 0);
- return n;
-}
-static int memop(p) Node p; {
- assert(p);
- assert(generic(p->op) == ASGN);
- assert(p->kids[0]);
- assert(p->kids[1]);
- if (generic(p->kids[1]->kids[0]->op) == INDIR
- && sametree(p->kids[0], p->kids[1]->kids[0]->kids[0]))
- return 3;
- else
- return LBURG_MAX;
-}
-static int sametree(p, q) Node p, q; {
- return p == NULL && q == NULL
- || p && q && p->op == q->op && p->syms[0] == q->syms[0]
- && sametree(p->kids[0], q->kids[0])
- && sametree(p->kids[1], q->kids[1]);
-}
-static void emit2(p) Node p; {
-#define preg(f) ((f)[getregnum(p->x.kids[0])]->x.name)
-
- if (p->op == CVCI)
- print("movsx %s,%s\n", p->syms[RX]->x.name
-, preg(charreg));
- else if (p->op == CVCU)
- print("movzx %s,%s\n", p->syms[RX]->x.name
-, preg(charreg));
- else if (p->op == CVSI)
- print("movsx %s,%s\n", p->syms[RX]->x.name
-, preg(shortreg));
- else if (p->op == CVSU)
- print("movzx %s,%s\n", p->syms[RX]->x.name
-, preg(shortreg));
- else if (p->op == CVIC || p->op == CVIS
- || p->op == CVUC || p->op == CVUS) {
- char *dst = shortreg[getregnum(p)]->x.name;
- char *src = preg(shortreg);
- if (dst != src)
- print("mov %s,%s\n", dst, src);
- }
-}
-
-static void doarg(p) Node p; {
- assert(p && p->syms[0]);
- mkactual(4, p->syms[0]->u.c.v.i);
-}
-static void blkfetch(k, off, reg, tmp)
-int k, off, reg, tmp; {}
-static void blkstore(k, off, reg, tmp)
-int k, off, reg, tmp; {}
-static void blkloop(dreg, doff, sreg, soff, size, tmps)
-int dreg, doff, sreg, soff, size, tmps[]; {}
-static void local(p) Symbol p; {
- if (isfloat(p->type))
- p->sclass = AUTO;
- if (askregvar(p, rmap[ttob(p->type)]) == 0)
- mkauto(p);
-}
-static void function(f, caller, callee, n)
-Symbol f, callee[], caller[]; int n; {
- int i;
-
- print("%s:\n", f->x.name);
- print("push ebx\n");
- print("push esi\n");
- print("push edi\n");
- print("push ebp\n");
- print("mov ebp,esp\n");
-usedmask[0] = usedmask[1] = 0;
-freemask[0] = freemask[1] = ~(unsigned)0;
- offset = 16 + 4;
- for (i = 0; callee[i]; i++) {
- Symbol p = callee[i];
- Symbol q = caller[i];
- assert(q);
- p->x.offset = q->x.offset = offset;
- p->x.name = q->x.name = stringf("%d", p->x.offset);
- p->sclass = q->sclass = AUTO;
- offset += roundup(q->type->size, 4);
- }
- assert(caller[i] == 0);
- offset = maxoffset = 0;
- gencode(caller, callee);
- framesize = roundup(maxoffset, 4);
- if (framesize > 0)
- print("sub esp,%d\n", framesize);
- emitcode();
- print("mov esp,ebp\n");
- print("pop ebp\n");
- print("pop edi\n");
- print("pop esi\n");
- print("pop ebx\n");
- print("ret\n");
-}
-static void defsymbol(p) Symbol p; {
- if (p->scope >= LOCAL && p->sclass == STATIC)
- p->x.name = stringf("L%d", genlabel(1));
- else if (p->generated)
- p->x.name = stringf("$L%s", p->name);
- else if (p->scope == GLOBAL || p->sclass == EXTERN)
- /* CHANGE THIS FOR a.out */
-#if 0
- p->x.name = stringf("$_%s", p->name);
-#else
- p->x.name = stringf("$%s", p->name);
-#endif
- else if (p->scope == CONSTANTS
- && (isint(p->type) || isptr(p->type))
- && p->name[0] == '0' && p->name[1] == 'x')
- p->x.name = stringf("0%sH", &p->name[2]);
- else
- p->x.name = p->name;
-}
-static void address(q, p, n) Symbol q, p; int n; {
- if (p->scope == GLOBAL
- || p->sclass == STATIC || p->sclass == EXTERN)
- q->x.name = stringf("%s%s%d",
- p->x.name, n >= 0 ? "+" : "", n);
- else {
- q->x.offset = p->x.offset + n;
- q->x.name = stringd(q->x.offset);
- }
-}
-static void defconst(ty, v) int ty; Value v; {
- switch (ty) {
- case C: print("db %d\n", v.uc); return;
- case S: print("dw %d\n", v.ss); return;
- case I: print("dd %d\n", v.i ); return;
- case U: print("dd 0%xH\n", v.u ); return;
- case P: print("dd 0%xH\n", v.p ); return;
- case F:
- print("dd 0%xH\n", *(unsigned *)&v.f);
- return;
- case D: {
- unsigned *p = (unsigned *)&v.d;
- print("dd 0%xH,0%xH\n", p[swap], p[1 - swap]);
- return;
- }
- }
- assert(0);
-}
-static void defaddress(p) Symbol p; {
- print("dd %s\n", p->x.name);
-}
-static void defstring(n, str) int n; char *str; {
- char *s;
- int inquote = 1;
-
- print("db '");
-
- for (s = str; s < str + n; s++)
- {
- if ((*s & 0x7F) == *s && *s >= ' ' && *s != '\'') {
- if (!inquote){
- print(", '");
- inquote = 1;
- }
- print("%c",*s);
- }
- else
- {
- if (inquote){
- print("', ");
- inquote = 0;
- }
- else
- print(", ");
- print("%d",*s);
- }
- }
- if (inquote) print("'");
- print("\n");
-}
-static void export(p) Symbol p; {
- print("[global %s]\n", p->x.name);
-}
-static void import(p) Symbol p; {
- if (p->ref > 0) {
- print("[extern %s]\n", p->x.name);
- }
-}
-static void global(p) Symbol p; {
- int i;
-
- if (p->u.seg == BSS)
- print("resb ($-$$) & %d\n",
- p->type->align > 4 ? 3 : p->type->align-1);
- else
- print("times ($-$$) & %d nop\n",
- p->type->align > 4 ? 3 : p->type->align-1);
- print("%s:\n", p->x.name);
- if (p->u.seg == BSS)
- print("resb %d\n", p->type->size);
-}
-static void space(n) int n; {
- int i;
-
- if (cseg != BSS)
- print("times %d db 0\n", n);
-}
-Interface x86nasmIR = {
- 1, 1, 0, /* char */
- 2, 2, 0, /* short */
- 4, 4, 0, /* int */
- 4, 4, 1, /* float */
- 8, 4, 1, /* double */
- 4, 4, 0, /* T * */
- 0, 4, 0, /* struct; so that ARGB keeps stack aligned */
- 1, /* little_endian */
- 0, /* mulops_calls */
- 0, /* wants_callb */
- 1, /* wants_argb */
- 0, /* left_to_right */
- 0, /* wants_dag */
- address,
- blockbeg,
- blockend,
- defaddress,
- defconst,
- defstring,
- defsymbol,
- emit,
- export,
- function,
- gen,
- global,
- import,
- local,
- progbeg,
- progend,
- segment,
- space,
- 0, 0, 0, 0, 0, 0, 0,
- {1, blkfetch, blkstore, blkloop,
- _label,
- _rule,
- _nts,
- _kids,
- _opname,
- _arity,
- _string,
- _templates,
- _isinstruction,
- _ntname,
- emit2,
- doarg,
- target,
- clobber,
-}
-};
diff --git a/macros.pl b/macros.pl
index 911da8db..14524ec8 100755
--- a/macros.pl
+++ b/macros.pl
@@ -57,12 +57,14 @@ sub charcify(@) {
if ($o < 32 || $o > 126 || $c eq '"' || $c eq "\\") {
$l .= sprintf("%3d,", $o);
} else {
+ $c =~ s/\'/\\'/; # << sanitize single quote.
$l .= "\'".$c."\',";
}
}
return $l;
}
+
#
# Generate macros.c
#
diff --git a/opflags.h b/opflags.h
index b4912445..c2b72b03 100644
--- a/opflags.h
+++ b/opflags.h
@@ -66,11 +66,10 @@
* 23: 256 bits (YWORD)
* 29: 128 bits (OWORD)
*
- * Bits 8-11 modifiers
+ * Bits 8-10 modifiers
* 8: TO
* 9: COLON
* 10: STRICT
- * 11: (reserved)
*
* Bits 12-15: type of operand
* 12: REGISTER
@@ -78,7 +77,7 @@
* 14: MEMORY (always has REGMEM attribute as well)
* 15: REGMEM (valid EA operand)
*
- * Bits 16-19, 28: subclasses
+ * Bits 11, 16-19, 28: subclasses
* With REG_CDT:
* 16: REG_CREG (CRx)
* 17: REG_DREG (DRx)
@@ -115,6 +114,8 @@
* 17: BYTENESS16 (-128..127)
* 18: BYTENESS32 (-128..127)
* 19: BYTENESS64 (-128..127)
+ * 28: SDWORD64 (-2^31..2^31-1)
+ * 11: UDWORD64 (0..2^32-1)
*
* Bits 20-22, 24-27: register classes
* 20: REG_CDT (CRx, DRx, TRx)
@@ -125,8 +126,6 @@
* 26: RM_XMM (XMMREG)
* 27: RM_YMM (YMMREG)
*
- * Bit 31 is currently unallocated.
- *
* 30: SAME_AS
* Special flag only used in instruction patterns; means this operand
* has to be identical to another operand. Currently only supported
@@ -151,7 +150,7 @@ typedef uint32_t opflags_t;
#define SIZE_MASK 0x208000FFU /* all the size attributes */
/* Modifiers */
-#define MODIFIER_MASK 0x00000f00U
+#define MODIFIER_MASK 0x00000700U
#define TO 0x00000100U /* reverse effect in FADD, FSUB &c */
#define COLON 0x00000200U /* operand is followed by a colon */
#define STRICT 0x00000400U /* do not optimize this operand */
@@ -197,7 +196,7 @@ typedef uint32_t opflags_t;
#define REG_EIP 0x00801004U /* EIP relative addressing */
/* Special GPRs */
-#define REG_SMASK 0x100f0000U /* a mask for the following */
+#define REG_SMASK 0x100f0800U /* a mask for the following */
#define REG_ACCUM 0x00219000U /* accumulator: AL, AX, EAX, RAX */
#define REG_AL 0x00219001U
#define REG_AX 0x00219002U
@@ -232,6 +231,8 @@ typedef uint32_t opflags_t;
#define SBYTE32 0x00042000U /* for op r32,immediate instrs. */
#define SBYTE64 0x00082000U /* for op r64,immediate instrs. */
#define BYTENESS 0x000e0000U /* for testing for byteness */
+#define SDWORD64 0x10002000U /* for op r64,simm32 instrs. */
+#define UDWORD64 0x00002800U /* for op r64,uimm32 instrs. */
/* special flags */
#define SAME_AS 0x40000000U
diff --git a/output/outbin.c b/output/outbin.c
index 97a29a89..21c042db 100644
--- a/output/outbin.c
+++ b/output/outbin.c
@@ -130,7 +130,7 @@ static struct Section {
struct bin_label *labels; /* linked-list of label handles for map output. */
struct bin_label **labels_end; /* Holds address of end of labels list. */
- struct Section *ifollows; /* Points to previous section (implicit follows). */
+ struct Section *prev; /* Points to previous section (implicit follows). */
struct Section *next; /* This links sections with a defined start address. */
/* The extended bin format allows for sections to have a "virtual"
@@ -201,28 +201,22 @@ static struct Section *find_section_by_index(int32_t index)
}
static struct Section *create_section(char *name)
-{ /* Create a new section. */
- last_section->next = nasm_malloc(sizeof(struct Section));
- last_section->next->ifollows = last_section;
- last_section = last_section->next;
- last_section->labels = NULL;
- last_section->labels_end = &(last_section->labels);
-
- /* Initialize section attributes. */
- last_section->name = nasm_strdup(name);
- last_section->contents = saa_init(1L);
- last_section->follows = last_section->vfollows = 0;
- last_section->length = 0;
- last_section->flags = 0;
- last_section->align = 0;
- last_section->valign = 0;
- last_section->start = 0;
- last_section->vstart = 0;
- last_section->next = NULL;
+{
+ struct Section *s = nasm_zalloc(sizeof(*s));
+
+ s->prev = last_section;
+ s->name = nasm_strdup(name);
+ s->labels_end = &(s->labels);
+ s->contents = saa_init(1L);
/* Register our sections with NASM. */
- last_section->vstart_index = seg_alloc();
- last_section->start_index = seg_alloc();
+ s->vstart_index = seg_alloc();
+ s->start_index = seg_alloc();
+
+ /* FIXME: Append to a tail, we need some helper */
+ last_section->next = s;
+ last_section = s;
+
return last_section;
}
@@ -489,9 +483,9 @@ static void bin_cleanup(int debuginfo)
nasm_error(ERR_FATAL|ERR_NOFILE,
"section %s vfollows unknown section (%s)",
g->name, g->vfollows);
- } else if (g->ifollows != NULL)
- for (s = sections; s && (s != g->ifollows); s = s->next) ;
- /* The .bss section is the only one with ifollows = NULL.
+ } else if (g->prev != NULL)
+ for (s = sections; s && (s != g->prev); s = s->next) ;
+ /* The .bss section is the only one with prev = NULL.
In this case we implicitly follow the last progbits
section. */
else
@@ -1262,7 +1256,7 @@ static int32_t bin_secname(char *name, int pass, int *bits)
sec->flags |= TYPE_DEFINED | TYPE_PROGBITS;
else if (!strcmp(name, ".bss")) {
sec->flags |= TYPE_DEFINED | TYPE_NOBITS;
- sec->ifollows = NULL;
+ sec->prev = NULL;
}
}
@@ -1433,18 +1427,13 @@ static void binfmt_init(void)
nsl_tail = &no_seg_labels;
/* Create default section (.text). */
- sections = last_section = nasm_malloc(sizeof(struct Section));
- last_section->next = NULL;
- last_section->name = nasm_strdup(".text");
- last_section->contents = saa_init(1L);
- last_section->follows = last_section->vfollows = 0;
- last_section->ifollows = NULL;
- last_section->length = 0;
- last_section->flags = TYPE_DEFINED | TYPE_PROGBITS;
- last_section->labels = NULL;
- last_section->labels_end = &(last_section->labels);
- last_section->start_index = seg_alloc();
- last_section->vstart_index = seg_alloc();
+ sections = last_section = nasm_zalloc(sizeof(struct Section));
+ last_section->name = nasm_strdup(".text");
+ last_section->contents = saa_init(1L);
+ last_section->flags = TYPE_DEFINED | TYPE_PROGBITS;
+ last_section->labels_end = &(last_section->labels);
+ last_section->start_index = seg_alloc();
+ last_section->vstart_index = seg_alloc();
}
/* Generate binary file output */
diff --git a/output/outcoff.c b/output/outcoff.c
index 5c1de013..6c728063 100644
--- a/output/outcoff.c
+++ b/output/outcoff.c
@@ -285,16 +285,11 @@ static int coff_make_section(char *name, uint32_t flags)
{
struct Section *s;
- s = nasm_malloc(sizeof(*s));
+ s = nasm_zalloc(sizeof(*s));
if (flags != BSS_FLAGS)
s->data = saa_init(1);
- else
- s->data = NULL;
- s->head = NULL;
s->tail = &s->head;
- s->len = 0;
- s->nrelocs = 0;
if (!strcmp(name, ".text"))
s->index = def_seg;
else
diff --git a/output/outelf32.c b/output/outelf32.c
index a85acf04..7feb802d 100644
--- a/output/outelf32.c
+++ b/output/outelf32.c
@@ -300,25 +300,21 @@ static int elf_make_section(char *name, int type, int flags, int align)
{
struct Section *s;
- s = nasm_malloc(sizeof(*s));
+ s = nasm_zalloc(sizeof(*s));
if (type != SHT_NOBITS)
s->data = saa_init(1L);
- s->head = NULL;
s->tail = &s->head;
- s->len = s->size = 0;
- s->nrelocs = 0;
if (!strcmp(name, ".text"))
s->index = def_seg;
else
s->index = seg_alloc();
add_sectname("", name);
- s->name = nasm_malloc(1 + strlen(name));
- strcpy(s->name, name);
- s->type = type;
- s->flags = flags;
- s->align = align;
- s->gsyms = NULL;
+
+ s->name = nasm_strdup(name);
+ s->type = type;
+ s->flags = flags;
+ s->align = align;
if (nsects >= sectlen)
sects = nasm_realloc(sects, (sectlen += SECT_DELTA) * sizeof(*sects));
@@ -606,16 +602,12 @@ static void elf_add_reloc(struct Section *sect, int32_t segment, int type)
{
struct Reloc *r;
- r = *sect->tail = nasm_malloc(sizeof(struct Reloc));
+ r = *sect->tail = nasm_zalloc(sizeof(struct Reloc));
sect->tail = &r->next;
- r->next = NULL;
r->address = sect->len;
- if (segment == NO_SEG)
- r->symbol = 0;
- else {
+ if (segment != NO_SEG) {
int i;
- r->symbol = 0;
for (i = 0; i < nsects; i++)
if (segment == sects[i]->index)
r->symbol = i + 2;
@@ -691,11 +683,11 @@ static int32_t elf_add_gsym_reloc(struct Section *sect,
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;
+ r->next = NULL;
+ r->address = sect->len;
+ r->symbol = GLOBAL_TEMP_BASE + sym->globnum;
+ r->type = type;
sect->nrelocs++;
diff --git a/output/outelf64.c b/output/outelf64.c
index 9807c2a2..46cc6aa5 100644
--- a/output/outelf64.c
+++ b/output/outelf64.c
@@ -308,25 +308,21 @@ static int elf_make_section(char *name, int type, int flags, int align)
{
struct Section *s;
- s = nasm_malloc(sizeof(*s));
+ s = nasm_zalloc(sizeof(*s));
if (type != SHT_NOBITS)
s->data = saa_init(1L);
- s->head = NULL;
s->tail = &s->head;
- s->len = s->size = 0;
- s->nrelocs = 0;
if (!strcmp(name, ".text"))
s->index = def_seg;
else
s->index = seg_alloc();
add_sectname("", name);
- s->name = nasm_malloc(1 + strlen(name));
- strcpy(s->name, name);
- s->type = type;
- s->flags = flags;
- s->align = align;
- s->gsyms = NULL;
+
+ s->name = nasm_strdup(name);
+ s->type = type;
+ s->flags = flags;
+ s->align = align;
if (nsects >= sectlen)
sects = nasm_realloc(sects, (sectlen += SECT_DELTA) * sizeof(*sects));
@@ -614,17 +610,15 @@ static void elf_add_reloc(struct Section *sect, int32_t segment,
int64_t offset, int type)
{
struct Reloc *r;
- r = *sect->tail = nasm_malloc(sizeof(struct Reloc));
+
+ r = *sect->tail = nasm_zalloc(sizeof(struct Reloc));
sect->tail = &r->next;
- r->next = NULL;
r->address = sect->len;
r->offset = offset;
- if (segment == NO_SEG)
- r->symbol = 0;
- else {
+
+ if (segment != NO_SEG) {
int i;
- r->symbol = 0;
for (i = 0; i < nsects; i++)
if (segment == sects[i]->index)
r->symbol = i + 2;
@@ -1692,9 +1686,7 @@ static void stabs64_generate(void)
ptr = stabslines;
- allfiles = (char **)nasm_malloc(numlinestabs * sizeof(char *));
- for (i = 0; i < numlinestabs; i++)
- allfiles[i] = 0;
+ allfiles = (char **)nasm_zalloc(numlinestabs * sizeof(char *));
numfiles = 0;
while (ptr) {
if (numfiles == 0) {
diff --git a/parser.c b/parser.c
index f3c60b29..42ac1097 100644
--- a/parser.c
+++ b/parser.c
@@ -843,7 +843,8 @@ is_expression:
if(optimizing >= 0 && !(result->oprs[operand].type & STRICT))
{
/* Be optimistic */
- result->oprs[operand].type |= SBYTE16 | SBYTE32 | SBYTE64;
+ result->oprs[operand].type |=
+ SBYTE16 | SBYTE32 | SBYTE64 | UDWORD64 | SDWORD64;
}
} else if (is_reloc(value)) { /* it's immediate */
result->oprs[operand].type |= IMMEDIATE;
@@ -865,6 +866,11 @@ is_expression:
result->oprs[operand].type |= SBYTE32;
if (v16 >= -128 && v16 <= 127)
result->oprs[operand].type |= SBYTE16;
+ if ((uint64_t)v64 <= UINT64_C(0xffffffff))
+ result->oprs[operand].type |= UDWORD64;
+ if (v64 >= -INT64_C(0x80000000) &&
+ v64 <= INT64_C(0x7fffffff))
+ result->oprs[operand].type |= SDWORD64;
}
}
} else { /* it's a register */
diff --git a/perllib/phash.ph b/perllib/phash.ph
index 6b31f0a0..936978a5 100644
--- a/perllib/phash.ph
+++ b/perllib/phash.ph
@@ -161,7 +161,7 @@ sub gen_perfect_hash($) {
for ($j = 0; $j < $maxj; $j++) {
$sv = $random_sv_vectors[$j];
@hashinfo = gen_hash_n($n, $sv, $href, $run++);
- return @hashinfo if (defined(@hashinfo));
+ return @hashinfo if (@hashinfo);
}
$n <<= 1;
}
@@ -170,32 +170,6 @@ sub gen_perfect_hash($) {
}
#
-# Read input file
-#
-sub read_input() {
- my $key,$val;
- my %out;
- my $x = 0;
-
- while (defined($l = <STDIN>)) {
- chomp $l;
- $l =~ s/\s*(\#.*|)$//;
-
- next if ($l eq '');
-
- if ($l =~ /^([^=]+)\=([^=]+)$/) {
- $out{$1} = $2;
- $x = $2;
- } else {
- $out{$l} = $x;
- }
- $x++;
- }
-
- return %out;
-}
-
-#
# Verify that the hash table is actually correct...
#
sub verify_hash_table($$)
diff --git a/phash.pl b/phash.pl
index e1071b2e..3ef6e714 100755
--- a/phash.pl
+++ b/phash.pl
@@ -38,6 +38,32 @@
require 'phash.ph';
#
+# Read input file
+#
+sub read_input() {
+ my $key,$val;
+ my %out;
+ my $x = 0;
+
+ while (defined($l = <STDIN>)) {
+ chomp $l;
+ $l =~ s/\s*(\#.*|)$//;
+
+ next if ($l eq '');
+
+ if ($l =~ /^([^=]+)\=([^=]+)$/) {
+ $out{$1} = $2;
+ $x = $2;
+ } else {
+ $out{$l} = $x;
+ }
+ $x++;
+ }
+
+ return %out;
+}
+
+#
# Main program
#
sub main() {
@@ -49,7 +75,7 @@ sub main() {
%data = read_input();
@hashinfo = gen_perfect_hash(\%data);
- if (!defined(@hashinfo)) {
+ if (!@hashinfo) {
die "$0: no hash found\n";
}
diff --git a/pptok.dat b/pptok.dat
index b78d138a..7680356a 100644
--- a/pptok.dat
+++ b/pptok.dat
@@ -50,20 +50,25 @@
%arg
%assign
%clear
+%comment
%define
%defstr
%deftok
%depend
%elif*
%else
+%endcomment
%endif
%endm
%endmacro
%endrep
+%endwhile
%error
%exitmacro
%exitrep
+%exitwhile
%fatal
+%final
%iassign
%idefine
%idefstr
@@ -92,4 +97,5 @@
%unmacro
%use
%warning
+%while*
%xdefine
diff --git a/pptok.pl b/pptok.pl
index c9738d37..be85b942 100755
--- a/pptok.pl
+++ b/pptok.pl
@@ -164,7 +164,7 @@ if ($what eq 'c') {
}
my @hashinfo = gen_perfect_hash(\%tokens);
- if (!defined(@hashinfo)) {
+ if (!@hashinfo) {
die "$0: no hash found\n";
}
diff --git a/preproc.c b/preproc.c
index 07179e12..5fdeab26 100644
--- a/preproc.c
+++ b/preproc.c
@@ -82,8 +82,8 @@
#include "tables.h"
typedef struct SMacro SMacro;
-typedef struct MMacro MMacro;
-typedef struct MMacroInvocation MMacroInvocation;
+typedef struct ExpDef ExpDef;
+typedef struct ExpInv ExpInv;
typedef struct Context Context;
typedef struct Token Token;
typedef struct Blocks Blocks;
@@ -114,64 +114,6 @@ struct SMacro {
};
/*
- * Store the definition of a multi-line macro. This is also used to
- * store the interiors of `%rep...%endrep' blocks, which are
- * effectively self-re-invoking multi-line macros which simply
- * don't have a name or bother to appear in the hash tables. %rep
- * blocks are signified by having a NULL `name' field.
- *
- * In a MMacro describing a `%rep' block, the `in_progress' field
- * isn't merely boolean, but gives the number of repeats left to
- * run.
- *
- * The `next' field is used for storing MMacros in hash tables; the
- * `next_active' field is for stacking them on istk entries.
- *
- * When a MMacro is being expanded, `params', `iline', `nparam',
- * `paramlen', `rotate' and `unique' are local to the invocation.
- */
-struct MMacro {
- MMacro *next;
- MMacroInvocation *prev; /* previous invocation */
- char *name;
- int nparam_min, nparam_max;
- bool casesense;
- bool plus; /* is the last parameter greedy? */
- bool nolist; /* is this macro listing-inhibited? */
- int64_t in_progress; /* is this macro currently being expanded? */
- int32_t max_depth; /* maximum number of recursive expansions allowed */
- Token *dlist; /* All defaults as one list */
- Token **defaults; /* Parameter default pointers */
- int ndefs; /* number of default parameters */
- Line *expansion;
-
- MMacro *next_active;
- MMacro *rep_nest; /* used for nesting %rep */
- Token **params; /* actual parameters */
- Token *iline; /* invocation line */
- unsigned int nparam, rotate;
- int *paramlen;
- uint64_t unique;
- int lineno; /* Current line number on expansion */
- uint64_t condcnt; /* number of if blocks... */
-};
-
-
-/* Store the definition of a multi-line macro, as defined in a
- * previous recursive macro expansion.
- */
-struct MMacroInvocation {
- MMacroInvocation *prev; /* previous invocation */
- Token **params; /* actual parameters */
- Token *iline; /* invocation line */
- unsigned int nparam, rotate;
- int *paramlen;
- uint64_t unique;
- uint64_t condcnt;
-};
-
-
-/*
* The context stack is composed of a linked list of these.
*/
struct Context {
@@ -230,34 +172,98 @@ struct Token {
};
/*
- * Multi-line macro definitions are stored as a linked list of
+ * Expansion definitions are stored as a linked list of
* these, which is essentially a container to allow several linked
* lists of Tokens.
*
* Note that in this module, linked lists are treated as stacks
* wherever possible. For this reason, Lines are _pushed_ on to the
- * `expansion' field in MMacro structures, so that the linked list,
- * if walked, would give the macro lines in reverse order; this
- * means that we can walk the list when expanding a macro, and thus
- * push the lines on to the `expansion' field in _istk_ in reverse
- * order (so that when popped back off they are in the right
- * order). It may seem cockeyed, and it relies on my design having
- * an even number of steps in, but it works...
- *
- * Some of these structures, rather than being actual lines, are
- * markers delimiting the end of the expansion of a given macro.
- * This is for use in the cycle-tracking and %rep-handling code.
- * Such structures have `finishes' non-NULL, and `first' NULL. All
- * others have `finishes' NULL, but `first' may still be NULL if
- * the line is blank.
+ * `last' field in ExpDef structures, so that the linked list,
+ * if walked, would emit the expansion lines in the proper order.
*/
struct Line {
Line *next;
- MMacro *finishes;
Token *first;
};
/*
+ * Expansion Types
+ */
+enum pp_exp_type {
+ EXP_NONE = 0, EXP_PREDEF,
+ EXP_MMACRO, EXP_REP,
+ EXP_IF, EXP_WHILE,
+ EXP_COMMENT, EXP_FINAL,
+ EXP_MAX = INT_MAX /* Keep compiler from reducing the range */
+};
+
+/*
+ * Store the definition of an expansion, in which is any
+ * preprocessor directive that has an ending pair.
+ *
+ * This design allows for arbitrary expansion/recursion depth,
+ * upto the DEADMAN_LIMIT.
+ *
+ * The `next' field is used for storing ExpDef in hash tables; the
+ * `prev' field is for the global `expansions` linked-list.
+ */
+struct ExpDef {
+ ExpDef *prev; /* previous definition */
+ ExpDef *next; /* next in hash table */
+ enum pp_exp_type type; /* expansion type */
+ char *name; /* definition name */
+ int nparam_min, nparam_max;
+ bool casesense;
+ bool plus; /* is the last parameter greedy? */
+ bool nolist; /* is this expansion listing-inhibited? */
+ Token *dlist; /* all defaults as one list */
+ Token **defaults; /* parameter default pointers */
+ int ndefs; /* number of default parameters */
+
+ int prepend; /* label prepend state */
+ Line *label;
+ Line *line;
+ Line *last;
+ int linecount; /* number of lines within expansion */
+
+ int64_t def_depth; /* current number of definition pairs deep */
+ int64_t cur_depth; /* current number of expansions */
+ int64_t max_depth; /* maximum number of expansions allowed */
+
+ int state; /* condition state */
+ bool ignoring; /* ignoring definition lines */
+};
+
+/*
+ * Store the invocation of an expansion.
+ *
+ * The `prev' field is for the `istk->expansion` linked-list.
+ *
+ * When an expansion is being expanded, `params', `iline', `nparam',
+ * `paramlen', `rotate' and `unique' are local to the invocation.
+ */
+struct ExpInv {
+ ExpInv *prev; /* previous invocation */
+ enum pp_exp_type type; /* expansion type */
+ ExpDef *def; /* pointer to expansion definition */
+ char *name; /* invocation name */
+ Line *label; /* pointer to label */
+ char *label_text; /* pointer to label text */
+ Line *current; /* pointer to current line in invocation */
+
+ Token **params; /* actual parameters */
+ Token *iline; /* invocation line */
+ unsigned int nparam, rotate;
+ int *paramlen;
+
+ uint64_t unique;
+ bool emitting;
+ int lineno; /* current line number in expansion */
+ int linnum; /* line number at invocation */
+ int relno; /* relative line number at invocation */
+};
+
+/*
* To handle an arbitrary level of file inclusion, we maintain a
* stack (ie linked list) of these things.
*/
@@ -265,10 +271,10 @@ struct Include {
Include *next;
FILE *fp;
Cond *conds;
- Line *expansion;
+ ExpInv *expansion;
char *fname;
int lineno, lineinc;
- MMacro *mstk; /* stack of active macros/reps */
+ int mmac_depth;
};
/*
@@ -288,10 +294,6 @@ struct IncPath {
* included from within the true branch of a `%if' won't terminate
* it and cause confusion: instead, rightly, it'll cause an error.)
*/
-struct Cond {
- Cond *next;
- int state;
-};
enum {
/*
* These states are for use just after %if or %elif: IF_TRUE
@@ -328,8 +330,7 @@ enum {
#define DIRECTIVE_FOUND 1
/*
- * This define sets the upper limit for smacro and recursive mmacro
- * expansions
+ * This define sets the upper limit for smacro and expansions
*/
#define DEADMAN_LIMIT (1 << 20)
@@ -359,15 +360,6 @@ static const enum pp_conds inverse_ccs[] = {
c_Z, c_NO, c_NP, c_PO, c_PE, -1, c_NS, c_NZ
};
-/*
- * Directive names.
- */
-/* If this is a an IF, ELIF, ELSE or ENDIF keyword */
-static int is_condition(enum preproc_token arg)
-{
- return PP_IS_COND(arg) || (arg == PP_ELSE) || (arg == PP_ENDIF);
-}
-
/* For TASM compatibility we need to be able to recognise TASM compatible
* conditional compilation directives. Using the NASM pre-processor does
* not work, so we look for them specifically from the following list and
@@ -404,9 +396,9 @@ static bool do_predef;
static ListGen *list;
/*
- * The current set of multi-line macros we have defined.
+ * The current set of expansion definitions we have defined.
*/
-static struct hash_table mmacros;
+static struct hash_table expdefs;
/*
* The current set of single-line macros we have defined.
@@ -414,15 +406,25 @@ static struct hash_table mmacros;
static struct hash_table smacros;
/*
- * The multi-line macro we are currently defining, or the %rep
- * block we are currently reading, if any.
+ * Linked List of all active expansion definitions
+ */
+struct ExpDef *expansions = NULL;
+
+/*
+ * The expansion we are currently defining
*/
-static MMacro *defining;
+static ExpDef *defining = NULL;
static uint64_t nested_mac_count;
static uint64_t nested_rep_count;
/*
+ * Linked-list of lines to preprocess, prior to cleanup
+ */
+static Line *finals = NULL;
+static bool in_final = false;
+
+/*
* The number of macro parameters to allocate space for at a time.
*/
#define PARAM_DELTA 16
@@ -467,7 +469,11 @@ static void *new_Block(size_t size);
static void delete_Blocks(void);
static Token *new_Token(Token * next, enum pp_token_type type,
const char *text, int txtlen);
+static Token *copy_Token(Token * tline);
static Token *delete_Token(Token * t);
+static Line *new_Line(void);
+static ExpDef *new_ExpDef(int exp_type);
+static ExpInv *new_ExpInv(int exp_type, ExpDef *ed);
/*
* Macros for safe checking of token pointers, avoid *(NULL)
@@ -477,6 +483,24 @@ static Token *delete_Token(Token * t);
#define tok_is_(x,v) (tok_type_((x), TOK_OTHER) && !strcmp((x)->text,(v)))
#define tok_isnt_(x,v) ((x) && ((x)->type!=TOK_OTHER || strcmp((x)->text,(v))))
+#ifdef NASM_TRACE
+
+#define dump_token(t) raw_dump_token(t, __FILE__, __LINE__, __func__);
+static void raw_dump_token(Token *token, const char *file, int line, const char *func)
+{
+ printf("---[%s (%s:%d): %p]---\n", func, file, line, (void *)token);
+ if (token) {
+ Token *t;
+ list_for_each(t, token) {
+ if (t->text)
+ printf("'%s' ", t->text);
+ }
+ printf("\n");
+ }
+}
+
+#endif
+
/*
* nasm_unquote with error if the string contains NUL characters.
* If the string contains NUL characters, issue an error and return
@@ -503,10 +527,10 @@ static Token *reverse_tokens(Token *t)
Token *next;
while (t) {
- next = t->next;
- t->next = prev;
- prev = t;
- t = next;
+ next = t->next;
+ t->next = prev;
+ prev = t;
+ t = next;
}
return prev;
@@ -618,15 +642,27 @@ static void free_llist(Line * list)
}
/*
- * Free an MMacro
+ * Free an ExpDef
*/
-static void free_mmacro(MMacro * m)
+static void free_expdef(ExpDef * ed)
{
- nasm_free(m->name);
- free_tlist(m->dlist);
- nasm_free(m->defaults);
- free_llist(m->expansion);
- nasm_free(m);
+ nasm_free(ed->name);
+ free_tlist(ed->dlist);
+ nasm_free(ed->defaults);
+ free_llist(ed->line);
+ nasm_free(ed);
+}
+
+/*
+ * Free an ExpInv
+ */
+static void free_expinv(ExpInv * ei)
+{
+ if (ei->name != NULL)
+ nasm_free(ei->name);
+ if (ei->label_text != NULL)
+ nasm_free(ei->label_text);
+ nasm_free(ei);
}
/*
@@ -649,25 +685,25 @@ static void free_smacro_table(struct hash_table *smt)
hash_free(smt);
}
-static void free_mmacro_table(struct hash_table *mmt)
+static void free_expdef_table(struct hash_table *edt)
{
- MMacro *m, *tmp;
+ ExpDef *ed, *tmp;
const char *key;
struct hash_tbl_node *it = NULL;
it = NULL;
- while ((m = hash_iterate(mmt, &it, &key)) != NULL) {
+ while ((ed = hash_iterate(edt, &it, &key)) != NULL) {
nasm_free((void *)key);
- list_for_each_safe(m ,tmp, m)
- free_mmacro(m);
+ list_for_each_safe(ed ,tmp, ed)
+ free_expdef(ed);
}
- hash_free(mmt);
+ hash_free(edt);
}
static void free_macros(void)
{
free_smacro_table(&smacros);
- free_mmacro_table(&mmacros);
+ free_expdef_table(&expdefs);
}
/*
@@ -676,7 +712,7 @@ static void free_macros(void)
static void init_macros(void)
{
hash_init(&smacros, HASH_LARGE);
- hash_init(&mmacros, HASH_LARGE);
+ hash_init(&expdefs, HASH_LARGE);
}
/*
@@ -726,7 +762,7 @@ hash_findix(struct hash_table *hash, const char *str)
}
/*
- * read line from standart macros set,
+ * read line from standard macros set,
* if there no more left -- return NULL
*/
static char *line_from_stdmac(void)
@@ -767,6 +803,7 @@ static char *line_from_stdmac(void)
stdmacpos = extrastdmac;
any_extrastdmac = false;
} else if (do_predef) {
+ ExpInv *ei;
Line *pd, *l;
Token *head, **tail, *t;
@@ -785,12 +822,13 @@ static char *line_from_stdmac(void)
tail = &(*tail)->next;
}
- l = nasm_malloc(sizeof(Line));
- l->next = istk->expansion;
- l->first = head;
- l->finishes = NULL;
-
- istk->expansion = l;
+ l = new_Line();
+ l->first = head;
+ ei = new_ExpInv(EXP_PREDEF, NULL);
+ ei->current = l;
+ ei->emitting = true;
+ ei->prev = istk->expansion;
+ istk->expansion = ei;
}
do_predef = false;
}
@@ -897,6 +935,11 @@ static Token *tokenize(char *line)
enum pp_token_type type;
Token *list = NULL;
Token *t, **tail = &list;
+ bool verbose = true;
+
+ if ((defining != NULL) && (defining->ignoring == true)) {
+ verbose = false;
+ }
while (*line) {
p = line;
@@ -914,14 +957,10 @@ static Token *tokenize(char *line)
type = TOK_PREPROC_ID;
} else if (*p == '{') {
p++;
- while (*p) {
- if (*p == '}')
- break;
+ while (*p && *p != '}') {
p[-1] = *p;
p++;
}
- if (*p != '}')
- error(ERR_WARNING | ERR_PASS1, "unterminated %{ construct");
p[-1] = '\0';
if (*p)
p++;
@@ -951,7 +990,7 @@ static Token *tokenize(char *line)
p--;
if (*p)
*p++ = '\0';
- if (lvl)
+ if (lvl && verbose)
error(ERR_NONFATAL, "unterminated %[ construct");
type = TOK_INDIRECT;
} else if (*p == '?') {
@@ -961,24 +1000,23 @@ static Token *tokenize(char *line)
type = TOK_PREPROC_QQ; /* %?? */
p++;
}
- } else if (*p == '!') {
- type = TOK_PREPROC_ID;
- p++;
- if (isidchar(*p)) {
- do {
- p++;
- }
- while (isidchar(*p));
- } else if (*p == '\'' || *p == '\"' || *p == '`') {
- p = nasm_skip_string(p);
- if (*p)
- p++;
- else
- error(ERR_NONFATAL|ERR_PASS1, "unterminated %! string");
- } else {
- /* %! without string or identifier */
- type = TOK_OTHER; /* Legacy behavior... */
- }
+ } else if (*p == '!') {
+ type = TOK_PREPROC_ID;
+ p++;
+ if (isidchar(*p)) {
+ do {
+ p++;
+ } while (isidchar(*p));
+ } else if (*p == '\'' || *p == '\"' || *p == '`') {
+ p = nasm_skip_string(p);
+ if (*p)
+ p++;
+ else if(verbose)
+ error(ERR_NONFATAL|ERR_PASS1, "unterminated %! string");
+ } else {
+ /* %! without string or identifier */
+ type = TOK_OTHER; /* Legacy behavior... */
+ }
} else if (isidchar(*p) ||
((*p == '!' || *p == '%' || *p == '$') &&
isidchar(p[1]))) {
@@ -1006,7 +1044,7 @@ static Token *tokenize(char *line)
if (*p) {
p++;
- } else {
+ } else if(verbose) {
error(ERR_WARNING|ERR_PASS1, "unterminated string");
/* Handling unterminated strings by UNV */
/* type = -1; */
@@ -1157,14 +1195,13 @@ static void *new_Block(size_t size)
/* first, get to the end of the linked list */
while (b->next)
b = b->next;
+
/* now allocate the requested chunk */
b->chunk = nasm_malloc(size);
/* now allocate a new block for the next request */
- b->next = nasm_malloc(sizeof(Blocks));
- /* and initialize the contents of the new block */
- b->next->next = NULL;
- b->next->chunk = NULL;
+ b->next = nasm_zalloc(sizeof(Blocks));
+
return b->chunk;
}
@@ -1224,6 +1261,34 @@ static Token *new_Token(Token * next, enum pp_token_type type,
return t;
}
+static Token *copy_Token(Token * tline)
+{
+ Token *t, *tt, *first = NULL, *prev = NULL;
+ int i;
+ for (tt = tline; tt != NULL; tt = tt->next) {
+ if (!freeTokens) {
+ freeTokens = (Token *) new_Block(TOKEN_BLOCKSIZE * sizeof(Token));
+ for (i = 0; i < TOKEN_BLOCKSIZE - 1; i++)
+ freeTokens[i].next = &freeTokens[i + 1];
+ freeTokens[i].next = NULL;
+ }
+ t = freeTokens;
+ freeTokens = t->next;
+ t->next = NULL;
+ t->text = tt->text ? nasm_strdup(tt->text) : NULL;
+ t->a.mac = tt->a.mac;
+ t->a.len = tt->a.len;
+ t->type = tt->type;
+ if (prev != NULL) {
+ prev->next = t;
+ } else {
+ first = t;
+ }
+ prev = t;
+ }
+ return first;
+}
+
static Token *delete_Token(Token * t)
{
Token *next = t->next;
@@ -1247,31 +1312,31 @@ static char *detoken(Token * tlist, bool expand_locals)
list_for_each(t, tlist) {
if (t->type == TOK_PREPROC_ID && t->text[1] == '!') {
- char *v;
- char *q = t->text;
-
- v = t->text + 2;
- if (*v == '\'' || *v == '\"' || *v == '`') {
- size_t len = nasm_unquote(v, NULL);
- size_t clen = strlen(v);
-
- if (len != clen) {
- error(ERR_NONFATAL | ERR_PASS1,
- "NUL character in %! string");
- v = NULL;
- }
- }
-
- if (v) {
- char *p = getenv(v);
- if (!p) {
- error(ERR_NONFATAL | ERR_PASS1,
- "nonexistent environment variable `%s'", v);
- p = "";
- }
- t->text = nasm_strdup(p);
- }
- nasm_free(q);
+ char *v;
+ char *q = t->text;
+
+ v = t->text + 2;
+ if (*v == '\'' || *v == '\"' || *v == '`') {
+ size_t len = nasm_unquote(v, NULL);
+ size_t clen = strlen(v);
+
+ if (len != clen) {
+ error(ERR_NONFATAL | ERR_PASS1,
+ "NUL character in %! string");
+ v = NULL;
+ }
+ }
+
+ if (v) {
+ char *p = getenv(v);
+ if (!p) {
+ error(ERR_NONFATAL | ERR_PASS1,
+ "nonexistent environment variable `%s'", v);
+ p = "";
+ }
+ t->text = nasm_strdup(p);
+ }
+ nasm_free(q);
}
/* Expand local macros here and not during preprocessing */
@@ -1289,6 +1354,25 @@ static char *detoken(Token * tlist, bool expand_locals)
t->text = p;
}
}
+
+ /* Expand %? and %?? directives */
+ if ((istk->expansion != NULL) &&
+ ((t->type == TOK_PREPROC_Q) ||
+ (t->type == TOK_PREPROC_QQ))) {
+ ExpInv *ei;
+ for (ei = istk->expansion; ei != NULL; ei = ei->prev){
+ if (ei->type == EXP_MMACRO) {
+ nasm_free(t->text);
+ if (t->type == TOK_PREPROC_Q) {
+ t->text = nasm_strdup(ei->name);
+ } else {
+ t->text = nasm_strdup(ei->def->name);
+ }
+ break;
+ }
+ }
+ }
+
if (t->type == TOK_WHITESPACE)
len++;
else if (t->text)
@@ -1312,6 +1396,62 @@ static char *detoken(Token * tlist, bool expand_locals)
}
/*
+ * Initialize a new Line
+ */
+static inline Line *new_Line(void)
+{
+ return (Line *)nasm_zalloc(sizeof(Line));
+}
+
+
+/*
+ * Initialize a new Expansion Definition
+ */
+static ExpDef *new_ExpDef(int exp_type)
+{
+ ExpDef *ed = (ExpDef*)nasm_zalloc(sizeof(ExpDef));
+ ed->type = exp_type;
+ ed->casesense = true;
+ ed->state = COND_NEVER;
+
+ return ed;
+}
+
+
+/*
+ * Initialize a new Expansion Instance
+ */
+static ExpInv *new_ExpInv(int exp_type, ExpDef *ed)
+{
+ ExpInv *ei = (ExpInv*)nasm_zalloc(sizeof(ExpInv));
+ ei->type = exp_type;
+ ei->def = ed;
+ ei->unique = ++unique;
+
+ if ((istk->mmac_depth < 1) &&
+ (istk->expansion == NULL) &&
+ (ed != NULL) &&
+ (ed->type != EXP_MMACRO) &&
+ (ed->type != EXP_REP) &&
+ (ed->type != EXP_WHILE)) {
+ ei->linnum = src_get_linnum();
+ src_set_linnum(ei->linnum - ed->linecount - 1);
+ } else {
+ ei->linnum = -1;
+ }
+ if ((istk->expansion == NULL) ||
+ (ei->type == EXP_MMACRO)) {
+ ei->relno = 0;
+ } else {
+ ei->relno = istk->expansion->lineno;
+ if (ed != NULL) {
+ ei->relno -= (ed->linecount + 1);
+ }
+ }
+ return ei;
+}
+
+/*
* A scanner, suitable for use by the expression evaluator, which
* operates on a line of Tokens. Expects a pointer to a pointer to
* the first token in the line to be passed in as its private_data
@@ -1491,43 +1631,17 @@ static Context *get_ctx(const char *name, const char **namep,
if (!all_contexts)
return ctx;
- /*
- * NOTE: In 2.10 we will not need lookup in extarnal
- * contexts, so this is a gentle way to inform users
- * about their source code need to be updated
- */
-
- /* first round -- check the current context */
- m = hash_findix(&ctx->localmac, name);
- while (m) {
- if (!mstrcmp(m->name, name, m->casesense))
- return ctx;
- m = m->next;
- }
-
- /* second round - external contexts */
- while ((ctx = ctx->next)) {
+ do {
/* Search for this smacro in found context */
m = hash_findix(&ctx->localmac, name);
while (m) {
- if (!mstrcmp(m->name, name, m->casesense)) {
- /* NOTE: deprecated as of 2.10 */
- static int once = 0;
- if (!once) {
- error(ERR_WARNING, "context-local macro expansion"
- " fall-through (automatic searching of outer"
- " contexts) will be deprecated starting in"
- " NASM 2.10, please see the NASM Manual for"
- " more information");
- once = 1;
- }
- error(ERR_WARNING, "`%s': context-local macro expansion fall-through", name);
+ if (!mstrcmp(m->name, name, m->casesense))
return ctx;
- }
m = m->next;
}
+ ctx = ctx->next;
}
-
+ while (ctx);
return NULL;
}
@@ -1563,11 +1677,11 @@ static FILE *inc_fopen(const char *file, StrList **dhead, StrList ***dtail,
while (1) {
sl = nasm_malloc(prefix_len+len+1+sizeof sl->next);
+ sl->next = NULL;
memcpy(sl->str, prefix, prefix_len);
memcpy(sl->str+prefix_len, file, len+1);
fp = fopen(sl->str, "r");
if (fp && dhead && !in_list(*dhead, sl->str)) {
- sl->next = NULL;
**dtail = sl;
*dtail = &sl->next;
} else {
@@ -1761,26 +1875,26 @@ static bool if_condition(Token * tline, enum preproc_token ct)
break;
case PPC_IFENV:
- tline = expand_smacro(tline);
+ tline = expand_smacro(tline);
j = false; /* have we matched yet? */
while (tline) {
skip_white_(tline);
if (!tline || (tline->type != TOK_ID &&
- tline->type != TOK_STRING &&
+ tline->type != TOK_STRING &&
(tline->type != TOK_PREPROC_ID ||
- tline->text[1] != '!'))) {
+ tline->text[1] != '!'))) {
error(ERR_NONFATAL,
"`%s' expects environment variable names",
- pp_directives[ct]);
+ pp_directives[ct]);
goto fail;
}
- p = tline->text;
- if (tline->type == TOK_PREPROC_ID)
- p += 2; /* Skip leading %! */
- if (*p == '\'' || *p == '\"' || *p == '`')
- nasm_unquote_cstr(p, ct);
- if (getenv(p))
- j = true;
+ p = tline->text;
+ if (tline->type == TOK_PREPROC_ID)
+ p += 2; /* Skip leading %! */
+ if (*p == '\'' || *p == '\"' || *p == '`')
+ nasm_unquote_cstr(p, ct);
+ if (getenv(p))
+ j = true;
tline = tline->next;
}
break;
@@ -1845,7 +1959,7 @@ static bool if_condition(Token * tline, enum preproc_token ct)
case PPC_IFMACRO:
{
bool found = false;
- MMacro searching, *mmac;
+ ExpDef searching, *ed;
skip_white_(tline);
tline = expand_id(tline);
@@ -1854,14 +1968,9 @@ static bool if_condition(Token * tline, enum preproc_token ct)
"`%s' expects a macro name", pp_directives[ct]);
goto fail;
}
+ memset(&searching, 0, sizeof(searching));
searching.name = nasm_strdup(tline->text);
searching.casesense = true;
- searching.plus = false;
- searching.nolist = false;
- searching.in_progress = 0;
- searching.max_depth = 0;
- searching.rep_nest = NULL;
- searching.nparam_min = 0;
searching.nparam_max = INT_MAX;
tline = expand_smacro(tline->next);
skip_white_(tline);
@@ -1901,17 +2010,15 @@ static bool if_condition(Token * tline, enum preproc_token ct)
tline = tline->next;
searching.plus = true;
}
- mmac = (MMacro *) hash_findix(&mmacros, searching.name);
- while (mmac) {
- if (!strcmp(mmac->name, searching.name) &&
- (mmac->nparam_min <= searching.nparam_max
- || searching.plus)
- && (searching.nparam_min <= mmac->nparam_max
- || mmac->plus)) {
+ ed = (ExpDef *) hash_findix(&expdefs, searching.name);
+ while (ed != NULL) {
+ if (!strcmp(ed->name, searching.name) &&
+ (ed->nparam_min <= searching.nparam_max || searching.plus) &&
+ (searching.nparam_min <= ed->nparam_max || ed->plus)) {
found = true;
break;
}
- mmac = mmac->next;
+ ed = ed->next;
}
if (tline && tline->next)
error(ERR_WARNING|ERR_PASS1,
@@ -2032,7 +2139,7 @@ static bool define_smacro(Context *ctx, const char *mname, bool casesense,
} else {
smtbl = ctx ? &ctx->localmac : &smacros;
smhead = (SMacro **) hash_findi_add(smtbl, mname);
- smac = nasm_malloc(sizeof(SMacro));
+ smac = nasm_zalloc(sizeof(SMacro));
smac->next = *smhead;
*smhead = smac;
}
@@ -2076,7 +2183,7 @@ static void undef_smacro(Context *ctx, const char *mname)
/*
* Parse a mmacro specification.
*/
-static bool parse_mmacro_spec(Token *tline, MMacro *def, const char *directive)
+static bool parse_mmacro_spec(Token *tline, ExpDef *def, const char *directive)
{
bool err;
@@ -2088,12 +2195,11 @@ static bool parse_mmacro_spec(Token *tline, MMacro *def, const char *directive)
return false;
}
- def->prev = NULL;
def->name = nasm_strdup(tline->text);
def->plus = false;
def->nolist = false;
- def->in_progress = 0;
- def->rep_nest = NULL;
+// def->in_progress = 0;
+// def->rep_nest = NULL;
def->nparam_min = 0;
def->nparam_max = 0;
@@ -2147,7 +2253,7 @@ static bool parse_mmacro_spec(Token *tline, MMacro *def, const char *directive)
def->dlist = NULL;
def->defaults = NULL;
}
- def->expansion = NULL;
+ def->line = NULL;
if (def->defaults && def->ndefs > def->nparam_max - def->nparam_min &&
!def->plus)
@@ -2196,13 +2302,12 @@ static int do_directive(Token * tline)
const char *mname;
Include *inc;
Context *ctx;
- Cond *cond;
- MMacro *mmac, **mmhead;
- Token *t, *tt, *param_start, *macro_start, *last, **tptr, *origline;
Line *l;
+ Token *t, *tt, *param_start, *macro_start, *last, **tptr, *origline;
struct tokenval tokval;
expr *evalresult;
- MMacro *tmp_defining; /* Used when manipulating rep_nest */
+ ExpDef *ed, *eed, **edhead;
+ ExpInv *ei, *eei;
int64_t count;
size_t len;
int severity;
@@ -2217,72 +2322,15 @@ static int do_directive(Token * tline)
i = pp_token_hash(tline->text);
- /*
- * FIXME: We zap execution of PP_RMACRO, PP_IRMACRO, PP_EXITMACRO
- * since they are known to be buggy at moment, we need to fix them
- * in future release (2.09-2.10)
- */
- if (i == PP_RMACRO || i == PP_RMACRO || i == PP_EXITMACRO) {
- error(ERR_NONFATAL, "unknown preprocessor directive `%s'",
- tline->text);
- return NO_DIRECTIVE_FOUND;
- }
-
- /*
- * If we're in a non-emitting branch of a condition construct,
- * or walking to the end of an already terminated %rep block,
- * we should ignore all directives except for condition
- * directives.
- */
- if (((istk->conds && !emitting(istk->conds->state)) ||
- (istk->mstk && !istk->mstk->in_progress)) && !is_condition(i)) {
- return NO_DIRECTIVE_FOUND;
- }
-
- /*
- * If we're defining a macro or reading a %rep block, we should
- * ignore all directives except for %macro/%imacro (which nest),
- * %endm/%endmacro, and (only if we're in a %rep block) %endrep.
- * If we're in a %rep block, another %rep nests, so should be let through.
- */
- if (defining && i != PP_MACRO && i != PP_IMACRO &&
- i != PP_RMACRO && i != PP_IRMACRO &&
- i != PP_ENDMACRO && i != PP_ENDM &&
- (defining->name || (i != PP_ENDREP && i != PP_REP))) {
- return NO_DIRECTIVE_FOUND;
- }
-
- if (defining) {
- if (i == PP_MACRO || i == PP_IMACRO ||
- i == PP_RMACRO || i == PP_IRMACRO) {
- nested_mac_count++;
- return NO_DIRECTIVE_FOUND;
- } else if (nested_mac_count > 0) {
- if (i == PP_ENDMACRO) {
- nested_mac_count--;
- return NO_DIRECTIVE_FOUND;
- }
- }
- if (!defining->name) {
- if (i == PP_REP) {
- nested_rep_count++;
- return NO_DIRECTIVE_FOUND;
- } else if (nested_rep_count > 0) {
- if (i == PP_ENDREP) {
- nested_rep_count--;
- return NO_DIRECTIVE_FOUND;
- }
- }
- }
- }
-
switch (i) {
case PP_INVALID:
+ if (defining != NULL) return NO_DIRECTIVE_FOUND;
error(ERR_NONFATAL, "unknown preprocessor directive `%s'",
tline->text);
return NO_DIRECTIVE_FOUND; /* didn't get it */
case PP_STACKSIZE:
+ if (defining != NULL) return NO_DIRECTIVE_FOUND;
/* Directive to tell NASM what the default stack size is. The
* default is for a 16-bit stack, and this can be overriden with
* %stacksize large.
@@ -2332,6 +2380,7 @@ static int do_directive(Token * tline)
return DIRECTIVE_FOUND;
case PP_ARG:
+ if (defining != NULL) return NO_DIRECTIVE_FOUND;
/* TASM like ARG directive to define arguments to functions, in
* the following form:
*
@@ -2401,6 +2450,7 @@ static int do_directive(Token * tline)
return DIRECTIVE_FOUND;
case PP_LOCAL:
+ if (defining != NULL) return NO_DIRECTIVE_FOUND;
/* TASM like LOCAL directive to define local variables for a
* function, in the following form:
*
@@ -2482,6 +2532,7 @@ static int do_directive(Token * tline)
return DIRECTIVE_FOUND;
case PP_CLEAR:
+ if (defining != NULL) return NO_DIRECTIVE_FOUND;
if (tline->next)
error(ERR_WARNING|ERR_PASS1,
"trailing garbage after `%%clear' ignored");
@@ -2491,6 +2542,7 @@ static int do_directive(Token * tline)
return DIRECTIVE_FOUND;
case PP_DEPEND:
+ if (defining != NULL) return NO_DIRECTIVE_FOUND;
t = tline->next = expand_smacro(tline->next);
skip_white_(t);
if (!t || (t->type != TOK_STRING &&
@@ -2516,6 +2568,7 @@ static int do_directive(Token * tline)
return DIRECTIVE_FOUND;
case PP_INCLUDE:
+ if (defining != NULL) return NO_DIRECTIVE_FOUND;
t = tline->next = expand_smacro(tline->next);
skip_white_(t);
@@ -2531,9 +2584,8 @@ static int do_directive(Token * tline)
p = t->text;
if (t->type != TOK_INTERNAL_STRING)
nasm_unquote_cstr(p, i);
- inc = nasm_malloc(sizeof(Include));
+ inc = nasm_zalloc(sizeof(Include));
inc->next = istk;
- inc->conds = NULL;
inc->fp = inc_fopen(p, dephead, &deptail, pass == 0);
if (!inc->fp) {
/* -MG given but file not found */
@@ -2543,7 +2595,6 @@ static int do_directive(Token * tline)
inc->lineno = src_set_linnum(0);
inc->lineinc = 1;
inc->expansion = NULL;
- inc->mstk = NULL;
istk = inc;
list->uplevel(LIST_INCLUDE);
}
@@ -2551,6 +2602,7 @@ static int do_directive(Token * tline)
return DIRECTIVE_FOUND;
case PP_USE:
+ if (defining != NULL) return NO_DIRECTIVE_FOUND;
{
static macros_t *use_pkg;
const char *pkg_macro = NULL;
@@ -2586,6 +2638,7 @@ static int do_directive(Token * tline)
case PP_PUSH:
case PP_REPL:
case PP_POP:
+ if (defining != NULL) return NO_DIRECTIVE_FOUND;
tline = tline->next;
skip_white_(tline);
tline = expand_id(tline);
@@ -2606,7 +2659,7 @@ static int do_directive(Token * tline)
}
if (i == PP_PUSH) {
- ctx = nasm_malloc(sizeof(Context));
+ ctx = nasm_zalloc(sizeof(Context));
ctx->next = cstk;
hash_init(&ctx->localmac, HASH_SMALL);
ctx->name = p;
@@ -2645,6 +2698,7 @@ static int do_directive(Token * tline)
goto issue_error;
issue_error:
+ if (defining != NULL) return NO_DIRECTIVE_FOUND;
{
/* Only error out if this is the final pass */
if (pass != 2 && i != PP_FATAL)
@@ -2671,39 +2725,58 @@ issue_error:
}
CASE_PP_IF:
- if (istk->conds && !emitting(istk->conds->state))
+ if (defining != NULL) {
+ if (defining->type == EXP_IF) {
+ defining->def_depth ++;
+ }
+ return NO_DIRECTIVE_FOUND;
+ }
+ if ((istk->expansion != NULL) &&
+ (istk->expansion->emitting == false)) {
j = COND_NEVER;
- else {
+ } else {
j = if_condition(tline->next, i);
tline->next = NULL; /* it got freed */
- j = j < 0 ? COND_NEVER : j ? COND_IF_TRUE : COND_IF_FALSE;
- }
- cond = nasm_malloc(sizeof(Cond));
- cond->next = istk->conds;
- cond->state = j;
- istk->conds = cond;
- if(istk->mstk)
- istk->mstk->condcnt ++;
+ j = (((j < 0) ? COND_NEVER : j) ? COND_IF_TRUE : COND_IF_FALSE);
+ }
+ ed = new_ExpDef(EXP_IF);
+ ed->state = j;
+ ed->nolist = NULL;
+ ed->def_depth = 0;
+ ed->cur_depth = 0;
+ ed->max_depth = 0;
+ ed->ignoring = ((ed->state == COND_IF_TRUE) ? false : true);
+ ed->prev = defining;
+ defining = ed;
free_tlist(origline);
return DIRECTIVE_FOUND;
CASE_PP_ELIF:
- if (!istk->conds)
+ if (defining != NULL) {
+ if ((defining->type != EXP_IF) || (defining->def_depth > 0)) {
+ return NO_DIRECTIVE_FOUND;
+ }
+ }
+ if ((defining == NULL) || (defining->type != EXP_IF)) {
error(ERR_FATAL, "`%s': no matching `%%if'", pp_directives[i]);
- switch(istk->conds->state) {
+ }
+ switch (defining->state) {
case COND_IF_TRUE:
- istk->conds->state = COND_DONE;
+ defining->state = COND_DONE;
+ defining->ignoring = true;
break;
case COND_DONE:
case COND_NEVER:
+ defining->ignoring = true;
break;
case COND_ELSE_TRUE:
case COND_ELSE_FALSE:
error_precond(ERR_WARNING|ERR_PASS1,
"`%%elif' after `%%else' ignored");
- istk->conds->state = COND_NEVER;
+ defining->state = COND_NEVER;
+ defining->ignoring = true;
break;
case COND_IF_FALSE:
@@ -2717,53 +2790,80 @@ issue_error:
*/
j = if_condition(expand_mmac_params(tline->next), i);
tline->next = NULL; /* it got freed */
- istk->conds->state =
+ defining->state =
j < 0 ? COND_NEVER : j ? COND_IF_TRUE : COND_IF_FALSE;
+ defining->ignoring = ((defining->state == COND_IF_TRUE) ? false : true);
break;
}
free_tlist(origline);
return DIRECTIVE_FOUND;
case PP_ELSE:
+ if (defining != NULL) {
+ if ((defining->type != EXP_IF) || (defining->def_depth > 0)) {
+ return NO_DIRECTIVE_FOUND;
+ }
+ }
if (tline->next)
error_precond(ERR_WARNING|ERR_PASS1,
"trailing garbage after `%%else' ignored");
- if (!istk->conds)
- error(ERR_FATAL, "`%%else': no matching `%%if'");
- switch(istk->conds->state) {
+ if ((defining == NULL) || (defining->type != EXP_IF)) {
+ error(ERR_FATAL, "`%s': no matching `%%if'", pp_directives[i]);
+ }
+ switch (defining->state) {
case COND_IF_TRUE:
case COND_DONE:
- istk->conds->state = COND_ELSE_FALSE;
+ defining->state = COND_ELSE_FALSE;
+ defining->ignoring = true;
break;
case COND_NEVER:
+ defining->ignoring = true;
break;
case COND_IF_FALSE:
- istk->conds->state = COND_ELSE_TRUE;
+ defining->state = COND_ELSE_TRUE;
+ defining->ignoring = false;
break;
case COND_ELSE_TRUE:
case COND_ELSE_FALSE:
error_precond(ERR_WARNING|ERR_PASS1,
"`%%else' after `%%else' ignored.");
- istk->conds->state = COND_NEVER;
+ defining->state = COND_NEVER;
+ defining->ignoring = true;
break;
}
free_tlist(origline);
return DIRECTIVE_FOUND;
case PP_ENDIF:
+ if (defining != NULL) {
+ if (defining->type == EXP_IF) {
+ if (defining->def_depth > 0) {
+ defining->def_depth --;
+ return NO_DIRECTIVE_FOUND;
+ }
+ } else {
+ return NO_DIRECTIVE_FOUND;
+ }
+ }
if (tline->next)
error_precond(ERR_WARNING|ERR_PASS1,
"trailing garbage after `%%endif' ignored");
- if (!istk->conds)
- error(ERR_FATAL, "`%%endif': no matching `%%if'");
- cond = istk->conds;
- istk->conds = cond->next;
- nasm_free(cond);
- if(istk->mstk)
- istk->mstk->condcnt --;
+ if ((defining == NULL) || (defining->type != EXP_IF)) {
+ error(ERR_NONFATAL, "`%%endif': no matching `%%if'");
+ return DIRECTIVE_FOUND;
+ }
+ ed = defining;
+ defining = ed->prev;
+ ed->prev = expansions;
+ expansions = ed;
+ ei = new_ExpInv(EXP_IF, ed);
+ ei->current = ed->line;
+ ei->emitting = true;
+ ei->prev = istk->expansion;
+ istk->expansion = ei;
free_tlist(origline);
return DIRECTIVE_FOUND;
@@ -2771,71 +2871,91 @@ issue_error:
case PP_IRMACRO:
case PP_MACRO:
case PP_IMACRO:
- if (defining) {
- error(ERR_FATAL, "`%s': already defining a macro",
- pp_directives[i]);
- return DIRECTIVE_FOUND;
+ if (defining != NULL) {
+ if (defining->type == EXP_MMACRO) {
+ defining->def_depth ++;
+ }
+ return NO_DIRECTIVE_FOUND;
}
- defining = nasm_malloc(sizeof(MMacro));
- defining->max_depth =
+ ed = new_ExpDef(EXP_MMACRO);
+ ed->max_depth =
(i == PP_RMACRO) || (i == PP_IRMACRO) ? DEADMAN_LIMIT : 0;
- defining->casesense = (i == PP_MACRO) || (i == PP_RMACRO);
- if (!parse_mmacro_spec(tline, defining, pp_directives[i])) {
- nasm_free(defining);
- defining = NULL;
+ ed->casesense = (i == PP_MACRO) || (i == PP_RMACRO);
+ if (!parse_mmacro_spec(tline, ed, pp_directives[i])) {
+ nasm_free(ed);
+ ed = NULL;
return DIRECTIVE_FOUND;
}
-
- mmac = (MMacro *) hash_findix(&mmacros, defining->name);
- while (mmac) {
- if (!strcmp(mmac->name, defining->name) &&
- (mmac->nparam_min <= defining->nparam_max
- || defining->plus)
- && (defining->nparam_min <= mmac->nparam_max
- || mmac->plus)) {
- error(ERR_WARNING|ERR_PASS1,
- "redefining multi-line macro `%s'", defining->name);
- return DIRECTIVE_FOUND;
+ ed->def_depth = 0;
+ ed->cur_depth = 0;
+ ed->max_depth = (ed->max_depth + 1);
+ ed->ignoring = false;
+ ed->prev = defining;
+ defining = ed;
+
+ eed = (ExpDef *) hash_findix(&expdefs, ed->name);
+ while (eed) {
+ if (!strcmp(eed->name, ed->name) &&
+ (eed->nparam_min <= ed->nparam_max || ed->plus) &&
+ (ed->nparam_min <= eed->nparam_max || eed->plus)) {
+ error(ERR_WARNING|ERR_PASS1,
+ "redefining multi-line macro `%s'", ed->name);
+ return DIRECTIVE_FOUND;
}
- mmac = mmac->next;
+ eed = eed->next;
}
free_tlist(origline);
return DIRECTIVE_FOUND;
case PP_ENDM:
case PP_ENDMACRO:
- if (! (defining && defining->name)) {
+ if (defining != NULL) {
+ if (defining->type == EXP_MMACRO) {
+ if (defining->def_depth > 0) {
+ defining->def_depth --;
+ return NO_DIRECTIVE_FOUND;
+ }
+ } else {
+ return NO_DIRECTIVE_FOUND;
+ }
+ }
+ if (!(defining) || (defining->type != EXP_MMACRO)) {
error(ERR_NONFATAL, "`%s': not defining a macro", tline->text);
return DIRECTIVE_FOUND;
}
- mmhead = (MMacro **) hash_findi_add(&mmacros, defining->name);
- defining->next = *mmhead;
- *mmhead = defining;
- defining = NULL;
+ edhead = (ExpDef **) hash_findi_add(&expdefs, defining->name);
+ defining->next = *edhead;
+ *edhead = defining;
+ ed = defining;
+ defining = ed->prev;
+ ed->prev = expansions;
+ expansions = ed;
+ ed = NULL;
free_tlist(origline);
return DIRECTIVE_FOUND;
case PP_EXITMACRO:
+ if (defining != NULL) return NO_DIRECTIVE_FOUND;
/*
* We must search along istk->expansion until we hit a
- * macro-end marker for a macro with a name. Then we
- * bypass all lines between exitmacro and endmacro.
+ * macro invocation. Then we disable the emitting state(s)
+ * between exitmacro and endmacro.
*/
- list_for_each(l, istk->expansion)
- if (l->finishes && l->finishes->name)
+ for (ei = istk->expansion; ei != NULL; ei = ei->prev) {
+ if(ei->type == EXP_MMACRO) {
break;
+ }
+ }
- if (l) {
+ if (ei != NULL) {
/*
- * Remove all conditional entries relative to this
- * macro invocation. (safe to do in this context)
+ * Set all invocations leading back to the macro
+ * invocation to a non-emitting state.
*/
- for ( ; l->finishes->condcnt > 0; l->finishes->condcnt --) {
- cond = istk->conds;
- istk->conds = cond->next;
- nasm_free(cond);
+ for (eei = istk->expansion; eei != ei; eei = eei->prev) {
+ eei->emitting = false;
}
- istk->expansion = l;
+ eei->emitting = false;
} else {
error(ERR_NONFATAL, "`%%exitmacro' not within `%%macro' block");
}
@@ -2844,26 +2964,33 @@ issue_error:
case PP_UNMACRO:
case PP_UNIMACRO:
+ if (defining != NULL) return NO_DIRECTIVE_FOUND;
{
- MMacro **mmac_p;
- MMacro spec;
+ ExpDef **ed_p;
+ ExpDef spec;
spec.casesense = (i == PP_UNMACRO);
if (!parse_mmacro_spec(tline, &spec, pp_directives[i])) {
return DIRECTIVE_FOUND;
}
- mmac_p = (MMacro **) hash_findi(&mmacros, spec.name, NULL);
- while (mmac_p && *mmac_p) {
- mmac = *mmac_p;
- if (mmac->casesense == spec.casesense &&
- !mstrcmp(mmac->name, spec.name, spec.casesense) &&
- mmac->nparam_min == spec.nparam_min &&
- mmac->nparam_max == spec.nparam_max &&
- mmac->plus == spec.plus) {
- *mmac_p = mmac->next;
- free_mmacro(mmac);
+ ed_p = (ExpDef **) hash_findi(&expdefs, spec.name, NULL);
+ while (ed_p && *ed_p) {
+ ed = *ed_p;
+ if (ed->casesense == spec.casesense &&
+ !mstrcmp(ed->name, spec.name, spec.casesense) &&
+ ed->nparam_min == spec.nparam_min &&
+ ed->nparam_max == spec.nparam_max &&
+ ed->plus == spec.plus) {
+ if (ed->cur_depth > 0) {
+ error(ERR_NONFATAL, "`%s' ignored on active macro",
+ pp_directives[i]);
+ break;
+ } else {
+ *ed_p = ed->next;
+ free_expdef(ed);
+ }
} else {
- mmac_p = &mmac->next;
+ ed_p = &ed->next;
}
}
free_tlist(origline);
@@ -2872,6 +2999,7 @@ issue_error:
}
case PP_ROTATE:
+ if (defining != NULL) return NO_DIRECTIVE_FOUND;
if (tline->next && tline->next->type == TOK_WHITESPACE)
tline = tline->next;
if (!tline->next) {
@@ -2897,26 +3025,33 @@ issue_error:
error(ERR_NONFATAL, "non-constant value given to `%%rotate'");
return DIRECTIVE_FOUND;
}
- mmac = istk->mstk;
- while (mmac && !mmac->name) /* avoid mistaking %reps for macros */
- mmac = mmac->next_active;
- if (!mmac) {
+ for (ei = istk->expansion; ei != NULL; ei = ei->prev) {
+ if (ei->type == EXP_MMACRO) {
+ break;
+ }
+ }
+ if (ei == NULL) {
error(ERR_NONFATAL, "`%%rotate' invoked outside a macro call");
- } else if (mmac->nparam == 0) {
+ } else if (ei->nparam == 0) {
error(ERR_NONFATAL,
"`%%rotate' invoked within macro without parameters");
} else {
- int rotate = mmac->rotate + reloc_value(evalresult);
+ int rotate = ei->rotate + reloc_value(evalresult);
- rotate %= (int)mmac->nparam;
+ rotate %= (int)ei->nparam;
if (rotate < 0)
- rotate += mmac->nparam;
-
- mmac->rotate = rotate;
+ rotate += ei->nparam;
+ ei->rotate = rotate;
}
return DIRECTIVE_FOUND;
case PP_REP:
+ if (defining != NULL) {
+ if (defining->type == EXP_REP) {
+ defining->def_depth ++;
+ }
+ return NO_DIRECTIVE_FOUND;
+ }
nolist = false;
do {
tline = tline->next;
@@ -2958,26 +3093,28 @@ issue_error:
count = 0;
}
free_tlist(origline);
-
- tmp_defining = defining;
- defining = nasm_malloc(sizeof(MMacro));
- defining->prev = NULL;
- defining->name = NULL; /* flags this macro as a %rep block */
- defining->casesense = false;
- defining->plus = false;
- defining->nolist = nolist;
- defining->in_progress = count;
- defining->max_depth = 0;
- defining->nparam_min = defining->nparam_max = 0;
- defining->defaults = NULL;
- defining->dlist = NULL;
- defining->expansion = NULL;
- defining->next_active = istk->mstk;
- defining->rep_nest = tmp_defining;
+ ed = new_ExpDef(EXP_REP);
+ ed->nolist = nolist;
+ ed->def_depth = 0;
+ ed->cur_depth = 1;
+ ed->max_depth = (count - 1);
+ ed->ignoring = false;
+ ed->prev = defining;
+ defining = ed;
return DIRECTIVE_FOUND;
case PP_ENDREP:
- if (!defining || defining->name) {
+ if (defining != NULL) {
+ if (defining->type == EXP_REP) {
+ if (defining->def_depth > 0) {
+ defining->def_depth --;
+ return NO_DIRECTIVE_FOUND;
+ }
+ } else {
+ return NO_DIRECTIVE_FOUND;
+ }
+ }
+ if ((defining == NULL) || (defining->type != EXP_REP)) {
error(ERR_NONFATAL, "`%%endrep': no matching `%%rep'");
return DIRECTIVE_FOUND;
}
@@ -2993,34 +3130,46 @@ issue_error:
* continues) until the whole expansion is forcibly removed
* from istk->expansion by a %exitrep.
*/
- l = nasm_malloc(sizeof(Line));
- l->next = istk->expansion;
- l->finishes = defining;
- l->first = NULL;
- istk->expansion = l;
-
- istk->mstk = defining;
-
- list->uplevel(defining->nolist ? LIST_MACRO_NOLIST : LIST_MACRO);
- tmp_defining = defining;
- defining = defining->rep_nest;
+ ed = defining;
+ defining = ed->prev;
+ ed->prev = expansions;
+ expansions = ed;
+ ei = new_ExpInv(EXP_REP, ed);
+ ei->current = ed->line;
+ ei->emitting = ((ed->max_depth > 0) ? true : false);
+ list->uplevel(ed->nolist ? LIST_MACRO_NOLIST : LIST_MACRO);
+ ei->prev = istk->expansion;
+ istk->expansion = ei;
free_tlist(origline);
return DIRECTIVE_FOUND;
case PP_EXITREP:
+ if (defining != NULL) return NO_DIRECTIVE_FOUND;
/*
* We must search along istk->expansion until we hit a
- * macro-end marker for a macro with no name. Then we set
- * its `in_progress' flag to 0.
+ * rep invocation. Then we disable the emitting state(s)
+ * between exitrep and endrep.
*/
- list_for_each(l, istk->expansion)
- if (l->finishes && !l->finishes->name)
+ for (ei = istk->expansion; ei != NULL; ei = ei->prev) {
+ if (ei->type == EXP_REP) {
break;
+ }
+ }
- if (l)
- l->finishes->in_progress = 1;
- else
+ if (ei != NULL) {
+ /*
+ * Set all invocations leading back to the rep
+ * invocation to a non-emitting state.
+ */
+ for (eei = istk->expansion; eei != ei; eei = eei->prev) {
+ eei->emitting = false;
+ }
+ eei->emitting = false;
+ eei->current = NULL;
+ eei->def->cur_depth = eei->def->max_depth;
+ } else {
error(ERR_NONFATAL, "`%%exitrep' not within `%%rep' block");
+ }
free_tlist(origline);
return DIRECTIVE_FOUND;
@@ -3028,6 +3177,7 @@ issue_error:
case PP_IXDEFINE:
case PP_DEFINE:
case PP_IDEFINE:
+ if (defining != NULL) return NO_DIRECTIVE_FOUND;
casesense = (i == PP_DEFINE || i == PP_XDEFINE);
tline = tline->next;
@@ -3119,6 +3269,7 @@ issue_error:
return DIRECTIVE_FOUND;
case PP_UNDEF:
+ if (defining != NULL) return NO_DIRECTIVE_FOUND;
tline = tline->next;
skip_white_(tline);
tline = expand_id(tline);
@@ -3142,6 +3293,7 @@ issue_error:
case PP_DEFSTR:
case PP_IDEFSTR:
+ if (defining != NULL) return NO_DIRECTIVE_FOUND;
casesense = (i == PP_DEFSTR);
tline = tline->next;
@@ -3165,11 +3317,9 @@ issue_error:
tline = delete_Token(tline);
p = detoken(tline, false);
- macro_start = nasm_malloc(sizeof(*macro_start));
- macro_start->next = NULL;
+ macro_start = nasm_zalloc(sizeof(*macro_start));
macro_start->text = nasm_quote(p, strlen(p));
macro_start->type = TOK_STRING;
- macro_start->a.mac = NULL;
nasm_free(p);
/*
@@ -3183,6 +3333,7 @@ issue_error:
case PP_DEFTOK:
case PP_IDEFTOK:
+ if (defining != NULL) return NO_DIRECTIVE_FOUND;
casesense = (i == PP_DEFTOK);
tline = tline->next;
@@ -3215,11 +3366,11 @@ issue_error:
return DIRECTIVE_FOUND;
}
- /*
- * Convert the string to a token stream. Note that smacros
- * are stored with the token stream reversed, so we have to
- * reverse the output of tokenize().
- */
+ /*
+ * Convert the string to a token stream. Note that smacros
+ * are stored with the token stream reversed, so we have to
+ * reverse the output of tokenize().
+ */
nasm_unquote_cstr(t->text, i);
macro_start = reverse_tokens(tokenize(t->text));
@@ -3234,6 +3385,7 @@ issue_error:
return DIRECTIVE_FOUND;
case PP_PATHSEARCH:
+ if (defining != NULL) return NO_DIRECTIVE_FOUND;
{
FILE *fp;
StrList *xsl = NULL;
@@ -3280,11 +3432,9 @@ issue_error:
p = xsl->str;
fclose(fp); /* Don't actually care about the file */
}
- macro_start = nasm_malloc(sizeof(*macro_start));
- macro_start->next = NULL;
+ macro_start = nasm_zalloc(sizeof(*macro_start));
macro_start->text = nasm_quote(p, strlen(p));
macro_start->type = TOK_STRING;
- macro_start->a.mac = NULL;
if (xsl)
nasm_free(xsl);
@@ -3300,6 +3450,7 @@ issue_error:
}
case PP_STRLEN:
+ if (defining != NULL) return NO_DIRECTIVE_FOUND;
casesense = true;
tline = tline->next;
@@ -3330,10 +3481,8 @@ issue_error:
return DIRECTIVE_FOUND;
}
- macro_start = nasm_malloc(sizeof(*macro_start));
- macro_start->next = NULL;
+ macro_start = nasm_zalloc(sizeof(*macro_start));
make_tok_num(macro_start, nasm_unquote(t->text, NULL));
- macro_start->a.mac = NULL;
/*
* We now have a macro name, an implicit parameter count of
@@ -3346,6 +3495,7 @@ issue_error:
return DIRECTIVE_FOUND;
case PP_STRCAT:
+ if (defining != NULL) return NO_DIRECTIVE_FOUND;
casesense = true;
tline = tline->next;
@@ -3407,6 +3557,7 @@ issue_error:
return DIRECTIVE_FOUND;
case PP_SUBSTR:
+ if (defining != NULL) return NO_DIRECTIVE_FOUND;
{
int64_t start, count;
size_t len;
@@ -3463,7 +3614,7 @@ issue_error:
while (tok_type_(tt, TOK_WHITESPACE))
tt = tt->next;
if (!tt) {
- count = 1; /* Backwards compatibility: one character */
+ count = 1; /* Backwards compatibility: one character */
} else {
tokval.t_type = TOKEN_INVALID;
evalresult = evaluate(ppscan, tptr, &tokval, NULL,
@@ -3482,7 +3633,6 @@ issue_error:
}
len = nasm_unquote(t->text, NULL);
-
/* make start and count being in range */
if (start < 0)
start = 0;
@@ -3493,11 +3643,9 @@ issue_error:
if (!len || count < 0 || start >=(int64_t)len)
start = -1, count = 0; /* empty string */
- macro_start = nasm_malloc(sizeof(*macro_start));
- macro_start->next = NULL;
+ macro_start = nasm_zalloc(sizeof(*macro_start));
macro_start->text = nasm_quote((start < 0) ? "" : t->text + start, count);
macro_start->type = TOK_STRING;
- macro_start->a.mac = NULL;
/*
* We now have a macro name, an implicit parameter count of
@@ -3512,6 +3660,7 @@ issue_error:
case PP_ASSIGN:
case PP_IASSIGN:
+ if (defining != NULL) return NO_DIRECTIVE_FOUND;
casesense = (i == PP_ASSIGN);
tline = tline->next;
@@ -3554,10 +3703,8 @@ issue_error:
return DIRECTIVE_FOUND;
}
- macro_start = nasm_malloc(sizeof(*macro_start));
- macro_start->next = NULL;
+ macro_start = nasm_zalloc(sizeof(*macro_start));
make_tok_num(macro_start, reloc_value(evalresult));
- macro_start->a.mac = NULL;
/*
* We now have a macro name, an implicit parameter count of
@@ -3569,6 +3716,7 @@ issue_error:
return DIRECTIVE_FOUND;
case PP_LINE:
+ if (defining != NULL) return NO_DIRECTIVE_FOUND;
/*
* Syntax is `%line nnn[+mmm] [filename]'
*/
@@ -3601,6 +3749,160 @@ issue_error:
free_tlist(origline);
return DIRECTIVE_FOUND;
+ case PP_WHILE:
+ if (defining != NULL) {
+ if (defining->type == EXP_WHILE) {
+ defining->def_depth ++;
+ }
+ return NO_DIRECTIVE_FOUND;
+ }
+ l = NULL;
+ if ((istk->expansion != NULL) &&
+ (istk->expansion->emitting == false)) {
+ j = COND_NEVER;
+ } else {
+ l = new_Line();
+ l->first = copy_Token(tline->next);
+ j = if_condition(tline->next, i);
+ tline->next = NULL; /* it got freed */
+ j = (((j < 0) ? COND_NEVER : j) ? COND_IF_TRUE : COND_IF_FALSE);
+ }
+ ed = new_ExpDef(EXP_WHILE);
+ ed->state = j;
+ ed->cur_depth = 1;
+ ed->max_depth = DEADMAN_LIMIT;
+ ed->ignoring = ((ed->state == COND_IF_TRUE) ? false : true);
+ if (ed->ignoring == false) {
+ ed->line = l;
+ ed->last = l;
+ } else if (l != NULL) {
+ delete_Token(l->first);
+ nasm_free(l);
+ l = NULL;
+ }
+ ed->prev = defining;
+ defining = ed;
+ free_tlist(origline);
+ return DIRECTIVE_FOUND;
+
+ case PP_ENDWHILE:
+ if (defining != NULL) {
+ if (defining->type == EXP_WHILE) {
+ if (defining->def_depth > 0) {
+ defining->def_depth --;
+ return NO_DIRECTIVE_FOUND;
+ }
+ } else {
+ return NO_DIRECTIVE_FOUND;
+ }
+ }
+ if (tline->next != NULL) {
+ error_precond(ERR_WARNING|ERR_PASS1,
+ "trailing garbage after `%%endwhile' ignored");
+ }
+ if ((defining == NULL) || (defining->type != EXP_WHILE)) {
+ error(ERR_NONFATAL, "`%%endwhile': no matching `%%while'");
+ return DIRECTIVE_FOUND;
+ }
+ ed = defining;
+ defining = ed->prev;
+ if (ed->ignoring == false) {
+ ed->prev = expansions;
+ expansions = ed;
+ ei = new_ExpInv(EXP_WHILE, ed);
+ ei->current = ed->line->next;
+ ei->emitting = true;
+ ei->prev = istk->expansion;
+ istk->expansion = ei;
+ } else {
+ nasm_free(ed);
+ }
+ free_tlist(origline);
+ return DIRECTIVE_FOUND;
+
+ case PP_EXITWHILE:
+ if (defining != NULL) return NO_DIRECTIVE_FOUND;
+ /*
+ * We must search along istk->expansion until we hit a
+ * while invocation. Then we disable the emitting state(s)
+ * between exitwhile and endwhile.
+ */
+ for (ei = istk->expansion; ei != NULL; ei = ei->prev) {
+ if (ei->type == EXP_WHILE) {
+ break;
+ }
+ }
+
+ if (ei != NULL) {
+ /*
+ * Set all invocations leading back to the while
+ * invocation to a non-emitting state.
+ */
+ for (eei = istk->expansion; eei != ei; eei = eei->prev) {
+ eei->emitting = false;
+ }
+ eei->emitting = false;
+ eei->current = NULL;
+ eei->def->cur_depth = eei->def->max_depth;
+ } else {
+ error(ERR_NONFATAL, "`%%exitwhile' not within `%%while' block");
+ }
+ free_tlist(origline);
+ return DIRECTIVE_FOUND;
+
+ case PP_COMMENT:
+ if (defining != NULL) {
+ if (defining->type == EXP_COMMENT) {
+ defining->def_depth ++;
+ }
+ return NO_DIRECTIVE_FOUND;
+ }
+ ed = new_ExpDef(EXP_COMMENT);
+ ed->ignoring = true;
+ ed->prev = defining;
+ defining = ed;
+ free_tlist(origline);
+ return DIRECTIVE_FOUND;
+
+ case PP_ENDCOMMENT:
+ if (defining != NULL) {
+ if (defining->type == EXP_COMMENT) {
+ if (defining->def_depth > 0) {
+ defining->def_depth --;
+ return NO_DIRECTIVE_FOUND;
+ }
+ } else {
+ return NO_DIRECTIVE_FOUND;
+ }
+ }
+ if ((defining == NULL) || (defining->type != EXP_COMMENT)) {
+ error(ERR_NONFATAL, "`%%endcomment': no matching `%%comment'");
+ return DIRECTIVE_FOUND;
+ }
+ ed = defining;
+ defining = ed->prev;
+ nasm_free(ed);
+ free_tlist(origline);
+ return DIRECTIVE_FOUND;
+
+ case PP_FINAL:
+ if (defining != NULL) return NO_DIRECTIVE_FOUND;
+ if (in_final != false) {
+ error(ERR_FATAL, "`%%final' cannot be used recursively");
+ }
+ tline = tline->next;
+ skip_white_(tline);
+ if (tline == NULL) {
+ error(ERR_NONFATAL, "`%%final' expects at least one parameter");
+ } else {
+ l = new_Line();
+ l->first = copy_Token(tline);
+ l->next = finals;
+ finals = l;
+ }
+ free_tlist(origline);
+ return DIRECTIVE_FOUND;
+
default:
error(ERR_FATAL,
"preprocessor directive `%s' not yet implemented",
@@ -3717,8 +4019,8 @@ static bool paste_tokens(Token **head, const struct tokseq_match *m,
char *tmp, *p;
while (tt && (PP_CONCAT_MASK(tt->type) & m[i].mask_tail)) {
- len += strlen(tt->text);
- tt = tt->next;
+ len += strlen(tt->text);
+ tt = tt->next;
}
/*
@@ -3762,7 +4064,7 @@ static bool paste_tokens(Token **head, const struct tokseq_match *m,
/*
* expands to a list of tokens from %{x:y}
*/
-static Token *expand_mmac_params_range(MMacro *mac, Token *tline, Token ***last)
+static Token *expand_mmac_params_range(ExpInv *ei, Token *tline, Token ***last)
{
Token *t = tline, **tt, *tm, *head;
char *pos;
@@ -3783,12 +4085,12 @@ static Token *expand_mmac_params_range(MMacro *mac, Token *tline, Token ***last)
goto err;
/* the values should be sane */
- if ((fst > (int)mac->nparam || fst < (-(int)mac->nparam)) ||
- (lst > (int)mac->nparam || lst < (-(int)mac->nparam)))
+ if ((fst > (int)ei->nparam || fst < (-(int)ei->nparam)) ||
+ (lst > (int)ei->nparam || lst < (-(int)ei->nparam)))
goto err;
- fst = fst < 0 ? fst + (int)mac->nparam + 1: fst;
- lst = lst < 0 ? lst + (int)mac->nparam + 1: lst;
+ fst = fst < 0 ? fst + (int)ei->nparam + 1: fst;
+ lst = lst < 0 ? lst + (int)ei->nparam + 1: lst;
/* counted from zero */
fst--, lst--;
@@ -3796,15 +4098,15 @@ static Token *expand_mmac_params_range(MMacro *mac, Token *tline, Token ***last)
/*
* it will be at least one token
*/
- tm = mac->params[(fst + mac->rotate) % mac->nparam];
+ tm = ei->params[(fst + ei->rotate) % ei->nparam];
t = new_Token(NULL, tm->type, tm->text, 0);
head = t, tt = &t->next;
if (fst < lst) {
for (i = fst + 1; i <= lst; i++) {
t = new_Token(NULL, TOK_OTHER, ",", 0);
*tt = t, tt = &t->next;
- j = (i + mac->rotate) % mac->nparam;
- tm = mac->params[j];
+ j = (i + ei->rotate) % ei->nparam;
+ tm = ei->params[j];
t = new_Token(NULL, tm->type, tm->text, 0);
*tt = t, tt = &t->next;
}
@@ -3812,8 +4114,8 @@ static Token *expand_mmac_params_range(MMacro *mac, Token *tline, Token ***last)
for (i = fst - 1; i >= lst; i--) {
t = new_Token(NULL, TOK_OTHER, ",", 0);
*tt = t, tt = &t->next;
- j = (i + mac->rotate) % mac->nparam;
- tm = mac->params[j];
+ j = (i + ei->rotate) % ei->nparam;
+ tm = ei->params[j];
t = new_Token(NULL, tm->type, tm->text, 0);
*tt = t, tt = &t->next;
}
@@ -3852,15 +4154,17 @@ static Token *expand_mmac_params(Token * tline)
char tmpbuf[30];
unsigned int n;
int i;
- MMacro *mac;
+ ExpInv *ei;
t = tline;
tline = tline->next;
- mac = istk->mstk;
- while (mac && !mac->name) /* avoid mistaking %reps for macros */
- mac = mac->next_active;
- if (!mac) {
+ for (ei = istk->expansion; ei != NULL; ei = ei->prev) {
+ if (ei->type == EXP_MMACRO) {
+ break;
+ }
+ }
+ if (ei == NULL) {
error(ERR_NONFATAL, "`%s': not in a macro call", t->text);
} else {
pos = strchr(t->text, ':');
@@ -3871,24 +4175,29 @@ static Token *expand_mmac_params(Token * tline)
* forms %1, %-1, %+1, %%foo, %0.
*/
case '0':
- type = TOK_NUMBER;
- snprintf(tmpbuf, sizeof(tmpbuf), "%d", mac->nparam);
- text = nasm_strdup(tmpbuf);
+ if ((strlen(t->text) > 2) && (t->text[2] == '0')) {
+ type = TOK_ID;
+ text = nasm_strdup(ei->label_text);
+ } else {
+ type = TOK_NUMBER;
+ snprintf(tmpbuf, sizeof(tmpbuf), "%d", ei->nparam);
+ text = nasm_strdup(tmpbuf);
+ }
break;
case '%':
type = TOK_ID;
snprintf(tmpbuf, sizeof(tmpbuf), "..@%"PRIu64".",
- mac->unique);
+ ei->unique);
text = nasm_strcat(tmpbuf, t->text + 2);
break;
case '-':
n = atoi(t->text + 2) - 1;
- if (n >= mac->nparam)
+ if (n >= ei->nparam)
tt = NULL;
else {
- if (mac->nparam > 1)
- n = (n + mac->rotate) % mac->nparam;
- tt = mac->params[n];
+ if (ei->nparam > 1)
+ n = (n + ei->rotate) % ei->nparam;
+ tt = ei->params[n];
}
cc = find_cc(tt);
if (cc == -1) {
@@ -3909,12 +4218,12 @@ static Token *expand_mmac_params(Token * tline)
break;
case '+':
n = atoi(t->text + 2) - 1;
- if (n >= mac->nparam)
+ if (n >= ei->nparam)
tt = NULL;
else {
- if (mac->nparam > 1)
- n = (n + mac->rotate) % mac->nparam;
- tt = mac->params[n];
+ if (ei->nparam > 1)
+ n = (n + ei->rotate) % ei->nparam;
+ tt = ei->params[n];
}
cc = find_cc(tt);
if (cc == -1) {
@@ -3929,15 +4238,15 @@ static Token *expand_mmac_params(Token * tline)
break;
default:
n = atoi(t->text + 1) - 1;
- if (n >= mac->nparam)
+ if (n >= ei->nparam)
tt = NULL;
else {
- if (mac->nparam > 1)
- n = (n + mac->rotate) % mac->nparam;
- tt = mac->params[n];
+ if (ei->nparam > 1)
+ n = (n + ei->rotate) % ei->nparam;
+ tt = ei->params[n];
}
if (tt) {
- for (i = 0; i < mac->paramlen[n]; i++) {
+ for (i = 0; i < ei->paramlen[n]; i++) {
*tail = new_Token(NULL, tt->type, tt->text, 0);
tail = &(*tail)->next;
tt = tt->next;
@@ -3951,7 +4260,7 @@ static Token *expand_mmac_params(Token * tline)
* seems we have a parameters range here
*/
Token *head, **last;
- head = expand_mmac_params_range(mac, t, &last);
+ head = expand_mmac_params_range(ei, t, &last);
if (head != t) {
*tail = head;
*last = tline;
@@ -4069,7 +4378,7 @@ again:
if (tline->type == TOK_ID) {
head = (SMacro *)hash_findix(&smacros, mname);
} else if (tline->type == TOK_PREPROC_ID) {
- ctx = get_ctx(mname, &mname, true);
+ ctx = get_ctx(mname, &mname, false);
head = ctx ? (SMacro *)hash_findix(&ctx->localmac, mname) : NULL;
} else
head = NULL;
@@ -4422,30 +4731,30 @@ static Token *expand_id(Token * tline)
/*
* Determine whether the given line constitutes a multi-line macro
- * call, and return the MMacro structure called if so. Doesn't have
+ * call, and return the ExpDef structure called if so. Doesn't have
* to check for an initial label - that's taken care of in
* expand_mmacro - but must check numbers of parameters. Guaranteed
* to be called with tline->type == TOK_ID, so the putative macro
* name is easy to find.
*/
-static MMacro *is_mmacro(Token * tline, Token *** params_array)
+static ExpDef *is_mmacro(Token * tline, Token *** params_array)
{
- MMacro *head, *m;
+ ExpDef *head, *ed;
Token **params;
int nparam;
- head = (MMacro *) hash_findix(&mmacros, tline->text);
+ head = (ExpDef *) hash_findix(&expdefs, tline->text);
/*
* Efficiency: first we see if any macro exists with the given
* name. If not, we can return NULL immediately. _Then_ we
* count the parameters, and then we look further along the
- * list if necessary to find the proper MMacro.
+ * list if necessary to find the proper ExpDef.
*/
- list_for_each(m, head)
- if (!mstrcmp(m->name, tline->text, m->casesense))
+ list_for_each(ed, head)
+ if (!mstrcmp(ed->name, tline->text, ed->casesense))
break;
- if (!m)
+ if (!ed)
return NULL;
/*
@@ -4455,36 +4764,23 @@ static MMacro *is_mmacro(Token * tline, Token *** params_array)
count_mmac_params(tline->next, &nparam, &params);
/*
- * So we know how many parameters we've got. Find the MMacro
+ * So we know how many parameters we've got. Find the ExpDef
* structure that handles this number.
*/
- while (m) {
- if (m->nparam_min <= nparam
- && (m->plus || nparam <= m->nparam_max)) {
- /*
- * This one is right. Just check if cycle removal
- * prohibits us using it before we actually celebrate...
- */
- if (m->in_progress > m->max_depth) {
- if (m->max_depth > 0) {
- error(ERR_WARNING,
- "reached maximum recursion depth of %i",
- m->max_depth);
- }
- nasm_free(params);
- return NULL;
- }
+ while (ed) {
+ if (ed->nparam_min <= nparam
+ && (ed->plus || nparam <= ed->nparam_max)) {
/*
* It's right, and we can use it. Add its default
* parameters to the end of our list if necessary.
*/
- if (m->defaults && nparam < m->nparam_min + m->ndefs) {
+ if (ed->defaults && nparam < ed->nparam_min + ed->ndefs) {
params =
nasm_realloc(params,
- ((m->nparam_min + m->ndefs +
+ ((ed->nparam_min + ed->ndefs +
1) * sizeof(*params)));
- while (nparam < m->nparam_min + m->ndefs) {
- params[nparam] = m->defaults[nparam - m->nparam_min];
+ while (nparam < ed->nparam_min + ed->ndefs) {
+ params[nparam] = ed->defaults[nparam - ed->nparam_min];
nparam++;
}
}
@@ -4493,8 +4789,8 @@ static MMacro *is_mmacro(Token * tline, Token *** params_array)
* we're in Plus mode), ignore parameters beyond
* nparam_max.
*/
- if (m->plus && nparam > m->nparam_max)
- nparam = m->nparam_max;
+ if (ed->plus && nparam > ed->nparam_max)
+ nparam = ed->nparam_max;
/*
* Then terminate the parameter list, and leave.
*/
@@ -4504,14 +4800,14 @@ static MMacro *is_mmacro(Token * tline, Token *** params_array)
}
params[nparam] = NULL;
*params_array = params;
- return m;
+ return ed;
}
/*
* This one wasn't right: look for the next one with the
* same name.
*/
- list_for_each(m, m->next)
- if (!mstrcmp(m->name, tline->text, m->casesense))
+ list_for_each(ed, ed->next)
+ if (!mstrcmp(ed->name, tline->text, ed->casesense))
break;
}
@@ -4526,64 +4822,19 @@ static MMacro *is_mmacro(Token * tline, Token *** params_array)
return NULL;
}
-
-/*
- * Save MMacro invocation specific fields in
- * preparation for a recursive macro expansion
- */
-static void push_mmacro(MMacro *m)
-{
- MMacroInvocation *i;
-
- i = nasm_malloc(sizeof(MMacroInvocation));
- i->prev = m->prev;
- i->params = m->params;
- i->iline = m->iline;
- i->nparam = m->nparam;
- i->rotate = m->rotate;
- i->paramlen = m->paramlen;
- i->unique = m->unique;
- i->condcnt = m->condcnt;
- m->prev = i;
-}
-
-
-/*
- * Restore MMacro invocation specific fields that were
- * saved during a previous recursive macro expansion
- */
-static void pop_mmacro(MMacro *m)
-{
- MMacroInvocation *i;
-
- if (m->prev) {
- i = m->prev;
- m->prev = i->prev;
- m->params = i->params;
- m->iline = i->iline;
- m->nparam = i->nparam;
- m->rotate = i->rotate;
- m->paramlen = i->paramlen;
- m->unique = i->unique;
- m->condcnt = i->condcnt;
- nasm_free(i);
- }
-}
-
-
/*
* Expand the multi-line macro call made by the given line, if
* there is one to be expanded. If there is, push the expansion on
- * istk->expansion and return 1. Otherwise return 0.
+ * istk->expansion and return true. Otherwise return false.
*/
-static int expand_mmacro(Token * tline)
+static bool expand_mmacro(Token * tline)
{
- Token *startline = tline;
Token *label = NULL;
int dont_prepend = 0;
- Token **params, *t, *mtok, *tt;
- MMacro *m;
- Line *l, *ll;
+ Token **params, *t, *mtok;
+ Line *l = NULL;
+ ExpDef *ed;
+ ExpInv *ei;
int i, nparam, *paramlen;
const char *mname;
@@ -4591,10 +4842,10 @@ static int expand_mmacro(Token * tline)
skip_white_(t);
/* if (!tok_type_(t, TOK_ID)) Lino 02/25/02 */
if (!tok_type_(t, TOK_ID) && !tok_type_(t, TOK_PREPROC_ID))
- return 0;
+ return false;
mtok = t;
- m = is_mmacro(t, &params);
- if (m) {
+ ed = is_mmacro(t, &params);
+ if (ed != NULL) {
mname = t->text;
} else {
Token *last;
@@ -4614,8 +4865,8 @@ static int expand_mmacro(Token * tline)
if (tok_type_(t, TOK_WHITESPACE))
last = t, t = t->next;
}
- if (!tok_type_(t, TOK_ID) || !(m = is_mmacro(t, &params)))
- return 0;
+ if (!tok_type_(t, TOK_ID) || !(ed = is_mmacro(t, &params)))
+ return false;
last->next = NULL;
mname = t->text;
tline = t;
@@ -4631,7 +4882,7 @@ static int expand_mmacro(Token * tline)
for (i = 0; params[i]; i++) {
int brace = false;
- int comma = (!m->plus || i < nparam - 1);
+ int comma = (!ed->plus || i < nparam - 1);
t = params[i];
skip_white_(t);
@@ -4652,127 +4903,111 @@ static int expand_mmacro(Token * tline)
}
}
+ if (ed->cur_depth >= ed->max_depth) {
+ if (ed->max_depth > 1) {
+ error(ERR_WARNING,
+ "reached maximum macro recursion depth of %i for %s",
+ ed->max_depth,ed->name);
+ }
+ return false;
+ } else {
+ ed->cur_depth ++;
+ }
+
/*
- * OK, we have a MMacro structure together with a set of
- * parameters. We must now go through the expansion and push
- * copies of each Line on to istk->expansion. Substitution of
+ * OK, we have found a ExpDef structure representing a
+ * previously defined mmacro. Create an expansion invocation
+ * and point it back to the expansion definition. Substitution of
* parameter tokens and macro-local tokens doesn't get done
* until the single-line macro substitution process; this is
* because delaying them allows us to change the semantics
* later through %rotate.
- *
- * First, push an end marker on to istk->expansion, mark this
- * macro as in progress, and set up its invocation-specific
- * variables.
*/
- ll = nasm_malloc(sizeof(Line));
- ll->next = istk->expansion;
- ll->finishes = m;
- ll->first = NULL;
- istk->expansion = ll;
+ ei = new_ExpInv(EXP_MMACRO, ed);
+ ei->name = nasm_strdup(mname);
+ //ei->label = label;
+ //ei->label_text = detoken(label, false);
+ ei->current = ed->line;
+ ei->emitting = true;
+ //ei->iline = tline;
+ ei->params = params;
+ ei->nparam = nparam;
+ ei->rotate = 0;
+ ei->paramlen = paramlen;
+ ei->lineno = 0;
+
+ ei->prev = istk->expansion;
+ istk->expansion = ei;
/*
- * Save the previous MMacro expansion in the case of
- * macro recursion
+ * Special case: detect %00 on first invocation; if found,
+ * avoid emitting any labels that precede the mmacro call.
+ * ed->prepend is set to -1 when %00 is detected, else 1.
*/
- if (m->max_depth && m->in_progress)
- push_mmacro(m);
-
- m->in_progress ++;
- m->params = params;
- m->iline = tline;
- m->nparam = nparam;
- m->rotate = 0;
- m->paramlen = paramlen;
- m->unique = unique++;
- m->lineno = 0;
- m->condcnt = 0;
-
- m->next_active = istk->mstk;
- istk->mstk = m;
-
- list_for_each(l, m->expansion) {
- Token **tail;
-
- ll = nasm_malloc(sizeof(Line));
- ll->finishes = NULL;
- ll->next = istk->expansion;
- istk->expansion = ll;
- tail = &ll->first;
-
- list_for_each(t, l->first) {
- Token *x = t;
- switch (t->type) {
- case TOK_PREPROC_Q:
- tt = *tail = new_Token(NULL, TOK_ID, mname, 0);
- break;
- case TOK_PREPROC_QQ:
- tt = *tail = new_Token(NULL, TOK_ID, m->name, 0);
- break;
- case TOK_PREPROC_ID:
- if (t->text[1] == '0' && t->text[2] == '0') {
+ if (ed->prepend == 0) {
+ for (l = ed->line; l != NULL; l = l->next) {
+ for (t = l->first; t != NULL; t = t->next) {
+ if ((t->type == TOK_PREPROC_ID) &&
+ (strlen(t->text) == 3) &&
+ (t->text[1] == '0') && (t->text[2] == '0')) {
dont_prepend = -1;
- x = label;
- if (!x)
- continue;
+ break;
}
- /* fall through */
- default:
- tt = *tail = new_Token(NULL, x->type, x->text, 0);
+ }
+ if (dont_prepend < 0) {
break;
}
- tail = &tt->next;
}
- *tail = NULL;
+ ed->prepend = ((dont_prepend < 0) ? -1 : 1);
}
/*
* If we had a label, push it on as the first line of
* the macro expansion.
*/
- if (label) {
- if (dont_prepend < 0)
- free_tlist(startline);
- else {
- ll = nasm_malloc(sizeof(Line));
- ll->finishes = NULL;
- ll->next = istk->expansion;
- istk->expansion = ll;
- ll->first = startline;
- if (!dont_prepend) {
- while (label->next)
- label = label->next;
- label->next = tt = new_Token(NULL, TOK_OTHER, ":", 0);
+ if (label != NULL) {
+ if (ed->prepend < 0) {
+ ei->label_text = detoken(label, false);
+ } else {
+ if (dont_prepend == 0) {
+ t = label;
+ while (t->next != NULL) {
+ t = t->next;
+ }
+ t->next = new_Token(NULL, TOK_OTHER, ":", 0);
}
+ l = new_Line();
+ l->first = copy_Token(label);
+ l->next = ei->current;
+ ei->current = l;
}
}
- list->uplevel(m->nolist ? LIST_MACRO_NOLIST : LIST_MACRO);
+ list->uplevel(ed->nolist ? LIST_MACRO_NOLIST : LIST_MACRO);
- return 1;
+ istk->mmac_depth++;
+ return true;
}
/* The function that actually does the error reporting */
static void verror(int severity, const char *fmt, va_list arg)
{
char buff[1024];
- MMacro *mmac = NULL;
- int delta = 0;
vsnprintf(buff, sizeof(buff), fmt, arg);
- /* get %macro name */
- if (istk && istk->mstk) {
- mmac = istk->mstk;
- /* but %rep blocks should be skipped */
- while (mmac && !mmac->name)
- mmac = mmac->next_active, delta++;
- }
-
- if (mmac)
- nasm_error(severity, "(%s:%d) %s",
- mmac->name, mmac->lineno - delta, buff);
- else
+ if (istk && istk->mmac_depth > 0) {
+ ExpInv *ei = istk->expansion;
+ int lineno = ei->lineno;
+ while (ei) {
+ if (ei->type == EXP_MMACRO)
+ break;
+ lineno += ei->relno;
+ ei = ei->prev;
+ }
+ nasm_error(severity, "(%s:%d) %s", ei->def->name,
+ lineno, buff);
+ } else
nasm_error(severity, "%s", buff);
}
@@ -4783,11 +5018,6 @@ static void verror(int severity, const char *fmt, va_list arg)
static void error(int severity, const char *fmt, ...)
{
va_list arg;
-
- /* If we're in a dead branch of IF or something like it, ignore the error */
- if (istk && istk->conds && !emitting(istk->conds->state))
- return;
-
va_start(arg, fmt);
verror(severity, fmt, arg);
va_end(arg);
@@ -4804,7 +5034,10 @@ static void error_precond(int severity, const char *fmt, ...)
va_list arg;
/* Only ignore the error if it's really in a dead branch */
- if (istk && istk->conds && istk->conds->state == COND_NEVER)
+ if ((istk != NULL) &&
+ (istk->expansion != NULL) &&
+ (istk->expansion->type == EXP_IF) &&
+ (istk->expansion->def->state == COND_NEVER))
return;
va_start(arg, fmt);
@@ -4818,13 +5051,8 @@ pp_reset(char *file, int apass, ListGen * listgen, StrList **deplist)
Token *t;
cstk = NULL;
- istk = nasm_malloc(sizeof(Include));
- istk->next = NULL;
- istk->conds = NULL;
- istk->expansion = NULL;
- istk->mstk = NULL;
+ istk = nasm_zalloc(sizeof(Include));
istk->fp = fopen(file, "r");
- istk->fname = NULL;
src_set_fname(nasm_strdup(file));
src_set_linnum(0);
istk->lineinc = 1;
@@ -4832,6 +5060,8 @@ pp_reset(char *file, int apass, ListGen * listgen, StrList **deplist)
error(ERR_FATAL|ERR_NOFILE, "unable to open input file `%s'",
file);
defining = NULL;
+ finals = NULL;
+ in_final = false;
nested_mac_count = 0;
nested_rep_count = 0;
init_macros();
@@ -4866,10 +5096,8 @@ pp_reset(char *file, int apass, ListGen * listgen, StrList **deplist)
* all the other builtins, because it is special -- it varies between
* passes.
*/
- t = nasm_malloc(sizeof(*t));
- t->next = NULL;
+ t = nasm_zalloc(sizeof(*t));
make_tok_num(t, apass);
- t->a.mac = NULL;
define_smacro(NULL, "__PASS__", true, 0, t);
}
@@ -4877,114 +5105,104 @@ static char *pp_getline(void)
{
char *line;
Token *tline;
+ ExpDef *ed;
+ ExpInv *ei;
+ Line *l;
+ int j;
while (1) {
/*
- * Fetch a tokenized line, either from the macro-expansion
+ * Fetch a tokenized line, either from the expansion
* buffer or from the input file.
*/
tline = NULL;
- while (istk->expansion && istk->expansion->finishes) {
- Line *l = istk->expansion;
- if (!l->finishes->name && l->finishes->in_progress > 1) {
- Line *ll;
- /*
- * This is a macro-end marker for a macro with no
- * name, which means it's not really a macro at all
- * but a %rep block, and the `in_progress' field is
- * more than 1, meaning that we still need to
- * repeat. (1 means the natural last repetition; 0
- * means termination by %exitrep.) We have
- * therefore expanded up to the %endrep, and must
- * push the whole block on to the expansion buffer
- * again. We don't bother to remove the macro-end
- * marker: we'd only have to generate another one
- * if we did.
- */
- l->finishes->in_progress--;
- list_for_each(l, l->finishes->expansion) {
- Token *t, *tt, **tail;
-
- ll = nasm_malloc(sizeof(Line));
- ll->next = istk->expansion;
- ll->finishes = NULL;
- ll->first = NULL;
- tail = &ll->first;
-
- list_for_each(t, l->first) {
- if (t->text || t->type == TOK_WHITESPACE) {
- tt = *tail = new_Token(NULL, t->type, t->text, 0);
- tail = &tt->next;
- }
+ while (1) { /* until we get a line we can use */
+ /*
+ * Fetch a tokenized line from the expansion buffer
+ */
+ if (istk->expansion != NULL) {
+ ei = istk->expansion;
+ if (ei->current != NULL) {
+ if (ei->emitting == false) {
+ ei->current = NULL;
+ continue;
}
-
- istk->expansion = ll;
- }
- } else {
- /*
- * Check whether a `%rep' was started and not ended
- * within this macro expansion. This can happen and
- * should be detected. It's a fatal error because
- * I'm too confused to work out how to recover
- * sensibly from it.
- */
- if (defining) {
- if (defining->name)
- error(ERR_PANIC,
- "defining with name in expansion");
- else if (istk->mstk->name)
- error(ERR_FATAL,
- "`%%rep' without `%%endrep' within"
- " expansion of macro `%s'",
- istk->mstk->name);
- }
-
- /*
- * FIXME: investigate the relationship at this point between
- * istk->mstk and l->finishes
- */
- {
- MMacro *m = istk->mstk;
- istk->mstk = m->next_active;
- if (m->name) {
- /*
- * This was a real macro call, not a %rep, and
- * therefore the parameter information needs to
- * be freed.
- */
- if (m->prev) {
- pop_mmacro(m);
- l->finishes->in_progress --;
- } else {
- nasm_free(m->params);
- free_tlist(m->iline);
- nasm_free(m->paramlen);
- l->finishes->in_progress = 0;
+ l = ei->current;
+ ei->current = l->next;
+ ei->lineno++;
+ tline = copy_Token(l->first);
+ if (((ei->type == EXP_REP) ||
+ (ei->type == EXP_MMACRO) ||
+ (ei->type == EXP_WHILE))
+ && (ei->def->nolist == false)) {
+ char *p = detoken(tline, false);
+ list->line(LIST_MACRO, p);
+ nasm_free(p);
+ }
+ if (ei->linnum > -1) {
+ src_set_linnum(src_get_linnum() + 1);
+ }
+ break;
+ } else if ((ei->type == EXP_REP) &&
+ (ei->def->cur_depth < ei->def->max_depth)) {
+ ei->def->cur_depth ++;
+ ei->current = ei->def->line;
+ ei->lineno = 0;
+ continue;
+ } else if ((ei->type == EXP_WHILE) &&
+ (ei->def->cur_depth < ei->def->max_depth)) {
+ ei->current = ei->def->line;
+ ei->lineno = 0;
+ tline = copy_Token(ei->current->first);
+ j = if_condition(tline, PP_WHILE);
+ tline = NULL;
+ j = (((j < 0) ? COND_NEVER : j) ? COND_IF_TRUE : COND_IF_FALSE);
+ if (j == COND_IF_TRUE) {
+ ei->current = ei->current->next;
+ ei->def->cur_depth ++;
+ } else {
+ ei->emitting = false;
+ ei->current = NULL;
+ ei->def->cur_depth = ei->def->max_depth;
+ }
+ continue;
+ } else {
+ istk->expansion = ei->prev;
+ ed = ei->def;
+ if (ed != NULL) {
+ if ((ei->emitting == true) &&
+ (ed->max_depth == DEADMAN_LIMIT) &&
+ (ed->cur_depth == DEADMAN_LIMIT)
+ ) {
+ error(ERR_FATAL, "runaway expansion detected, aborting");
}
- } else
- free_mmacro(m);
+ if (ed->cur_depth > 0) {
+ ed->cur_depth --;
+ } else if (ed->type != EXP_MMACRO) {
+ expansions = ed->prev;
+ free_expdef(ed);
+ }
+ if ((ei->type == EXP_REP) ||
+ (ei->type == EXP_MMACRO) ||
+ (ei->type == EXP_WHILE)) {
+ list->downlevel(LIST_MACRO);
+ if (ei->type == EXP_MMACRO) {
+ istk->mmac_depth--;
+ }
+ }
+ }
+ if (ei->linnum > -1) {
+ src_set_linnum(ei->linnum);
+ }
+ free_expinv(ei);
+ continue;
}
- istk->expansion = l->next;
- nasm_free(l);
- list->downlevel(LIST_MACRO);
}
- }
- while (1) { /* until we get a line we can use */
- if (istk->expansion) { /* from a macro expansion */
- char *p;
- Line *l = istk->expansion;
- if (istk->mstk)
- istk->mstk->lineno++;
- tline = l->first;
- istk->expansion = l->next;
- nasm_free(l);
- p = detoken(tline, false);
- list->line(LIST_MACRO, p);
- nasm_free(p);
- break;
- }
+ /*
+ * Read in line from input and tokenize
+ */
line = read_line();
if (line) { /* from the current input file */
line = prepreproc(line);
@@ -4992,44 +5210,46 @@ static char *pp_getline(void)
nasm_free(line);
break;
}
+
/*
* The current file has ended; work down the istk
*/
{
Include *i = istk;
fclose(i->fp);
- if (i->conds) {
- /* nasm_error can't be conditionally suppressed */
- nasm_error(ERR_FATAL,
- "expected `%%endif' before end of file");
+ if (i->expansion != NULL) {
+ error(ERR_FATAL,
+ "end of file while still in an expansion");
}
/* only set line and file name if there's a next node */
if (i->next) {
src_set_linnum(i->lineno);
nasm_free(src_set_fname(nasm_strdup(i->fname)));
}
+ if ((i->next == NULL) && (finals != NULL)) {
+ in_final = true;
+ ei = new_ExpInv(EXP_FINAL, NULL);
+ ei->emitting = true;
+ ei->current = finals;
+ istk->expansion = ei;
+ finals = NULL;
+ continue;
+ }
istk = i->next;
list->downlevel(LIST_INCLUDE);
nasm_free(i);
- if (!istk)
- return NULL;
- if (istk->expansion && istk->expansion->finishes)
- break;
+ if (istk == NULL) {
+ if (finals != NULL) {
+ in_final = true;
+ } else {
+ return NULL;
+ }
+ }
+ continue;
}
}
- /*
- * We must expand MMacro parameters and MMacro-local labels
- * _before_ we plunge into directive processing, to cope
- * with things like `%define something %1' such as STRUC
- * uses. Unless we're _defining_ a MMacro, in which case
- * those tokens should be left alone to go into the
- * definition; and unless we're in a non-emitting
- * condition, in which case we don't want to meddle with
- * anything.
- */
- if (!defining && !(istk->conds && !emitting(istk->conds->state))
- && !(istk->mstk && !istk->mstk->in_progress)) {
+ if (defining == NULL) {
tline = expand_mmac_params(tline);
}
@@ -5038,41 +5258,39 @@ static char *pp_getline(void)
*/
if (do_directive(tline) == DIRECTIVE_FOUND) {
continue;
- } else if (defining) {
+ } else if (defining != NULL) {
/*
- * We're defining a multi-line macro. We emit nothing
- * at all, and just
- * shove the tokenized line on to the macro definition.
+ * We're defining an expansion. We emit nothing at all,
+ * and just shove the tokenized line on to the definition.
*/
- Line *l = nasm_malloc(sizeof(Line));
- l->next = defining->expansion;
- l->first = tline;
- l->finishes = NULL;
- defining->expansion = l;
+ if (defining->ignoring == false) {
+ Line *l = new_Line();
+ l->first = tline;
+ if (defining->line == NULL) {
+ defining->line = l;
+ defining->last = l;
+ } else {
+ defining->last->next = l;
+ defining->last = l;
+ }
+ } else {
+ free_tlist(tline);
+ }
+ defining->linecount++;
continue;
- } else if (istk->conds && !emitting(istk->conds->state)) {
+ } else if ((istk->expansion != NULL) &&
+ (istk->expansion->emitting != true)) {
/*
- * We're in a non-emitting branch of a condition block.
+ * We're in a non-emitting branch of an expansion.
* Emit nothing at all, not even a blank line: when we
- * emerge from the condition we'll give a line-number
+ * emerge from the expansion we'll give a line-number
* directive so we keep our place correctly.
*/
free_tlist(tline);
continue;
- } else if (istk->mstk && !istk->mstk->in_progress) {
- /*
- * We're in a %rep block which has been terminated, so
- * we're walking through to the %endrep without
- * emitting anything. Emit nothing at all, not even a
- * blank line: when we emerge from the %rep block we'll
- * give a line-number directive so we keep our place
- * correctly.
- */
- free_tlist(tline);
- continue;
} else {
tline = expand_smacro(tline);
- if (!expand_mmacro(tline)) {
+ if (expand_mmacro(tline) != true) {
/*
* De-tokenize the line again, and emit it.
*/
@@ -5080,36 +5298,37 @@ static char *pp_getline(void)
free_tlist(tline);
break;
} else {
- continue; /* expand_mmacro calls free_tlist */
+ continue;
}
}
}
-
return line;
}
static void pp_cleanup(int pass)
{
- if (defining) {
- if (defining->name) {
- error(ERR_NONFATAL,
- "end of file while still defining macro `%s'",
- defining->name);
- } else {
- error(ERR_NONFATAL, "end of file while still in %%rep");
+ if (defining != NULL) {
+ error(ERR_NONFATAL, "end of file while still defining an expansion");
+ while (defining != NULL) {
+ ExpDef *ed = defining;
+ defining = ed->prev;
+ free_expdef(ed);
}
-
- free_mmacro(defining);
defining = NULL;
}
- while (cstk)
+ while (cstk != NULL)
ctx_pop();
free_macros();
- while (istk) {
+ while (istk != NULL) {
Include *i = istk;
istk = istk->next;
fclose(i->fp);
nasm_free(i->fname);
+ while (i->expansion != NULL) {
+ ExpInv *ei = i->expansion;
+ i->expansion = ei->prev;
+ free_expinv(ei);
+ }
nasm_free(i);
}
while (cstk)
@@ -5130,11 +5349,10 @@ static void pp_cleanup(int pass)
void pp_include_path(char *path)
{
- IncPath *i;
+ IncPath *i = nasm_zalloc(sizeof(IncPath));
- i = nasm_malloc(sizeof(IncPath));
- i->path = path ? nasm_strdup(path) : NULL;
- i->next = NULL;
+ if (path)
+ i->path = nasm_strdup(path);
if (ipath) {
IncPath *j = ipath;
@@ -5155,10 +5373,9 @@ void pp_pre_include(char *fname)
space = new_Token(name, TOK_WHITESPACE, NULL, 0);
inc = new_Token(space, TOK_PREPROC_ID, "%include", 0);
- l = nasm_malloc(sizeof(Line));
+ l = new_Line();
l->next = predef;
l->first = inc;
- l->finishes = NULL;
predef = l;
}
@@ -5177,10 +5394,9 @@ void pp_pre_define(char *definition)
if (equals)
*equals = '=';
- l = nasm_malloc(sizeof(Line));
+ l = new_Line();
l->next = predef;
l->first = def;
- l->finishes = NULL;
predef = l;
}
@@ -5193,18 +5409,15 @@ void pp_pre_undefine(char *definition)
def = new_Token(space, TOK_PREPROC_ID, "%undef", 0);
space->next = tokenize(definition);
- l = nasm_malloc(sizeof(Line));
+ l = new_Line();
l->next = predef;
l->first = def;
- l->finishes = NULL;
predef = l;
}
/*
- * Added by Keith Kanios:
- *
* This function is used to assist with "runtime" preprocessor
- * directives. (e.g. pp_runtime("%define __BITS__ 64");)
+ * directives, e.g. pp_runtime("%define __BITS__ 64");
*
* ERRORS ARE IGNORED HERE, SO MAKE COMPLETELY SURE THAT YOU
* PASS A VALID STRING TO THIS FUNCTION!!!!!
diff --git a/test/align13.asm b/test/align13.asm
index 556373fc..4a41a779 100644
--- a/test/align13.asm
+++ b/test/align13.asm
@@ -1,3 +1,6 @@
+;Testname=unoptimized; Arguments=-O0 -fbin -oalign13.bin; Files=stdout stderr align13.bin
+;Testname=optimized; Arguments=-Ox -fbin -oalign13.bin; Files=stdout stderr align13.bin
+
; Test of non-power-of-2 alignment
bits 32
diff --git a/test/align13s.asm b/test/align13s.asm
index dab21a20..7f783175 100644
--- a/test/align13s.asm
+++ b/test/align13s.asm
@@ -1,4 +1,8 @@
+;Testname=unoptimized; Arguments=-O0 -fbin -oalign13s.bin; Files=stdout stderr align13s.bin
+;Testname=optimized; Arguments=-Ox -fbin -oalign13s.bin; Files=stdout stderr align13s.bin
+
; Test of non-power-of-2 alignment
+
%use smartalign
bits 32
diff --git a/test/alonesym-obj.asm b/test/alonesym-obj.asm
index 6be4d5db..8db3a2c4 100644
--- a/test/alonesym-obj.asm
+++ b/test/alonesym-obj.asm
@@ -1,3 +1,6 @@
+;Testname=unoptimized; Arguments=-O0 -fobj -oalonesym-obj.obj; Files=stdout stderr alonesym-obj.obj
+;Testname=optimized; Arguments=-Ox -fobj -oalonesym-obj.obj; Files=stdout stderr alonesym-obj.obj
+
section DOS32DATA align=16 public use32 FLAT class=DOS32DATA
global sym0000
diff --git a/test/bcd.asm b/test/bcd.asm
index bb45ca64..b58d81aa 100644
--- a/test/bcd.asm
+++ b/test/bcd.asm
@@ -1,3 +1,5 @@
+;Testname=optimized; Arguments=-Ox -fbin -obcd.bin; Files=stdout stderr bcd.bin
+
dt 765432109876543210p
dt -765432109876543210p
dt +765432109876543210p
diff --git a/test/br2003451.asm b/test/br2003451.asm
index fb309a99..74e32345 100644
--- a/test/br2003451.asm
+++ b/test/br2003451.asm
@@ -1,3 +1,5 @@
+;Testname=optimized; Arguments=-Ox -fbin -obr2003451.bin; Files=stdout stderr br2003451.bin
+
cpu 8086
org 0
diff --git a/test/br2030823.asm b/test/br2030823.asm
index ce7ba43d..fd8f5eba 100644
--- a/test/br2030823.asm
+++ b/test/br2030823.asm
@@ -1,4 +1,6 @@
- bits 64
+;Testname=optimized; Arguments=-Ox -fbin -obr2030823.bin; Files=stdout stderr br2030823.bin
+
+bits 64
VFMADDPD xmm0, xmm1, [0], xmm3
VFMADDPD xmm0, xmm1, xmm2, [0]
VFMADDPD ymm0, ymm1, [0], ymm3
diff --git a/test/br3005117.asm b/test/br3005117.asm
index 4e7a5b5b..66a46f8f 100644
--- a/test/br3005117.asm
+++ b/test/br3005117.asm
@@ -1,3 +1,5 @@
+;Testname=br3005117; Arguments=-Ox -felf -obr3005117.o; Files=stdout stderr br3005117.o
+
%macro B_STRUC 1-*
%push foo
%define %$strucname %1
diff --git a/test/br3026808.asm b/test/br3026808.asm
index 5c61c953..d84923a1 100644
--- a/test/br3026808.asm
+++ b/test/br3026808.asm
@@ -1,3 +1,5 @@
+;Testname=br3026808; Arguments=-Ox -fbin -obr3026808.o; Files=stdout stderr br3026808.o
+
%imacro proc 1
%push proc
%assign %$arg 1
diff --git a/test/br3028880.asm b/test/br3028880.asm
index 20c8bd09..b6b2cf2b 100644
--- a/test/br3028880.asm
+++ b/test/br3028880.asm
@@ -1,3 +1,5 @@
+;Testname=br3028880; Arguments=-Ox -fbin -obr3028880.o; Files=stdout stderr br3028880.o
+
%macro import 1
%define %%incfile %!PROJECTBASEDIR/%{1}.inc
%endmacro
diff --git a/test/br3058845.asm b/test/br3058845.asm
index b0de5607..c42f5d50 100644
--- a/test/br3058845.asm
+++ b/test/br3058845.asm
@@ -11,4 +11,4 @@ cmp eax, 0xFFFF_FFFF
BITS 64
cmp ax, 0xFFFF
-cmp eax, 0xFFFF_FFFF ; shouldn't warn, but does currently
+cmp eax, 0xFFFF_FFFF
diff --git a/test/br3066383.asm b/test/br3066383.asm
index 09222ac7..d6a8646b 100644
--- a/test/br3066383.asm
+++ b/test/br3066383.asm
@@ -1,3 +1,5 @@
+;Testname=br3066383; Arguments=-Ox -fbin -obr3066383.bin; Files=stdout stderr br3066383.bin
+
;
; this is a for BR3005117
; http://sourceforge.net/tracker/?func=detail&aid=3005117&group_id=6208&atid=106208
diff --git a/test/br3074517.asm b/test/br3074517.asm
new file mode 100644
index 00000000..96978095
--- /dev/null
+++ b/test/br3074517.asm
@@ -0,0 +1,12 @@
+;%define UNDEFINED
+%macro macro 0
+ %ifndef UNDEFINED
+ %rep 1
+ %fatal This should display "fatal: (m:3)"
+ %endrep
+ %endif
+ %fatal This should display "fatal: (m:6)" if 'UNDEFINED' defined
+%endmacro
+
+macro
+
diff --git a/test/br3092924.asm b/test/br3092924.asm
new file mode 100644
index 00000000..3f9cde04
--- /dev/null
+++ b/test/br3092924.asm
@@ -0,0 +1,25 @@
+%define RNUM 0x10000 ; max of relocations in a section is 0xffff
+
+section .data1
+ r1 dd RNUM
+
+section .data2
+ r2 dd RNUM
+
+%macro x1 1
+ mov eax, [r1 + %1]
+%endmacro
+
+%macro x2 1
+ mov eax, [r2 + %1]
+%endmacro
+
+section .text1
+
+ %assign i 0
+ %rep RNUM
+ x1 i
+ x2 i
+ %assign i i+1
+ %endrep
+
diff --git a/test/br3104312.asm b/test/br3104312.asm
new file mode 100644
index 00000000..0dee16b8
--- /dev/null
+++ b/test/br3104312.asm
@@ -0,0 +1,11 @@
+%if 1 < 8000_0002h
+ %warning No bug with 8000_0002h
+%else
+ %warning Bug with 8000_0002h
+%endif
+
+%if 1 < 8000_0001h
+ %warning No bug with 8000_0001h
+%else
+ %warning Bug with 8000_0001h
+%endif
diff --git a/test/imm64.asm b/test/imm64.asm
index d90a0642..a1140443 100644
--- a/test/imm64.asm
+++ b/test/imm64.asm
@@ -9,3 +9,53 @@
mov [rax],dword 11223344h ; 32-bit operation
mov qword [rax],11223344h
mov qword [rax],dword 11223344h
+
+ mov rax,0_ffffffff_8899aabbh
+ mov rax,dword 0_ffffffff_8899aabbh
+ mov eax,0_ffffffff_8899aabbh
+ mov [rax],dword 0_ffffffff_8899aabbh ; 32-bit operation
+ mov qword [rax],0_ffffffff_8899aabbh
+ mov qword [rax],dword 0_ffffffff_8899aabbh
+
+ mov rax,7fffffffh
+ mov rax,80000000h
+ mov rax,0_ffffffffh
+ mov rax,1_00000000h
+ mov rax,0_ffffffff_7fffffffh
+ mov rax,0_ffffffff_80000000h
+
+ mov rax,0_11223344_8899aabbh
+ mov rax,dword 0_11223344_8899aabbh
+ mov eax,0_11223344_8899aabbh
+ mov [rax],dword 0_11223344_8899aabbh ; 32-bit operation
+ mov qword [rax],0_11223344_8899aabbh
+ mov qword [rax],dword 0_11223344_8899aabbh
+
+ mov rax,strict 11223344h
+ mov rax,strict dword 11223344h
+ mov eax,strict 11223344h
+ mov [rax],strict dword 11223344h ; 32-bit operation
+ mov qword [rax],strict 11223344h
+ mov qword [rax],strict dword 11223344h
+
+ mov rax,strict 0_ffffffff_8899aabbh
+ mov rax,strict dword 0_ffffffff_8899aabbh
+ mov eax,strict 0_ffffffff_8899aabbh
+ mov [rax],strict dword 0_ffffffff_8899aabbh ; 32-bit operation
+ mov qword [rax],strict 0_ffffffff_8899aabbh
+ mov qword [rax],strict dword 0_ffffffff_8899aabbh
+
+ mov rax,strict 7fffffffh
+ mov rax,strict 80000000h
+ mov rax,strict 0_ffffffffh
+ mov rax,strict 1_00000000h
+ mov rax,strict 0_ffffffff_7fffffffh
+ mov rax,strict 0_ffffffff_80000000h
+
+ mov rax,strict 0_11223344_8899aabbh
+ mov rax,strict dword 0_11223344_8899aabbh
+ mov eax,strict 0_11223344_8899aabbh
+ mov [rax],strict dword 0_11223344_8899aabbh ; 32-bit operation
+ mov qword [rax],strict 0_11223344_8899aabbh
+ mov qword [rax],strict dword 0_11223344_8899aabbh
+
diff --git a/test/prefix66.asm b/test/prefix66.asm
new file mode 100644
index 00000000..4d9eb00a
--- /dev/null
+++ b/test/prefix66.asm
@@ -0,0 +1,28 @@
+;Testname=test; Arguments=-fbin -oprefix66.bin; Files=stdout stderr prefix66.bin
+
+BITS 16
+cmp ax, 1
+o16 cmp ax, 1
+o32 cmp ax, 1
+
+cmp eax, 1
+o16 cmp eax, 1
+o32 cmp eax, 1
+
+BITS 32
+cmp ax, 1
+o16 cmp ax, 1
+o32 cmp ax, 1
+
+cmp eax, 1
+o16 cmp eax, 1
+o32 cmp eax, 1
+
+BITS 64
+cmp ax, 1
+o16 cmp ax, 1
+o32 cmp ax, 1
+
+cmp eax, 1
+o16 cmp eax, 1
+o32 cmp eax, 1
diff --git a/test/sreg.asm b/test/sreg.asm
new file mode 100644
index 00000000..11449a50
--- /dev/null
+++ b/test/sreg.asm
@@ -0,0 +1,65 @@
+ bits 64
+ mov es,rax
+ mov ss,rax
+ mov ds,rax
+ mov fs,rax
+ mov gs,rax
+ mov es,eax
+ mov ss,eax
+ mov ds,eax
+ mov fs,eax
+ mov gs,eax
+ mov es,ax
+ mov ss,ax
+ mov ds,ax
+ mov fs,ax
+ mov gs,ax
+ mov es,[rsi]
+ mov ss,[rsi]
+ mov ds,[rsi]
+ mov fs,[rsi]
+ mov gs,[rsi]
+ mov es,word [rsi]
+ mov ss,word [rsi]
+ mov ds,word [rsi]
+ mov fs,word [rsi]
+ mov gs,word [rsi]
+ mov es,qword [rsi]
+ mov ss,qword [rsi]
+ mov ds,qword [rsi]
+ mov fs,qword [rsi]
+ mov gs,qword [rsi]
+ mov rax,es
+ mov rax,cs
+ mov rax,ss
+ mov rax,ds
+ mov rax,fs
+ mov rax,gs
+ mov eax,es
+ mov eax,ss
+ mov eax,ds
+ mov eax,fs
+ mov eax,fs
+ mov ax,es
+ mov ax,ss
+ mov ax,ds
+ mov ax,fs
+ mov ax,gs
+ mov [rdi],es
+ mov [rdi],cs
+ mov [rdi],ss
+ mov [rdi],ds
+ mov [rdi],fs
+ mov [rdi],gs
+ mov word [rdi],es
+ mov word [rdi],cs
+ mov word [rdi],ss
+ mov word [rdi],ds
+ mov word [rdi],fs
+ mov word [rdi],gs
+ mov qword [rdi],es
+ mov qword [rdi],cs
+ mov qword [rdi],ss
+ mov qword [rdi],ds
+ mov qword [rdi],fs
+ mov qword [rdi],gs
diff --git a/tokhash.pl b/tokhash.pl
index 0c69c034..6c058026 100755
--- a/tokhash.pl
+++ b/tokhash.pl
@@ -183,7 +183,7 @@ if ($output eq 'h') {
#
@hashinfo = gen_perfect_hash(\%tokens);
- if (!defined(@hashinfo)) {
+ if (!@hashinfo) {
die "$0: no hash found\n";
}
diff --git a/version b/version
index 54985aee..7612887f 100644
--- a/version
+++ b/version
@@ -1 +1 @@
-2.09.08
+2.10rc4