diff --git a/.gitignore b/.gitignore index de8fed98b..d55e31f80 100644 --- a/.gitignore +++ b/.gitignore @@ -40,6 +40,7 @@ TAGS /*.1 /Makefile /asm/directbl.c +/asm/directbl.h /asm/directiv.h /asm/pptok.c /asm/pptok.h diff --git a/Makefile.in b/Makefile.in index 9a8e2defe..949d0131c 100644 --- a/Makefile.in +++ b/Makefile.in @@ -50,7 +50,7 @@ XMLTO = @XMLTO@ MAKENSIS = makensis -MKDIR = mkdir +MKDIR = mkdir -p RM_F = rm -f RM_RF = rm -rf LN_S = @LN_S@ @@ -67,7 +67,7 @@ ifeq ($(TRACE),1) endif .SUFFIXES: -.SUFFIXES: .c .i .s .$(O) .$(A) $(X) .1 .txt .xml +.SUFFIXES: $(X) .$(O) .$(A) .xml .1 .c .i .s .txt .PHONY: all doc rdf install clean distclean cleaner spotless install_rdf test .PHONY: install_doc everything install_everything strip perlreq dist tags TAGS @@ -277,6 +277,13 @@ asm/directbl.c: asm/directiv.dat nasmlib/perfhash.pl perllib/phash.ph perlreq: $(PERLREQ) +# This rule is only used for RDOFF +.$(O)$(X): + $(CC) $(ALL_CFLAGS) -o $@ $< $(LDFLAGS) $(RDFLIB) $(NASMLIB) $(LIBS) + +RDFLN = cd rdoff && ln -s +RDFLNPFX = + #-- Begin RDOFF Shared Rules --# RDFLIBOBJ = rdoff/rdoff.$(O) rdoff/rdfload.$(O) rdoff/symtab.$(O) \ @@ -291,31 +298,23 @@ RDF2BINLINKS = rdoff/rdf2com$(X) rdoff/rdf2ith$(X) \ RDFLIB = rdoff/librdoff.$(A) RDFLIBS = $(RDFLIB) $(NASMLIB) -# This rule is only used for rdoff, to allow common rules -MAKERDF = $(CC) $(ALL_CFLAGS) $(LDFLAGS) -o $@ $< $(RDFLIB) $(NASMLIB) $(LIBS) - rdoff/rdfdump$(X): rdoff/rdfdump.$(O) $(RDFLIBS) - $(MAKERDF) rdoff/ldrdf$(X): rdoff/ldrdf.$(O) $(RDFLIBS) - $(MAKERDF) rdoff/rdx$(X): rdoff/rdx.$(O) $(RDFLIBS) - $(MAKERDF) rdoff/rdflib$(X): rdoff/rdflib.$(O) $(RDFLIBS) - $(MAKERDF) rdoff/rdf2bin$(X): rdoff/rdf2bin.$(O) $(RDFLIBS) - $(MAKERDF) rdoff/rdf2com$(X): rdoff/rdf2bin$(X) $(RM_F) rdoff/rdf2com$(X) - cd rdoff && $(LN_S) rdf2bin$(X) rdf2com$(X) + $(RDFLN) $(RDFLNPFX)rdf2bin$(X) $(RDFLNPFX)rdf2com$(X) rdoff/rdf2ith$(X): rdoff/rdf2bin$(X) $(RM_F) rdoff/rdf2ith$(X) - cd rdoff && $(LN_S) rdf2bin$(X) rdf2ith$(X) + $(RDFLN) $(RDFLNPFX)rdf2bin$(X) $(RDFLNPFX)rdf2ith$(X) rdoff/rdf2ihx$(X): rdoff/rdf2bin$(X) $(RM_F) rdoff/rdf2ihx$(X) - cd rdoff && $(LN_S) rdf2bin$(X) rdf2ihx$(X) + $(RDFLN) $(RDFLNPFX)rdf2bin$(X) $(RDFLNPFX)rdf2ihx$(X) rdoff/rdf2srec$(X): rdoff/rdf2bin$(X) $(RM_F) rdoff/rdf2srec$(X) - cd rdoff && $(LN_S) rdf2bin$(X) rdf2srec$(X) + $(RDFLN) $(RDFLNPFX)rdf2bin$(X) $(RDFLNPFX)rdf2srec$(X) #-- End RDOFF Shared Rules --# @@ -345,10 +344,10 @@ nsis: nsis/nasm.nsi nsis/arch.nsh nsis/version.nsh manpages: nasm.1 ndisasm.1 install: nasm$(X) ndisasm$(X) - $(MKDIR) -p $(DESTDIR)$(bindir) + $(MKDIR) $(DESTDIR)$(bindir) $(INSTALL_PROGRAM) nasm$(X) $(DESTDIR)$(bindir)/nasm$(X) $(INSTALL_PROGRAM) ndisasm$(X) $(DESTDIR)$(bindir)/ndisasm$(X) - $(MKDIR) -p $(DESTDIR)$(mandir)/man1 + $(MKDIR) $(DESTDIR)$(mandir)/man1 $(INSTALL_DATA) $(srcdir)/nasm.1 $(DESTDIR)$(mandir)/man1/nasm.1 $(INSTALL_DATA) $(srcdir)/ndisasm.1 $(DESTDIR)$(mandir)/man1/ndisasm.1 @@ -397,7 +396,7 @@ cscope: cscope -b -f cscope.out rdf_install install_rdf install_rdoff: - $(MKDIR) -p $(DESTDIR)$(bindir) + $(MKDIR) $(DESTDIR)$(bindir) for f in $(RDFPROGS); do \ $(INSTALL_PROGRAM) "$$f" '$(DESTDIR)$(bindir)'/ ; \ done @@ -406,7 +405,7 @@ rdf_install install_rdf install_rdoff: bn=`basename "$$f"` && $(RM_F) "$$bn" && \ $(LN_S) rdf2bin$(X) "$$bn" ; \ done - $(MKDIR) -p $(DESTDIR)$(mandir)/man1 + $(MKDIR) $(DESTDIR)$(mandir)/man1 $(INSTALL_DATA) $(srcdir)/rdoff/*.1 $(DESTDIR)$(mandir)/man1/ doc: diff --git a/Mkfiles/msvc.mak b/Mkfiles/msvc.mak index 430fa2d37..9aec80fc8 100644 --- a/Mkfiles/msvc.mak +++ b/Mkfiles/msvc.mak @@ -46,7 +46,7 @@ RUNPERL = $(PERL) $(PERLFLAGS) MAKENSIS = makensis -RM_F = del /f +RM_F = -del /f LN_S = copy # Binary suffixes @@ -54,15 +54,11 @@ O = obj A = lib X = .exe .SUFFIXES: -.SUFFIXES: .c .i .s .$(O) .$(A) .exe .1 .man +.SUFFIXES: $(X) .$(A) .$(O) .c .i .s .1 .man .c.obj: $(CC) /c $(ALL_CFLAGS) /Fo$@ $< -# This rule is only used for rdoff -.obj.exe: - $(CC) $(ALL_CFLAGS) /Fe$@ $< $(LDFLAGS) $(RDFLIB) $(NASMLIB) $(LIBS) - #-- Begin File Lists --# # Edit in Makefile.in, not here! NASM = asm\nasm.$(O) @@ -252,6 +248,13 @@ asm\directbl.c: asm\directiv.dat nasmlib\perfhash.pl perllib\phash.ph perlreq: $(PERLREQ) +# This rule is only used for RDOFF +.obj.exe: + $(CC) /Fe$@ $< $(LDFLAGS) $(RDFLIB) $(NASMLIB) $(LIBS) + +RDFLN = copy +RDFLNPFX = rdoff^\ + #-- Begin RDOFF Shared Rules --# # Edit in Makefile.in, not here! @@ -267,31 +270,23 @@ RDF2BINLINKS = rdoff\rdf2com$(X) rdoff\rdf2ith$(X) \ RDFLIB = rdoff\librdoff.$(A) RDFLIBS = $(RDFLIB) $(NASMLIB) -# This rule is only used for rdoff, to allow common rules -MAKERDF = $(CC) $(ALL_CFLAGS) $(LDFLAGS) -o $@ $< $(RDFLIB) $(NASMLIB) $(LIBS) - rdoff\rdfdump$(X): rdoff\rdfdump.$(O) $(RDFLIBS) - $(MAKERDF) rdoff\ldrdf$(X): rdoff\ldrdf.$(O) $(RDFLIBS) - $(MAKERDF) rdoff\rdx$(X): rdoff\rdx.$(O) $(RDFLIBS) - $(MAKERDF) rdoff\rdflib$(X): rdoff\rdflib.$(O) $(RDFLIBS) - $(MAKERDF) rdoff\rdf2bin$(X): rdoff\rdf2bin.$(O) $(RDFLIBS) - $(MAKERDF) rdoff\rdf2com$(X): rdoff\rdf2bin$(X) $(RM_F) rdoff\rdf2com$(X) - cd rdoff && $(LN_S) rdf2bin$(X) rdf2com$(X) + $(RDFLN) $(RDFLNPFX)rdf2bin$(X) $(RDFLNPFX)rdf2com$(X) rdoff\rdf2ith$(X): rdoff\rdf2bin$(X) $(RM_F) rdoff\rdf2ith$(X) - cd rdoff && $(LN_S) rdf2bin$(X) rdf2ith$(X) + $(RDFLN) $(RDFLNPFX)rdf2bin$(X) $(RDFLNPFX)rdf2ith$(X) rdoff\rdf2ihx$(X): rdoff\rdf2bin$(X) $(RM_F) rdoff\rdf2ihx$(X) - cd rdoff && $(LN_S) rdf2bin$(X) rdf2ihx$(X) + $(RDFLN) $(RDFLNPFX)rdf2bin$(X) $(RDFLNPFX)rdf2ihx$(X) rdoff\rdf2srec$(X): rdoff\rdf2bin$(X) $(RM_F) rdoff\rdf2srec$(X) - cd rdoff && $(LN_S) rdf2bin$(X) rdf2srec$(X) + $(RDFLN) $(RDFLNPFX)rdf2bin$(X) $(RDFLNPFX)rdf2srec$(X) #-- End RDOFF Shared Rules --# @@ -384,21 +379,21 @@ dep: msvc.dep # Include and/or generate msvc.dep as needed. This is too complex to # use the include-command feature, but we can open-code it here. -!IF $(EXTERNAL_DEPENDENCIES) == 1 -!IFDEF MKDEP +MKDEP=0 +!IF $(EXTERNAL_DEPENDENCIES) == 1 && $(MKDEP) == 0 !IF EXISTS(msvc.dep) !INCLUDE msvc.dep -!ENDIF !ELSEIF [$(MAKE) /c MKDEP=1 /f Mkfiles\msvc.mak msvc.dep] == 0 !INCLUDE msvc.dep !ELSE !ERROR Unable to rebuild dependencies file msvc.dep !ENDIF +!ENDIF #-- Magic hints to mkdep.pl --# # @object-ending: ".$(O)" # @path-separator: "\" -# @exclude: "config/config.h" +# @exclude: "config\config.h" # @external: "msvc.dep" # @selfrule: "1" #-- Everything below is generated by mkdep.pl - do not edit --# diff --git a/asm/assemble.c b/asm/assemble.c index aef9b7962..da58d1284 100644 --- a/asm/assemble.c +++ b/asm/assemble.c @@ -208,6 +208,8 @@ enum match_result { MERR_ENCMISMATCH, MERR_BADBND, MERR_BADREPNE, + MERR_REGSETSIZE, + MERR_REGSET, /* * Matching success; the conditional ones first */ @@ -537,9 +539,9 @@ static bool jmp_match(int32_t segment, int64_t offset, int bits, if (((c & ~1) != 0370) || (ins->oprs[0].type & STRICT)) return false; - if (!optimizing) + if (!optimizing.level || (optimizing.flag & OPTIM_DISABLE_JMP_MATCH)) return false; - if (optimizing < 0 && c == 0371) + if (optimizing.level < 0 && c == 0371) return false; isize = calcsize(segment, offset, bits, ins, temp); @@ -803,6 +805,12 @@ int64_t assemble(int32_t segment, int64_t start, int bits, insn *instruction) (has_prefix(instruction, PPS_REP, P_REPNE) ? "repne" : "repnz")); break; + case MERR_REGSETSIZE: + nasm_error(ERR_NONFATAL, "invalid register set size"); + break; + case MERR_REGSET: + nasm_error(ERR_NONFATAL, "register set not valid for operand"); + break; default: nasm_error(ERR_NONFATAL, "invalid combination of opcode and operands"); @@ -2191,7 +2199,7 @@ static enum match_result matches(const struct itemplate *itemp, /* * Is it legal? */ - if (!(optimizing > 0) && itemp_has(itemp, IF_OPT)) + if (!(optimizing.level > 0) && itemp_has(itemp, IF_OPT)) return MERR_INVALOP; /* @@ -2334,9 +2342,14 @@ static enum match_result matches(const struct itemplate *itemp, if (~ideco & deco & (Z_MASK|STATICRND_MASK|SAE_MASK)) return MERR_DECONOTHERE; - if (itemp->opd[i] & ~type & ~SIZE_MASK) { + if (itemp->opd[i] & ~type & ~(SIZE_MASK|REGSET_MASK)) return MERR_INVALOP; - } else if (template_opsize) { + + if (~itemp->opd[i] & type & REGSET_MASK) + return (itemp->opd[i] & REGSET_MASK) + ? MERR_REGSETSIZE : MERR_REGSET; + + if (template_opsize) { if (template_opsize != insn_opsize) { if (insn_opsize) { return MERR_INVALOP; diff --git a/asm/directiv.c b/asm/directiv.c index 13ef5eb71..d2c5e9c34 100644 --- a/asm/directiv.c +++ b/asm/directiv.c @@ -399,6 +399,7 @@ bool process_directives(char *directive) "in pass two"); in_absolute = true; location.segment = NO_SEG; + location.offset = absolute.offset; break; } diff --git a/asm/error.c b/asm/error.c index 116e871b2..0c7aa64bb 100644 --- a/asm/error.c +++ b/asm/error.c @@ -69,6 +69,7 @@ const struct warning warnings[ERR_WARN_ALL+1] = { {"not-my-pragma", "%pragma not applicable to this compilation", false}, {"unknown-warning", "unknown warning in -W/-w or warning directive", false}, {"negative-rep", "regative %rep count", true}, + {"phase", "phase error during stabilization", false}, /* THIS ENTRY MUST COME LAST */ {"all", "all possible warnings", false} diff --git a/asm/eval.c b/asm/eval.c index 816983b93..7c5190461 100644 --- a/asm/eval.c +++ b/asm/eval.c @@ -585,7 +585,7 @@ static expr *expr5(int critical) " scalar values"); return NULL; } - if (j != '*' && !is_unknown(f) && reloc_value(f) == 0) { + if (j != '*' && !is_just_unknown(f) && reloc_value(f) == 0) { nasm_error(ERR_NONFATAL, "division by zero"); return NULL; } diff --git a/asm/float.c b/asm/float.c index dcf69feac..ff3d9c8f6 100644 --- a/asm/float.c +++ b/asm/float.c @@ -182,7 +182,7 @@ static int32_t read_exponent(const char *string, int32_t max) } else if (*string == '_') { /* do nothing */ } else { - nasm_error(ERR_NONFATAL|ERR_PASS1, + nasm_error(ERR_NONFATAL, "invalid character in floating-point constant %s: '%c'", "exponent", *string); return INT32_MAX; @@ -219,7 +219,7 @@ static bool ieee_flconvert(const char *string, fp_limb *mant, if (!seendot) { seendot = true; } else { - nasm_error(ERR_NONFATAL|ERR_PASS1, + nasm_error(ERR_NONFATAL, "too many periods in floating-point constant"); return false; } @@ -234,7 +234,7 @@ static bool ieee_flconvert(const char *string, fp_limb *mant, *p++ = *string - '0'; } else { if (!warned) { - nasm_error(ERR_WARNING|ERR_WARN_FL_TOOLONG|ERR_PASS1, + nasm_error(ERR_WARNING|ERR_WARN_FL_TOOLONG|ERR_PASS2, "floating-point constant significand contains " "more than %i digits", MANT_DIGITS); warned = true; @@ -247,7 +247,7 @@ static bool ieee_flconvert(const char *string, fp_limb *mant, } else if (*string == '_') { /* do nothing */ } else { - nasm_error(ERR_NONFATAL|ERR_PASS1, + nasm_error(ERR_NONFATAL|ERR_PASS2, "invalid character in floating-point constant %s: '%c'", "significand", *string); return false; @@ -533,7 +533,7 @@ static bool ieee_flconvert_bin(const char *string, int bits, if (!seendot) seendot = true; else { - nasm_error(ERR_NONFATAL|ERR_PASS1, + nasm_error(ERR_NONFATAL, "too many periods in floating-point constant"); return false; } @@ -575,7 +575,7 @@ static bool ieee_flconvert_bin(const char *string, int bits, } else if (c == '_') { /* ignore */ } else { - nasm_error(ERR_NONFATAL|ERR_PASS1, + nasm_error(ERR_NONFATAL, "floating-point constant: `%c' is invalid character", c); return false; } @@ -608,6 +608,8 @@ static void ieee_shr(fp_limb *mant, int i) if (offs) for (j = MANT_LIMBS-1; j >= offs; j--) mant[j] = mant[j-offs]; + } else if (MANT_LIMBS-1-offs < 0) { + j = MANT_LIMBS-1; } else { n = mant[MANT_LIMBS-1-offs] >> sr; for (j = MANT_LIMBS-1; j > offs; j--) { @@ -673,7 +675,7 @@ static int to_packed_bcd(const char *str, const char *p, int tv = -1; if (fmt != &ieee_80) { - nasm_error(ERR_NONFATAL|ERR_PASS1, + nasm_error(ERR_NONFATAL, "packed BCD requires an 80-bit format"); return 0; } @@ -683,7 +685,7 @@ static int to_packed_bcd(const char *str, const char *p, if (c >= '0' && c <= '9') { if (tv < 0) { if (n == 9) { - nasm_error(ERR_WARNING|ERR_PASS1, + nasm_error(ERR_WARNING|ERR_PASS2, "packed BCD truncated to 18 digits"); } tv = c-'0'; @@ -696,7 +698,7 @@ static int to_packed_bcd(const char *str, const char *p, } else if (c == '_') { /* do nothing */ } else { - nasm_error(ERR_NONFATAL|ERR_PASS1, + nasm_error(ERR_NONFATAL, "invalid character `%c' in packed BCD constant", c); return 0; } @@ -757,7 +759,7 @@ static int to_float(const char *str, int s, uint8_t *result, type = FL_INFINITY; break; default: - nasm_error(ERR_NONFATAL|ERR_PASS1, + nasm_error(ERR_NONFATAL, "internal error: unknown FP constant token `%s'\n", str); type = FL_QNAN; break; @@ -805,7 +807,7 @@ static int to_float(const char *str, int s, uint8_t *result, type = FL_NORMAL; } else if (exponent > 0) { if (pass0 == 1) - nasm_error(ERR_WARNING|ERR_WARN_FL_OVERFLOW|ERR_PASS1, + nasm_error(ERR_WARNING|ERR_WARN_FL_OVERFLOW|ERR_PASS2, "overflow in floating-point constant"); type = FL_INFINITY; } else { @@ -840,11 +842,11 @@ static int to_float(const char *str, int s, uint8_t *result, } else { if (daz || is_zero(mant)) { /* Flush denormals to zero */ - nasm_error(ERR_WARNING|ERR_WARN_FL_UNDERFLOW|ERR_PASS1, + nasm_error(ERR_WARNING|ERR_WARN_FL_UNDERFLOW|ERR_PASS2, "underflow in floating-point constant"); goto zero; } else { - nasm_error(ERR_WARNING|ERR_WARN_FL_DENORM|ERR_PASS1, + nasm_error(ERR_WARNING|ERR_WARN_FL_DENORM|ERR_PASS2, "denormal floating-point constant"); } } @@ -860,7 +862,7 @@ static int to_float(const char *str, int s, uint8_t *result, ieee_shr(mant, 1); exponent++; if (exponent >= (expmax << 1)-1) { - nasm_error(ERR_WARNING|ERR_WARN_FL_OVERFLOW|ERR_PASS1, + nasm_error(ERR_WARNING|ERR_WARN_FL_OVERFLOW|ERR_PASS2, "overflow in floating-point constant"); type = FL_INFINITY; goto overflow; diff --git a/asm/labels.c b/asm/labels.c index 88edc9ed2..c00d6e5b5 100644 --- a/asm/labels.c +++ b/asm/labels.c @@ -72,6 +72,21 @@ static bool ismagic(const char *l) return l[0] == '.' && l[1] == '.' && l[2] != '@'; } +/* + * Return true if we should update the local label base + * as a result of this symbol. We must exclude local labels + * as well as any kind of special labels, including ..@ ones. + */ +static bool set_prevlabel(const char *l) +{ + if (tasm_compatible_mode) { + if (l[0] == '@' && l[1] == '@') + return false; + } + + return l[0] != '.'; +} + #define LABEL_BLOCK 128 /* no. of labels/block */ #define LBLK_SIZE (LABEL_BLOCK * sizeof(union label)) @@ -146,7 +161,7 @@ static void out_symdef(union label *lptr) case LBL_EXTERN: case LBL_COMMON: if (lptr->defn.special) - ofmt->symdef(lptr->defn.label, 0, 0, 3, lptr->defn.special); + ofmt->symdef(lptr->defn.mangled, 0, 0, 3, lptr->defn.special); break; default: break; @@ -160,6 +175,7 @@ static void out_symdef(union label *lptr) /* Clean up this hack... */ switch(lptr->defn.type) { case LBL_GLOBAL: + case LBL_EXTERN: backend_type = 1; backend_offset = lptr->defn.offset; break; @@ -203,6 +219,8 @@ static union label *find_label(const char *label, bool create, bool *created) char *label_str = NULL; struct hash_insert ip; + nasm_assert(label != NULL); + if (islocal(label)) label = label_str = nasm_strcat(prevlabel, label); @@ -336,15 +354,23 @@ handle_herelabel(union label *lptr, int32_t *segment, int64_t *offset) if (oldseg == location.segment && *offset == location.offset) { /* This label is defined at this location */ int32_t newseg; + bool copyoffset = false; nasm_assert(lptr->defn.mangled); newseg = ofmt->herelabel(lptr->defn.mangled, lptr->defn.type, - oldseg, &lptr->defn.subsection); + oldseg, &lptr->defn.subsection, ©offset); if (likely(newseg == oldseg)) return; *segment = newseg; - *offset = switch_segment(newseg); + if (copyoffset) { + /* Maintain the offset from the old to the new segment */ + switch_segment(newseg); + location.offset = *offset; + } else { + /* Keep a separate offset for the new segment */ + *offset = switch_segment(newseg); + } } } @@ -383,7 +409,7 @@ static bool declare_label_lptr(union label *lptr, type == LBL_EXTERN) { if (!lptr->defn.special) lptr->defn.special = perm_copy(special); - return true; + return false; /* Don't call define_label() after this! */ } nasm_error(ERR_NONFATAL, "symbol `%s' declared both as %s and %s", @@ -394,10 +420,7 @@ static bool declare_label_lptr(union label *lptr, bool declare_label(const char *label, enum label_type type, const char *special) { - union label *lptr; - bool created; - - lptr = find_label(label, true, &created); + union label *lptr = find_label(label, true, NULL); return declare_label_lptr(lptr, type, special); } @@ -419,13 +442,14 @@ void define_label(const char *label, int32_t segment, */ lptr = find_label(label, true, &created); - if (pass0 > 1) { - if (created) - nasm_error(ERR_WARNING, "label `%s' defined on pass two", label); - } - - if (!segment) + if (segment) { + /* We are actually defining this label */ + if (lptr->defn.type == LBL_EXTERN) /* auto-promote EXTERN to GLOBAL */ + lptr->defn.type = LBL_GLOBAL; + } else { + /* It's a pseudo-segment (extern, common) */ segment = lptr->defn.segment ? lptr->defn.segment : seg_alloc(); + } if (lptr->defn.defined || lptr->defn.type == LBL_BACKEND) { /* We have seen this on at least one previous pass */ @@ -436,9 +460,8 @@ void define_label(const char *label, int32_t segment, if (ismagic(label) && lptr->defn.type == LBL_LOCAL) lptr->defn.type = LBL_SPECIAL; - if (!islocal(label) && normal) { + if (set_prevlabel(label) && normal) prevlabel = lptr->defn.label; - } if (lptr->defn.type == LBL_COMMON) { size = offset; @@ -447,7 +470,8 @@ void define_label(const char *label, int32_t segment, size = 0; /* This is a hack... */ } - changed = !lptr->defn.defined || lptr->defn.segment != segment || + changed = created || !lptr->defn.defined || + lptr->defn.segment != segment || lptr->defn.offset != offset || lptr->defn.size != size; global_offset_changed += changed; @@ -456,9 +480,11 @@ void define_label(const char *label, int32_t segment, * special case, LBL_SPECIAL symbols are allowed to be changed * even during the last pass. */ - if (changed && pass0 == 2 && lptr->defn.type != LBL_SPECIAL) - nasm_error(ERR_WARNING, "label `%s' changed during code generation", - lptr->defn.label); + if (changed && pass0 > 1 && lptr->defn.type != LBL_SPECIAL) { + nasm_error(ERR_WARNING, "label `%s' %s during code generation", + lptr->defn.label, + created ? "defined" : "changed"); + } lptr->defn.segment = segment; lptr->defn.offset = offset; diff --git a/asm/nasm.c b/asm/nasm.c index 3b987727d..545a81b18 100644 --- a/asm/nasm.c +++ b/asm/nasm.c @@ -117,7 +117,8 @@ const struct dfmt *dfmt; static FILE *error_file; /* Where to write error messages */ FILE *ofile = NULL; -int optimizing = MAX_OPTIMIZE; /* number of optimization passes to take */ +struct optimization optimizing = + { MAX_OPTIMIZE, OPTIM_ALL_ENABLED }; /* number of optimization passes to take */ static int cmd_sb = 16; /* by default */ iflag_t cpu; @@ -424,6 +425,13 @@ int main(int argc, char **argv) tolower_init(); src_init(); + /* + * We must call init_labels() before the command line parsing, + * because we may be setting prefixes/suffixes from the command + * line. + */ + init_labels(); + offsets = raa_init(); forwrefs = saa_init((int32_t)sizeof(struct forwrefinfo)); @@ -473,9 +481,15 @@ int main(int argc, char **argv) if (ofmt->stdmac) preproc->extra_stdmac(ofmt->stdmac); - /* no output file name? */ - if (!outname) - outname = filename_set_extension(inname, ofmt->extension); + /* + * If no output file name provided and this + * is a preprocess mode, we're perfectly + * fine to output into stdout. + */ + if (!outname) { + if (!(operating_mode & OP_PREPROCESS)) + outname = filename_set_extension(inname, ofmt->extension); + } /* define some macros dependent of command-line */ define_macros_late(); @@ -553,13 +567,6 @@ int main(int argc, char **argv) nasm_fatal_fl(ERR_NOFILE, "unable to open output file `%s'", outname); - /* - * We must call init_labels() before ofmt->init() since - * some object formats will want to define labels in their - * init routines. (eg OS/2 defines the FLAT group) - */ - init_labels(); - ofmt->init(); dfmt->init(); @@ -867,7 +874,7 @@ static bool process_arg(char *p, char *q, int pass) if (!*param) { /* Naked -O == -Ox */ - optimizing = MAX_OPTIMIZE; + optimizing.level = MAX_OPTIMIZE; } else { while (*param) { switch (*param) { @@ -875,12 +882,12 @@ static bool process_arg(char *p, char *q, int pass) case '5': case '6': case '7': case '8': case '9': opt = strtoul(param, ¶m, 10); - /* -O0 -> optimizing == -1, 0.98 behaviour */ - /* -O1 -> optimizing == 0, 0.98.09 behaviour */ + /* -O0 -> optimizing.level == -1, 0.98 behaviour */ + /* -O1 -> optimizing.level == 0, 0.98.09 behaviour */ if (opt < 2) - optimizing = opt - 1; + optimizing.level = opt - 1; else - optimizing = opt; + optimizing.level = opt; break; case 'v': @@ -891,7 +898,7 @@ static bool process_arg(char *p, char *q, int pass) case 'x': param++; - optimizing = MAX_OPTIMIZE; + optimizing.level = MAX_OPTIMIZE; break; default: @@ -900,8 +907,8 @@ static bool process_arg(char *p, char *q, int pass) break; } } - if (optimizing > MAX_OPTIMIZE) - optimizing = MAX_OPTIMIZE; + if (optimizing.level > MAX_OPTIMIZE) + optimizing.level = MAX_OPTIMIZE; } } break; @@ -1434,7 +1441,7 @@ static void assemble_file(const char *fname, StrList **depend_ptr) while ((line = preproc->getline())) { if (++globallineno > nasm_limit[LIMIT_LINES]) nasm_fatal("overall line count exceeds the maximum %"PRId64"\n", - nasm_limit[LIMIT_LINES]); + nasm_limit[LIMIT_LINES]); /* * Here we parse our directives; this is not handled by the @@ -1446,7 +1453,7 @@ static void assemble_file(const char *fname, StrList **depend_ptr) /* Not a directive, or even something that starts with [ */ parse_line(pass1, line, &output_ins); - if (optimizing > 0) { + if (optimizing.level > 0) { if (forwref != NULL && globallineno == forwref->lineno) { output_ins.forw_ref = true; do { @@ -1472,13 +1479,11 @@ static void assemble_file(const char *fname, StrList **depend_ptr) /* forw_ref */ if (output_ins.opcode == I_EQU) { - if (!output_ins.label) - nasm_error(ERR_NONFATAL, - "EQU not preceded by label"); - - if (output_ins.operands == 1 && - (output_ins.oprs[0].type & IMMEDIATE) && - output_ins.oprs[0].wrt == NO_SEG) { + if (!output_ins.label) { + nasm_error(ERR_NONFATAL, "EQU not preceded by label"); + } else if (output_ins.operands == 1 && + (output_ins.oprs[0].type & IMMEDIATE) && + output_ins.oprs[0].wrt == NO_SEG) { define_label(output_ins.label, output_ins.oprs[0].segment, output_ins.oprs[0].offset, false); @@ -1611,14 +1616,35 @@ static void assemble_file(const char *fname, StrList **depend_ptr) nasm_free(line); } /* end while (line = preproc->getline... */ - if (pass0 == 2 && global_offset_changed && !terminate_after_phase) - nasm_error(ERR_NONFATAL, - "phase error detected at end of assembly."); + if (global_offset_changed && !terminate_after_phase) { + switch (pass0) { + case 1: + nasm_error(ERR_WARNING|ERR_WARN_PHASE, + "phase error during stabilization pass, hoping for the best"); + break; + + case 2: + nasm_error(ERR_NONFATAL, + "phase error during code generation pass"); + break; + + default: + /* This is normal, we'll keep going... */ + break; + } + } if (pass1 == 1) preproc->cleanup(1); - if ((passn > 1 && !global_offset_changed) || pass0 == 2) { + /* + * Always run at least two optimization passes (pass0 == 0); + * things like subsections will fail miserably without that. + * Once we commit to a stabilization pass (pass0 == 1), we can't + * go back, and if something goes bad, we can only hope + * that we don't end up with a phase error at the end. + */ + if ((passn > 1 && !global_offset_changed) || pass0 > 0) { pass0++; } else if (global_offset_changed && global_offset_changed < prev_offset_changed) { @@ -1941,14 +1967,16 @@ static void help(const char xopt) " -w-foo disable warning foo (equiv. -Wno-foo)\n" " -w[+-]error[=foo]\n" " promote [specific] warnings to errors\n" - " -h show invocation summary and exit\n\n" + " -h show invocation summary and exit (also --help)\n\n" " --pragma str pre-executes a specific %%pragma\n" " --before str add line (usually a preprocessor statement) before the input\n" " --prefix str prepend the given string to all the given string\n" - " to all extern, common and global symbols\n" - " --suffix str append the given string to all the given string\n" - " to all extern, common and global symbols\n" + " to all extern, common and global symbols (also --gprefix)\n" + " --postfix str append the given string to all the given string\n" + " to all extern, common and global symbols (also --gpostfix)\n" " --lprefix str prepend the given string to all other symbols\n" + " --lpostfix str append the given string to all other symbols\n" + " --keep-all output files will not be removed even if an error happens\n" " --limit-X val set execution limit X\n"); for (i = 0; i <= LIMIT_MAX; i++) { diff --git a/asm/parser.c b/asm/parser.c index d5a457532..78f347fa1 100644 --- a/asm/parser.c +++ b/asm/parser.c @@ -486,7 +486,8 @@ restart_parse: * Generally fix things. I think this is right as it is, but * am still not certain. */ - define_label(result->label, location.segment, + define_label(result->label, + in_absolute ? absolute.segment : location.segment, location.offset, true); } } @@ -1027,7 +1028,7 @@ is_expression: op->segment = NO_SEG; /* don't care again */ op->wrt = NO_SEG; /* still don't care */ - if(optimizing >= 0 && !(op->type & STRICT)) { + if(optimizing.level >= 0 && !(op->type & STRICT)) { /* Be optimistic */ op->type |= UNITY | SBYTEWORD | SBYTEDWORD | UDWORD | SDWORD; @@ -1044,7 +1045,7 @@ is_expression: if (is_simple(value)) { if (n == 1) op->type |= UNITY; - if (optimizing >= 0 && !(op->type & STRICT)) { + if (optimizing.level >= 0 && !(op->type & STRICT)) { if ((uint32_t) (n + 128) <= 255) op->type |= SBYTEDWORD; if ((uint16_t) (n + 128) <= 255) @@ -1077,6 +1078,7 @@ is_expression: } } else { /* it's a register */ opflags_t rs; + uint64_t regset_size = 0; if (value->type >= EXPR_SIMPLE || value->value != 1) { nasm_error(ERR_NONFATAL, "invalid operand type"); @@ -1084,13 +1086,32 @@ is_expression: } /* - * check that its only 1 register, not an expression... + * We do not allow any kind of expression, except for + * reg+value in which case it is a register set. */ - for (i = 1; value[i].type; i++) - if (value[i].value) { + for (i = 1; value[i].type; i++) { + if (!value[i].value) + continue; + + switch (value[i].type) { + case EXPR_SIMPLE: + if (!regset_size) { + regset_size = value[i].value + 1; + break; + } + /* fallthrough */ + default: nasm_error(ERR_NONFATAL, "invalid operand type"); goto fail; } + } + + if ((regset_size & (regset_size - 1)) || + regset_size >= (UINT64_C(1) << REGSET_BITS)) { + nasm_error(ERR_NONFATAL | ERR_PASS2, + "invalid register set size"); + regset_size = 0; + } /* clear overrides, except TO which applies to FPU regs */ if (op->type & ~TO) { @@ -1099,12 +1120,31 @@ is_expression: * is different from the register size */ rs = op->type & SIZE_MASK; - } else + } else { rs = 0; + } + + /* + * Make sure we're not out of nasm_reg_flags, still + * probably this should be fixed when we're defining + * the label. + * + * An easy trigger is + * + * e equ 0x80000000:0 + * pshufw word e-0 + * + */ + if (value->type < EXPR_REG_START || + value->type > EXPR_REG_END) { + nasm_error(ERR_NONFATAL, "invalid operand type"); + goto fail; + } op->type &= TO; op->type |= REGISTER; op->type |= nasm_reg_flags[value->type]; + op->type |= (regset_size >> 1) << REGSET_SHIFT; op->decoflags |= brace_flags; op->basereg = value->type; diff --git a/asm/pragma.c b/asm/pragma.c index 71861a945..a4e760944 100644 --- a/asm/pragma.c +++ b/asm/pragma.c @@ -1,6 +1,6 @@ /* ----------------------------------------------------------------------- * * - * Copyright 1996-2017 The NASM Authors - All Rights Reserved + * Copyright 1996-2018 The NASM Authors - All Rights Reserved * See the file AUTHORS included with the NASM distribution for * the specific copyright holders. * @@ -49,7 +49,7 @@ #include "assemble.h" #include "error.h" -static enum directive_result asm_pragma(const struct pragma *pragma); +static enum directive_result output_pragma(const struct pragma *pragma); static enum directive_result limit_pragma(const struct pragma *pragma); /* @@ -87,14 +87,14 @@ static enum directive_result limit_pragma(const struct pragma *pragma); */ static struct pragma_facility global_pragmas[] = { - { "asm", asm_pragma }, + { "asm", NULL }, { "limit", limit_pragma }, { "list", NULL }, { "file", NULL }, { "input", NULL }, - /* None of these should actually happen... */ - { "preproc", NULL }, /* This shouldn't happen... */ + /* None of these should actually happen due to special handling */ + { "preproc", NULL }, /* Handled in the preprocessor by necessity */ { "output", NULL }, { "debug", NULL }, { "ignore", NULL }, @@ -110,6 +110,7 @@ static struct pragma_facility global_pragmas[] = */ static bool search_pragma_list(const struct pragma_facility *list, const char *default_name, + pragma_handler generic_handler, struct pragma *pragma) { const struct pragma_facility *pf; @@ -137,6 +138,10 @@ found_it: else rv = DIRR_UNKNOWN; + /* Is there an additional, applicable generic handler? */ + if (rv == DIRR_UNKNOWN && generic_handler) + rv = generic_handler(pragma); + switch (rv) { case DIRR_UNKNOWN: switch (pragma->opcode) { @@ -210,15 +215,16 @@ void process_pragma(char *str) pragma.tail = nasm_trim_spaces(p); /* Look for a global pragma namespace */ - if (search_pragma_list(global_pragmas, NULL, &pragma)) + if (search_pragma_list(global_pragmas, NULL, NULL, &pragma)) return; /* Look to see if it is an output backend pragma */ - if (search_pragma_list(ofmt->pragmas, ofmt->shortname, &pragma)) + if (search_pragma_list(ofmt->pragmas, ofmt->shortname, + output_pragma, &pragma)) return; /* Look to see if it is a debug format pragma */ - if (search_pragma_list(dfmt->pragmas, dfmt->shortname, &pragma)) + if (search_pragma_list(dfmt->pragmas, dfmt->shortname, NULL, &pragma)) return; /* @@ -234,9 +240,10 @@ void process_pragma(char *str) } /* - * Pragmas for the assembler proper + * Generic pragmas that apply to all output backends; these are handled + * specially so they can be made selective based on the output format. */ -static enum directive_result asm_pragma(const struct pragma *pragma) +static enum directive_result output_pragma(const struct pragma *pragma) { switch (pragma->opcode) { case D_PREFIX: @@ -258,6 +265,9 @@ static enum directive_result asm_pragma(const struct pragma *pragma) } } +/* + * %pragma limit to set resource limits + */ static enum directive_result limit_pragma(const struct pragma *pragma) { return nasm_set_limit(pragma->opname, pragma->tail); diff --git a/asm/preproc.c b/asm/preproc.c index fbdfedb74..0c357d0f4 100644 --- a/asm/preproc.c +++ b/asm/preproc.c @@ -2210,8 +2210,7 @@ static int parse_size(const char *str) { { "byte", "dword", "oword", "qword", "tword", "word", "yword" }; static const int sizes[] = { 0, 1, 4, 16, 8, 10, 2, 32 }; - - return sizes[bsii(str, size_names, ARRAY_SIZE(size_names))+1]; + return str ? sizes[bsii(str, size_names, ARRAY_SIZE(size_names))+1] : 0; } /* @@ -3948,6 +3947,8 @@ static Token *expand_mmac_params_range(MMacro *mac, Token *tline, Token ***last) * only first token will be passed. */ tm = mac->params[(fst + mac->rotate) % mac->nparam]; + if (!tm) + goto err; head = new_Token(NULL, tm->type, tm->text, 0); tt = &head->next, tm = tm->next; while (tok_isnt_(tm, ",")) { @@ -4472,7 +4473,9 @@ again: } if (tline->type == TOK_SMAC_END) { - tline->a.mac->in_progress = false; + /* On error path it might already be dropped */ + if (tline->a.mac) + tline->a.mac->in_progress = false; tline = delete_Token(tline); } else { t = *tail = tline; diff --git a/disasm/disasm.c b/disasm/disasm.c index a75d839e8..fd3eb42a0 100644 --- a/disasm/disasm.c +++ b/disasm/disasm.c @@ -49,6 +49,15 @@ #include "regdis.h" #include "disp8.h" +#define fetch_safe(_start, _ptr, _size, _need, _op) \ + do { \ + if (((_ptr) - (_start)) >= ((_size) - (_need))) \ + _op; \ + } while (0) + +#define fetch_or_return(_start, _ptr, _size, _need) \ + fetch_safe(_start, _ptr, _size, _need, return 0) + /* * Flags that go into the `segment' field of `insn' structures * during disassembly. @@ -1108,8 +1117,8 @@ static const char * const condition_name[16] = { "s", "ns", "pe", "po", "l", "nl", "ng", "g" }; -int32_t disasm(uint8_t *data, char *output, int outbufsize, int segsize, - int64_t offset, int autosync, iflag_t *prefer) +int32_t disasm(uint8_t *data, int32_t data_size, char *output, int outbufsize, int segsize, + int64_t offset, int autosync, iflag_t *prefer) { const struct itemplate * const *p, * const *best_p; const struct disasm_index *ix; @@ -1144,41 +1153,52 @@ int32_t disasm(uint8_t *data, char *output, int outbufsize, int segsize, switch (*data) { case 0xF2: case 0xF3: + fetch_or_return(origdata, data, data_size, 1); prefix.rep = *data++; break; case 0x9B: + fetch_or_return(origdata, data, data_size, 1); prefix.wait = *data++; break; case 0xF0: + fetch_or_return(origdata, data, data_size, 1); prefix.lock = *data++; break; case 0x2E: + fetch_or_return(origdata, data, data_size, 1); segover = "cs", prefix.seg = *data++; break; case 0x36: + fetch_or_return(origdata, data, data_size, 1); segover = "ss", prefix.seg = *data++; break; case 0x3E: + fetch_or_return(origdata, data, data_size, 1); segover = "ds", prefix.seg = *data++; break; case 0x26: + fetch_or_return(origdata, data, data_size, 1); segover = "es", prefix.seg = *data++; break; case 0x64: + fetch_or_return(origdata, data, data_size, 1); segover = "fs", prefix.seg = *data++; break; case 0x65: + fetch_or_return(origdata, data, data_size, 1); segover = "gs", prefix.seg = *data++; break; case 0x66: + fetch_or_return(origdata, data, data_size, 1); prefix.osize = (segsize == 16) ? 32 : 16; prefix.osp = *data++; break; case 0x67: + fetch_or_return(origdata, data, data_size, 1); prefix.asize = (segsize == 32) ? 16 : 32; prefix.asp = *data++; break; @@ -1186,6 +1206,7 @@ int32_t disasm(uint8_t *data, char *output, int outbufsize, int segsize, case 0xC4: case 0xC5: if (segsize == 64 || (data[1] & 0xc0) == 0xc0) { + fetch_or_return(origdata, data, data_size, 2); prefix.vex[0] = *data++; prefix.vex[1] = *data++; @@ -1193,6 +1214,7 @@ int32_t disasm(uint8_t *data, char *output, int outbufsize, int segsize, prefix.vex_c = RV_VEX; if (prefix.vex[0] == 0xc4) { + fetch_or_return(origdata, data, data_size, 1); prefix.vex[2] = *data++; prefix.rex |= (~prefix.vex[1] >> 5) & 7; /* REX_RXB */ prefix.rex |= (prefix.vex[2] >> (7-3)) & REX_W; @@ -1214,6 +1236,7 @@ int32_t disasm(uint8_t *data, char *output, int outbufsize, int segsize, case 0x62: { if (segsize == 64 || ((data[1] & 0xc0) == 0xc0)) { + fetch_or_return(origdata, data, data_size, 4); data++; /* 62h EVEX prefix */ prefix.evex[0] = *data++; prefix.evex[1] = *data++; @@ -1237,6 +1260,7 @@ int32_t disasm(uint8_t *data, char *output, int outbufsize, int segsize, case 0x8F: if ((data[1] & 030) != 0 && (segsize == 64 || (data[1] & 0xc0) == 0xc0)) { + fetch_or_return(origdata, data, data_size, 3); prefix.vex[0] = *data++; prefix.vex[1] = *data++; prefix.vex[2] = *data++; @@ -1272,6 +1296,7 @@ int32_t disasm(uint8_t *data, char *output, int outbufsize, int segsize, case REX_P + 0xE: case REX_P + 0xF: if (segsize == 64) { + fetch_or_return(origdata, data, data_size, 1); prefix.rex = *data++; if (prefix.rex & REX_W) prefix.osize = 64; @@ -1293,8 +1318,10 @@ int32_t disasm(uint8_t *data, char *output, int outbufsize, int segsize, return 0; /* No instruction table at all... */ dp = data; + fetch_or_return(origdata, dp, data_size, 1); ix += *dp++; while (ix->n == -1) { + fetch_or_return(origdata, dp, data_size, 1); ix = (const struct disasm_index *)ix->p + *dp++; } @@ -1431,6 +1458,9 @@ int32_t disasm(uint8_t *data, char *output, int outbufsize, int segsize, slen += snprintf(output + slen, outbufsize - slen, "to "); slen += snprintf(output + slen, outbufsize - slen, "%s", nasm_reg_names[reg-EXPR_REG_START]); + if (t & REGSET_MASK) + slen += snprintf(output + slen, outbufsize - slen, "+%d", + (int)((t & REGSET_MASK) >> (REGSET_SHIFT-1))-1); if (is_evex && deco) slen += append_evex_reg_deco(output + slen, outbufsize - slen, deco, ins.evex_p); diff --git a/disasm/disasm.h b/disasm/disasm.h index 6c89293ef..053474d2f 100644 --- a/disasm/disasm.h +++ b/disasm/disasm.h @@ -42,8 +42,8 @@ #define INSN_MAX 32 /* one instruction can't be longer than this */ -int32_t disasm(uint8_t *data, char *output, int outbufsize, int segsize, - int64_t offset, int autosync, iflag_t *prefer); +int32_t disasm(uint8_t *data, int32_t data_size, char *output, int outbufsize, int segsize, + int64_t offset, int autosync, iflag_t *prefer); int32_t eatbyte(uint8_t *data, char *output, int outbufsize, int segsize); #endif diff --git a/disasm/ndisasm.c b/disasm/ndisasm.c index a4a217dbc..2d0cf1536 100644 --- a/disasm/ndisasm.c +++ b/disasm/ndisasm.c @@ -316,9 +316,8 @@ int main(int argc, char **argv) nextsync = next_sync(offset, &synclen); } while (p > q && (p - q >= INSN_MAX || lenread == 0)) { - lendis = - disasm((uint8_t *) q, outbuf, sizeof(outbuf), bits, - offset, autosync, &prefer); + lendis = disasm((uint8_t *)q, INSN_MAX, outbuf, sizeof(outbuf), + bits, offset, autosync, &prefer); if (!lendis || lendis > (p - q) || ((nextsync || synclen) && (uint32_t)lendis > nextsync - offset)) diff --git a/doc/changes.src b/doc/changes.src index ddfe6b388..b2f092c2c 100644 --- a/doc/changes.src +++ b/doc/changes.src @@ -7,7 +7,70 @@ The NASM 2 series supports x86-64, and is the production version of NASM since 2007. -\S{cl-2.13.04} Version 2.13.04 +\S{cl-2.14} Version 2.14 + +\b Fixed null dereference in corrupted invalid single line macros. + +\b Fixed division by zero which may happen if source code is malformed. + +\b Fixed out of bound access in processing of malformed segment override. + +\b Fixed out of bound access in certain \c{EQU} parsing. + +\b Fixed buffer underflow in float parsing. + +\b Added \c{SGX} (Intel Software Guard Extensions) instructions. + +\b Added \c{+n} syntax for multiple contiguous registers. + +\b Fixed \c{subsections_via_symbols} for \c{macho} object format. + +\b Added the \c{--gprefix}, \c{--gpostfix}, \c{--lprefix}, and +\c{--lpostfix} command line options, to allow command line base symbol +renaming. See \k{opt-pfix}. + +\b Allow label renaming to be specified by \c{%pragma} in addition to +from the command line. See \k{mangling}. + +\b Supported generic \c{%pragma} namespaces, \c{output} and \c{debug}. See +\k{gen-namespace}. + +\b Added the \c{--pragma} command line option to inject a \c{%pragma} +directive. See \k{opt-pragma}. + +\b Added the \c{--before} command line option to accept preprocess +statement before input. See \k{opt-before}. + +\b Added \c{AVX512} \c{VBMI2} (Additional Bit Manipulation), \c{VNNI} (Vector +Neural Network), \c{BITALG} (Bit Algorithm), and \c{GFNI} (Galois Field New +Instruction) instructions. + +\b Added the \c{STATIC} directive for local symbols that should be +renamed using global-symbol rules. See \k{static}. + +\b Allow a symbol to be defined as \c{EXTERN} and then later +overridden as \c{GLOBAL} or \c{COMMON}. Furthermore, a symbol declared +\c{EXTERN} and then defined will be treated as \c{GLOBAL}. See \k{extern}. + +\b The \c{GLOBAL} directive no longer is required to precede the +definition of the symbol. + +\b Support \c{private_extern} as \c{macho} specific extension to the +\c{GLOBAL} directive. See \k{macho-pext}. + +\b Updated \c{UD0} encoding to match with the specification + +\b Added the \c{--limit-X} command line option to set execution +limits. See \k{opt-limit}. + +\b Updated the \c{Codeview} version number to be aligned with \c{MASM}. + +\b Added the \c{--keep-all} command line option to preserve output +files. See \k{opt-keep-all}. + +\b Added the \c{--include} command line option, an alias to \c{-P} (\k{opt-p}). + +\b Added the \c{--help} command line option as an alias to \c{-h} (\k{syntax}). \b Added \c{-W}, \c{-D}, and \c{-Q} suffix aliases for \c{RET} instructions so the operand sizes of these instructions can be diff --git a/doc/nasmdoc.src b/doc/nasmdoc.src index 7b331d354..fb140e99f 100644 --- a/doc/nasmdoc.src +++ b/doc/nasmdoc.src @@ -368,6 +368,8 @@ To get further usage instructions from NASM, try typing \c nasm -h +\c{--help} option is also the same. + As \c{-hf}, this will also list the available output file formats, and what they are. @@ -657,10 +659,13 @@ option. So running is equivalent to running \c{nasm myfile.asm} and placing the directive \c{%include "myinc.inc"} at the start of the file. +\c{--include} option is also accepted. + For consistency with the \c{-I}, \c{-D} and \c{-U} options, this option can also be specified as \c{-P}. + \S{opt-d} The \i\c{-d}\I\c{-D} Option: \I{pre-defining macros}Pre-Define a Macro \I\c{%define}Just as the \c{-p} option gives an alternative to placing @@ -917,13 +922,72 @@ is indicated by an asterisk. For example: \c dwarf elf32 (i386) dwarf debug format for Linux -\S{opt-pfix} The \i\c{--prefix} and \i\c{--postfix} Options. +\S{opt-pfix} The \i\c{--(g|l)prefix}, \i\c{--(g|l)postfix} Options. -The \c{--prefix} and \c{--postfix} options prepend or append -(respectively) the given argument to all \c{global} or -\c{extern} variables. E.g. \c{--prefix _} will prepend the -underscore to all global and external variables, as C requires it in -some, but not all, system calling conventions. +The \c{--(g)prefix} options prepend the given argument +to all \c{extern}, \c{common}, \c{static}, and \c{global} symbols, and the +\c{--lprefix} option prepends to all other symbols. Similarly, +\c{--(g)postfix} and \c{--lpostfix} options append +the argument in the exactly same way as the \c{--xxprefix} options does. + +Running this: + +\c nasm -f macho --gprefix _ + +is equivalent to place the directive with \c{%pragma macho gprefix _} +at the start of the file (\k{mangling}). It will prepend the underscore +to all global and external variables, as C requires it in some, but not all, +system calling conventions. + +\S{opt-pragma} The \i\c{--pragma} Option + +NASM accepts an argument as \c{%pragma} option, which is like placing +a \c{%pragma} preprocess statement at the beginning of the source. +Running this: + +\c nasm -f macho --pragma "macho gprefix _" + +is equivalent to the example in \k{opt-pfix}. + + +\S{opt-before} The \i\c{--before} Option + +A preprocess statement can be accepted with this option. The example +shown in \k{opt-pragma} is the same as running this: + +\c nasm -f macho --before "%pragma macho gprefix _" + + +\S{opt-limit} The \i\c{--limit-X} Option + +This option allows user to setup various maximum values for these: + +\b\c{--limit-passes}: Number of maximum allowed passes. Default is +effectively unlimited. + +\b\c{--limit-stalled-passes}: Maximum number of allowed unfinished +passes. Default is 1000. + +\b\c{--limit-macro-levels}: Define maximum depth of macro expansion +(in preprocess). Default is 1000000. + +\b\c{--limit-rep}: Maximum number of allowed preprocessor loop, defined +under \c{%rep}. Default is 1000000. + +\b\c{--limit-eval}: This number sets the boundary condition of allowed +expression length. Default is 1000000. + +\b\c{--limit-lines}: Total number of source lines as allowed to be +processed. Default is 2000000000. + +In example, running this limits the maximum line count to be 1000. + +\c nasm --limit-lines 1000 + + +\S{opt-keep-all} The \i\c{--keep-all} Option + +This option doesn't delete any output files even if an error happens. \S{nasmenv} The \i\c{NASMENV} \i{Environment} Variable @@ -4540,8 +4604,12 @@ only in that it can take only one argument at a time: the support for multiple arguments is implemented at the preprocessor level. You can declare the same variable as \c{EXTERN} more than once: NASM -will quietly ignore the second and later redeclarations. You can't -declare a variable as \c{EXTERN} as well as something else, though. +will quietly ignore the second and later redeclarations. + +If a variable is declared both \c{GLOBAL} and \c{EXTERN}, or if it is +declared as \c{EXTERN} and then defined, it will be treated as +\c{GLOBAL}. If a variable is declared both as \c{COMMON} and +\c{EXTERN}, it will be treated as \c{COMMON}. \H{global} \i\c{GLOBAL}: \i{Exporting Symbols} to Other Modules @@ -4552,9 +4620,6 @@ linker errors, some other module must actually \e{define} the symbol and declare it as \c{GLOBAL}. Some assemblers use the name \i\c{PUBLIC} for this purpose. -The \c{GLOBAL} directive applying to a symbol must appear \e{before} -the definition of the symbol. - \c{GLOBAL} uses the same syntax as \c{EXTERN}, except that it must refer to symbols which \e{are} defined in the same module as the \c{GLOBAL} directive. For example: @@ -4607,6 +4672,61 @@ Once again, like \c{EXTERN} and \c{GLOBAL}, the primitive form of \c{COMMON} differs from the user-level form only in that it can take only one argument at a time. +\H{static} \i\c{STATIC}: Local Symbols within Modules + +Opposite to \c{EXTERN} and \c{GLOBAL}, \c{STATIC} is local symbol, but +should be named according to the global mangling rules (named by +analogy with the C keyword \c{static} as applied to functions or +global variables). + +\c static foo +\c foo: +\c ; codes + +Unlike \c{GLOBAL}, \c{STATIC} does not allow object formats to accept +private extensions mentioned in \k{global}. + +\H{mangling} \i\c{(G|L)PREFIX}, \i\c{(G|L)POSTFIX}: Mangling Symbols + +\c{PREFIX}, \c{GPREFIX}, \c{LPREFIX}, \c{POSTFIX}, \c{GPOSTFIX}, and +\c{LPOSTFIX} directives can prepend or append the given argument to +a certain type of symbols. The directive should be as a preprocess +statement. Each usage is: + +\b\c{PREFIX}|\c{GPREFIX}: Prepend the argument to all \c{EXTERN} +\c{COMMON}, \c{STATIC}, and \c{GLOBAL} symbols + +\b\c{LPREFIX}: Prepend the argument to all other symbols +such as Local Labels, and backend defined symbols + +\b\c{POSTFIX}|\c{GPOSTFIX}: Append the argument to all \c{EXTERN} +\c{COMMON}, \c{STATIC}, and \c{GLOBAL} symbols + +\b\c{LPOSTFIX}: Append the argument to all other symbols +such as Local Labels, and backend defined symbols + +This is a macro implemented as a \c{%pragma}: + +\c %pragma macho lprefix L_ + +Commandline option is also possible. See also \k{opt-pfix}. + + +\H{gen-namespace} \i\c{OUTPUT}, \i\c{DEBUG}: Generic Namespaces + +\c{OUTPUT} and \c{DEBUG} are generic \c{%pragma} namespaces that are +supposed to redirect to the current output and debug formats. +For example, when mangling local symbols via the generic namespace: + +\c %pragma output gprefix _ + +This is useful when the directive is needed to be output format +agnostic. + +The example is also euquivalent to this, when the output format is \c{elf}: + +\c %pragma elf gprefix _ + \H{CPU} \i\c{CPU}: Defining CPU Dependencies @@ -5658,7 +5778,7 @@ comma. The following flags can also be specified: \b \c{data} - this section contains initialized data items -\b \c{text} - this section contains code exclusively +\b \c{code} - this section contains code exclusively \b \c{mixed} - this section contains both code and data @@ -5731,6 +5851,19 @@ non-Mach-O builds of the same source code: \c %pragma macho no_dead_strip symbol... +\S{macho-pext} \c{macho} specific extensions to the \c{GLOBAL} +Directive: \i\c{private_extern} + +The directive extension to \c{GLOBAL} marks the symbol with limited +global scope. For example, you can specify the global symbol with +this extension: + +\c global foo:private_extern +\c foo: +\c ; codes + +Using with static linker will clear the private extern attribute. +But linker option like \c{-keep_private_externs} can avoid it. \H{elffmt} \i\c{elf32}, \i\c{elf64}, \i\c{elfx32}: \I{ELF}\I{linux, elf}\i{Executable and Linkable Format} Object Files diff --git a/doc/opt_var.txt b/doc/opt_var.txt index 4482e5d89..af15c03d4 100644 --- a/doc/opt_var.txt +++ b/doc/opt_var.txt @@ -6,7 +6,8 @@ GLOBAL variables: - optimizing -1 flags nasm 0.98 compatible operation; + optimizing optimization meta data (with level and flag info) + .level -1 flags nasm 0.98 compatible operation; offsets usually are explicit (short/near) no optimization passes 0 flags non-optimized assembly; forward @@ -17,7 +18,8 @@ GLOBAL variables: the actual recommended minimum setting optimization passes (2 or more, plus passes 1 and 2 will be required) - + .flag 0 allow all optimizations + 1 disallow jump match optimization pass0 0 flags an optimizer pass (multiple passes) 1 flags pass1 (define labels) diff --git a/doc/pspdf.pl b/doc/pspdf.pl index 238806682..ef9f2900e 100755 --- a/doc/pspdf.pl +++ b/doc/pspdf.pl @@ -23,6 +23,9 @@ while ($ARGV[0] =~ /^-(.*)$/) { } } +# Ghostscript executable name. "gs" on Unix-based systems. +my $gs = 'gs'; + my ($in, $out) = @ARGV; if (!defined($out)) { @@ -70,6 +73,17 @@ sub win32_gs_help() { $ENV{'PATH'} .= ';' . $gs[0]->{'/GS_LIB'}; $ENV{'GS_FONTPATH'} .= (defined($ENV{'GS_FONTPATH'}) ? ';' : '') . $ENV{'windir'}.'\\fonts'; + + my $gsp = undef; + foreach my $p (split(/\;/, $gs[0]->{'/GS_LIB'})) { + foreach my $exe ('gswin64c.exe', 'gswin32c.exe', 'gs.exe') { + last if (defined($gsp)); + my $e = File::Spec->catpath($p, $exe); + $gsp = $e if (-f $e && -x _); + } + } + + $gs = $gsp if (defined($gsp)); } # Remove output file @@ -80,13 +94,19 @@ my $r = system('acrodist', '-n', '-q', '--nosecurity', '-o', $out, $in); exit 0 if ( !$r && -f $out ); # 2. ps2pdf (from Ghostscript) -# The -I clause helps Ghostscript pick up the Fontdir file written by findfont.ph -# GhostScript uses # rather than - to separate options and values on Windows, it seems... +# +# GhostScript uses # rather than = to separate options and values on Windows, +# it seems. Call gs directly rather than ps2pdf, because -dSAFER +# breaks font discovery on some systems, apparently. win32_gs_help(); -my $o = $win32_ok ? '#' : '-'; -my $r = system('ps2pdf', "-dOptimize${o}true", "-dEmbedAllFonts${o}true", +my $o = $win32_ok ? '#' : '='; +my $r = system($gs, "-dCompatibilityLevel${o}1.4", "-q", + "-P-", "-dNOPAUSE", "-dBATCH", "-sDEVICE${o}pdfwrite", + "-sstdout${o}%stderr", "-sOutputFile${o}${out}", + "-dOptimize${o}true", "-dEmbedAllFonts${o}true", "-dCompressPages${o}" . ($compress ? 'true' : 'false'), - "-dUseFlateCompression${o}true", $in, $out); + "-dUseFlateCompression${o}true", + "-c", ".setpdfwrite", "-f", $in); exit 0 if ( !$r && -f $out ); # 3. pstopdf (BSD/MacOS X utility) diff --git a/doc/rdsrc.pl b/doc/rdsrc.pl index 1ca71681f..447bb9d40 100644 --- a/doc/rdsrc.pl +++ b/doc/rdsrc.pl @@ -1,7 +1,7 @@ #!/usr/bin/perl ## -------------------------------------------------------------------------- ## -## Copyright 1996-2017 The NASM Authors - All Rights Reserved +## Copyright 1996-2018 The NASM Authors - All Rights Reserved ## See the file AUTHORS included with the NASM distribution for ## the specific copyright holders. ## @@ -325,7 +325,7 @@ sub got_para { $snum = 0; $xref = "section-$cnum.$hnum"; $pflags = "head $cnum.$hnum :$xref"; - die "badly formatted heading: $_\n" if !/^\\[HP]{([^\}]*)}\s*(.*)$/; + die "badly formatted heading: $_\n" if !/^\\[HP]\{([^\}]*)\}\s*(.*)$/; $refs{$1} = "section $cnum.$hnum"; $node = "Section $cnum.$hnum"; &add_item($node, 2); diff --git a/include/error.h b/include/error.h index ae336de9a..08d562b8f 100644 --- a/include/error.h +++ b/include/error.h @@ -115,9 +115,10 @@ static inline vefunc nasm_set_verror(vefunc ve) #define ERR_WARN_NOTMY_PRAGMA WARN(19) /* pragma inapplicable */ #define ERR_WARN_UNK_WARNING WARN(20) /* unknown warning */ #define ERR_WARN_NEG_REP WARN(21) /* negative repeat count */ +#define ERR_WARN_PHASE WARN(22) /* phase error in pass 1 */ /* The "all" warning acts as a global switch, it must come last */ -#define ERR_WARN_ALL 22 /* Do not use WARN() here */ +#define ERR_WARN_ALL 23 /* Do not use WARN() here */ struct warning { const char *name; diff --git a/include/nasm.h b/include/nasm.h index 5c838a5f7..fc56c3e3f 100644 --- a/include/nasm.h +++ b/include/nasm.h @@ -728,10 +728,11 @@ enum directive_result { * as part of the struct pragma. */ struct pragma; +typedef enum directive_result (*pragma_handler)(const struct pragma *); struct pragma_facility { const char *name; - enum directive_result (*handler)(const struct pragma *); + pragma_handler handler; }; /* @@ -911,9 +912,14 @@ struct ofmt { * The offset isn't passed; and may not be stable at this point. * The subsection number is a field available for use by the * backend. It is initialized to NO_SEG. + * + * If "copyoffset" is set by the backend then the offset is + * copied from the previous segment, otherwise the new segment + * is treated as a new segment the normal way. */ int32_t (*herelabel)(const char *name, enum label_type type, - int32_t seg, int32_t *subsection); + int32_t seg, int32_t *subsection, + bool *copyoffset); /* * This procedure is called to modify section alignment, @@ -1243,11 +1249,25 @@ enum decorator_tokens { * 2 = pass 2 */ +/* + * flag to disable optimizations selectively + * this is useful to turn-off certain optimizations + */ +enum optimization_disable_flag { + OPTIM_ALL_ENABLED = 0, + OPTIM_DISABLE_JMP_MATCH = 1 +}; + +struct optimization { + int level; + int flag; +}; + extern int pass0; extern int64_t passn; /* Actual pass number */ extern bool tasm_compatible_mode; -extern int optimizing; +extern struct optimization optimizing; extern int globalbits; /* 16, 32 or 64-bit mode */ extern int globalrel; /* default to relative addressing? */ extern int globalbnd; /* default to using bnd prefix? */ diff --git a/include/opflags.h b/include/opflags.h index ef2838c14..28bb236f6 100644 --- a/include/opflags.h +++ b/include/opflags.h @@ -1,6 +1,6 @@ /* ----------------------------------------------------------------------- * * - * Copyright 1996-2013 The NASM Authors - All Rights Reserved + * Copyright 1996-2018 The NASM Authors - All Rights Reserved * See the file AUTHORS included with the NASM distribution for * the specific copyright holders. * @@ -40,6 +40,7 @@ #include "compiler.h" #include "tables.h" /* for opflags_t and nasm_reg_flags[] */ +#include "regs.h" /* * Here we define the operand types. These are implemented as bit @@ -117,6 +118,16 @@ #define SIZE_MASK OP_GENMASK(SIZE_BITS, SIZE_SHIFT) #define GEN_SIZE(bit) OP_GENBIT(bit, SIZE_SHIFT) +/* + * Register set count + * + * Bits: 47 - 43 + */ +#define REGSET_SHIFT (43) +#define REGSET_BITS (5) +#define REGSET_MASK OP_GENMASK(REGSET_BITS, REGSET_SHIFT) +#define GEN_REGSET(bit) OP_GENBIT(bit, REGSET_SHIFT) + /* * Bits distribution (counted from 0) * @@ -131,6 +142,7 @@ * .......................................11111111................. subclasses * ................................1111111......................... specials * .....................11111111111................................ sizes + * ................11111........................................... regset count */ #define REGISTER GEN_OPTYPE(0) /* register number in 'basereg' */ @@ -165,8 +177,17 @@ #define REG_CLASS_OPMASK GEN_REG_CLASS(8) #define REG_CLASS_BND GEN_REG_CLASS(9) -#define is_class(class, op) (!((opflags_t)(class) & ~(opflags_t)(op))) -#define is_reg_class(class, reg) is_class((class), nasm_reg_flags[(reg)]) +static inline bool is_class(opflags_t class, opflags_t op) +{ + return !(class & ~op); +} + +static inline bool is_reg_class(opflags_t class, opflags_t reg) +{ + if (reg >= EXPR_REG_START && reg <= EXPR_REG_END) + return is_class(class, nasm_reg_flags[reg]); + return false; +} #define IS_SREG(reg) is_reg_class(REG_SREG, (reg)) #define IS_FSGS(reg) is_reg_class(REG_FSGS, (reg)) @@ -268,4 +289,11 @@ #define ZMM0 (GEN_SUBCLASS(1) | GEN_SUBCLASS(6) | ZMMREG) /* ZMM register zero */ #define ZMM_L16 ( GEN_SUBCLASS(6) | ZMMREG) /* ZMM register 0 ~ 15 */ +/* Register set sizes */ +#define RS2 GEN_REGSET(0) +#define RS4 GEN_REGSET(1) +#define RS8 GEN_REGSET(2) +#define RS16 GEN_REGSET(3) +#define RS32 GEN_REGSET(4) + #endif /* NASM_OPFLAGS_H */ diff --git a/output/outdbg.c b/output/outdbg.c index c9b60e7e5..a318f9218 100644 --- a/output/outdbg.c +++ b/output/outdbg.c @@ -137,14 +137,17 @@ static int32_t dbg_section_names(char *name, int pass, int *bits) } static int32_t dbg_herelabel(const char *name, enum label_type type, - int32_t oldseg, int32_t *subsection) + int32_t oldseg, int32_t *subsection, + bool *copyoffset) { int32_t newseg = oldseg; if (subsections_via_symbols && type != LBL_LOCAL) { newseg = *subsection; - if (newseg == NO_SEG) + if (newseg == NO_SEG) { newseg = *subsection = seg_alloc(); + *copyoffset = true; /* Minic MachO for now */ + } } fprintf(ofile, "herelabel %s type %d (seg %08x) -> %08x\n", name, type, oldseg, newseg); diff --git a/output/outmacho.c b/output/outmacho.c index ddb362d69..f5673c89a 100644 --- a/output/outmacho.c +++ b/output/outmacho.c @@ -363,7 +363,7 @@ static struct section *get_section_by_index(int32_t index) if (index < 0 || index >= SEG_ABS || (index & 1)) return NULL; - return (struct section *)raa_read(section_by_index, index >> 1); + return raa_read_ptr(section_by_index, index >> 1); } struct dir_list { @@ -495,7 +495,7 @@ static int64_t add_reloc(struct section *sect, int32_t section, r = nasm_malloc(sizeof(struct reloc)); r->addr = sect->size & ~R_SCATTERED; r->ext = 1; - adjust = bytes; + adjust = 0; /* match byte count 1, 2, 4, 8 to length codes 0, 1, 2, 3 respectively */ r->length = ilog2_32(bytes); @@ -514,7 +514,6 @@ static int64_t add_reloc(struct section *sect, int32_t section, if (section == NO_SEG) { /* absolute (can this even happen?) */ r->ext = 0; - r->snum = NO_SECT; } else if (fi == NO_SECT) { /* external */ r->snum = raa_read(extsyms, section); @@ -522,7 +521,6 @@ static int64_t add_reloc(struct section *sect, int32_t section, /* local */ r->ext = 0; r->snum = fi; - adjust = -sect->size; } break; @@ -531,40 +529,27 @@ static int64_t add_reloc(struct section *sect, int32_t section, r->type = fmt.reloc_rel; r->pcrel = 1; if (section == NO_SEG) { - /* absolute - seems to produce garbage no matter what */ - nasm_error(ERR_NONFATAL, "Mach-O does not support relative " - "references to absolute addresses"); - goto bail; -#if 0 - /* This "seems" to be how it ought to work... */ - - struct symbol *sym = macho_find_sym(&absolute_sect, offset, - false, false); - if (!sym) - goto bail; - - sect->extreloc = 1; - r->snum = NO_SECT; - adjust = -sect->size; -#endif + /* may optionally be converted below by fmt.forcesym */ + r->ext = 0; } else if (fi == NO_SECT) { /* external */ sect->extreloc = 1; r->snum = raa_read(extsyms, section); if (reltype == RL_BRANCH) r->type = X86_64_RELOC_BRANCH; - else if (r->type == GENERIC_RELOC_VANILLA) - adjust = -sect->size; } else { /* local */ r->ext = 0; r->snum = fi; - adjust = -sect->size; + if (reltype == RL_BRANCH) + r->type = X86_64_RELOC_BRANCH; } break; - case RL_SUB: - r->pcrel = 0; + case RL_SUB: /* obsolete */ + nasm_error(ERR_WARNING, "relcation with subtraction" + "becomes to be obsolete"); + r->ext = 0; r->type = X86_64_RELOC_SUBTRACTOR; break; @@ -581,34 +566,46 @@ static int64_t add_reloc(struct section *sect, int32_t section, goto needsym; needsym: - r->pcrel = 1; + r->pcrel = (fmt.ptrsize == 8 ? 1 : 0); if (section == NO_SEG) { nasm_error(ERR_NONFATAL, "Unsupported use of use of WRT"); + goto bail; } else if (fi == NO_SECT) { /* external */ r->snum = raa_read(extsyms, section); } else { - /* internal - does it really need to be global? */ - struct symbol *sym = macho_find_sym(s, offset, true, - reltype != RL_TLV); - if (!sym) + /* internal - GOTPCREL doesn't need to be in global */ + struct symbol *sym = macho_find_sym(s, offset, + false, /* reltype != RL_TLV */ + true); + if (!sym) { + nasm_error(ERR_NONFATAL, "Symbol for WRT not found"); goto bail; + } + adjust -= sym->symv[0].key; r->snum = sym->initial_snum; } break; } - /* For 64-bit Mach-O, force a symbol reference if at all possible */ - if (!r->ext && r->snum != NO_SECT && fmt.forcesym) { - struct symbol *sym = macho_find_sym(s, offset, false, false); + /* + * For 64-bit Mach-O, force a symbol reference if at all possible + * Allow for r->snum == R_ABS by searching absolute_sect + */ + if (!r->ext && fmt.forcesym) { + struct symbol *sym = macho_find_sym(s ? s : &absolute_sect, + offset, false, false); if (sym) { - adjust = bytes - sym->symv[0].key; + adjust -= sym->symv[0].key; r->snum = sym->initial_snum; r->ext = 1; } } + if (r->pcrel) + adjust += ((r->ext && fmt.ptrsize == 8) ? bytes : -(int64_t)sect->size); + /* NeXT as puts relocs in reversed order (address-wise) into the ** files, so we do the same, doesn't seem to make much of a ** difference either way */ @@ -661,6 +658,9 @@ static void macho_output(int32_t secto, const void *data, if (is_bss && type != OUT_RESERVE) { nasm_error(ERR_WARNING, "attempt to initialize memory in " "BSS section: ignored"); + /* FIXME */ + nasm_error(ERR_WARNING, "section size may be negative" + "with address symbols"); s->size += realsize(type, size); return; } @@ -698,8 +698,11 @@ static void macho_output(int32_t secto, const void *data, "Mach-O 64-bit format does not support" " 32-bit absolute addresses"); } else { - add_reloc(s, section, addr, RL_ABS, asize); + addr += add_reloc(s, section, addr, RL_ABS, asize); } + } else if (wrt == macho_tlvp_sect && fmt.ptrsize != 8 && + asize == (int) fmt.ptrsize) { + addr += add_reloc(s, section, addr, RL_TLV, asize); } else { nasm_error(ERR_NONFATAL, "Mach-O format does not support" " this use of WRT"); @@ -785,7 +788,7 @@ static void macho_output(int32_t secto, const void *data, reltype = RL_GOTLOAD; } } - } else if (wrt == macho_tlvp_sect) { + } else if (wrt == macho_tlvp_sect && fmt.ptrsize == 8) { reltype = RL_TLV; } else { nasm_error(ERR_NONFATAL, "Mach-O format does not support" @@ -1008,7 +1011,8 @@ static int32_t macho_section(char *name, int pass, int *bits) } static int32_t macho_herelabel(const char *name, enum label_type type, - int32_t section, int32_t *subsection) + int32_t section, int32_t *subsection, + bool *copyoffset) { struct section *s; int32_t subsec; @@ -1033,6 +1037,7 @@ static int32_t macho_herelabel(const char *name, enum label_type type, } s->subsection = subsec; + *copyoffset = true; /* Maintain previous offset */ return subsec; } @@ -1045,8 +1050,8 @@ static void macho_symdef(char *name, int32_t section, int64_t offset, #if defined(DEBUG) && DEBUG>2 nasm_error(ERR_DEBUG, - " macho_symdef: %s, sec=%"PRIx32", off=%"PRIx64", is_global=%d, %s\n", - name, section, offset, is_global, special); + " macho_symdef: %s, pass0=%d, passn=%"PRId64", sec=%"PRIx32", off=%"PRIx64", is_global=%d, %s\n", + name, pass0, passn, section, offset, is_global, special); #endif if (is_global == 3) { @@ -1109,6 +1114,9 @@ static void macho_symdef(char *name, int32_t section, int64_t offset, special_used = true; } + /* track the initially allocated symbol number for use in future fix-ups */ + sym->initial_snum = nsyms; + if (section == NO_SEG) { /* symbols in no section get absolute */ sym->type |= N_ABS; @@ -1123,9 +1131,6 @@ static void macho_symdef(char *name, int32_t section, int64_t offset, /* get the in-file index of the section the symbol was defined in */ sym->sect = s ? s->fileindex : NO_SECT; - /* track the initially allocated symbol number for use in future fix-ups */ - sym->initial_snum = nsyms; - if (!s) { /* remember symbol number of references to external ** symbols, this works because every external symbol gets @@ -1874,6 +1879,9 @@ macho_pragma(const struct pragma *pragma) if (real) head_flags |= MH_SUBSECTIONS_VIA_SYMBOLS; + /* Jmp-match optimization conflicts */ + optimizing.flag |= OPTIM_DISABLE_JMP_MATCH; + return DIRR_OK; case D_NO_DEAD_STRIP: diff --git a/output/outobj.c b/output/outobj.c index 347e96f93..f3880a4b6 100644 --- a/output/outobj.c +++ b/output/outobj.c @@ -1380,9 +1380,10 @@ static int32_t obj_segment(char *name, int pass, int *bits) attrs++; } - obj_idx = 1; - for (seg = seghead; seg; seg = seg->next) { - obj_idx++; + for (seg = seghead, obj_idx = 1; ; seg = seg->next, obj_idx++) { + if (!seg) + break; + if (!strcmp(seg->name, name)) { if (attrs > 0 && pass == 1) nasm_error(ERR_WARNING, "segment attributes specified on" @@ -1403,7 +1404,7 @@ static int32_t obj_segment(char *name, int pass, int *bits) seg->obj_index = obj_idx; seg->grp = NULL; any_segs = true; - seg->name = NULL; + seg->name = nasm_strdup(name); seg->currentpos = 0; seg->align = 1; /* default */ seg->use32 = false; /* default */ diff --git a/test/Makefile b/test/Makefile index ebd8c3f3c..7cba37ece 100644 --- a/test/Makefile +++ b/test/Makefile @@ -12,46 +12,46 @@ $(NASM): $(MAKE) -C .. %.bin: %.asm $(NASMDEP) - $(NASM) $(NASMOPT) -f bin -o $@ -MD $@.dep -l $*.lst $< + $(NASM) $(NASMOPT) -f bin -o $@ -MD $@.dep -l $@.lst $< %.ith: %.asm $(NASMDEP) - $(NASM) $(NASMOPT) -f ith -o $@ -MD $@.dep -l $*.lst $< + $(NASM) $(NASMOPT) -f ith -o $@ -MD $@.dep -l $@.lst $< %.srec: %.asm $(NASMDEP) - $(NASM) $(NASMOPT) -f srec -o $@ -MD $@.dep -l $*.lst $< + $(NASM) $(NASMOPT) -f srec -o $@ -MD $@.dep -l $@.lst $< %.o: %.asm $(NASMDEP) - $(NASM) $(NASMOPT) -f elf32 -o $@ -MD $@.dep -l $*.lst $< + $(NASM) $(NASMOPT) -f elf32 -o $@ -MD $@.dep -l $@.lst $< %.o64: %.asm $(NASMDEP) - $(NASM) $(NASMOPT) -f elf64 -o $@ -MD $@.dep -l $*.lst $< + $(NASM) $(NASMOPT) -f elf64 -o $@ -MD $@.dep -l $@.lst $< %.obj: %.asm $(NASMDEP) - $(NASM) $(NASMOPT) -f obj -o $@ -MD $@.dep -l $*.lst $< + $(NASM) $(NASMOPT) -f obj -o $@ -MD $@.dep -l $@.lst $< %.rdf: %.asm $(NASMDEP) - $(NASM) $(NASMOPT) -f rdf -o $@ -MD $@.dep -l $*.lst $< + $(NASM) $(NASMOPT) -f rdf -o $@ -MD $@.dep -l $@.lst $< %.od: %.obj ../misc/omfdump ../misc/omfdump $< > $@ %.coff: %.asm $(NASMDEP) - $(NASM) $(NASMOPT) -f coff -o $@ -MD $@.dep -l $*.lst $< + $(NASM) $(NASMOPT) -f coff -o $@ -MD $@.dep -l $@.lst $< %.win32: %.asm $(NASMDEP) - $(NASM) $(NASMOPT) -f win32 -o $@ -MD $@.dep -l $*.lst $< + $(NASM) $(NASMOPT) -f win32 -o $@ -MD $@.dep -l $@.lst $< %.win64: %.asm $(NASMDEP) - $(NASM) $(NASMOPT) -f win64 -o $@ -MD $@.dep -l $*.lst $< + $(NASM) $(NASMOPT) -f win64 -o $@ -MD $@.dep -l $@.lst $< %.mo32: %.asm $(NASMDEP) - $(NASM) $(NASMOPT) -f macho32 -o $@ -MD $@.dep -l $*.lst $< + $(NASM) $(NASMOPT) -f macho32 -o $@ -MD $@.dep -l $@.lst $< %.mo64: %.asm $(NASMDEP) - $(NASM) $(NASMOPT) -f macho64 -o $@ -MD $@.dep -l $*.lst $< + $(NASM) $(NASMOPT) -f macho64 -o $@ -MD $@.dep -l $@.lst $< %.dbg: %.asm $(NASMDEP) - $(NASM) $(NASMOPT) -f dbg -o $@ -MD $@.dep -l $*.lst $< + $(NASM) $(NASMOPT) -f dbg -o $@ -MD $@.dep -l $@.lst $< %.asm: %.pl $(PERL) $< > $@ @@ -83,7 +83,7 @@ spotless: clean # Test for ELF32 shared libraries; assumes an x86 Linux system # elfso.o: elfso.asm $(NASMDEP) - $(NASM) $(NASMOPT) -f elf32 -F stabs -o $@ -MD $@.dep -l $*.lst $< + $(NASM) $(NASMOPT) -f elf32 -F stabs -o $@ -MD $@.dep -l $@.lst $< elfso.so: elfso.o $(LD) -m elf_i386 -shared -o $@ -MD $@.dep $< @@ -96,7 +96,7 @@ elftest: elftest.c elfso.so # Test for ELF64 shared libraries; assumes an x86-64 Linux system # elf64so.o: elf64so.asm $(NASMDEP) - $(NASM) $(NASMOPT) -f elf64 -F dwarf -o $@ -MD $@.dep -l $*.lst $< + $(NASM) $(NASMOPT) -f elf64 -F dwarf -o $@ -MD $@.dep -l $@.lst $< elf64so.so: elf64so.o $(LD) -shared -o $@ -MD $@.dep $< diff --git a/test/absolute.asm b/test/absolute.asm index 31c8178c9..969a85e90 100644 --- a/test/absolute.asm +++ b/test/absolute.asm @@ -1,5 +1,7 @@ ;Testname=bin; Arguments=-fbin -oabsolute.bin; Files=stdout stderr absolute.bin +%ifmacro org org 7c00h +%endif init_foo: jmp init_bar nop @@ -15,7 +17,7 @@ init_foo: nop nop nop - + init_bar: mov [b1],dl mov [b2],edx @@ -33,8 +35,7 @@ init_bar: nop nop ret - + absolute init_bar+7 b1: resb 1 b2: resd 6 - diff --git a/test/ctxlocal.asm b/test/ctxlocal.asm new file mode 100644 index 000000000..93e9fcae4 --- /dev/null +++ b/test/ctxlocal.asm @@ -0,0 +1,25 @@ +;; +;; Test of context-local labels +;; + + bits 64 + extern everywhere ; Test of extern -> global promotion, too + extern tjosan +here: + jz .there +%push foo + jo %$mordor + hlt +%$mordor: + nop +%pop +.there: + ret + +everywhere: + ret + + global everywhere + +tjosan: + ret diff --git a/test/elf_visibility.asm b/test/elf_visibility.asm new file mode 100644 index 000000000..4874b62dd --- /dev/null +++ b/test/elf_visibility.asm @@ -0,0 +1,10 @@ +global foo +global foo_hidden:function hidden + +SECTION .text align=16 + +foo: +foo_hidden: +foo_label: +ret + diff --git a/test/subsection.asm b/test/subsection.asm index ce8ed4aad..8ba619786 100644 --- a/test/subsection.asm +++ b/test/subsection.asm @@ -4,9 +4,9 @@ ; Test of Mach-O subsection_by_symbol ; -%pragma output subsections_via_symbols -%pragma asm gprefix _ -%pragma asm lprefix L_ +%pragma macho subsections_via_symbols +%pragma macho gprefix _ +%pragma macho lprefix L. bits 32 diff --git a/test/v4.asm b/test/v4.asm new file mode 100644 index 000000000..a64d3c663 --- /dev/null +++ b/test/v4.asm @@ -0,0 +1,12 @@ + bits 64 + v4fmaddps zmm0,zmm1+3,[rax] + v4fnmaddps zmm2,zmm3,[rax] + v4fmaddss zmm4,zmm5+3,[rax] + v4fnmaddss zmm6,zmm7+3,[rax] + + v4dpwssds zmm8,zmm9,[rax] + v4dpwssd zmm10,zmm11+3,[rax] + v4dpwssd zmm10+0,zmm11+3,[rax] +; v4dpwssd zmm10+1,zmm11+3,[rax] +; v4dpwssd zmm10,zmm11+4,[rax] +; v4dpwssd zmm10,zmm11+7,[rax] diff --git a/tools/mkdep.pl b/tools/mkdep.pl index e84cc3581..8c89f39a1 100755 --- a/tools/mkdep.pl +++ b/tools/mkdep.pl @@ -51,6 +51,9 @@ $barrier = "#-- Everything below is generated by mkdep.pl - do not edit --#\n"; # This converts from filenames to full pathnames for our dependencies %dep_path = {}; +# List of files that cannot be found; these *must* be excluded +@must_exclude = (); + # # Scan files for dependencies # @@ -70,7 +73,8 @@ sub scandeps($) { if ( $line =~ /^\s*\#\s*include\s+\"(.*)\"\s*$/ ) { my $nf = $1; if (!defined($dep_path{$nf})) { - die "$0: cannot determine path for dependency: $file -> $nf\n"; + push(@must_exclude, $nf); + next; } $nf = $dep_path{$nf}; $mdeps{$nf}++; @@ -138,7 +142,7 @@ sub _insert_deps($$) { my $selfrule = 0; my $do_external = 0; my $maxline = 78; # Seems like a reasonable default - my @exclude = (); # Don't exclude anything + my %exclude = (); # Don't exclude anything my @genhdrs = (); my $external = undef; my $raw_output = 0; @@ -165,7 +169,7 @@ sub _insert_deps($$) { } elsif ( $parm eq 'continuation' ) { $cont = $val; } elsif ( $parm eq 'exclude' ) { - @exclude = split(/\,/, $val); + $excludes{$val}++; } elsif ( $parm eq 'include-command' ) { $include_command = $val; } elsif ( $parm eq 'external' ) { @@ -201,10 +205,6 @@ sub _insert_deps($$) { } my $e; - my %do_exclude = (); - foreach $e (@exclude) { - $do_exclude{$e} = 1; - } foreach my $dfile ($external, sort(keys(%deps)) ) { my $ofile; @@ -222,7 +222,7 @@ sub _insert_deps($$) { my $len = length($ofile); print $out $ofile; foreach my $dep (@deps) { - unless ($do_exclude{$dep}) { + unless ($excludes{$dep}) { my $str = convert_file($dep, $sep); my $sl = length($str)+1; if ( $len+$sl > $maxline-2 ) { diff --git a/x86/insns-iflags.ph b/x86/insns-iflags.ph index 43bf70e89..c5311c6cd 100644 --- a/x86/insns-iflags.ph +++ b/x86/insns-iflags.ph @@ -1,7 +1,7 @@ #!/usr/bin/perl ## -------------------------------------------------------------------------- ## -## Copyright 1996-2016 The NASM Authors - All Rights Reserved +## Copyright 1996-2018 The NASM Authors - All Rights Reserved ## See the file AUTHORS included with the NASM distribution for ## the specific copyright holders. ## @@ -142,7 +142,15 @@ my %insns_flag_bit = ( "AVX512VBMI" => [$f++, "AVX-512 VBMI instructions"], "AES" => [$f++, "AES instructions"], "VAES" => [$f++, "AES AVX instructions"], - "VPCLMULQDQ" => [$f++, "Carry-Less Multiplication extention"], + "VPCLMULQDQ" => [$f++, "AVX Carryless Multiplication"], + "GFNI" => [$f++, "Galois Field instructions"], + "AVX512VBMI2" => [$f++, "AVX-512 VBMI2 instructions"], + "AVX512VNNI" => [$f++, "AVX-512 VNNI instructions"], + "AVX512BITALG" => [$f++, "AVX-512 Bit Algorithm instructions"], + "AVX512VPOPCNTDQ" => [$f++, "AVX-512 VPOPCNTD/VPOPCNTQ"], + "AVX5124FMAPS" => [$f++, "AVX-512 4-iteration multiply-add"], + "AVX5124VNNIW" => [$f++, "AVX-512 4-iteration dot product"], + "SGX" => [$f++, "Intel Software Guard Extensions (SGX)"], # Put these last "OBSOLETE" => [$f++, "Instruction removed from architecture"], diff --git a/x86/insns.dat b/x86/insns.dat index 47367bf72..e9e455670 100644 --- a/x86/insns.dat +++ b/x86/insns.dat @@ -2093,7 +2093,6 @@ VAESENCLAST zmmreg,zmmreg*,zmmrm512 [rvm:fv: evex.nds.512.66.0f38.wig dd /r] AV VAESDEC zmmreg,zmmreg*,zmmrm512 [rvm:fv: evex.nds.512.66.0f38.wig de /r] AVX512,VAES,FUTURE VAESDECLAST zmmreg,zmmreg*,zmmrm512 [rvm:fv: evex.nds.512.66.0f38.wig df /r] AVX512,VAES,FUTURE - ;# Intel AVX instructions VADDPD xmmreg,xmmreg*,xmmrm128 [rvm: vex.nds.128.66.0f 58 /r] AVX,SANDYBRIDGE VADDPD ymmreg,ymmreg*,ymmrm256 [rvm: vex.nds.256.66.0f 58 /r] AVX,SANDYBRIDGE @@ -5198,6 +5197,156 @@ PCOMMIT void [ 66 0f ae f8] ; AMD Zen v1 CLZERO void [ 0f 01 fc] FUTURE,AMD +;# Processor trace write +PTWRITE rm32 [m: np 0f ae /4] FUTURE +PTWRITE rm64 [m: o64 np 0f ae /4] X64,FUTURE + +;# Instructions from the Intel Instruction Set Extensions, +;# doc 319433-034 May 2018 +CLDEMOTE mem [m: np 0f 1c /0] FUTURE +MOVDIRI mem32,reg32 [mr: np 0f 38 f9 /r] FUTURE,SD +MOVDIRI mem64,reg64 [mr: o64 0f 38 f9 /r] FUTURE,X64,SQ +MOVDIR64B reg16,mem512 [rm: a16 66 0f 38 f8 /r] FUTURE,NOLONG +MOVDIR64B reg32,mem512 [rm: a32 66 0f 38 f8 /r] FUTURE +MOVDIR64B reg64,mem512 [rm: a64 66 0f 38 f8 /r] FUTURE,X64 +PCONFIG void [ np 0f 01 c5] FUTURE +TPAUSE reg32 [m: 66 0f ae /6] FUTURE +TPAUSE reg32,reg_edx,reg_eax [m--: 66 0f ae /6] FUTURE,ND +UMONITOR reg16 [m: a16 f3 0f ae /6] FUTURE,NOLONG +UMONITOR reg32 [m: a32 f3 0f ae /6] FUTURE +UMONITOR reg64 [m: a64 f3 0f ae /6] FUTURE,X64 +UMWAIT reg32 [m: f2 0f ae /6] FUTURE +UMWAIT reg32,reg_edx,reg_eax [m--: f2 0f ae /6] FUTURE,ND +WBNOINVD void [ f3 0f 09] FUTURE + +;# Galois field operations (GFNI) +GF2P8AFFINEINVQB xmmreg,xmmrm128,imm8 [rmi: 66 0f 3a cf /r ib] GFNI,SSE,FUTURE +VGF2P8AFFINEINVQB xmmreg,xmmreg*,xmmrm128,imm8 [rvmi: vex.nds.128.66.0f3a.w1 cf /r ib] GFNI,AVX,FUTURE +VGF2P8AFFINEINVQB ymmreg,ymmreg*,ymmrm256,imm8 [rvmi: vex.nds.256.66.0f3a.w1 cf /r ib] GFNI,AVX,FUTURE +VGF2P8AFFINEINVQB xmmreg|mask|z,xmmreg*,xmmrm128|b64,imm8 [rvmi:fv: evex.nds.128.66.0f3a.w1 cf /r ib] GFNI,AVX512VL,FUTURE +VGF2P8AFFINEINVQB ymmreg|mask|z,ymmreg*,ymmrm256|b64,imm8 [rvmi:fv: evex.nds.256.66.0f3a.w1 cf /r ib] GFNI,AVX512VL,FUTURE +VGF2P8AFFINEINVQB zmmreg|mask|z,zmmreg*,zmmrm512|b64,imm8 [rvmi:fv: evex.nds.512.66.0f3a.w1 cf /r ib] GFNI,AVX512,FUTURE +GF2P8AFFINEQB xmmreg,xmmrm128,imm8 [rmi: 66 0f 3a ce /r ib] GFNI,SSE,FUTURE +VGF2P8AFFINEQB xmmreg,xmmreg*,xmmrm128,imm8 [rvmi: vex.nds.128.66.0f3a.w1 ce /r ib] GFNI,AVX,FUTURE +VGF2P8AFFINEQB ymmreg,ymmreg*,ymmrm256,imm8 [rvmi: vex.nds.256.66.0f3a.w1 ce /r ib] GFNI,AVX,FUTURE +VGF2P8AFFINEQB xmmreg|mask|z,xmmreg*,xmmrm128|b64,imm8 [rvmi:fv: evex.nds.128.66.0f3a.w1 ce /r ib] GFNI,AVX512VL,FUTURE +VGF2P8AFFINEQB ymmreg|mask|z,ymmreg*,ymmrm256|b64,imm8 [rvmi:fv: evex.nds.256.66.0f3a.w1 ce /r ib] GFNI,AVX512VL,FUTURE +VGF2P8AFFINEQB zmmreg|mask|z,zmmreg*,zmmrm512|b64,imm8 [rvmi:fv: evex.nds.512.66.0f3a.w1 ce /r ib] GFNI,AVX512,FUTURE +GF2P8MULB xmmreg,xmmrm128 [rm: 66 0f 38 cf /r] GFNI,SSE,FUTURE +VGF2P8MULB xmmreg,xmmreg*,xmmrm128 [rvm: vex.nds.128.66.0f38.w0 cf /r] GFNI,AVX,FUTURE +VGF2P8MULB ymmreg,ymmreg*,ymmrm256 [rvm: vex.nds.256.66.0f38.w0 cf /r] GFNI,AVX,FUTURE +VGF2P8MULB xmmreg|mask|z,xmmreg*,xmmrm128 [rvm:fvm: evex.nds.128.66.0f38.w0 cf /r] GFNI,AVX512VL,FUTURE +VGF2P8MULB ymmreg|mask|z,ymmreg*,ymmrm256 [rvm:fvm: evex.nds.256.66.0f38.w0 cf /r] GFNI,AVX512VL,FUTURE +VGF2P8MULB zmmreg|mask|z,zmmreg*,zmmrm512 [rvm:fvm: evex.nds.512.66.0f38.w0 cf /r] GFNI,AVX512,FUTURE + +;# AVX512 Vector Bit Manipulation Instructions 2 +VPCOMPRESSB mem128|mask,xmmreg [mr:t1s: evex.128.66.0f38.w0 63 /r] AVX512VBMI2,AVX512VL,FUTURE +VPCOMPRESSB mem256|mask,ymmreg [mr:t1s: evex.256.66.0f38.w0 63 /r] AVX512VBMI2,AVX512VL,FUTURE +VPCOMPRESSB mem512|mask,zmmreg [mr:t1s: evex.512.66.0f38.w0 63 /r] AVX512VBMI2,FUTURE +VPCOMPRESSB xmmreg|mask|z,xmmreg [mr: evex.128.66.0f38.w0 63 /r] AVX512VBMI2,AVX512VL,FUTURE +VPCOMPRESSB ymmreg|mask|z,ymmreg [mr: evex.256.66.0f38.w0 63 /r] AVX512VBMI2,AVX512VL,FUTURE +VPCOMPRESSB zmmreg|mask|z,zmmreg [mr: evex.512.66.0f38.w0 63 /r] AVX512VBMI2,FUTURE +VPCOMPRESSW mem128|mask,xmmreg [mr:t1s: evex.128.66.0f38.w1 63 /r] AVX512VBMI2,AVX512VL,FUTURE +VPCOMPRESSW mem256|mask,ymmreg [mr:t1s: evex.256.66.0f38.w1 63 /r] AVX512VBMI2,AVX512VL,FUTURE +VPCOMPRESSW mem512|mask,zmmreg [mr:t1s: evex.512.66.0f38.w1 63 /r] AVX512VBMI2,FUTURE +VPCOMPRESSW xmmreg|mask|z,xmmreg [mr: evex.128.66.0f38.w1 63 /r] AVX512VBMI2,AVX512VL,FUTURE +VPCOMPRESSW ymmreg|mask|z,ymmreg [mr: evex.256.66.0f38.w1 63 /r] AVX512VBMI2,AVX512VL,FUTURE +VPCOMPRESSW zmmreg|mask|z,zmmreg [mr: evex.512.66.0f38.w1 63 /r] AVX512VBMI2,FUTURE +VPEXPANDB mem128|mask,xmmreg [mr:t1s: evex.128.66.0f38.w0 62 /r] AVX512VBMI2,AVX512VL,FUTURE +VPEXPANDB mem256|mask,ymmreg [mr:t1s: evex.256.66.0f38.w0 62 /r] AVX512VBMI2,AVX512VL,FUTURE +VPEXPANDB mem512|mask,zmmreg [mr:t1s: evex.512.66.0f38.w0 62 /r] AVX512VBMI2,FUTURE +VPEXPANDB xmmreg|mask|z,xmmreg [mr: evex.128.66.0f38.w0 62 /r] AVX512VBMI2,AVX512VL,FUTURE +VPEXPANDB ymmreg|mask|z,ymmreg [mr: evex.256.66.0f38.w0 62 /r] AVX512VBMI2,AVX512VL,FUTURE +VPEXPANDB zmmreg|mask|z,zmmreg [mr: evex.512.66.0f38.w0 62 /r] AVX512VBMI2,FUTURE +VPEXPANDW mem128|mask,xmmreg [mr:t1s: evex.128.66.0f38.w1 62 /r] AVX512VBMI2,AVX512VL,FUTURE +VPEXPANDW mem256|mask,ymmreg [mr:t1s: evex.256.66.0f38.w1 62 /r] AVX512VBMI2,AVX512VL,FUTURE +VPEXPANDW mem512|mask,zmmreg [mr:t1s: evex.512.66.0f38.w1 62 /r] AVX512VBMI2,FUTURE +VPEXPANDW xmmreg|mask|z,xmmreg [mr: evex.128.66.0f38.w1 62 /r] AVX512VBMI2,AVX512VL,FUTURE +VPEXPANDW ymmreg|mask|z,ymmreg [mr: evex.256.66.0f38.w1 62 /r] AVX512VBMI2,AVX512VL,FUTURE +VPEXPANDW zmmreg|mask|z,zmmreg [mr: evex.512.66.0f38.w1 62 /r] AVX512VBMI2,FUTURE +VPSHLDW xmmreg|mask|z,xmmreg*,xmmrm128,imm8 [rvmi:fvm: evex.nds.128.66.0f3a.w1 70 /r ib] AVX512VBMI2,AVX512VL,FUTURE +VPSHLDW ymmreg|mask|z,ymmreg*,ymmrm256,imm8 [rvmi:fvm: evex.nds.256.66.0f3a.w1 70 /r ib] AVX512VBMI2,AVX512VL,FUTURE +VPSHLDW zmmreg|mask|z,zmmreg*,zmmrm512,imm8 [rvmi:fvm: evex.nds.512.66.0f3a.w1 70 /r ib] AVX512VBMI2,FUTURE +VPSHLDD xmmreg|mask|z,xmmreg*,xmmrm128|b32,imm8 [rvmi:fv: evex.nds.128.66.0f3a.w0 71 /r ib] AVX512VBMI2,AVX512VL,FUTURE +VPSHLDD ymmreg|mask|z,ymmreg*,ymmrm256|b32,imm8 [rvmi:fv: evex.nds.256.66.0f3a.w0 71 /r ib] AVX512VBMI2,AVX512VL,FUTURE +VPSHLDD zmmreg|mask|z,zmmreg*,zmmrm512|b32,imm8 [rvmi:fv: evex.nds.512.66.0f3a.w0 71 /r ib] AVX512VBMI2,FUTURE +VPSHLDQ xmmreg|mask|z,xmmreg*,xmmrm128|b64,imm8 [rvmi:fv: evex.nds.128.66.0f3a.w1 71 /r ib] AVX512VBMI2,AVX512VL,FUTURE +VPSHLDQ ymmreg|mask|z,ymmreg*,ymmrm256|b64,imm8 [rvmi:fv: evex.nds.256.66.0f3a.w1 71 /r ib] AVX512VBMI2,AVX512VL,FUTURE +VPSHLDQ zmmreg|mask|z,zmmreg*,zmmrm512|b64,imm8 [rvmi:fv: evex.nds.512.66.0f3a.w1 71 /r ib] AVX512VBMI2,FUTURE +VPSHLDVW xmmreg|mask|z,xmmreg*,xmmrm128 [rvmi:fvm: evex.dds.128.66.0f38.w1 70 /r ib] AVX512VBMI2,AVX512VL,FUTURE +VPSHLDVW ymmreg|mask|z,ymmreg*,ymmrm256 [rvmi:fvm: evex.dds.256.66.0f38.w1 70 /r ib] AVX512VBMI2,AVX512VL,FUTURE +VPSHLDVW zmmreg|mask|z,zmmreg*,zmmrm512 [rvmi:fvm: evex.dds.512.66.0f38.w1 70 /r ib] AVX512VBMI2,FUTURE +VPSHLDVD xmmreg|mask|z,xmmreg*,xmmrm128|b32 [rvmi:fv: evex.dds.128.66.0f38.w0 71 /r ib] AVX512VBMI2,AVX512VL,FUTURE +VPSHLDVD ymmreg|mask|z,ymmreg*,ymmrm256|b32 [rvmi:fv: evex.dds.256.66.0f38.w0 71 /r ib] AVX512VBMI2,AVX512VL,FUTURE +VPSHLDVD zmmreg|mask|z,zmmreg*,zmmrm512|b32 [rvmi:fv: evex.dds.512.66.0f38.w0 71 /r ib] AVX512VBMI2,FUTURE +VPSHLDVQ xmmreg|mask|z,xmmreg*,xmmrm128|b64 [rvmi:fv: evex.dds.128.66.0f38.w1 71 /r ib] AVX512VBMI2,AVX512VL,FUTURE +VPSHLDVQ ymmreg|mask|z,ymmreg*,ymmrm256|b64 [rvmi:fv: evex.dds.256.66.0f38.w1 71 /r ib] AVX512VBMI2,AVX512VL,FUTURE +VPSHLDVQ zmmreg|mask|z,zmmreg*,zmmrm512|b64 [rvmi:fv: evex.dds.512.66.0f38.w1 71 /r ib] AVX512VBMI2,FUTURE +VPSHRDW xmmreg|mask|z,xmmreg*,xmmrm128,imm8 [rvmi:fvm: evex.nds.128.66.0f3a.w1 72 /r ib] AVX512VBMI2,AVX512VL,FUTURE +VPSHRDW ymmreg|mask|z,ymmreg*,ymmrm256,imm8 [rvmi:fvm: evex.nds.256.66.0f3a.w1 72 /r ib] AVX512VBMI2,AVX512VL,FUTURE +VPSHRDW zmmreg|mask|z,zmmreg*,zmmrm512,imm8 [rvmi:fvm: evex.nds.512.66.0f3a.w1 72 /r ib] AVX512VBMI2,FUTURE +VPSHRDD xmmreg|mask|z,xmmreg*,xmmrm128|b32,imm8 [rvmi:fv: evex.nds.128.66.0f3a.w0 73 /r ib] AVX512VBMI2,AVX512VL,FUTURE +VPSHRDD ymmreg|mask|z,ymmreg*,ymmrm256|b32,imm8 [rvmi:fv: evex.nds.256.66.0f3a.w0 73 /r ib] AVX512VBMI2,AVX512VL,FUTURE +VPSHRDD zmmreg|mask|z,zmmreg*,zmmrm512|b32,imm8 [rvmi:fv: evex.nds.512.66.0f3a.w0 73 /r ib] AVX512VBMI2,FUTURE +VPSHRDQ xmmreg|mask|z,xmmreg*,xmmrm128|b64,imm8 [rvmi:fv: evex.nds.128.66.0f3a.w1 73 /r ib] AVX512VBMI2,AVX512VL,FUTURE +VPSHRDQ ymmreg|mask|z,ymmreg*,ymmrm256|b64,imm8 [rvmi:fv: evex.nds.256.66.0f3a.w1 73 /r ib] AVX512VBMI2,AVX512VL,FUTURE +VPSHRDQ zmmreg|mask|z,zmmreg*,zmmrm512|b64,imm8 [rvmi:fv: evex.nds.512.66.0f3a.w1 73 /r ib] AVX512VBMI2,FUTURE +VPSHRDVW xmmreg|mask|z,xmmreg*,xmmrm128 [rvmi:fvm: evex.dds.128.66.0f38.w1 72 /r ib] AVX512VBMI2,AVX512VL,FUTURE +VPSHRDVW ymmreg|mask|z,ymmreg*,ymmrm256 [rvmi:fvm: evex.dds.256.66.0f38.w1 72 /r ib] AVX512VBMI2,AVX512VL,FUTURE +VPSHRDVW zmmreg|mask|z,zmmreg*,zmmrm512 [rvmi:fvm: evex.dds.512.66.0f38.w1 72 /r ib] AVX512VBMI2,FUTURE +VPSHRDVD xmmreg|mask|z,xmmreg*,xmmrm128|b32 [rvmi:fv: evex.dds.128.66.0f38.w0 73 /r ib] AVX512VBMI2,AVX512VL,FUTURE +VPSHRDVD ymmreg|mask|z,ymmreg*,ymmrm256|b32 [rvmi:fv: evex.dds.256.66.0f38.w0 73 /r ib] AVX512VBMI2,AVX512VL,FUTURE +VPSHRDVD zmmreg|mask|z,zmmreg*,zmmrm512|b32 [rvmi:fv: evex.dds.512.66.0f38.w0 73 /r ib] AVX512VBMI2,FUTURE +VPSHRDVQ xmmreg|mask|z,xmmreg*,xmmrm128|b64 [rvmi:fv: evex.dds.128.66.0f38.w1 73 /r ib] AVX512VBMI2,AVX512VL,FUTURE +VPSHRDVQ ymmreg|mask|z,ymmreg*,ymmrm256|b64 [rvmi:fv: evex.dds.256.66.0f38.w1 73 /r ib] AVX512VBMI2,AVX512VL,FUTURE +VPSHRDVQ zmmreg|mask|z,zmmreg*,zmmrm512|b64 [rvmi:fv: evex.dds.512.66.0f38.w1 73 /r ib] AVX512VBMI2,FUTURE + +;# AVX512 VNNI +VPDPBUSD xmmreg|mask|z,xmmreg*,xmmrm128|b32 [rvm:fv: evex.dds.128.66.0f38.w0 50 /r] AVX512VNNI,AVX512VL,FUTURE +VPDPBUSD ymmreg|mask|z,ymmreg*,ymmrm256|b32 [rvm:fv: evex.dds.256.66.0f38.w0 50 /r] AVX512VNNI,AVX512VL,FUTURE +VPDPBUSD zmmreg|mask|z,zmmreg*,zmmrm512|b32 [rvm:fv: evex.dds.512.66.0f38.w0 50 /r] AVX512VNNI,FUTURE +VPDPBUSDS xmmreg|mask|z,xmmreg*,xmmrm128|b32 [rvm:fv: evex.dds.128.66.0f38.w0 51 /r] AVX512VNNI,AVX512VL,FUTURE +VPDPBUSDS ymmreg|mask|z,ymmreg*,ymmrm256|b32 [rvm:fv: evex.dds.256.66.0f38.w0 51 /r] AVX512VNNI,AVX512VL,FUTURE +VPDPBUSDS zmmreg|mask|z,zmmreg*,zmmrm512|b32 [rvm:fv: evex.dds.512.66.0f38.w0 51 /r] AVX512VNNI,FUTURE +VPDPWSSD xmmreg|mask|z,xmmreg*,xmmrm128|b32 [rvm:fv: evex.dds.128.66.0f38.w0 52 /r] AVX512VNNI,AVX512VL,FUTURE +VPDPWSSD ymmreg|mask|z,ymmreg*,ymmrm256|b32 [rvm:fv: evex.dds.256.66.0f38.w0 52 /r] AVX512VNNI,AVX512VL,FUTURE +VPDPWSSD zmmreg|mask|z,zmmreg*,zmmrm512|b32 [rvm:fv: evex.dds.512.66.0f38.w0 52 /r] AVX512VNNI,FUTURE +VPDPWSSDS xmmreg|mask|z,xmmreg*,xmmrm128|b32 [rvm:fv: evex.dds.128.66.0f38.w0 53 /r] AVX512VNNI,AVX512VL,FUTURE +VPDPWSSDS ymmreg|mask|z,ymmreg*,ymmrm256|b32 [rvm:fv: evex.dds.256.66.0f38.w0 53 /r] AVX512VNNI,AVX512VL,FUTURE +VPDPWSSDS zmmreg|mask|z,zmmreg*,zmmrm512|b32 [rvm:fv: evex.dds.512.66.0f38.w0 53 /r] AVX512VNNI,FUTURE + +;# AVX512 Bit Algorithms +VPOPCNTB xmmreg|mask|z,xmmrm128 [rm:fvm: evex.128.66.0f38.w0 54 /r] AVX512BITALG,AVX512VL,FUTURE +VPOPCNTB ymmreg|mask|z,ymmrm256 [rm:fvm: evex.256.66.0f38.w0 54 /r] AVX512BITALG,AVX512VL,FUTURE +VPOPCNTB zmmreg|mask|z,zmmrm512 [rm:fvm: evex.512.66.0f38.w0 54 /r] AVX512BITALG,FUTURE +VPOPCNTW xmmreg|mask|z,xmmrm128 [rm:fvm: evex.128.66.0f38.w1 54 /r] AVX512BITALG,AVX512VL,FUTURE +VPOPCNTW ymmreg|mask|z,ymmrm256 [rm:fvm: evex.256.66.0f38.w1 54 /r] AVX512BITALG,AVX512VL,FUTURE +VPOPCNTW zmmreg|mask|z,zmmrm512 [rm:fvm: evex.512.66.0f38.w1 54 /r] AVX512BITALG,FUTURE +VPOPCNTD xmmreg|mask|z,xmmrm128 [rm:fv: evex.128.66.0f38.w0 55 /r] AVX512VPOPCNTDQ,AVX512VL,FUTURE +VPOPCNTD ymmreg|mask|z,ymmrm256 [rm:fv: evex.256.66.0f38.w0 55 /r] AVX512VPOPCNTDQ,AVX512VL,FUTURE +VPOPCNTD zmmreg|mask|z,zmmrm512 [rm:fv: evex.512.66.0f38.w0 55 /r] AVX512VPOPCNTDQ,FUTURE +VPOPCNTQ xmmreg|mask|z,xmmrm128 [rm:fv: evex.128.66.0f38.w1 55 /r] AVX512VPOPCNTDQ,AVX512VL,FUTURE +VPOPCNTQ ymmreg|mask|z,ymmrm256 [rm:fv: evex.256.66.0f38.w1 55 /r] AVX512VPOPCNTDQ,AVX512VL,FUTURE +VPOPCNTQ zmmreg|mask|z,zmmrm512 [rm:fv: evex.512.66.0f38.w1 55 /r] AVX512VPOPCNTDQ,FUTURE +VPSHUFBITQMB kreg|mask,xmmreg,xmmrm128 [rvm:fvm: evex.nds.128.66.0f38.w0 8f /r] AVX512BITALG,AVX512VL,FUTURE +VPSHUFBITQMB kreg|mask,ymmreg,ymmrm256 [rvm:fvm: evex.nds.256.66.0f38.w0 8f /r] AVX512BITALG,AVX512VL,FUTURE +VPSHUFBITQMB kreg|mask,zmmreg,zmmrm512 [rvm:fvm: evex.nds.512.66.0f38.w0 8f /r] AVX512BITALG,FUTURE + +;# AVX512 4-iteration Multiply-Add +V4FMADDPS zmmreg|mask|z,zmmreg|rs4,mem [rvm:m128:evex.dds.512.f2.0f38.w0 9a /r] AVX5124FMAPS,FUTURE,SO +V4FNMADDPS zmmreg|mask|z,zmmreg|rs4,mem [rvm:m128:evex.dds.512.f2.0f38.w0 aa /r] AVX5124FMAPS,FUTURE,SO +V4FMADDSS zmmreg|mask|z,zmmreg|rs4,mem [rvm:m128:evex.dds.lig.f2.0f38.w0 9b /r] AVX5124FMAPS,FUTURE,SO +V4FNMADDSS zmmreg|mask|z,zmmreg|rs4,mem [rvm:m128:evex.dds.lig.f2.0f38.w0 ab /r] AVX5124FMAPS,FUTURE,SO + +;# AVX512 4-iteration Dot Product +V4DPWSSDS zmmreg|mask|z,zmmreg|rs4,mem [rvm:m128:evex.dds.512.f2.0f38.w0 53 /r] AVX5124VNNIW,FUTURE,SO +V4DPWSSD zmmreg|mask|z,zmmreg|rs4,mem [rvm:m128:evex.dds.512.f2.0f38.w0 52 /r] AVX5124VNNIW,FUTURE,SO + +;# Intel Software Guard Extensions (SGX) +ENCLS void [ np 0f 01 cf] SGX,FUTURE +ENCLU void [ np 0f 01 d7] SGX,FUTURE +ENCLV void [ np 0f 01 c0] SGX,FUTURE + ;# Systematic names for the hinting nop instructions ; These should be last in the file HINT_NOP0 rm16 [m: o16 0f 18 /0] P6,UNDOC