diff options
48 files changed, 2212 insertions, 2501 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 @@ -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 95e7b3b9..41614fc7 100644 --- a/doc/changes.src +++ b/doc/changes.src @@ -7,10 +7,23 @@ 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.05} Version 2.09.06 \b Fix missed section attribute initialization in \c{bin} output target. + \S{cl-2.09.05} Version 2.09.05 \b Fix arguments encoding for VPEXTRW instruction. diff --git a/doc/nasmdoc.src b/doc/nasmdoc.src index 4b2c2acd..515a8bb2 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 @@ -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; @@ -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 @@ -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 */ @@ -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, -} -}; @@ -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 # @@ -1,6 +1,6 @@ /* ----------------------------------------------------------------------- * * - * 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. * @@ -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) { @@ -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($$) @@ -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"; } @@ -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 @@ -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"; } @@ -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, ¶ms); /* - * 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, ¶ms); - if (m) { + ed = is_mmacro(t, ¶ms); + 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, ¶ms))) - return 0; + if (!tok_type_(t, TOK_ID) || !(ed = is_mmacro(t, ¶ms))) + 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(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,37 +5298,38 @@ 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); nasm_free(i); + while (i->expansion != NULL) { + ExpInv *ei = i->expansion; + i->expansion = ei->prev; + free_expinv(ei); + } } while (cstk) ctx_pop(); @@ -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 @@ -183,7 +183,7 @@ if ($output eq 'h') { # @hashinfo = gen_perfect_hash(\%tokens); - if (!defined(@hashinfo)) { + if (!@hashinfo) { die "$0: no hash found\n"; } @@ -1 +1 @@ -2.09.06 +2.10rc3 |