Compare commits

...

267 commits

Author SHA1 Message Date
H. Peter Anvin (Intel)
fbdc88565c AUTHORS: update maintainer for 2+, no longer with Intel
Some checks failed
NASM CI/CD / Build and test (push) Failing after 4s
NASM CI/CD / Build with MSVC (Windows) (push) Has been cancelled
Even though NASM is now using 3.xx version numbers, I'm still the main
maintainer :)

2026-08-15 was my last day employed by Intel Corporation, so anything
since are not their copyright.

Signed-off-by: H. Peter Anvin <hpa@zytor.com>
2026-08-19 16:45:00 -07:00
H. Peter Anvin (Intel)
b2734a91bd output/outobj.c: free the section name on cleanup
It is a completely unimportant memory leak as the process is about to
exit, but it is easy to clean up.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-07-07 15:43:40 -07:00
H. Peter Anvin (Intel)
9248a85f97 asm/error.c: handle -w* during command line parsing
During command line parsing, warning_state_init is NULL as the warning
stack is naturally not set up yet. Furthermore, -w* would mean return
to command-line default, which isn't even defined yet.

Rather than ignoring it or returning an error, do something useful by
allowing -w* to reset to the *compile time* default when specified on
the command line.

Reported-by: <momo-trip@github.com>
Fixes: https://github.com/netwide-assembler/nasm/issues/155
Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-07-07 15:43:40 -07:00
H. Peter Anvin (Intel)
63abf28933 doc/source.src: remove note about "make warnings"
The idea of embedded warning documentation text in the source code was
a cute idea, but the resulting build dependency mess really made it
more painful than it was worth.

The warning declarations were moved to asm/warnings.dat quite a while
ago; remove stray note in the documentation.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-07-07 15:43:40 -07:00
H. Peter Anvin (Intel)
6393f99455 doc/pspdf.pl: fix Ghostscript executable path construction on Windows
win32_gs_help() looks up Ghostscript's install directory (GS_LIB) from
the registry and then tries to locate gswin64c.exe/gswin32c.exe/gs.exe
in it, but used File::Spec->catpath($p, $exe) to build the candidate
path. catpath() takes three arguments (volume, directory, file); called
with only two, $exe is interpreted as the directory and the file
component is left undef, so the result is just $exe on its own --
never a path that actually exists -- meaning the registry-based lookup
silently always failed and pspdf.pl fell back to a bare 'gs' on PATH
(which choco's ghostscript package does not add). Use catfile($p, $exe)
instead, which is the correct call for joining a directory and a
filename. Confirmed via real MSVC CI that Ghostscript is now found
purely from the registry, matching doc/source.src's documented
requirement that Ghostscript need not be on PATH.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-07-07 15:26:53 -07:00
H. Peter Anvin (Intel)
8317d7ae2f Mkfiles/msvc.mak: make the docs: target actually work under real nmake
The docs: target fed doc/Makefile.in directly to nmake, but that file
relies on several GNU make-only constructs nmake cannot parse at all:
the $^ automatic variable (not valid nmake macro syntax -- fatal
parse error), $< used outside of an inference rule (silently
unsupported, since nmake only defines $< within .SUFFIXES-style
rules), and the GNU-only "-include *.dep" optional wildcard include
directive (nmake only understands the unrelated "!include"
directive). Add tools/mkmsvcdocmak.pl, which rewrites just those
constructs to their explicit nmake-safe equivalents in a generated
copy (doc/Makefile.msvc), leaving doc/Makefile.in itself untouched for
the Unix/GNU make build. Verified by rewriting doc/Makefile.in this
way and building nasmdoc.pdf through it with GNU make standing in for
nmake.

Also, doc/Makefile.in expects doc/warnings.src, doc/perlbreq.src and
doc/pptok.src to have already been generated -- the Unix "doc" target
does this via the top-level Makefile.in before recursing into doc/,
but msvc.mak's docs: target had no equivalent step. warnings.src and
pptok.src already had msvc.mak rules (just not wired up as
prerequisites of docs:); perlbreq.src had no rule at all, since the
top-level Makefile.in generates it with a POSIX find/sed pipeline that
doesn't translate to Windows. Add tools/genperlbreq.pl, a portable
pure-Perl equivalent (using File::Find), and a doc\perlbreq.src rule
in msvc.mak that uses it; verified it produces output byte-identical
to the existing POSIX pipeline.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-07-07 15:26:53 -07:00
H. Peter Anvin (Intel)
5d727e1253 Mkfiles/msvc.mak: document docs rule's tool requirements
Note that building the documentation via the "docs" nmake target
requires Ghostscript and the Roboto/Roboto Mono fonts, per
doc/source.src. This target previously also had to work around
doc/Makefile.in containing a bare, unexpanded "@SET_MAKE@" line
(fixed in the preceding commit), which made it a hard nmake parse
error; that workaround is no longer needed.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-07-07 15:26:53 -07:00
H. Peter Anvin (Intel)
56200857e2 build: only use @SET_MAKE@ in the top-level Makefile.in
@SET_MAKE@ (AC_PROG_MAKE_SET) is a legacy autoconf substitution needed
only for very old Unix make implementations that don't automatically
propagate $(MAKE) to recursively invoked sub-makes. Every Makefile.in
in the tree carried its own copy, but that's unnecessary: exporting
MAKE once, from the top-level Makefile.in, is sufficient for it to
reach any sub-make invoked (directly or transitively) from there.

Replace the top-level @SET_MAKE@ with the pair "@SET_MAKE@" followed
by "export MAKE", and drop the now-redundant @SET_MAKE@ line from
doc/Makefile.in, misc/Makefile.in and test/Makefile.in.

This incidentally fixes doc/Makefile.in being usable when fed directly
to nmake (as Mkfiles/msvc.mak's "docs" rule does, since it predates
running ./configure): a bare "@SET_MAKE@" line, left unexpanded, is
not a valid nmake assignment or rule and previously caused a hard
parse error (U1035, "expected ':' or '=' separator").

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-07-07 15:26:53 -07:00
H. Peter Anvin (Intel)
186be201d5 ci: build the Windows NSIS installer in the MSVC job
Install NSIS via choco (not preinstalled on windows-latest), Ghostscript
via choco, and the Roboto/Roboto Mono fonts (matching the exact
versions Fedora's google-roboto-fonts and google-roboto-mono-fonts
packages ship, dropped straight into %windir%\Fonts, which
doc/findfont.ph's directory-scan fallback picks up without needing
font registration). Then run 'nmake docs' (builds nasmdoc.pdf via
NASM's own Perl-based doc toolchain, which needs exactly those tools --
see doc/source.src) followed by 'nmake nsis' to produce the installer
via nsis/nasm.nsi, and upload it as a workflow artifact.

Ghostscript is located by doc/pspdf.pl via the Windows registry keys
the official installer creates, not via PATH, so no PATH setup is
needed for it.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-07-07 15:26:53 -07:00
H. Peter Anvin (Intel)
c68bf5ef57 ci: add a real-MSVC (cl.exe/nmake) build job
Add a build-msvc job on windows-latest that uses
step-security/msvc-dev-cmd to set up the MSVC developer environment,
builds NASM with 'nmake /f Mkfiles/msvc.mak', and smoke-tests the
resulting nasm.exe/ndisasm.exe by assembling and disassembling a tiny
program and building a win64 object file.

step-security/msvc-dev-cmd is a StepSecurity-maintained, drop-in
replacement for the more widely known ilammy/msvc-dev-cmd@v1 action;
the latter's newest release (v1.13.0, Jan 2024) still targets the
now-deprecated Node.js 20 runtime with no newer release in sight,
while step-security's fork tracks Node.js 24.

This is the first CI coverage of the MSVC build path (Mkfiles/msvc.mak
+ config/msvc.h), which previously had no automated verification.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-07-07 13:22:36 -07:00
H. Peter Anvin (Intel)
ace0078261 file.c: include <windows.h> before <stringapiset.h>
nasmlib/file.c included <stringapiset.h> directly (for
MultiByteToWideChar()/CompareStringOrdinal()) without first including
<windows.h>. Windows SDK headers like <stringapiset.h> are only
guaranteed to work when pulled in through the normal <windows.h>
pipeline, which sets up SDK-internal architecture macros (_X86_,
_AMD64_, ...) derived from the compiler's own _M_IX86/_M_X64/etc.
Including them directly skips that setup and can fail with a
'No Target Architecture' #error from <winnt.h> -- which is exactly
what happened building with a real cl.exe/nmake in CI.

<windows.h> is deliberately *not* pulled in globally from compiler.h:
it #defines NEAR and FAR as legacy no-op calling-convention keywords,
which clash with NASM's own NEAR/FAR opflags bits (include/opflags.h).
Keep the inclusion local to file.c, the only file that currently needs
Windows API declarations, guarded by WIN32_LEAN_AND_MEAN to keep the
exposed surface minimal.

Confirmed fixed with a real MSVC (cl.exe/nmake) build in CI.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-07-07 13:12:06 -07:00
H. Peter Anvin (Intel)
e2f38a8aed config/msvc.h: fill in gaps versus configure.ac/config.h.in
Cross-referenced configure.ac's AC_CHECK_HEADERS/AC_CHECK_FUNCS/PA_*
tests (as materialized into config/config.h.in) against config/msvc.h
and added definitions for macros MSVC actually supports:

- HAVE_STDARG_H, HAVE_STDIO_H, HAVE_WCHAR_H: always present.
- HAVE_STDINT_H: available starting with Visual Studio 2010
  (_MSC_VER >= 1600).
- HAVE_INTRIN_H plus an #include <intrin.h>, gated on Visual Studio
  2005 (_MSC_VER >= 1400) when the header was introduced.
- HAVE_ISCNTRL: always present.
- HAVE_ISASCII plus '#define isascii __isascii', since MSVC only
  provides the underscore-prefixed spelling.
- HAVE__BYTESWAP_USHORT/_ULONG/_UINT64: always present, declared in
  <stdlib.h>, matching the names PA_FIND_FUNC probes for in
  autoconf/m4/pa_endian.m4.
- HAVE__BITSCANREVERSE (>=1400) and HAVE__BITSCANREVERSE64 (>=1400 and
  only on _M_X64/_M_ARM64, since the 64-bit intrinsic does not exist
  on 32-bit x86).
- HAVE_UNSIGNED_LONG_LONG_INT: always present.
- HAVE_UINTMAX_T, gated on '#ifdef HAVE_STDINT_H' rather than a
  separate version check, with a textual 'unsigned long long'
  fallback for uintmax_t otherwise; gating strictly on HAVE_STDINT_H
  avoids the fallback macro clobbering <stdint.h>'s own uintmax_t
  typedef when both would otherwise be available.

Deliberately left out anything that is POSIX/GNU/BSD-only or does not
exist verbatim on MSVC (strcasecmp/strsep/strlcpy/mempcpy, getuid/
getrlimit/realpath, GCC __builtin_*/attribute probes, byteswap.h/
endian.h family, C23 stdbit.h, etc.), since compiler.h and the
relevant call sites already handle those cases separately for MSVC.

Verified with x86_64-w64-mingw32-gcc -fsyntax-only using manually
defined _MSC_VER/_M_X64/_M_ARM64 across Visual Studio versions
1310/1400/1600/1800/1929 (mingw-w64 declares the same intrinsics in
the expected headers), then confirmed end-to-end with a real MSVC
(cl.exe/nmake) build in CI.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-07-07 12:57:50 -07:00
H. Peter Anvin (Intel)
18c778c590 files: formalize storing "mapped" file names in the filenames system
Formalize the mechanism for storing mapped (non-filesystem) filenames
in the filenames array. These are not compared against input or output
files for overwrite checks.

Add the infrastructure for comparing more than one input filename
(future proofing.)

Move the Makefile dependency target name to the filenames system.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-07-06 17:08:01 -07:00
H. Peter Anvin (Intel)
339ee194fc files: use nasm_compare_paths()
Instead of doing a simple string comparison, call nasm_compare_paths()
to compare infile and outfile paths.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-07-06 17:06:49 -07:00
H. Peter Anvin (Intel)
1c3d3dc554 nasmlib: add path name comparison function
Add nasm_compare_paths(). At this point, the only effect is wide
character/case insensitivity canonicalization on Windows, but in the
future it might be doing things like comparing st_dev:st_inode pairs
on Unix or compare nasm_realpath().

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-07-06 16:57:38 -07:00
H. Peter Anvin (Intel)
86c6b34bd3 Rename travis.mk[.in] -> travis.mak[.in]
Rename travis.mk to .mak to match the convention for all other
Makefiles in the tree (that aren't simply named "Makefile".)

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-07-06 14:09:02 -07:00
H. Peter Anvin (Intel)
75024b8109 test: remove test/performtest.pl and redirect {test,golden} targets
Remove the long-since-unmaintained test/performtest.pl script and
redirect the "test" and "golden" Makefile targets to their respective
travis targets.

The test/ directory still has two important functions:

1. Running ad hoc tests manually. The test/ directory has
   infrastructure for running a quick test manually in a large number
   of configurations. This is highly useful during development.

2. It contains the infrastructure for running regression tests on
   external applications, far too big to include into NASM itself.

Reported-by: Ross Burton <ross@burtonini.com>
Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-07-06 13:58:35 -07:00
H. Peter Anvin (Intel)
c0b64a692b Mkfiles/: sync with Makefile.in
Sync the standalone Makefiles with Makefile.in (adding
x86/insns-cc.ph.)

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-07-06 13:54:38 -07:00
H. Peter Anvin (Intel)
87968c3596 editors/nasmtok.pl: break nasmtok.json into lines
Instead of generating one single huge line of text, add newlines after
suitable commas to make it at least a manageable text file.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-07-04 19:58:07 -07:00
H. Peter Anvin (Intel)
620dd315ee editors/builtin.mac: sync with executable (pick up the list options macros)
Regenerate editors/buildin.mac to pick up the new list options macros.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-07-04 19:52:16 -07:00
Joshua Watt
851460a10b Add --debug-prefix-map option
Adds an option to remap file prefixes in output object files. This is
analogous to the "-fdebug-prefix-map" option in GCC, and allows files to
be built in a reproducible manner regardless of the build directory.

[ hpa: this still needs to be documented in doc/running.src. ]

Signed-off-by: Joshua Watt <JPEWhacker@gmail.com>
Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-07-04 19:22:48 -07:00
H. Peter Anvin (Intel)
c577f357d1 travis: disable the cv8struc test
The cv8struc test ends up with embedded absolute pathnames. This is a
known problem with the reproducibility of this test (see
https://github.com/netwide-assembler/nasm/pull/8) and so disable it
for now, as it generates false positive failures.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-07-04 19:12:12 -07:00
H. Peter Anvin (Intel)
87e9a45891 github: save travis.log from CI/CD tests
It is more or less impossible to debug CI/CD test failures without
this file, so make github keep a copy of it.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-07-04 19:05:08 -07:00
H. Peter Anvin (Intel)
c138d532fb github: update test.yml to be compatible with newer requirements
The test.yml file uses actions/checkout@v4, which apparently is being
deprecated; bump to @v6 (using Node.js 24) instead.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-07-04 18:52:44 -07:00
H. Peter Anvin (Intel)
081a097909 testgen: document %ifdef ERROR error-case coverage
Adds a "Error-case (%ifdef ERROR) coverage" section describing the
needs64/avoid64 dual-source design and the nasm-t.py json convention
reused from travis/ret/ret.json, notes on the two branch-operand bugs
discovered and fixed along the way, and updates the "Known
limitations" and "Validation" sections with the final 2612/10
mnemonic counts and 1976/2612 error-coverage numbers.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-07-04 13:43:20 -07:00
H. Peter Anvin (Intel)
eee1384bf5 testgen: add %ifdef ERROR error-case coverage, fix branch-operand bugs
Add error-case ("negative test") coverage per the user's preferred
convention: rather than a separate source file, error-triggering
instruction lines are appended to the existing per-mnemonic .asm file
under a %ifdef ERROR guard, and the harness assembles the same file
twice -- once without -DERROR (existing positive-path coverage,
unaffected) and once with -DERROR (expected to fail, per nasm-t.py's
"error": "expected" json convention, matching the pre-existing
travis/ret/ret.json pattern).

The error material comes for free from lines the generator already
knows are bit-width-incompatible:

- Lines needing 64-bit encodings (reg64/imm64 operands, hireg r8-r15,
  apxreg r16-r31, etc. -- %needs64_token / build_variant_line) are, by
  construction, exactly the lines already excluded from the 16/32-bit
  "narrow" body. They're appended to the narrow file under %ifdef
  ERROR and probed at --bits 16/32 with -DERROR; only widths where the
  block actually fails become json entries.

- Symmetrically, CALL/JMP near-indirect targets via rm16/rm32 (only
  rm64 is valid in 64-bit mode -- confirmed empirically, matches the
  NOLONG flag on those insns.xda templates) are appended to the full
  (64-bit) body under %ifdef ERROR and probed at --bits 64 with
  -DERROR.

Each candidate block is probed before being turned into a json entry,
so a line that unexpectedly *does* assemble at some width (this
generator doesn't model every mode restriction) doesn't turn into a
bogus "expected error" test; a mnemonic whose *only* surviving
coverage would be error entries is also rejected (see below), since
"this never assembles" isn't meaningful regression coverage on its
own.

While wiring this up, discovered and fixed two related bugs in the
existing branch-mnemonic handling (gen_operand()'s is_branch
substitution):

1. is_branch replaced *every* operand of a branch mnemonic with the
   ".L1" local-label text, not just genuine relative/near/short/abs
   branch-displacement operands. This produced nonsensical lines like
   "loop .L1, .L1" (LOOP's address-size-override form takes a fixed
   "cx"/"ecx"/"rcx" second operand, not a branch target) and "call
   .L1" for JMP/CALL's indirect (rm16/32/64) and far-pointer
   (imm16:imm16) forms instead of an actual register/memory operand.
   These bogus lines silently poisoned assembly for the whole
   mnemonic, and LOOP/LOOPE/LOOPNE/LOOPNZ/LOOPZ/JCXZ were silently
   dropped entirely as a result (present in the "16 dropped" list).
   Restricting the substitution to base tokens matching
   /^imm(?:8|16|32|64)$/ fixes both LOOP's operand and JMP/CALL's
   indirect/far forms, and recovers all six previously-dropped
   mnemonics with correct coverage.

2. Once (1) exposed genuine rm16/rm32 operand generation for CALL/JMP,
   a new bit-width interaction appeared: rm16/rm32 near-indirect
   targets are only valid in 16/32-bit mode (unlike ordinary reg16/32
   operands elsewhere, which work at any bit width), so a line built
   from one now broke 64-bit assembly for the whole mnemonic the same
   way a needs64 line breaks 16/32-bit assembly. Added
   branch_narrow_only() and a parallel avoid64 line flag (mirroring
   needs64) to exclude these lines from the 64-bit "full" body -- this
   is also what feeds the new symmetric 64-bit error-case coverage
   described above.

Also added a safety-net to the existing "couldn't assemble in any
mode, drop the directory" check: a directory is now only kept if it
has at least one *non*-error json entry, preventing a future bug
symmetric to (1) from silently producing a directory whose only
content is error-case entries.

Verified via full scratch regeneration (2612 mnemonics generated / 10
dropped, up from 2606/16 thanks to the LOOP-family/JCXZ fix) +
nasm-t.py run (10918/10918 PASS, 0 FAIL) + per-mnemonic non-error
.json entry-count diff against the prior committed tree (identical
except the 6 newly-recovered mnemonics, confirming no regressions).
1976/2612 mnemonics gained at least one error-case entry (3951 error
json entries total). Regenerated travis/insns/ and validated via
'make -j32 travis' (all PASS, ~27s).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-07-04 13:41:59 -07:00
H. Peter Anvin (Intel)
6de2898d8d testgen: document implicitly-sized memory operand coverage
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-07-04 12:39:10 -07:00
H. Peter Anvin (Intel)
5422294119 testgen: add implicitly-sized memory operand coverage
For instruction operand tokens that carry an explicit size in their own
name (mem8/16/32/64/..., rm8/16/32/64, xmmrm.../ymmrm256/zmmrm512,
mmxrm/mmxrm64), the generator previously always emitted an explicit size
keyword (e.g. "dword", "oword") for the memory operand. This never
exercised NASM's SM-flag-driven implicit-size-inference path, where the
size of an ambiguous memory operand is inferred from a paired
already-sized operand (typically a same-width register) in the same
instruction template (e.g. ADD reg32,rm32 or MOVBE reg32,mem32 don't
need an explicit size keyword).

Add build_implicitsize_line(), which replaces the first memory-capable
operand whose base token has a nonzero %mem_sizebits entry with a bare
(size-keyword-free) memory operand, leaving all other operands as
normally generated. As with the other coverage buckets (hireg, apxreg,
mask/maskz/broadcast/saeer, disp8/32 boundary), the candidate line is
routed through the shared cumulative staged probe and only kept if it
actually assembles for that instruction -- this avoids needing to parse
and replicate NASM's own SM/AR flag-driven operand-size-disambiguation
logic.

Note: for tokens with no size in their own name (plain "mem"), the
existing mem_operand($rng, 0) generator path already omits the size
keyword unconditionally, so that half of implicit-size coverage was
already exercised prior to this change; only explicitly-sized tokens
needed the new candidate.

Verified via full scratch regeneration (2606 mnemonics / 16 dropped,
unchanged) + nasm-t.py run (6955/6955 PASS, 0 FAIL) + per-mnemonic
.json entry-count diff against the prior committed tree (zero
differences, confirming no bit-width regressions). 1922/2606
mnemonics gained new implicit-size coverage lines. Regenerated
travis/insns/ and validated via 'make -j32 travis' (all PASS, ~26s).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-07-04 12:38:36 -07:00
H. Peter Anvin (Intel)
5d8ec1742c tools/testgen: document disp8/disp32 boundary coverage in README
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-07-04 12:22:30 -07:00
H. Peter Anvin (Intel)
941aa2ba16 testgen: add modrm-memory disp8/disp32 boundary coverage
Extend gen-insn-tests.pl to synthesize, for every distinct template
across a mnemonic's entire template set that has a modrm-memory-
capable operand (mem*, rm*, xmmrm*/ymmrm256/zmmrm512, mmxrm*), two
additional candidate lines using [eax+1] and [eax+64] addressing in
place of that operand's usual bare-displacement or register form.

Whether an instruction has a disp8-encodable form (or, for EVEX, what
its compressed-displacement scale factor is) is instruction-specific,
so rather than computing the exact boundary per instruction these two
fixed offsets are used as a baseline: +1 is unambiguously disp8-
encodable everywhere, and +64 lands past the disp8 boundary for
byte-granular encodings while still being a clean multiple of the
larger EVEX compressed-displacement scales.

[eax+N] (rather than a bare displacement, or a bit-width-specific base
register) is used because it's valid addressing syntax at every
--bits width via the 0x67 address-size prefix, confirmed empirically.
Candidates are routed through the same staged, cumulative probe as the
hireg/apxreg/EVEX-decorator buckets, so one bad candidate (e.g. an
instruction with memory-operand restrictions this generator doesn't
model) can't cost a mnemonic its pre-existing coverage.

Regenerated travis/insns/ (2606 mnemonics, 16 dropped, unchanged from
before; 1987 mnemonics gained at least one disp-boundary line).
Validated: nasm-t.py run against a scratch regeneration is 6955/6955
PASS/0 FAIL with per-mnemonic bit-width success counts identical to
the previous committed baseline, and make -j32 travis passes in ~26s.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-07-04 12:21:31 -07:00
H. Peter Anvin (Intel)
fe6bb359e4 tools/testgen: document EVEX decorator coverage in README
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-07-04 12:07:02 -07:00
H. Peter Anvin (Intel)
1ac35569b1 testgen: add EVEX decorator coverage (mask/{z}/broadcast/sae/er)
Extend gen-insn-tests.pl to recognize the four independent EVEX
decorator families encoded in insns.xda operand tokens (|mask, |z,
|b16|b32|b64, |sae|er) and synthesize additional candidate lines
exercising each:

  - mask:      {k1}-{k7} appended to the marked register/memory operand
  - maskz:     mask + trailing {z} (zeroing), only where |z co-occurs
  - broadcast: {1toN} on a memory operand, N derived from the token's
               vector width (xmm/ymm/zmm or explicit mem/rm size) and
               the b16/b32/b64 element-width marker
  - sae/er:    a separate trailing {sae} or {rn|rd|ru|rz-sae} pseudo-
               operand, only legal when the marked operand resolves to
               a register sized per the token's own declared width
               (e.g. rm64|er needs a 64-bit register, not rm32)

Candidate lines are generated once per *distinct* template across each
mnemonic's entire template set, not just the capped per-mnemonic
sample -- EVEX/AVX512 forms are frequently appended well after a
mnemonic's plain SSE/AVX forms in insns.xda (e.g. VMOVAPD's mask-on-
memory-destination forms), so relying on the sample alone would
silently skip them for many mnemonics.

Generalized the item-2 hireg/apxreg staged-fallback probe into a
per-category, cumulative probing loop over all six extra-line buckets
(hireg, apxreg, mask, maskz, broadcast, saeer): each candidate bucket
is tentatively merged into the accepted line set and kept only if the
result still assembles, avoiding the combinatorial blowup of trying
every subset as the number of independent categories grows.

Regenerated travis/insns/ (2606 mnemonics, 16 dropped, unchanged from
before). Validated: nasm-t.py run against a scratch regeneration is
6955/6955 PASS/0 FAIL (identical per-mnemonic bit-width success counts
to the committed baseline), and make -j32 travis passes in ~26s.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-07-04 12:05:56 -07:00
H. Peter Anvin (Intel)
6ca6b03467 tools/testgen: document high-register-number coverage in README
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-07-04 11:40:34 -07:00
H. Peter Anvin (Intel)
629cf75c3d tools/testgen: cover high register numbers (r8-r15, r16-r31)
Add register-number-focused coverage for every operand-class token that
has a hireg (r8-r15 / xmm-zmm8-15) or apxreg (r16-r31 / xmm-zmm16-31)
tier: registers 8+ only exist in 64-bit mode (they need a REX prefix,
or REX2/EVEX register-extension bits for 16-31), so this coverage is
64-bit-only regardless of the base token's own size.

Per template with at least one such token, generate one extra all-hireg
and one extra all-apxreg instruction line (once per template, not once
per --variants instance). Since NASM's own template-matching engine
transparently selects an alternate (e.g. APX/EVEX-encoded) pattern when
the operand syntax calls for it, the generator doesn't need to special-
case APX/EVEX iflags to decide whether extended registers are legal for
a given mnemonic -- it can simply try assembling and keep whichever
combination works. A staged-fallback probe (try hireg+apxreg, then
hireg alone, then apxreg alone, then neither) avoids letting one
genuinely-incompatible extra line (e.g. NOAPX/NOLONG-only mnemonics)
cost the whole mnemonic its pre-existing 64-bit coverage; the probe
checks --bits 16/32 too whenever a mnemonic's *only* templates need
64-bit registers regardless of number (e.g. URDMSR/UWRMSR), since in
that case the generated 'full' file is reused for every bit width.

Also fixes a latent bug: xmmreg/ymmreg/zmmreg previously drew uniformly
from registers 0-15, but 8-15 needs 64-bit mode just like the GPR
case -- so a template could non-deterministically lose its 16/32-bit
coverage whenever the RNG happened to land on 8-15 (e.g. ADDPD was
missing bin16/bin32 goldens before this fix). Register pools are now
split into explicit low (0-7)/hireg (8-15)/apxreg (16-31) tiers per
register class, threaded through gen_operand() via a new
parameter (defaulting to the existing 'low' behavior at all pre-
existing call sites).

Regenerated travis/insns/ (2606 mnemonics, 16 dropped -- unchanged
counts). Full suite validated via make -j32 travis: all tests PASS in
~27s.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-07-04 11:38:35 -07:00
H. Peter Anvin (Intel)
1891551544 tools/testgen: document optional-operand coverage in README
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-07-04 11:05:11 -07:00
H. Peter Anvin (Intel)
70dae61029 tools/testgen: cover optional (*/?) operand omitted forms
x86/insns.xda marks operands with a trailing '*' (optional source,
duplicates the previous operand in the encoding when omitted --
insns.pl's relaxed_forms() implements the actual encoding semantics for
the C generators) or '?' (optional destination, entirely absent from
the encoding when omitted, e.g. APX NDD forms). Previously the
generator always emitted every operand in a template, so the
omitted-operand parsing/encoding path was never exercised, and
reg8?/reg16?/reg32?-marked templates fell back to the generic '?'-
unaware base_token() lookup and were silently dropped as unsupported
(only the reg64? case happened to have an explicit, redundant table
entry).

base_token() now strips a trailing '?' the same way it already stripped
'*', so all four reg#?  variants resolve to their plain register
generator (the redundant explicit reg8?/16?/32?/64? %gen entries are
removed as now-dead code). A new optional_operand_index() locates the
(at most one, per insns.xda) marked operand in a template, and the
per-mnemonic driver emits one additional reduced-arity instruction line
per template (dropping that operand) alongside the existing full-arity
line, so both forms get captured as goldens.

Regenerated travis/insns/ (2606 mnemonics, 16 dropped -- unchanged counts,
since this only adds coverage lines to existing mnemonic asm files, not
new mnemonics). Full suite validated via make -j32 travis: all tests
PASS in ~26s.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-07-04 11:04:49 -07:00
H. Peter Anvin (Intel)
35016d4880 x86/insns.pl, tools/testgen: share cc/scc condition-code tables
Extract the condition-code suffix table (%conds, @conds, and the
c_ccmask/c_nd/c_cc/c_scc bitmasks) out of x86/insns.pl's
conditional_forms() into a new shared x86/insns-cc.ph module, adding
cc_suffix_list($is_scc) to return the suffix list applicable to a
'...cc'-family (Jcc, SETcc, CMOVcc, CFCMOVcc) or '...scc'-family
(CCMPscc, CTESTscc, CMPccXADD, SETccZU) placeholder mnemonic. insns.pl
is refactored to use it (behavior-preserving: verified byte-identical
x86/insnsa.c, insnsb.c, insnsd.c, insnsi.h, insnsn.c, iflag.c,
iflaggen.h, asm/tokhash.c, asm/tokens.h before/after).

tools/testgen/gen-insn-tests.pl now requires the same module instead
of hand-rolling a 16-suffix 'cc'-only expansion table, closing the gap
where the APX 'scc'-suffix families (CCMPscc/CTESTscc/CMPccXADD/
SETccZU) were dropped as unsupported. The generator now detects and
expands any '...cc'/'...scc' placeholder mnemonic the same way
insns.pl's conditional_forms() does (case-sensitive /s?cc/ match and
substitution), so future new cc/scc families need no generator
changes. Mnemonics with generated tests: 2432 -> 2606 (+174, one per
newly-expanded scc-family condition); dropped: 20 -> 16.

Regenerated travis/insns/ (174 new mnemonic dirs for the APX scc
families; existing 2432 regenerated byte-identically, confirming
determinism). Full suite validated both via
tools/travis/nasm-t.py --directory=./travis run (4427 total, 4426
PASS, 1 pre-existing SKIP, 0 FAIL) and via make -j32 travis (all
tests PASS, ~28s).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-07-02 00:05:47 -07:00
H. Peter Anvin (Intel)
c95b04bc7d tools/testgen: add README documenting design, usage, and limitations
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-07-01 23:44:51 -07:00
H. Peter Anvin (Intel)
28bf46e532 tools/testgen: pseudorandom instruction test generator
Add gen-insn-tests.pl, a prototype tool that generates one travis test
directory per non-pseudo instruction mnemonic (asm + json + golden
output), by parsing x86/insns.xda (the already-generated, macro-
expanded, one-template-per-line intermediate NASM produces from
insns.dat) rather than insnsa.c/insnsb.c or hooking insns.pl.

Rationale: insnsa.c/insnsb.c encode operands as opaque bitmask
constants and index into an explicitly-unstable, shared bytecode array
(x86/bytecode.txt: byte codes can be moved and recycled at any time),
making them fragile/high-effort to parse from outside insns.pl.
insns.xda already provides exactly the needed semantic info (mnemonic,
comma-separated operand-type tokens, flags) in a small stable text
grammar, with zero changes to insns.pl or the build. We only need
valid operand *syntax* per operand-type token -- NASM picks the
encoding itself from mnemonic + operand syntax -- so the generated
tests are regression tests against a golden captured from a known-good
nasm build, consistent with the rest of travis/.

Includes UNDOC/OBSOLETE/NEVER-flagged instructions (only PSEUDO
pseudo-ops are excluded): where these emit an expected warning (e.g.
-w+obsolete-removed), the generator declares a stderr target so the
warning text itself becomes part of the golden, verifying the warning
fires rather than skipping the coverage.

Delegates golden capture to tools/travis/nasm-t.py update instead of
re-implementing it, so goldens get the harness's existing correctness
properties (reproducible-build NASMENV, path-embedding conventions,
etc.) for free.

Generated travis/insns/<mnemonic>/ for all 2432 assemblable mnemonics
(16/32/64-bit variants as applicable). Full suite validated via
tools/travis/nasm-t.py: 4225 total, 4224 PASS, 1 pre-existing SKIP,
0 FAIL.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-07-01 23:42:14 -07:00
H. Peter Anvin (Intel)
73abe9374b travis: run from a Makefile to parallelize testing
The travis tool itself runs all tests it is given in series. Use make
to parallelize running the tests, leaving a log in each subdirectory
in addition to the global log.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-06-30 23:12:52 -07:00
H. Peter Anvin (Intel)
7f69cf689c travis: reorganize directories, add tests from the test/ directory
This is a mostly automated, partially AI-assisted migration of tests
from the test/ directory into the travis framework.

Running tests manually in the test/ directory is still supported, but
move common include files into travis/test and add a default -I option
to Makefile.in in the test/ directory.

The incbin test fails for pre-existing reasons; for now it contains an
stderr file with the errors. The problem is that INCBIN is both a
macro and a special instruction (not even a directive...), but there
currently is no way to handle prefixes, *especially* TIMES, in
multi-line macros. This is a separate problem and needs to be dealt
with as such.

Reorganize the travis directory so that each test or collection of
tests are in a separate subdirectory of travis/, and travis itself
lives in tools/travis to avoid creating deeper paths.

Add support for recording compression options in the travis .json
files, so that compressed files can be recreated with the same
options: because of the generally repetitive nature of the binary
output test files, the parameters used for xz compression can matter
enormously.

These are combined into a single huge commit to avoid adding large
binary files into the repository that then would immediately be
obsoleted, but still retained in git.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-06-30 20:54:46 -07:00
H. Peter Anvin (Intel)
3cc3654e08 travis: replace riprel.stderr reference file xz file
Compress this quite large file with xz now when travis supports
xz-compressed reference files.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-06-30 19:19:58 -07:00
H. Peter Anvin (Intel)
c460d1112f travis: support .xz compressed golden reference files
Some tests may by necessity generate very large output files. Allow
.xz compression of the reference files to avoid bloating the git
repository too much. The committer of very large files will need to
carefully consider the xz options used to maximize compressibility
especially of highly regular files.

This commit was AI-assisted (Copilot/Claude Sonnet 5).

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-06-30 19:16:59 -07:00
H. Peter Anvin (Intel)
386f5d44f7 test/amx: suppress obsolete-removed warning for TMMULTF32PS
TMMULTF32PS was retagged never, suppress the warning to avoid a travis
failure.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-06-30 17:22:13 -07:00
H. Peter Anvin (Intel)
844f409f8d x86/insns.dat: make TMMULTF32PS as NEVER
The TMMULTF32PS instruction will not be implemented, mark it as NEVER.

Reported-by: Christian Ludloff <ludloff@github.com>
Fixes: https://github.com/netwide-assembler/nasm/issues/259
Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-06-30 14:07:21 -07:00
Nick Clifton
8890d723d0 outobj: fix buffer overflow when too many segments in a group
The number of entries in a group was hard-coded, but not enforced.

Reported-by: <BreakingBad6@github.com>
Fixes: https://github.com/netwide-assembler/nasm/issues/203
Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-06-29 18:22:44 -07:00
H. Peter Anvin (Intel)
dad1d8ca42 outbin: register the mapfile; check for input clobber; remove on fail
- Register the map file with the filename system.
- Check to see if the mapfile is clobbering the input.
- Remove the map file if the output file is also removed.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-06-29 18:22:39 -07:00
H. Peter Anvin (Intel)
720a32672c Refactor the handling of primary input/output files
Replace the direct setting of variables for input and output variables
with accessors. This allows for properly tracking the lifetimes of the
data and allows for things like checking of the overwrite of the
primary input file to be centralized.

It isn't possible *in the general case* to check for overwrite of
*any* of the input files, although in the particularly important case
of the assembler proper it ought to be possible to do a bit better:

it should be able to guard for overwrites of non-primary input files
except for the error file or the list file if and only if -Lp is used.

That is, however, a latter project.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-06-29 18:22:26 -07:00
H. Peter Anvin (Intel)
9d94cac7ae nasmlib/file: add nasm_remove()
Add nasm_remove() to mangle a filename if necessary before calling
an OS-specific remove() function. This allows calling _wremove() on
Windows.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-06-29 13:30:03 -07:00
H. Peter Anvin (Intel)
9000d56aec doc: fix the example for saving and restoring list options
The example used %define but it really needs to use %xdefine in order
to snapshot the value of __?LIST_OPTIONS?__.

Tidy it up a little as well.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-06-29 07:10:26 -07:00
H. Peter Anvin (Intel)
4a56d66ed9 NASM 3.02 2026-06-28 20:37:13 -07:00
H. Peter Anvin (Intel)
47f1cd8ede test: add test for %pragma list options and __?LIST_OPTIONS*?__
A simple test for tweaking the list options from the source code.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-06-28 20:35:56 -07:00
H. Peter Anvin (Intel)
27500eee7f preproc.c: check do_delete_Token() actually has a token
It seems pretty clear from the API that [do_]delete_Token() always was
intended to allow for a NULL option; the test for "if (tp)" is
somewhat pointless when invoking the delete_Token() macro which does a
do_delete_Token(&(t)).

Add in the null check to *tp as well.

Fixes: https://github.com/netwide-assembler/nasm/issues/176
Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-06-28 20:18:43 -07:00
H. Peter Anvin (Intel)
9969b34454 listing: add __?LIST_OPTIONS?__ and __?LIST_OPTIONS_DEFAULT?__ macros
Add macros to query the current state of the listing options, add
appropriate documentation.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-06-28 20:13:30 -07:00
H. Peter Anvin (Intel)
06f9a1855e listing.[ch]: allow ! to be used in %pragma and * to reset to cmdline
Do allow the ! as a wildcard for all options to be used in %pragma as
well as on the command line.

Keep track of the command-line default to allow the * modifier (like
warnings) to reset to the command-line default.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-06-28 20:04:25 -07:00
H. Peter Anvin (Intel)
8fe7600cde NASM 3.02rc13 2026-06-28 19:04:16 -07:00
H. Peter Anvin (Intel)
640c7e0f5b preproc: fix memory leak: long tokens never freed
When tokens exceeded INLINE_TEXT, free_Token() had managed to miss
freeing the allocated token buffer.

This is different from the pull request merely in forward-porting the
change to the current code base.

Reported-by: <sorokin@github.com>
Fixes: https://github.com/netwide-assembler/nasm/pull/70
Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-06-28 18:55:25 -07:00
H. Peter Anvin (Intel)
096c82e141 fpu.asm: test a few more syntax combinations
This also underscores the missing "to" forms of some instructions, but
that is not a regression of any kind; in fact seems to have been there
since the very beginning.

It is probably so that we should use the 2-operand forms as the
preferred disassembly forms, but that's a totally different task.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-06-28 18:41:20 -07:00
H. Peter Anvin (Intel)
4d18bdd318 listing: allow the user to suppress abbreviation of TIMES and INCBIN
Allow the user to suppress the abbreviation of the output from TIMES
(and therefore ALIGN) and INCBIN.

Sync the documentation with the help text, too.

Fixes: https://github.com/netwide-assembler/nasm/issues/211
Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-06-28 18:11:40 -07:00
H. Peter Anvin (Intel)
5b9dce55cb outas86.c: fix memory leak during initialization
It is just an O(1) memory leak but might as well fix it.
filename_set_extension() returns a newly allocated string,
as86_add_string() does not consume a string reference, so the string
is left danging at the end; add nasm_free() to free it.

Reported-by: <for-just-we@github.com>
Fixes: https://github.com/netwide-assembler/nasm/issues/255
Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-06-28 16:40:17 -07:00
H. Peter Anvin (Intel)
6051380c34 nasm.c: in preprocessor mode (-E) free the line data after printing
pp_getline() returns a string in heap storage, it needs to be freed.
This is done correctly in the other modes, but in preprocessor mode,
the freeing was missed.

This also replaces nasm_free() ... assignment with the nasm_strto()
idiom.

Reported-by: <for-just-we@github.com>
Fixes: https://github.com/netwide-assembler/nasm/issues/254
Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-06-28 16:35:31 -07:00
H. Peter Anvin (Intel)
cdfe73e4b9 NASM 3.02rc12 2026-06-26 17:49:01 -07:00
H. Peter Anvin (Intel)
7bc82e7daf asm/nasm.c: fix use-after-free for -M* options in -@ files
-M* options in response files would hold on to a pointer to the new
value, but in response files that is not a persistent buffer. Make
sure to make a copy instead.

This uses the new nasm_str[dup]to() helpers.

(Note that calling nasm_free() on a NULL pointer is guaranteed safe.)

Reported-by: <BreakingBad6@github.com>
Fixes: https://github.com/netwide-assembler/nasm/issues/222
Fixes: CVE-2026-6068
Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-06-26 17:35:33 -07:00
H. Peter Anvin (Intel)
44245e4684 Add nasm_strdupto() and nasm_strto(), to replace a string variable
It is common enough that one wants to set a string pointer to a newly
allocated string, freeing the old one if it is not NULL.

Add specific helper functions for this.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-06-26 17:25:23 -07:00
H. Peter Anvin (Intel)
7b4e77dae2 Drop const from the output of filename_set_extension()
filename_set_extension() always returns a newly allocated string
buffer, drop the "const" from the return type.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-06-26 17:24:17 -07:00
H. Peter Anvin (Intel)
e47a62ed4d nasmlib.h: modify nasm_assert_pointer() to work with void pointers
nasm_assert_pointer() would fail with newer gcc when passed a void *,
because the construct sizeof(*(p)) is invalid for void pointers, as is
sizeof(&*(p)).

Instead, make use of the fact that the ternary operator ? : requires
type compatibility between the two sides, and const volatile void * is
type-compatible with any pointer.

Since some compilers are known to elide this check when one side is
NULL, make it a explicit pointer to an arbitrary
object cast to (const volatile void *). zero_buffer[] seems a logical
choice.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-06-26 16:59:12 -07:00
H. Peter Anvin (Intel)
20cf91df63 NASM 3.02rc11 2026-06-26 14:40:20 -07:00
H. Peter Anvin (Intel)
24263bc4c1 doc/changes.src: document defanging of "%[i]rmacro"
Formally document in the change notes that %[i]rmacro falls back to
%[i]macro with a warning.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-06-26 14:39:12 -07:00
H. Peter Anvin (Intel)
139986238a editors/dumpbuiltin.sh: make a little more user-friendly
If no $NASM is defined and no nasm path has been given on the command
line, default to "../nasm".

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-06-26 14:35:07 -07:00
H. Peter Anvin (Intel)
3f269f2dc8 x86/insns.dat: add "UDW" as a (likely temporary) mnemonic for FF FF
sandpile.org are referring to FF FF as "UDW" for the FF FF subcase of
FF /7. Accept that mnemonic; allow it in disassembly as well until
such time as an official mnemonic exists for this pseudo-instruction
(or the opcode ends up being actually used, which would almost
certainly be a very bad thing.)

Fixes: https://github.com/netwide-assembler/nasm/issues/249
Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-06-26 14:29:00 -07:00
H. Peter Anvin (Intel)
a55b5930b3 changes.src: document fixing $-escaped symbols in directives
Document the fix of $-escaped symbols in directives. Tidy up the
source formatting (no output change) of one of the bullet points.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-06-26 14:20:31 -07:00
H. Peter Anvin (Intel)
414ea824d9 directiv.c: correct the parsing of $-symbols in directives, again
1fc631a173 [directiv.c: $-hex requires nasm_isnumstart, not just nasm_isnumchar]

... was accidentally a commit of a wrong, broken version of the fix
(SIGMY: My fault (core dumped)).

Both the nasm_isidchar() and !nasm_isnumstart() checks need to be
applied to the *same* character, the one immediately after '$'.

Huge special thanks to ecm-pushbx for the quick testing and timely bug
report!

Reported-by: <ecm-pushbx@github.com>
Fixes: https://github.com/netwide-assembler/nasm/issues/252
Fixes: 1fc631a173
Fixes: 178a1b7443
Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-06-26 14:11:19 -07:00
H. Peter Anvin (Intel)
6950581b35 NASM 3.02rc10 2026-06-25 15:16:19 -07:00
alexvoste
cfcfe9e701 asm/labels: fix memory leak in local label structures
Travis CI testing with AddressSanitizer (ASan) triggered a severe memory
leak in the assembler label tracking. Local label structures were not
properly freed during cleanup stages. This fix adds proper verification
and destruction of tracking labels, resolving the ASan memory leak.

Signed-off-by: alexvoste <alexvostedev@proton.me>
[ hpa: fixed indentation style and removed unnecessary { } ]
Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-06-25 15:13:47 -07:00
alexvoste
3a33d83610 parser: fix invalid segment override on EQU FAR pointers
The parser incorrectly treated colons as memory segment overrides inside
EQU directives because of an inverted far_jmp_ok check. This regression
was introduced in commit 8981724. Removing the incorrect negation
restores proper parsing of FAR pointer constants.

Fixes #242

Signed-off-by: alexvoste <alexvostedev@proton.me>
2026-06-25 15:11:05 -07:00
H. Peter Anvin (Intel)
90ba5bbc23 doc: fix spelling of "syntactically"
Fix spelling error.

Fixes: https://github.com/netwide-assembler/nasm/issues/251
Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-06-25 15:02:58 -07:00
H. Peter Anvin (Intel)
2b37c0ad75 directiv.c: include leading $ in a token if missing an identifier
When complaining about a valid token where an identifier was expected,
do include the leading $ if at all applicable to avoid confusing the
user.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-06-25 14:59:33 -07:00
H. Peter Anvin (Intel)
1fc631a173 directiv.c: $-hex requires nasm_isnumstart, not just nasm_isnumchar
For identifier-escapes beginning with $a-f to work, the $ hexadecimal
prefix cannot be used, nor could it ever be used, with A-F immediately
after the $. This is the main reason the $-hex has been deprecated.

When adding the non-dollarhex mode, this got accidentally promoted to
nasm_isnumchar() instead of nasm_isnumstart(), which broke using
$-escaped identifiers in directives.

To fix this properly, it would be a good thing to add a central
identifier-skipping function.

Fixes: https://github.com/netwide-assembler/nasm/issues/223
Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-06-25 14:58:22 -07:00
H. Peter Anvin (Intel)
19125b6d46 builtin.mac: synchronize with the NASM binary
Update builtin.mac to match the current set of built-in NASM macros.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-06-24 15:56:50 -07:00
H. Peter Anvin (Intel)
08a369628e Rename emacstok.pl back to nasmtok.pl
This script can output more than just Emacs format these days; it is
already used to produce both Emacs and JSON output, and it seems
unlikely that we would want to create another script to output any
additional file formats.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-06-21 14:34:09 -07:00
H. Peter Anvin (Intel)
f0c3b0e6c7 NASM 3.02rc9
Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-06-11 15:26:28 -07:00
H. Peter Anvin (Intel)
5e6a181fec insns.pl: fix unnecessary build reproducibility failure
Instead of sorting the list of flags by number, it sorted it by hash.

Reported-by: <bbhtt@bbhtt.in>
Fixes: https://github.com/netwide-assembler/nasm/issues/220
Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-06-11 15:20:12 -07:00
H. Peter Anvin (Intel)
6f830c1c74 labels: handle the sequence EXTERN, GLOBAL, defined
The sequence EXTERN, GLOBAL, definition would fail, because the EXTERN
would create a pseudo-segment and consider it a definition, whereas
GLOBAL would set change it to a global definition, but leaving the
definition existing, which is not the normal case for a GLOBAL symbol
(define_label would not be called.)

Therefore, explicitly "undefine" the symbol by setting defn.defined to
0, as it would be after a GLOBAL statement, as as it is when an EXTERN
statement is followed by a definition (causing it to be implicitly
promoted to GLOBAL.)

Reported-by: E. C. Masloch <ecm-pushbx@github.com>
Reported-by: <roel-z@github.com>
Fixes: https://github.com/netwide-assembler/nasm/issues/224
Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-06-11 15:08:27 -07:00
H. Peter Anvin (Intel)
022586090d changes.src: document %clear directive fix
Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-06-11 14:42:55 -07:00
H. Peter Anvin (Intel)
0c9baa8f3a preproc: ensure forward process in %clear loop
The %clear loop was missing advancing to the next token. Also allow
the list to be comma-separated, like most other cases in NASM.
Reported-by: <magicelk235@gmail.com>
Fixes: https://github.com/netwide-assembler/nasm/issues/227
Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-06-11 14:40:01 -07:00
H. Peter Anvin (Intel)
9052efaa63 preproc: warn if the user tries to use %rmacro
Unfortunately, the %rmacro and %irmacro directives were not disabled
when recursive macros were removed due to the implementation did not
work. Make them issue a warning and document that they might change in
the future.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-06-11 14:29:41 -07:00
Jiri Malak
8d1f35b78f open-watcom: fix Open Watcom build make file
Resolves Conflicts:
	Mkfiles/openwcom.mak
Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-06-11 14:05:52 -07:00
H. Peter Anvin (Intel)
7b267445b6 preproc.src: document the limitations of case insensitivity
For the longest time, NASM has allowed non-ASCII characters is macros
and identifiers, but they have always been treated as opaque
bytes.

NASM has never done case insensitive matching of identifiers, only
keywords and macros. Keywords are compile-time-defined and are always
ASCII, but macros can be user-defined, so document the limitations.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-06-11 13:57:29 -07:00
H. Peter Anvin (Intel)
018406b870 SubmittingPatches: more up to date information about the patch format
It has not been considered valid to omit the long patch description
for a long time. Try to explain in more detail what the long patch
description is actually expected to contain.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-06-11 12:47:32 -07:00
H. Peter Anvin (Intel)
6015afc6d7 omfdump.c: add updates from Bernd Böckmann
Bernd Böcknann has been maintaining a fork of this tool on github:

      https://github.com/boeckmann/omfdump

Sync with his latest version. In the future it might be possible to
drop this tool from the NASM distribution entirely.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-06-07 21:00:04 -07:00
H. Peter Anvin (Intel)
ed8864e342 NASM 3.02rc8
Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-06-07 20:56:10 -07:00
H. Peter Anvin (Intel)
d832776ccb Revert "parser: fix invalid segment override on EQU FAR pointers"
This reverts commit 35ffac3ea0.

This commit caused a regression, causing segment overrides to get
lost. Multiple travis tests failed as a result.

Revert this until a proper solution exists.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-06-07 20:54:47 -07:00
Joe Konno
6d8ea837c6 x86: fix {er} decorator placement for integer-source VCVT* instructions
For `VCVTUSI2SD`, `VCVTUSI2SS`, and `VCVTUSI2SH`, the `|er` flag in
`insns.dat` was attached to the XMM pass-through source (operand 2, the
vvvv field) rather than the integer source (operand 3, the rm field).
This caused NASM to require the embedded-rounding decorator before the
integer register rather than after it, which is wrong; the correct
syntax is `vcvtusi2ss xmm0,xmm1,eax,{rn-sae}`, not `vcvtusi2ss
xmm0,xmm1,{rn-sae},eax`.

Move `|er` to the integer source operand for all six affected entries,
and change the XMM source from `xmmreg|er` to `xmmreg*` (optional
duplicate of the destination, consistent with every other scalar
integer-to-float convert in the file).

Also fix a copy-paste error in `insns.dat` where the second `VCVTUSI2SH`
entry (W=1, rm64) was mis-labeled as `VCVTUSI2SS`.

Update `travis/test/avx512f.asm` to use the correct decorator syntax
(`reg,{rN-sae}` instead of `{rN-sae},reg`) for the ER forms of
`VCVTSI2SD`, `VCVTSI2SS`, `VCVTUSI2SD`, and `VCVTUSI2SS`; regenerate the
golden `avx512f.bin.t`. The encoded bytes are unchanged.

`travis/test/avx512f.json` had a trailing comma after the last field of
the JSON object, making it invalid JSON. Remove the trailing comma.

Signed-off-by: Joe Konno <joe.konno@intel.com>
Fixes: https://github.com/netwide-assembler/nasm/pull/229
Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-06-07 20:23:45 -07:00
xmoezzz
d2541cb884 nasm.c: response file (-@) option parsing UAF affecting debug format selection (-F / -g)
Fixes: https://github.com/netwide-assembler/nasm/pull/189
[ hpa: added necessary cast to nasm_free() ]
Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-06-07 20:21:09 -07:00
SEt
dee2d13f2c Proper handling of several code sections in Codeview debug information
Current Codeview implementation assumes there is only one actual code
section and all line number information is pulled there. With support
of comdat that assumption becomes incorrect, so proper generation of
line number information table per code section is required.

Also solved an issue with incorrect relocation for symbol with the
same name as some section.

New code assumes that coff_nsects doesn't change during generation of
debug information.

Fixes: https://github.com/netwide-assembler/nasm/pull/183
Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-06-07 20:17:36 -07:00
Kacper Michajłow
1c9e16a03f output/codeview: don't panic when there is not code section
Simply skip the tables that require code section and source information.

Fixes: https://github.com/netwide-assembler/nasm/issues/216
Fixes: https://github.com/netwide-assembler/nasm/pull/178#issuecomment-4156226648
Signed-off-by: Kacper Michajłow <kasper93@gmail.com>
Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-06-07 20:13:27 -07:00
knut st. osmundsen
05ad1e46b2 doc/outfmt.src: Documented 'function' win32/64 symbol type.
Documented the 'function' win32/64 extension to the global, extern
and static directives.

Resolved Conflicts:
	doc/outfmt.src

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-06-07 20:10:15 -07:00
knut st. osmundsen
c8be7b7a3f outcoff.c: Added support for 'function' type on global symbols.
Setting the symbol type is necessary for the control flow guard (CFG)
stuff on windows.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-06-07 20:08:03 -07:00
knut st. osmundsen
3ad8e6c533 outcoff.c: Prevent elimination of extern safeseh symbol.
Do a lookup of the symbol given to safeseh to prevent out_symdef() from
thinking it is unused.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-06-07 20:06:49 -07:00
knut st. osmundsen
251b9c6825 test/wrtsymtab.asm: reproducible
Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-06-07 20:05:20 -07:00
knut st. osmundsen
06d2606b06 outcoff.c: fix warnings
Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-06-07 20:05:20 -07:00
knut st. osmundsen
f1e4e6fe16 outcoff.c: dd symbol wrt ..symtab
Added a special symbol ..symtab for emitting the COFF symbol table
index of a symbol rather than some kind of address.  For use with ehcont
metadata and possible other stuff.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-06-07 20:05:20 -07:00
H. Peter Anvin (Intel)
f216d5b65d editors: rename nasmtok.pl to emacstok.pl
Rename this script to reflect its function within the NASM tree. The
output file is still called nasmtok.el, however, as it reflects its
function within an Emacs environment.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-06-07 20:04:50 -07:00
H. Peter Anvin (Intel)
5b4d5cf2a7 editors/nasmtok.pl: don't overquote nasm-token-lists
The definition of nasm-token-lists was double quoted: both the list
itself and the tokens inside were quoted, which is not the right
thing.

Remove the unnecessary inner quoting.

Reported-by: 8dcc <8dcc@github.com>
Fixes: https://github.com/netwide-assembler/nasm/issues/231
Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-06-07 19:56:20 -07:00
H. Peter Anvin (Intel)
dc68633fa3 Fix tuple type for V{MOV,ADD,SUB,MUL,DIV}SH to t1s16
These use a 16-bit tuple type, not one derived from EVEX.W. All of
this is really messy... it would be better to have a much more
explicit handling of the displacement type than relying on "tuples".

Reported by: MSander-OptiCode <msander-opticode@gmail.com>
Fixes: https://github.com/netwide-assembler/nasm/issues/245
Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-06-07 19:51:54 -07:00
H. Peter Anvin (Intel)
93bb528742 Remove nroff from configure.ac and Makefile.in
Converting nroff man pages to other formats was obsoleted with the use
of asciidoc. No need to check for them.

Reported-by: Ross Burton <rossburton@github.com>
Fixes: https://github.com/netwide-assembler/nasm/issues/236
Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-06-07 18:27:49 -07:00
H. Peter Anvin (Intel)
471073c0d0 changes.src: update release notes
Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-06-07 18:25:57 -07:00
alexvoste
6e8cdf8d59 x86: Fix VCVTPD2PH and add missing VMINPH/VMAXPH AVX512-FP16 instructions
Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-06-07 18:21:52 -07:00
alexvoste
35ffac3ea0 parser: fix invalid segment override on EQU FAR pointers
The parser incorrectly treated colons as memory segment overrides inside
EQU directives because of an inverted far_jmp_ok check. This regression
was introduced in commit 8981724. Removing the incorrect negation restores
proper parsing of FAR pointer constants.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-06-07 18:21:39 -07:00
H. Peter Anvin (Intel)
de7a94e884 asm/preproc.c: remove unused variable bad_bracket
This variable was assigned but never used.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-06-04 10:52:15 -07:00
H. Peter Anvin (Intel)
0114c92101 asm/assemble.c: remove unused variable this_good
This variable was assigned but never used.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-06-04 10:51:49 -07:00
H. Peter Anvin (Intel)
ea675d0af7 autoconf: sync with upstream pa_option_lto.m4
This change has no effect on NASM, but syncs with the upstream
collection. RANLIB should be defaulting to : if not present.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-06-04 10:50:54 -07:00
H. Peter Anvin (Intel)
3ee140842f autoconf: separate -g3 and -ggdb
The -g3 and -ggdb options are really separate, treat them as
such. Trying -ggdb3 -g3 is not only inefficient, it is wrong when the
compiler supports only -ggdb.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-06-04 10:42:01 -07:00
H. Peter Anvin (Intel)
ccb73b72b2 autoconf: fix up search for "gcc-ar" and "gcc-ranlib"
The detection for "gcc-ar" and "gcc-ranlib" when building with LTO for
gcc was broken, fix it.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-06-04 10:40:50 -07:00
H. Peter Anvin (Intel)
113191195b configure.ac: if "strip" isn't found, dummy it out
There is no reason to error out if "strip" is missing.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-06-04 10:40:06 -07:00
H. Peter Anvin (Intel)
aa12d3381a NASM 3.02rc7 2026-04-22 09:10:32 -07:00
Yongjie2017
498afdba1b output/outelf.c: fix address sanitizer findings in elf output format
In elf_init, cur_path is a malloced one, and should be freed.

This patch adds a free operation by the end of the elf_init.

Signed-off-by: Yongjie Sheng (Intel) <sheng.yongjie@outlook.com>
2026-04-17 06:38:10 +08:00
Yongjie2017
b5235c49f0 asm/preproc.c: fix https://nvd.nist.gov/vuln/detail/CVE-2025-8842
When there is an ill formed assembly (e.g. a macro without a correct
ending), the assembly processing will end with a defining->refcnt
in non-zero value that further causes a nasm_assert in free_mmacro,
the nasm_assert causes a panic.

Force the defining->refcnt to zero in pp_clean_pass as a bailout.

Signed-off-by: Yongjie Sheng (Intel) <sheng.yongjie@outlook.com>
2026-04-17 06:35:57 +08:00
Yongjie2017
8c3f3fbe36 asm/preproc.c: fix https://nvd.nist.gov/vuln/detail/CVE-2025-8844
When there is an invalid radix specifier, the parse_smacro_template
set the current char pointer (cp) to NULL, but the tailing processing
of the for loop increases the cp so its value is 0x1 that deceives
the for loop condition check.

Add a NULL pointer checking on the cp after the switch statement
to quit the for loop because of the invalid radix specifier.

Signed-off-by: Yongjie Sheng (Intel) <sheng.yongjie@outlook.com>
2026-04-17 06:33:06 +08:00
H. Peter Anvin (Intel)
3cb6231581 asm/preproc.c: remove git merge crap in comment
A comment accidentally was left with a merge resolution
annotation. This was of course harmless, being in a comment, but it
shouldn't be there.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-04-10 13:21:41 -07:00
H. Peter Anvin (Intel)
97db0b96c2 NASM 3.02rc6 2026-04-10 13:18:31 -07:00
H. Peter Anvin (Intel)
e1e03770f7 asm/preproc.c: remove dead code, improve comment
ppscan() had a break; statement followed immediately by a return
statement. The latter was left over from code restructuring and is
dead code.

Remove it.

Fix a nearby comment indicating that we should not need to strip a
const from a string pointer. Probably Token::t_charptr should be
const, but it might need additional work.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-04-10 13:10:16 -07:00
H. Peter Anvin (Intel)
c8ea2d906d asm/preproc.c: fix NULL pointer on %exitrep outside %rep
When %exitrep incorrectly occurs outside a %rep block, do_exit_macro()
returns NULL, but the %exitrep code would try to set m->in_progress =
1 anyway, causing a NULL pointer dereference and crashing NASM.

Add a NULL pointer guard around this assignment; an error has already
been issued.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-04-10 13:06:34 -07:00
H. Peter Anvin (Intel)
d7c7de072f asm/preproc.c: correct the parameter string size calculation
In list_smacro_def(), the number of characters required for the
parameter string description was off by one; fix.

Improve the comment to explain the exact calculation, and make it more
explicit by specifying the calculation as (5+3+1) instead of just 9.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-04-10 13:03:51 -07:00
H. Peter Anvin (Intel)
d1e9ce5ab0 asm/preproc.c: merge end-of-input code
Normally, end of included files or special inputs should be handled by
pp_tokline(), but under some conditions it might be handled by
pp_cleanup_pass(). The latter case would assume the input was from a
file, which would cause a crash if istk->fp is NULL.

Although this should never happen, this is a good reason to merge
these two pieces of code, which ought to be doing the same thing
anyway.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-04-10 12:55:55 -07:00
InstLatx64
4bcfe7a838 AVX512BMM instructions
- 3 new AVX512BMM instructions, supported in AMD Zen6
Source: https://sourceware.org/pipermail/binutils/2025-November/145449.html

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-04-09 18:28:59 -07:00
H. Peter Anvin (Intel)
31ae053886 travis: update travis golden copy for br3392528.stderr
The format of this message has changed, change the golden copy to
match.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-04-09 18:26:43 -07:00
bonsthie
207b3727c7 elf: add support for GNU indirect function symbol type (gnu_ifunc)
This feature enables emission of IFUNC symbols for global directive.

Example syntax:
```asm
    global  func_ifunc:function

    global  func:gnu_ifunc
    func    equ func_ifunc
```
2026-04-09 18:23:57 -07:00
Raphaël Deschênes
21904008f5 doc: fix documentation for booleanizing operators
Fix the or and improve the xor

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-04-09 18:19:06 -07:00
Yongjie Sheng
8058e5df17 Add project test for cryptography-primitives
Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-04-09 18:13:38 -07:00
H. Peter Anvin (Intel)
00fe1077dc Add \^ escape sequences for Ctrl characters
It is fairly common to want to represent characters like
Ctrl-Z. Instead of having to use character codes, allow these to be
coded as `\^z` or `\^Z` instead.

`\^?` is DEL.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-04-09 18:08:21 -07:00
H. Peter Anvin (Intel)
fe5235ffc9 limits: allow querying limits, and reset limits for each pass
Allow limits to be queried via a %limit() preprocessor function and a
__?NASM_LIMITS?__ macro.

Reset limits at the top of each pass. Note that the pass number limits
are checked at the *end* of the pass, so a %pragma limit will be
properly honored anyway.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-04-09 17:00:49 -07:00
H. Peter Anvin (Intel)
444ef5a122 asm/preproc.c: remove (void) on variable which is actually used
stdmac_env() actually uses nparams, so don't (void) it.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-04-09 16:54:47 -07:00
H. Peter Anvin (Intel)
4afd70f404 assemble_file(): make stall_count static
This function is invoked separately for each pass; therefore the stall
count would never get incremented. Make it a static variable to make
sure it does get incremented correctly.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-04-09 16:51:52 -07:00
H. Peter Anvin (Intel)
a9e46d4572 doc: update changes to the limit option and pragmas
Add --limit-params and the default and maximum keywords.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-04-09 15:19:36 -07:00
H. Peter Anvin (Intel)
a8d44ce956 limits: revamp the limit processor, change params limit to dynamic
Revamp the limit processor to allow a limit to have an absolute
maximum other than LIMIT_MAX_VAL.

Use LIMIT_MAX as a final enum parameter == parameter count == final
actual value + 1, which is the more usual construct and doesn't need
manual updating.

Allow setting a limit to the default value by setting it to "0" or
"default".

Accept "max" or "maximum" instead of "unlimited", specifically to
better handle the case of a fixed maximum < LIMIT_MAX_VAL.

Change the mmacro limit parameter to a dynamic limit, in case someone
needs it.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-04-09 15:12:19 -07:00
H. Peter Anvin (Intel)
e856c2e1dd asm/preproc.c: limit the mmacro parameter count to 16383
There is no conceivable way that a *specified* mmacro parameter count
of anywhere near that much would make sense, and as such almost
certainly represents an error.

Note that the code will still support varadic macros with an excessive
number of parameters.

Use int64_t to make (reasonably) sure that we actually catch
overflows.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-04-09 14:48:46 -07:00
H. Peter Anvin (Intel)
ab0cb6afcb asm/preproc.c: set MAX_TEXT to INT_MAX >> 2
There are still places in the code where "int" are used as
length. Reduce MAX_TEXT to INT_MAX >> 2 so that even adding two
lengths together should make a valid "int".

A token shouldn't be 512GB anyway...

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-04-09 13:52:13 -07:00
H. Peter Anvin (Intel)
b41191e29d warnings.dat: fix a missing "is"
Another editorial change.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-04-08 02:21:20 -07:00
H. Peter Anvin (Intel)
6f8dc8116f warnings.dat: correct regative -> negative spelling
Correct a typo.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-04-08 02:17:50 -07:00
H. Peter Anvin (Intel)
55e064dccb preproc: %env() function
Add an %env() function for expanding environment variables as a more
flexible and robust alternative to %! (the variable name can be
computed without doing weird things like %tok(%strcat("%!",...)) and a
fallback value can be specified by the user.)

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-04-08 01:14:17 -07:00
H. Peter Anvin (Intel)
cf770c08e8 changes.src: document fix to generating binary constants in smacros
Document the fix to smacro argument evaluation that caused truncation
to 63 bits.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-04-07 23:55:34 -07:00
H. Peter Anvin (Intel)
2ac469c93e preproc: for a parameter of type =x/ub, the topmost bit was lost
The buffer size passed in did not account for the terminating zero,
even though space was allocated for it. Explicitly use the size of the
buffer minus two bytes for the radix prefix instead of 64 (which is
the maximum possible number of digits, not the length of the string
buffer.)

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-04-07 23:49:00 -07:00
H. Peter Anvin (Intel)
6251fc5908 nasmlib/numstr.c: check for buflen == 0
buflen == 0 is an error, but be paranoid about it; the code already
checks for a valid base so it is better to check for a valid buffer
size as well.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-04-07 23:09:21 -07:00
H. Peter Anvin (Intel)
93c8f343d9 output/outform.c: change "Legacy alias" -> "Alias" in help text
Aliases aren't necessarily "legacy".

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-04-06 18:16:10 -07:00
H. Peter Anvin (Intel)
6b0e02de3a outform.h: add "omf", "omf2" and "os2" as aliases for obj[2]
Add aliases for the OMF object code formats.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-04-06 18:14:56 -07:00
H. Peter Anvin (Intel)
447bb02e1d Changes: document arith AL,imm8 fix
Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-04-06 18:09:48 -07:00
H. Peter Anvin (Intel)
b1ee0338a3 NASM 3.02rc5 2026-04-06 17:57:13 -07:00
H. Peter Anvin (Intel)
e63209628f nasmlib/file.c: on Win32, need <stringapiset.h>
MultiByteToWideChar() and its constants are defined in
<stringapiset.h>, which is *not* included in <windows.h>.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-04-06 17:55:29 -07:00
H. Peter Anvin (Intel)
c8ce9504ca x86/insns.pl: show the correct instruction flags in comments
Adding the pattern number broke show_iflags(). This only produced
incorrect code comments and so had no actual effect, but it definitely
is not good for debugging!

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-04-06 17:42:54 -07:00
H. Peter Anvin (Intel)
0894bdae30 x86/insns.dat: remove APX flag from MSR immediate instructions
These aren't APX instructions; the vex+ annotation automatically adds
the APX flag when appropriate.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-04-06 17:16:52 -07:00
H. Peter Anvin (Intel)
fcb49f5dd6 NASM 3.02rc4 2026-04-06 16:56:18 -07:00
H. Peter Anvin (Intel)
4b37759129 nasmlib/file.c: Win32: add missing filename argument to conversion
In os_mangle_filename() with _WIN32, MultiByteToWideChar() was being
called with five arguments instead of six, missing the actual
string to convert(!)

Fixes: 5dfcfc8cab
Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-04-06 16:53:11 -07:00
H. Peter Anvin (Intel)
0dd578ce68 nasmlib/alloc.c: no reason to clear q in nasm_free()
q is passed in by reference and the value of q is never examined, so
there is absolutely no reason to set q = NULL in nasm_free().

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-04-06 16:48:18 -07:00
H. Peter Anvin (Intel)
8d4733962e saa: make saa_wleb128[us]() take appropriate types; recode
Make saa_wleb128[us]() take uint64_t and int64_t, respectively, rather
than int.

Notably, if saa_wleb128u() were to receive negative int, it would have
looped forever.

Recode these functions in a style more consistent with NASM code in
general, and possibly a bit simpler.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-04-06 16:43:51 -07:00
H. Peter Anvin (Intel)
9fdc7eab6e nasmlib/path.c: filename_set_extension() missing NUL termination
filename_set_extension() with extension "" would leave the string not
NUL-terminated, because elen == 0.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-04-06 15:49:23 -07:00
Iouri Kharon
8ccb56cb10 insns.dat: add missing reg_al,imm8 (04+ opcode) to the arithmetic macro
The "reg_al,imm8" (04+ opcodes) were missing from the $arith macro.
Check via: 04 11 => must be add al, 11

Fixes: f0dc7c220d
Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-04-06 15:42:47 -07:00
H. Peter Anvin (Intel)
1e494b46c1 NASM 3.02rc3 2026-03-06 18:00:05 -08:00
H. Peter Anvin (Intel)
c8fa17205b Add support for C2y-style \o and braced escapes, and \d for decimal
C2y adds \o for octal byte escapes, and allows \x, \o, or \u escape
sequences to be enclosed in braces to indicate their termination.

Add a \d sequence as a NASM extension to allow decimal bytes to be
specified.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-03-06 17:59:28 -08:00
H. Peter Anvin (Intel)
b1909cf39b listing: move LIST_* enums to listing.h
The LIST_* enums belongs in listing.h, move them there and actually
use them in listing.c.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-03-04 14:14:02 -08:00
H. Peter Anvin (Intel)
89e1d6203a assemble: for -LX emit specific template number as well
When using -LX to debug template selection, emit the specific template
number (as per insnsa.c) as well as the xda line number.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-03-04 14:12:55 -08:00
H. Peter Anvin (Intel)
5606bdb335 listing: move the setting of options to one function
Disentangle the list option setting from the list option
checking. This makes the code simpler for the compiler to grok, and
centralizing code is usually a good idea.

The option setting is hardly performance critical anyway.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-03-03 15:26:56 -08:00
H. Peter Anvin (Intel)
fe9586f201 listing: separate "user" and "debug" flag, add matching debug option
Adding information about the NASM internal state to the list file can
be useful for debugging purposes. Separate the list of options that
are "user" options and those that are "debugging" options. The latter
are not implied by -L+ and are intended for NASM developer use.

Introduce -LX, which lists which instruction patterns are matched by
each instruction.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-03-03 14:12:48 -08:00
H. Peter Anvin (Intel)
a4c5b2829c changes.src: document JMP/CALL immediate size fix
- Document the fix to the JMP/CALL immediate size.
- Keep the convention to use capitals for keywords and instructions.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-03-03 13:23:26 -08:00
H. Peter Anvin (Intel)
7f92d306a9 NASM 3.02rc2 2026-03-03 13:17:56 -08:00
H. Peter Anvin (Intel)
5de64ecd20 changes.src: minor formatting fixes
- Minor format cleanups
- Correct the statement on PUSH.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-03-03 13:17:05 -08:00
Maciej Wieczor-Retman
e7aa83c68e doc: Update changelogs with bugfixes
Write up regression solving results for the upcoming 3.02.

Signed-off-by: Maciej Wieczor-Retman <maciej.wieczor-retman@intel.com>
2026-03-03 13:09:16 -08:00
H. Peter Anvin (Intel)
2aab21b3fb Fix the handling of the "rel" and "iwd" byte codes with oXX prefixes
The "rel" and "iwd" byte codes are supposed to be sensitive to the
operand size of the instruction, but inadvertently were only sensitive
to the CPU mode or an explicit size override for the operand.

"rel" affects direct near jumps, calls, and XBEGIN; "iwd" direct far
jumps and calls. No other instructions use these opcodes.

Fix this, so that e.g. "o32 jmp foo" is treated the same as "jmp dword
foo".

Correct the golden copies of the jmpxx travis tests (which were always
wrong.)

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-03-03 09:57:44 -08:00
H. Peter Anvin (Intel)
fbacd59cce struct itemplate: add insns.xda line number to the structure
Add the line number from insns.xda to struct itemplate. NASM itself
doesn't need this information, but it makes debugging matching *much*
easier; it is worth a few more bytes.

In theory it could be conditionalized on --enable-debug, but it is
probably not worth it.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-03-03 09:55:27 -08:00
H. Peter Anvin (Intel)
99898edfc1 test/crc32.asm: remove "bits BITS" hack
The --bits option makes this pointless.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-03-03 08:54:01 -08:00
H. Peter Anvin (Intel)
b4f74befce test/immsize2.asm: remove bits BITS
The --bits option makes this pointless.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-03-03 08:54:01 -08:00
H. Peter Anvin (Intel)
5bb69e6c8b test.inc: remove BITS hack
The --bits option makes the BITS hack unnecessary, and it somewhat
conflicts with the directive name itself.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-03-03 08:54:01 -08:00
Maciej Wieczor-Retman
320bc224b5 travis: Fix v4 tests
Update the test after fixing the typo in the mnemonic.

Signed-off-by: Maciej Wieczor-Retman <maciej.wieczor-retman@intel.com>
2026-03-03 08:53:44 -08:00
Maciej Wieczor-Retman
ddcf4d4f99 insns.dat: Fix issue #200 - push not allowing dword keyword
After macroization PUSH lost the NOLONG flags. That in turn caused
matching the 32-bit template when using the dword size specifier and
when in 64-bit mode. Giving the o32 entry the NOLONG flag seems to force
the o64 template instead which doesn't trigger warnings about 32-bit
sizes not being allowed.

Signed-off-by: Maciej Wieczor-Retman <maciej.wieczor-retman@intel.com>
2026-03-03 08:53:44 -08:00
Maciej Wieczor-Retman
f0dc7c220d preinsns: Fix issue #159 - incorrect byte encoding
Revert part of macroization that caused incorrect instruction template
matching. The behavior known at 2.16.03 changed due to the rm#,sbyte#
format overtaking other formats. To get back to the previous behavior
the patterns need to intertwine just as is presented here.

Signed-off-by: Maciej Wieczor-Retman <maciej.wieczor-retman@intel.com>
2026-03-03 08:53:44 -08:00
Maciej Wieczor-Retman
e68a08cd7d insns.dat: travis: Fix lost FAR encoding
Previous disassembler fix caused the FAR enconding not getting properly
applied when using the rm format.

Put the disassembler entries at the back so they are preffered by the
assembler and the FAR versions of memory references are correctly
matched.

Update the far tests.

Signed-off-by: Maciej Wieczor-Retman <maciej.wieczor-retman@intel.com>
2026-03-03 08:53:44 -08:00
Maciej Wieczor-Retman
f4defff3ea insns.dat: Fix issue #157 - POP not accepting valid size prefixes
POP doesn't have the OSIZE iflag which made it match the 16-bit
instruction variant and the reject valid osize prefixes likes o32 in 32
bit mode.

Signed-off-by: Maciej Wieczor-Retman <maciej.wieczor-retman@intel.com>
2026-03-03 08:53:44 -08:00
Maciej Wieczor-Retman
2fe0c39bdc travis: Update test binaries
Update the travis test binaries that the tests are compared against.
Changes were made to some instruction patterns and the binaries need to
be refreshed.

Signed-off-by: Maciej Wieczor-Retman <maciej.wieczor-retman@intel.com>
2026-03-03 08:53:44 -08:00
H. Peter Anvin (Intel)
c2344472c2 test: add a test for pushing immediates. Add a common header file.
- Add a test for pushing immediates and popping registers of various
  sizes.
- Add a common header file which probably will be useful for many
  tests.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-03-02 12:50:49 -08:00
H. Peter Anvin (Intel)
7c6bcd9589 test: add additional test for immediate sizes and arithmetic
Immediate sizes in arithmetic instructions can be tricky when using
optimization.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-03-02 12:13:21 -08:00
Maciej Wieczor-Retman
9dbff83e77 insns.dat: Fix JMP not assembling sometimes
After readding the JMP rm# variant, to fix the disassembler not
recognizing it, some patterns stopped assembling. It happened due to the
program matching an incorrect template and then complaining that it's
illegal.

Adding the NOLONG to word and dword versions (similarly to CALL) fixes
the problem.

Signed-off-by: Maciej Wieczor-Retman <maciej.wieczor-retman@intel.com>
2026-02-27 13:48:05 +01:00
H. Peter Anvin (Intel)
f7a4d8fd1b openwcom.mak: add zlib to the VPATH
It isn't clear if this is actually mandatory, but it is consistent
with the rest of the directories.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-02-26 15:44:17 -08:00
H. Peter Anvin (Intel)
724efa686f Merge remote-tracking branch 'maciej/for-hpa-fixes' 2026-02-26 15:32:29 -08:00
Maciej Wieczor-Retman
ef587a2566 docs: Fix issue #190 - no cp -u on MacOS prevents building
Use cp without -u to generate the documentation as the -u option doesn't
have to be present on other POSIX platforms and breaks builing the
project on MacOS.

Signed-off-by: Maciej Wieczor-Retman <maciej.wieczor-retman@intel.com>
2026-02-26 07:53:04 +01:00
Maciej Wieczor-Retman
85cd46de67 insns.dat: Fix issue #164 - broken dissasembly on JMP, JMPE and CALL
After macroization it seems the 'JMP rm' form was replaced by 'JPM
rm#|near' which caused the dissasembler to not emit anything.

Signed-off-by: Maciej Wieczor-Retman <maciej.wieczor-retman@intel.com>
2026-02-23 14:29:58 +01:00
Maciej Wieczor-Retman
14f887fb4e insns.dat: Fix issue #171 - valid prefixes not allowed
Instructions like IRET, POPF and PUSHF used to not have a operand size
specifier but after applying macros they received the 'osm' one -
meaning must be the same as the BITS mode. Which is not true for these
instructions, using the operand size prefix doesn't change their
encoding and their default 64-bit encoding is the 32-bit version.

Align these with other similar instructions like RET, RETF and use the
'od#' keyword which returns their previous behavior.

Signed-off-by: Maciej Wieczor-Retman <maciej.wieczor-retman@intel.com>
2026-02-20 19:35:26 +01:00
H. Peter Anvin (Intel)
184f8485b5 nxdisasm.pl: script to use objdump + ndisasm for better disassembly
Add a script which uses objdump to discover sections and symbols from
a binary, and call ndisasm accordingly, then add symbol references to
the ndisasm output.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-02-09 16:11:58 -08:00
H. Peter Anvin (Intel)
ed23d3ba34 ndisasm: add -z option for data size; clean up address handling
- Add a -z option to set the data size to be read (useful with -e)
- Clean up at least some remaining 32-bit assumptions.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2026-02-09 16:10:32 -08:00
Maciej Wieczor-Retman
8744226309 doc: Document jump size behavior
Document the logic behind determining the jump sizes, amounts of bytes
emitted related to size and length keywords. Change is related to
issue #181.

Also fix the JMPABS not being visible due to wrong tag used.

Signed-off-by: Maciej Wieczor-Retman <maciej.wieczor-retman@intel.com>
2026-02-06 19:40:52 +01:00
Maciej Wieczor-Retman
1ef93d643d doc: Fix issue #191 - badly formatted link
Fix bad link formatting that prevents building the documentation.

Signed-off-by: Maciej Wieczor-Retman <maciej.wieczor-retman@intel.com>
2026-02-06 19:15:52 +01:00
Maciej Wieczor-Retman
627ec8b865 insns.dat: Fix issue #196 - CMP not being lockable
Using LOCK on any CMP configuration of operands will result in #UD.

Remove the possibility of adding the LOCK prefix to the CMP instruction.

Signed-off-by: Maciej Wieczor-Retman <maciej.wieczor-retman@intel.com>
2026-02-06 18:13:09 +01:00
Maciej Wieczor-Retman
3910b58e96 parser.c: Fix issue #181 - redundancy needed to avoid NEAR optimized out
To assemble a JMP in the NEAR form the STRICT keyword is needed. This
change introduced recently reportedly breaks building boot sectors and
is non-intuitive since other JMP versions don't behave this way.

Disable optimizing the JMP size if the NEAR keyword is used.

Signed-off-by: Maciej Wieczor-Retman <maciej.wieczor-retman@intel.com>
2026-02-04 17:18:44 +01:00
Maciej Wieczor-Retman
bbff2d7ec6 parser.c: Fix issue #182 - no warning when size is omitted with labels
In cases such as "mov [es:bx], a_label" the operation defaults to a BYTE
size which copies only part of the label value.

Implement a check that warns the user of this issue when no size
specifier is used.

Signed-off-by: Maciej Wieczor-Retman <maciej.wieczor-retman@intel.com>
2026-02-03 23:12:46 +01:00
Maciej Wieczor-Retman
0058d91bec travis: Fix tests after instruction corrections
The UWRMSR was incorrectly encoded with operands swapped. Correct that
mistake.

Some AVX512 and AVX10.2 instructions had incorrect operands in the
database. Correct the tests after fixing the database entries.

Signed-off-by: Maciej Wieczor-Retman <maciej.wieczor-retman@intel.com>
2026-02-03 23:12:42 +01:00
Maciej Wieczor-Retman
89682def9b disp8: Fix issue #185 - EVEX compressed shift for MOVDDUP tuple type
MOVDDUP tuple type uses a compression shift for the disp8 addressing
scheme. The shift depends on the vector lenght and is defined as 8 for
128 bits, 32 for 256 bits and 64 for 512 bits.

Current implementation doesn't work for the 128 bit vector case since
the expression used evaluates to 16 instead of 8. Fix it with a special
if check before the current expression is returned.

Signed-off-by: Maciej Wieczor-Retman <maciej.wieczor-retman@intel.com>
2026-01-27 22:24:25 +01:00
RMarx1456
3f188d7222 disasm.c: Fix issue #193 by swapping arguments of is_class
Incorrect ordering led to specific encoding for implicit shift by one
(M1 - UNITY from include/opflags.h & x86/insnsd.c) being skipped over in
disasm.c:1519.

The skip over the is_class UNITY check would lead to adding 0x0 to the
end of the instruction and moving onwards having emitted the incorrect
immediate operand.

Fixes: 56567a0c4c ("disasm: fix the disassembler for many APX cases")
2026-01-27 22:24:25 +01:00
Maciej Wieczor-Retman
5c224e169e insns.dat: Fix typos and incorrect operands
Fix errors found through comparing XED and NASM instruction encodings.

From APX the UWRMSR instruction had swapped operands.

Most fixes related to AVX/AVX512 deal with operand sizes not matching
the SDM nor the XED produced encodings. Some (like VGETEXPSH) had a
wrong amont of operands. Others (like VP4DPWSSDS) had misspelled
mnemonics.

At last some AVX10.2 instructions had wrong operands sizes that didn't
match the newest (june 2025) AVX10.2 documentation.

Signed-off-by: Maciej Wieczor-Retman <maciej.wieczor-retman@intel.com>
2026-01-27 22:24:25 +01:00
Maciej Wieczor-Retman
d9c93e06ae insns.dat: Fix issue #186 - scalar AVX512 instructions treated as vector operations
Multiple AVX512 instructions were incorrectly encoded when it comes to
the embedded rounding value - they were treated as 128 bit vector
operations when in reality they are scalar operations.

Correct the following instructions' EVEX encodings:

VCVTSD2SI
VCVTSD2USI
VCVTSS2SI
VCVTSS2USI
VCVTTSD2SI
VCVTTSD2USI
VCVTTSS2SI
VCVTTSS2USI
VGETEXPSH
VGETMANTSH

Signed-off-by: Maciej Wieczor-Retman <maciej.wieczor-retman@intel.com>
2026-01-27 22:24:12 +01:00
H. Peter Anvin (Intel)
22a9118f1e nasmlib: mmap.c included the deleted "file.h", but didn't need it
The recently removed "file.h" was #included by mmap.c, but mmap.c just
needed a few standard header files.

Similarly, remove <sys/mman.h> from file.c.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2025-12-16 17:32:25 -08:00
H. Peter Anvin (Intel)
ff7a315acb nasmlib: move filename_set_extension() into path.c
Move filename_set_extension() into path.c, so it has access to the
filesystem-specific character constants. This prevents something like:

	nasm-code.d/foobar

... from getting truncated to ...

	nasm-code.bin

... instead of producing ...

	nasm-code.d/foobar.bin

Make the extension character (normally '.') configurable; this MIGHT
be usable on RISCOS at some point, although it is not entirely clear
that trying to make sense of RISCOS paths actually is meaningful,
because RISCOS compiler chains seem to do all kinds of path
translation magic trying to behave like other operating systems... it
might simply be more trouble than it is worth, especially for a
non-x86 platform.

As a side bonus, this removes the only use of strrchrnul(), so that
function can be dropped.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2025-12-15 09:58:42 -08:00
H. Peter Anvin (Intel)
795daf3d2d nasmlib: split file.c into file.c and fileio.c; remove file.h
file.h was only included from file.c; combine the two and declare
functions not used anywhere else as static.

Split out the checking I/O routines into a separate routine fileio.c
as they are (mostly) not host operating system specific, whereas
file.c is mostly host operating system generalization code.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2025-12-14 17:47:47 -08:00
H. Peter Anvin (Intel)
5dfcfc8cab Windows: use MultiByteToWideChar() instead of mbsrtowcs()
In the Windows-specific filename translation code, use
MultiByteToWideChar() instead of mbsrtowcs(). As this is
Windows-specific code it makes more sense to use the Windows-specific
API, and it might be more widely supported?

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2025-12-14 17:18:59 -08:00
SEt
b8c2a63286 Fix several issues with Codeview debug information 2025-12-09 16:44:35 -08:00
H. Peter Anvin (Intel)
f4f7d18c06 error: factor out error functions into separate files
Tidy up a *lot* of code by moving error functions into separate source
files. This required breaking out some of the assembler-only files
into a separate library, as it conflicts with stubs in the
disassembler.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2025-11-07 14:42:33 -08:00
H. Peter Anvin (Intel)
c0e4def0fe assemble: factor out calcsize_speculative()
Currently speculative size calculations is only done during
jmp_match(), but it might be used for other things in the
future. Either way, it is cleaner to have it factored out into a
separate function.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2025-11-07 11:51:01 -08:00
redzimski
94c6ecda5b fix [warning push] causing "unknown warning name"
[warning push] emitted a "unknown warning name" warning when
-w+unknown-warning is set.
2025-11-04 10:23:54 -08:00
Petr Sumbera
ca178f80d8 Fix for big endian platforms.
https://bugzilla.nasm.us/show_bug.cgi?id=3392745
2025-11-04 10:14:49 -08:00
H. Peter Anvin (Intel)
acfeb7df6c zlib: pass 15 not 0 to inflateInit2()
The convention of passing 0 to inflateInit2() to autodetect the window
size is not supported in really old versions of zlib. The only
downside with simply passing in the maximum value (15) is potential
additional memory buffer allocations, but it is a drop in the bucket
for NASM.

Fixes: https://github.com/netwide-assembler/nasm/issues/165
Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2025-11-04 00:38:17 -08:00
H. Peter Anvin (Intel)
94923e1382 travis: improve the RET instruction test
Split the RET instruction test by mode for ease of disassembly, and
test more subcases.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2025-10-15 22:51:34 -07:00
H. Peter Anvin (Intel)
e19c989bd5 insns.dat: correct the handling of RET instructions with prefixes
NASM would throw a warning on some valid prefixed RET instructions,
e.g. "o32 ret" instead of "retd" in 16-bit mode.  Correct that.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2025-10-15 22:44:23 -07:00
H. Peter Anvin (Intel)
4709cfe493 Show instruction mismatch errors if another error terminates assembly
Instruction mismatch errors have been held until the last assembly
pass in case changed %if statements cause a code path to be elided in
subsequent passes. However, it is confusing to the user if error
messages aren't shown if another error terminates assembly.

Use the already existing mechanism for warnings to hold the messages
unless another error terminates assembly.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2025-10-15 22:32:36 -07:00
H. Peter Anvin
ca67f50341 travis: unbreak the ret.asm test
The ret.asm test was broken because the assembly expected -DERROR=1
whereas the run script provided -DERROR, masking all the actual
errors...

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2025-10-15 22:32:32 -07:00
H. Peter Anvin
bf16907c9d travis: unbreak the ret.asm test
The ret.asm test was broken because the assembly expected -DERROR=1
whereas the run script provided -DERROR, masking all the actual
errors...

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2025-10-15 22:29:01 -07:00
H. Peter Anvin
1a907c27a5 travis: always generate a list file; show subtest number
Always generate a list file and point output at a given filename, even
if failure is expected.

Remove ad hoc -o output names that generally don't point into safe
locations.

The result is that the preprocessing options (-E) no longer output to
stdout, so change the tests accordingly.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2025-10-15 22:11:09 -07:00
H. Peter Anvin (Intel)
94dd4d30a7 test: improve ret.asm
Add more valid and invalid combinations of return instructions.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2025-10-15 21:12:58 -07:00
H. Peter Anvin (Intel)
1b939ecf3d errors: add the ability to hold errors, not just warnings
Re-introduce ERR_HOLD, which means that an error is treated like a
warning except for the last pass, but unlike ERR_PASS2 the error
message *will* be issued if another error happens on the same pass, just
like warnings.

This will be used to improve error messages on instruction mismatch.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2025-10-15 21:09:05 -07:00
H. Peter Anvin (Intel)
9503778d6e ndisasm: handle byte code 0300..0303 (HINT_NOP)
Avoid ndisasm printing error messages due to an unknown byte code.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2025-10-15 21:05:46 -07:00
H. Peter Anvin (Intel)
fc56538bce Makefile: include $(PROGOBJ) in $(DIRS) dependency
The $(DIRS) dependency didn't include $(PROGOBJ), which could cause
Make to try to build asm/nasm.o or disasm/ndisasm.o before the
corresponding object subdirectory had been created.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2025-10-15 20:00:36 -07:00
H. Peter Anvin (Intel)
efe066ef40 nasm.c: if enabled, print a pass report even on failure
If printing a pass report is enabled, then do so even if the assembly
session failed -- except for a critical or panic failure (e.g. if
running out of memory, which could cause recursive failures.)

This can help discovering e.g. why certain error messages don't appear
when one would expect them (because they have not been detected in the
current pass.)

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2025-10-15 17:34:42 -07:00
H. Peter Anvin (Intel)
ab8787a1fa Rename "headers" directory to "templates", add .h template
Rename the "headers" directory to "templates", and rename the files
within as template.* with the appropriate file types so that editors
will pick up the correct type. Add a .h file template.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2025-10-15 17:34:29 -07:00
H. Peter Anvin (Intel)
f520436a7a Make Watcom workarounds a little less obnoxious
Duplicated code is asking for trouble. Make the Watcom brain damage
workarounds at least patternized.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2025-10-15 17:34:10 -07:00
KO Myung-Hun
e86773d70b openwcom.mak: clean up internal zlib directory
Signed-off-by: KO Myung-Hun <komh78@gmail.com>
2025-10-15 17:31:44 -07:00
H. Peter Anvin (Intel)
44ec97993a compiler: add and use unreachable() macro
C23 defines unreachable() as a macro in <stddef.h>. For earlier
versions of gcc, __builtin_unreachable() is possible.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2025-10-13 17:53:42 -07:00
H. Peter Anvin (Intel)
9ba21c1e50 .gitignore: add .bin16, .bin32, .bin64
New test format suffixes. These are output files and should be ignored
by git.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2025-10-12 13:43:00 -07:00
H. Peter Anvin (Intel)
746e7c9efa compiler.h: the test for "neither C++ nor C23" still wrong
The test needs to test for neither nor; as it was it tested "(not C++)
or C23" which was not at all what was intended...

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2025-10-12 13:05:55 -07:00
H. Peter Anvin (Intel)
dfb3b0013e version: now working on 3.02... 2025-10-12 12:59:14 -07:00
H. Peter Anvin (Intel)
0bc4333150 Change JMPE encoding from being relative to being absolute
Apparently NASM has been doing this in violation of the spec since
JMPE was first added. Hopefully fixing it won't cause new problems...

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2025-10-12 12:58:04 -07:00
H. Peter Anvin (Intel)
44e89ba9b6 compiler.h: drop the stupid C++-style cast-to-bool hack
The C++-style cast-to-bool hack was broken in concept that it doesn't help the
fundamental problem -- implicit conversions are broken for the
backwards compatibility enum definition -- as well as in
implementation, as it misspelled __STDC_VERSION__ as __STDC_VERSION.

The #ifdef bool test *should* have prevented this problem, but
apparently several compilers do define "bool" in <stdbool.h> even when
it is a keyword, in violation of the C23 spec.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2025-10-12 12:48:32 -07:00
H. Peter Anvin (Intel)
587ed5e36d x86/bytecode.txt: improve byte code documentation
Improve the byte code reference documentation to make a few opcodes
more clear and add some general properties about the byte codes,
including the files that need to be changed when the byte code
changes.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2025-10-12 11:23:28 -07:00
H. Peter Anvin (Intel)
e9fac2faa6 NASM 3.01 2025-10-10 23:42:56 -07:00
Yongjie Sheng
3e925ee75c add project test for intel-ipsec-mb isa-l_crypto isa-l 2025-10-11 09:49:07 +08:00
H. Peter Anvin (Intel)
5d655306f9 NASM 3.01rc9 2025-10-10 17:23:52 -07:00
H. Peter Anvin (Intel)
e20b3087cc changes.src: update release notes
A few more changes.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2025-10-10 16:37:04 -07:00
H. Peter Anvin (Intel)
8f1cd30fcb insns.dat: fix CMPXCHG operand size
The operand size prefix byte code (o#) was missing in the CMPXCHG
pattern.

Reported-by: Yongjie Sheng <sheng.yongjie@intel.com>
Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2025-10-10 16:24:22 -07:00
H. Peter Anvin (Intel)
a7457e66cf Fix matching of branch instructions with prefixes and sizes
Matching of branch instructions with prefixes and sizes is, to say the
least, tricky. Work through it, and add a new macro to help.

Fixes: https://github.com/netwide-assembler/nasm/issues/144
Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2025-10-10 13:07:46 -07:00
H. Peter Anvin (Intel)
2c71e67762 travis: don't stop on failure
Don't stop travis after a single test failure. It is better to run all
the tests and get a comprehensive list of failing tests.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2025-10-10 10:55:11 -07:00
H. Peter Anvin (Intel)
c0aec6969b directives: correctly handle quoted strings in directives
Quoted strings should be valid inside directives, including ones that
contain a ] character. Also check for garbage on the line after the
directive.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2025-10-10 10:41:09 -07:00
H. Peter Anvin (Intel)
5a6b276b89 travis: make travis output list files for debugging
It is so much easier to debug problems with a list file in hand.
Generate them, always.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2025-10-09 22:28:34 -07:00
H. Peter Anvin (Intel)
4cdb62ffb6 listing: modify active_list_options, not just list_options
If the assembly stops after the first pass, only active_list_options
will be seen; this is also the value that applies for local changes in
the list options. Thus, both variables need to be tweaked.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2025-10-09 20:09:33 -07:00
H. Peter Anvin (Intel)
7e82d9d1e3 Add a default-error warning for impossible o64, a64, or a16 prefixes
The o64, a64 and a16 prefixes are only possible in specific
modes. It is a lot easier to debug with a more sensible error message.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2025-10-09 19:24:07 -07:00
H. Peter Anvin (Intel)
a16571a705 doc/directiv.src: fix missing ] in prefix/suffix documentation
The prefix/suffix directive documentation were missing some brackets,
lost in the course of editing.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2025-10-09 17:29:00 -07:00
H. Peter Anvin (Intel)
b8e256a475 changes.src: add missing \>
Add missing \> marker (bulleted list continuation.)

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2025-10-09 17:25:54 -07:00
H. Peter Anvin (Intel)
f87fb5c957 nasm.spec.in: change http:// to https://
Change URLs to https://.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2025-10-09 17:19:54 -07:00
H. Peter Anvin (Intel)
b453f9e8ea nasm.spec.in: be extra obnoxious about build requirements
It is better to put in too many BuildRequires than too few.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2025-10-09 17:19:09 -07:00
Igor Glücksmann
35ef2e2d1a Fixed PDF doc line overflow
Resolved Conflicts:
	doc/nasmdoc.src

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2025-10-09 17:08:35 -07:00
H. Peter Anvin (Intel)
69c25535ae NASM 3.01rc8 2025-10-09 16:15:52 -07:00
H. Peter Anvin (Intel)
ddf85b55ed changes.src: update release notes
Add recent changes to the release notes.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2025-10-09 16:14:58 -07:00
H. Peter Anvin (Intel)
3d96ea651a assemble: weaken the test for "absolute address can not be RIP-relative"
The test for "absolute address can not be RIP-relative" is too strict
and causes false positive failures.

Fixes: https://github.com/netwide-assembler/nasm/issues/145
Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2025-10-09 16:10:35 -07:00
Nico Weber
a8a1dc2b0c Fix Wbitwise-instead-of-logical warning
`a || b` only evaluates b if a is false. `a | b` always evaluates
both a and b. If a and b are of type bool, || is usually what you
want, so clang now warns on `|` where both arguments are of type bool.

This warning fires once in nasm. It looks like `|` is an (inconsequential)
typo of `||`, so use that instead.

No intended behavior change.
2025-10-09 15:48:18 -07:00
H. Peter Anvin (Intel)
9b101e9316 insns.pl: register 0 should add RN_ZERO, not RM_ZERO
Not all registers are valid as memory references, and thus
using RM_ZERO is incorrect. Use RN_ZERO instead, which is simply the
zero-register bit.

Fixes: https://github.com/netwide-assembler/nasm/issues/140
Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2025-10-09 15:42:29 -07:00
KO Myung-Hun
0c8379825e openwcom.mak: use internal commands if possible
[ hpa: added comment that "rm" really is a WMAKE internal command. ]

Signed-off-by: KO Myung-Hun <komh78@gmail.com>
Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2025-10-09 15:05:29 -07:00
KO Myung-Hun
29a5aabd7a Fix compilation with Open Watcom
Open Watcom does not support 64-bit constants at 'case'.

[ hpa: I'm pulling this, but I'm really, *really* questioning its
supportability long term. The OpenWatcom people need to fix this, or
we are just going to have to say "OW is not supported."

At some point we *are* going to move to a "C99 is baseline" policy for
code; there are simply too many features in C99 that are actively
painful to be without.

That is, unless we decide to go to C++, which is under consideration
but is a much bigger job. In that case, the target will probably be
either C++11 or C++14 as those C++ versions contain some pretty
essential features. ]

Signed-off-by: KO Myung-Hun <komh78@gmail.com>
Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2025-10-09 14:52:29 -07:00
H. Peter Anvin (Intel)
013db3d446 nasmlib: rename crc32.c to crc32b.c to avoid conflict with zlib/crc32.c
For the benefit of those platforms which have to rely on VPATH, avoid
having the same filename in multiple subdirectories.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2025-10-09 14:49:22 -07:00
InstLatx64
378ee0e9c5 AMX-TRANSPOSE: removed, retag instructions NEVER.
All the 16 AMX-TRANSPOSE instructions were removed from the 59th
edition of "Intel Architecture Instruction Set Extensions and Future
Features Programming Reference" September 2025, 319433-059.

Similar to PCOMMIT, they are tagged as 'NEVER'

[ hpa: don't remove from tests, but suppress the warnings.  Don't
  remove the CPUID tag; a future version of NASM will actually implement
  CPU filtering based on the various CPUID tags; that development is
  genuinely in progress. ]

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2025-10-09 14:44:24 -07:00
InstLatx64
62b610ad86 Feature flag change, remove duplicate: AVX512FC16->F16C
VEX version of VCVTPH2PS, VCVTPS2PH is F16C

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2025-10-09 14:29:09 -07:00
H. Peter Anvin (Intel)
43f9a71fc0 NASM 3.01rc7 2025-10-08 13:12:29 -07:00
Yongjie2017
a684942de0 the list file existing or not should not fail the copy instead fail the nasm compiling itself so nasm -v is excused 2025-10-08 13:07:07 -07:00
Yongjie Sheng
420313da8c add project test support to dav1d 2025-10-08 13:07:07 -07:00
H. Peter Anvin (Intel)
be03f169b9 travis: let "make travis" show the errors if any
Grep for FAIL in the log and print any errors, otherwise a success
message.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2025-10-08 13:03:40 -07:00
H. Peter Anvin (Intel)
51dce26137 travis improvements: look for python3, log output, option to filter
Use autoconf to find either python3 or python.

Add option to travis to filter the contents of stdout or stderr.

Generate the _version.stdout travis matching file from the version
file.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2025-10-08 12:56:00 -07:00
H. Peter Anvin (Intel)
a398a41f0a travis: update AMX test
Update AMX test per previous commit from IntLatx64.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2025-10-08 11:59:23 -07:00
InstLatx64
019615f85f AMX fix
-- AMX instruction fixes
-- AMX test file extension with new levels
according to Intel ISA Extension Guide 58th edition

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2025-10-08 11:59:23 -07:00
InstLatx64
292d852f55 AVX-NE-CONVERT fix
AVX-NE-CONVERT fix:
- only VCVTNEPS2BF16 has EVEX version
AVX-NE-CONVERT32b/64b test files
Checked with XED version: [v2025.06.08]
2025-10-08 11:51:04 -07:00
Iouri Kharon
5a5057ad95 bug in new macro (typo?): alias is SAL (to SHL), not SAR 2025-10-08 11:49:54 -07:00
H. Peter Anvin (Intel)
e027b5919f NASM 3.01rc6 2025-10-07 20:27:43 -07:00
H. Peter Anvin (Intel)
ae9335a0b9 labels: make the prefix/suffix options and pragmas consistent
Make the spellings for the label-mangling options and pragmas
consistent, and implement the directive forms which were documented
but never implemented.

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
2025-10-07 18:46:39 -07:00
H. Peter Anvin (Intel)
c08b4edca1 Sync builtin.mac 2025-10-07 18:06:34 -07:00
19790 changed files with 256427 additions and 11682 deletions

View file

@ -20,7 +20,7 @@ jobs:
apt-get update && apt-get install -y automake perl python3 build-essential
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v6
- name: Prepare build system
run: |
@ -35,3 +35,113 @@ jobs:
- name: Run travis tests
run: |
make travis
- name: Upload travis.log
if: always()
uses: actions/upload-artifact@v7
with:
name: travis-log
path: travis.log
if-no-files-found: warn
build-msvc:
name: Build with MSVC (Windows)
runs-on: windows-latest
steps:
- name: Checkout repository
uses: actions/checkout@v6
- name: Set up MSVC developer environment
# step-security/msvc-dev-cmd is a StepSecurity-maintained,
# actively updated (Node 24) drop-in replacement for
# ilammy/msvc-dev-cmd@v1, which is Node 20 and has no newer
# release addressing that.
uses: step-security/msvc-dev-cmd@v1
with:
arch: x64
- name: Install NSIS
# Needed to build the Windows installer (nsis/nasm.nsi) via the
# "nsis" nmake target below. Not preinstalled on windows-latest.
# choco updates the machine PATH, but that doesn't propagate to
# the already-running Actions Runner process (and thus not to
# later steps), so add makensis's directory to $GITHUB_PATH
# explicitly.
run: |
choco install nsis --no-progress -y
Get-Item "${env:ProgramFiles(x86)}\NSIS", "$env:ProgramFiles\NSIS" -ErrorAction SilentlyContinue |
Select-Object -First 1 -ExpandProperty FullName |
Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
- name: Install Perl CPAN modules for doc build
# doc/genps.pl's font-metrics computation needs Font::TTF, and
# the wider doc toolchain needs a handful of other non-core
# CPAN modules; see doc/perlbreq.src (generated from
# doc/source.src's requirements list by tools/genperlbreq.pl)
# for the authoritative list. windows-latest ships Strawberry
# Perl, which bundles cpanm.
shell: cmd
run: cpanm --notest Font::TTF JSON Sort::Versions Compress::Zlib Win32::TieRegistry
- name: Install Ghostscript and doc-build fonts
# nasmdoc.pdf (packaged into the installer) is built via
# doc/pspdf.pl, which shells out to Ghostscript, and
# doc/genps.pl, which needs the Roboto and Roboto Mono font
# files to compute glyph metrics (see doc/source.src, "Optional
# Build Tools"). Neither is preinstalled on windows-latest.
#
# Font versions match what Fedora's google-roboto-fonts (from
# github.com/google/roboto, release v2.138) and
# google-roboto-mono-fonts (from github.com/googlefonts/RobotoMono)
# packages ship, which is known-good: only Bold/BoldItalic/
# Italic/Regular of Roboto and Bold/Medium/Regular of Roboto
# Mono are actually used by doc/psfonts.ph. Dropping the .ttf
# files straight into %windir%\Fonts is sufficient: findfont.ph
# falls back to scanning that directory directly and identifies
# faces from each file's own name table, no font-registration
# step required.
shell: pwsh
run: |
choco install ghostscript --no-progress -y
$fontsDir = "$env:windir\Fonts"
Invoke-WebRequest -Uri "https://github.com/google/roboto/releases/download/v2.138/roboto-unhinted.zip" -OutFile roboto.zip
Expand-Archive -Path roboto.zip -DestinationPath roboto-unhinted
foreach ($f in "Regular", "Bold", "Italic", "BoldItalic") {
Copy-Item "roboto-unhinted\Roboto-$f.ttf" $fontsDir
}
foreach ($f in "Regular", "Bold", "Medium") {
Invoke-WebRequest -Uri "https://raw.githubusercontent.com/googlefonts/RobotoMono/main/fonts/ttf/RobotoMono-$f.ttf" -OutFile "$fontsDir\RobotoMono-$f.ttf"
}
- name: Build with nmake/cl.exe
shell: cmd
run: |
nmake /f Mkfiles\msvc.mak
- name: Smoke-test the resulting binaries
shell: cmd
run: |
nasm.exe --version
ndisasm.exe --version
echo mov eax, 1 > smoke.asm
echo ret >> smoke.asm
nasm.exe -f bin smoke.asm -o smoke.bin
ndisasm.exe -b 64 smoke.bin
nasm.exe -f win64 smoke.asm -o smoke.obj
- name: Build documentation and NSIS installer
shell: cmd
run: |
nmake /f Mkfiles\msvc.mak docs
nmake /f Mkfiles\msvc.mak nsis
- name: Upload installer artifact
uses: actions/upload-artifact@v7
with:
name: nasm-windows-installer
path: nasm-*-installer-*.exe
if-no-files-found: error

7
.gitignore vendored
View file

@ -2,6 +2,9 @@
*.aout
*.aoutb
*.bin
*.bin16
*.bin32
*.bin64
*.coff
*.com
*.dbg
@ -11,6 +14,7 @@
*.ith
*.lib
*.lst
*.log
*.map
*.mo32
*.mo64
@ -96,6 +100,8 @@ TAGS
/test/testresults
/test/ffmpegtest
/test/x264test
/travis.mk
/travis.mak
/version.h
/version.mac
/version.mak
@ -119,3 +125,4 @@ TAGS
/autoconf/config.*
/autoconf/install-sh
/autoconf/clean.sh
/travis/_version/_version.stdout

View file

@ -52,8 +52,8 @@ D: RDOFF support
N: H. Peter Anvin
E: hpa@zytor.com
D: Primary maintainer for the 0.98, late 0.98.x and 2.x releases.
C: Contributions since 2008-12-15 are Copyright Intel Corporation.
D: Primary maintainer for the 0.98, late 0.98.x and 2+ releases.
C: Contributions from 2008-12-15 to 2026-08-15 are Copyright Intel Corporation.
N: John Fine
E: johnfine@earthlink.net

View file

@ -5,6 +5,7 @@
# Auto-configuring Makefile for the Netwide Assembler.
@SET_MAKE@
export MAKE
PACKAGE_NAME = @PACKAGE_NAME@
PACKAGE_TARNAME = @PACKAGE_TARNAME@
@ -60,14 +61,14 @@ RUNPERL = $(PERL) $(PERLFLAGS)
EMPTY = : >
SIDE = @: Generated by side effect
PYTHON3 = python3
PYTHON3 = @PYTHON3@
GREP = grep
INSTALL = @INSTALL@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_DATA = @INSTALL_DATA@
# Optional tools
NROFF = @NROFF@
ASCIIDOC = @ASCIIDOC@
XMLTO = @XMLTO@
MAKENSIS = @MAKENSIS@
@ -108,7 +109,7 @@ PHONY =
.PHONY: all doc misc install clean distclean cleaner spotless test
.PHONY: install_doc everything install_everything strip perlreq warnings
.PHONY: dist tags TAGS nothing manpages nsis editors
.PHONY: dist tags TAGS nothing manpages nsis editors travis
.c.$(O):
$(CC) -c $(ALL_CFLAGS) -o $@ $<
@ -134,6 +135,45 @@ NDISASM = disasm/ndisasm.$(O)
PROGOBJ = $(NASM) $(NDISASM)
PROGS = nasm$(X) ndisasm$(X)
# Objects for the local copy of zlib. The variable ZLIB is set to
# $(ZLIBOBJ) if the internal version of zlib should be used.
ZLIBOBJ = \
zlib/adler32.$(O) \
zlib/crc32.$(O) \
zlib/infback.$(O) \
zlib/inffast.$(O) \
zlib/inflate.$(O) \
zlib/inftrees.$(O) \
zlib/zutil.$(O)
# Common library objects
LIBOBJ_COM = \
stdlib/snprintf.$(O) stdlib/vsnprintf.$(O) stdlib/strlcpy.$(O) \
stdlib/strnlen.$(O) \
\
nasmlib/ver.$(O) \
nasmlib/alloc.$(O) nasmlib/asprintf.$(O) \
nasmlib/crc32b.$(O) nasmlib/crc64.$(O) nasmlib/md5c.$(O) \
nasmlib/string.$(O) nasmlib/nctype.$(O) \
nasmlib/file.$(O) nasmlib/fileio.$(O) nasmlib/mmap.$(O) \
nasmlib/realpath.$(O) nasmlib/path.$(O) \
nasmlib/ilog2.$(O) nasmlib/numstr.$(O) \
nasmlib/rlimit.$(O) \
nasmlib/zerobuf.$(O) nasmlib/bsi.$(O) \
nasmlib/rbtree.$(O) nasmlib/hashtbl.$(O) \
nasmlib/raa.$(O) nasmlib/saa.$(O) \
nasmlib/strlist.$(O) \
nasmlib/perfhash.$(O) nasmlib/badenum.$(O) \
nasmlib/readnum.$(O) \
\
common/common.$(O) common/errstubs.$(O) common/files.$(O) \
\
x86/insnsa.$(O) x86/insnsb.$(O) x86/insnsn.$(O) \
x86/regs.$(O) x86/regvals.$(O) x86/regflags.$(O) \
x86/iflag.$(O) \
\
$(ZLIB)
# Files dependent on warnings.dat
WARNOBJ = asm/warnings.$(O)
WARNFILES = asm/warnings_c.h include/warnings.h doc/warnings.src
@ -147,10 +187,8 @@ OUTPUTOBJ = \
output/outdbg.$(O) output/outieee.$(O) output/outmacho.$(O) \
output/codeview.$(O)
# The source files for these objects are scanned for warnings
LIBOBJ_W = \
nasmlib/readnum.$(O) \
\
# Assembler-only library objects
LIBOBJ_ASM = \
asm/error.$(O) \
asm/floats.$(O) \
asm/directiv.$(O) \
@ -164,17 +202,6 @@ LIBOBJ_W = \
asm/segalloc.$(O) \
asm/rdstrnum.$(O) \
asm/srcfile.$(O) \
\
$(OUTPUTOBJ)
# The source files for these objects are NOT scanned for warnings;
# normally this will include all generated files.
# It is entirely possible that it may be necessary to move some of these
# files to LIBOBJ_W, notably $(OUTPUTOBJ)
LIBOBJ_NW = \
stdlib/snprintf.$(O) stdlib/vsnprintf.$(O) stdlib/strlcpy.$(O) \
stdlib/strnlen.$(O) stdlib/strrchrnul.$(O) \
\
asm/directbl.$(O) \
asm/pptok.$(O) \
asm/tokhash.$(O) \
@ -182,47 +209,17 @@ LIBOBJ_NW = \
\
macros/macros.$(O) \
\
nasmlib/ver.$(O) \
nasmlib/alloc.$(O) nasmlib/asprintf.$(O) \
nasmlib/crc32.$(O) nasmlib/crc64.$(O) nasmlib/md5c.$(O) \
nasmlib/string.$(O) nasmlib/nctype.$(O) \
nasmlib/file.$(O) nasmlib/mmap.$(O) nasmlib/ilog2.$(O) \
nasmlib/realpath.$(O) nasmlib/path.$(O) \
nasmlib/filename.$(O) nasmlib/rlimit.$(O) \
nasmlib/numstr.$(O) \
nasmlib/zerobuf.$(O) nasmlib/bsi.$(O) \
nasmlib/rbtree.$(O) nasmlib/hashtbl.$(O) \
nasmlib/raa.$(O) nasmlib/saa.$(O) \
nasmlib/strlist.$(O) \
nasmlib/perfhash.$(O) nasmlib/badenum.$(O) \
\
common/common.$(O) \
\
x86/insnsa.$(O) x86/insnsb.$(O) x86/insnsn.$(O) \
x86/regs.$(O) x86/regvals.$(O) x86/regflags.$(O) \
x86/iflag.$(O) \
\
$(WARNOBJ)
$(WARNOBJ) \
$(OUTPUTOBJ)
# Objects which are only used for the disassembler
LIBOBJ_DIS = \
disasm/disasm.$(O) disasm/sync.$(O) disasm/prefix.$(O) \
disasm/diserror.$(O) \
\
x86/insnsd.$(O) x86/regdis.$(O)
# Objects for the local copy of zlib. The variable ZLIB is set to
# $(ZLIBOBJ) if the internal version of zlib should be used.
ZLIBOBJ = \
zlib/adler32.$(O) \
zlib/crc32.$(O) \
zlib/infback.$(O) \
zlib/inffast.$(O) \
zlib/inflate.$(O) \
zlib/inftrees.$(O) \
zlib/zutil.$(O)
LIBOBJ = $(LIBOBJ_W) $(LIBOBJ_NW) $(ZLIB)
ALLOBJ_W = $(NASM) $(LIBOBJ_W)
LIBOBJ = $(LIBOBJ_COM) $(LIBOBJ_ASM) $(LIBOBJ_DIS)
ALLOBJ = $(PROGOBJ) $(LIBOBJ)
SUBDIRS = stdlib nasmlib include config output asm disasm x86 \
common zlib macros misc
@ -240,28 +237,34 @@ $(DIRS):
@$(MKDIR_P) $(SUBDIRS) $(XSUBDIRS)
NASMLIB = libnasm.$(A)
DISLIB = libndis.$(A)
ASMLIB = libasm.$(A)
DISLIB = libdis.$(A)
$(NASMLIB): $(LIBOBJ)
$(NASMLIB): $(LIBOBJ_COM)
$(RM_F) $(NASMLIB)
$(AR) cq $(NASMLIB) $(LIBOBJ)
$(AR) cq $(NASMLIB) $(LIBOBJ_COM)
$(RANLIB) $(NASMLIB)
$(ASMLIB): $(LIBOBJ_ASM)
$(RM_F) $(ASMLIB)
$(AR) cq $(ASMLIB) $(LIBOBJ_ASM)
$(RANLIB) $(ASMLIB)
$(DISLIB): $(LIBOBJ_DIS)
$(RM_F) $(DISLIB)
$(AR) cq $(DISLIB) $(LIBOBJ_DIS)
$(RANLIB) $(DISLIB)
nasm$(X): $(NASM) $(MANIFEST) $(NASMLIB)
nasm$(X): $(NASM) $(MANIFEST) $(ASMLIB) $(NASMLIB)
$(CC) $(ALL_LDFLAGS) -o $@ $(NASM) $(MANIFEST) \
$(NASMLIB) $(LIBS)
$(ASMLIB) $(NASMLIB) $(LIBS)
ndisasm$(X): $(NDISASM) $(MANIFEST) $(DISLIB) $(NASMLIB)
$(CC) $(ALL_LDFLAGS) -o $@ $(NDISASM) $(MANIFEST) \
$(DISLIB) $(NASMLIB) $(LIBS)
# Make sure we have subdirectories set up...
$(LIBOBJ) $(LIBOBJ_DIS): $(DIRS)
$(ALLOBJ): $(DIRS)
#-- Begin Generated File Rules --#
@ -282,7 +285,7 @@ PERLREQ_CLEANABLE = \
PERLREQ = $(PERLREQ_CLEANABLE)
INSDEP = x86/insns.xda x86/insns.pl x86/insns-iflags.ph x86/iflags.ph
INSDEP = x86/insns.xda x86/insns.pl x86/insns-iflags.ph x86/iflags.ph x86/insns-cc.ph
x86/insns.xda: x86/insns.dat x86/preinsns.pl $(DIRS)
$(RUNPERL) $(srcdir)/x86/preinsns.pl $(srcdir)/x86/insns.dat $@
@ -560,17 +563,17 @@ nasm.spec: nasm.spec.in nasm.spec.sed version.sed perlbreq.si
splint:
splint -weak *.c
.PHONY: test
test: $(PROGS)
cd $(srcdir)/test && \
$(RUNPERL) performtest.pl --nasm=../nasm$(X) *.asm
#
# Travis tests
#
travis test: $(PROGS)
$(MAKE) -f travis.mak all
golden: $(PROGS)
cd $(srcdir)/test && \
$(RUNPERL) performtest.pl --golden --nasm=../nasm$(X) *.asm
clean-travis travis-clean:
$(MAKE) -f travis.mak clean
travis: $(PROGS)
$(PYTHON3) travis/nasm-t.py run
update-travis travis-update golden:
$(MAKE) -f travis.mak update
#
# Rules to run autogen if necessary

View file

@ -86,7 +86,46 @@ NDISASM = disasm\ndisasm.obj
PROGOBJ = $(NASM) $(NDISASM)
PROGS = nasm$(X) ndisasm$(X)
# Files dependent on extracted warnings
# Objects for the local copy of zlib. The variable ZLIB is set to
# $(ZLIBOBJ) if the internal version of zlib should be used.
ZLIBOBJ = \
zlib\adler32.obj \
zlib\crc32.obj \
zlib\infback.obj \
zlib\inffast.obj \
zlib\inflate.obj \
zlib\inftrees.obj \
zlib\zutil.obj
# Common library objects
LIBOBJ_COM = \
stdlib\snprintf.obj stdlib\vsnprintf.obj stdlib\strlcpy.obj \
stdlib\strnlen.obj \
\
nasmlib\ver.obj \
nasmlib\alloc.obj nasmlib\asprintf.obj \
nasmlib\crc32b.obj nasmlib\crc64.obj nasmlib\md5c.obj \
nasmlib\string.obj nasmlib\nctype.obj \
nasmlib\file.obj nasmlib\fileio.obj nasmlib\mmap.obj \
nasmlib\realpath.obj nasmlib\path.obj \
nasmlib\ilog2.obj nasmlib\numstr.obj \
nasmlib\rlimit.obj \
nasmlib\zerobuf.obj nasmlib\bsi.obj \
nasmlib\rbtree.obj nasmlib\hashtbl.obj \
nasmlib\raa.obj nasmlib\saa.obj \
nasmlib\strlist.obj \
nasmlib\perfhash.obj nasmlib\badenum.obj \
nasmlib\readnum.obj \
\
common\common.obj common\errstubs.obj common\files.obj \
\
x86\insnsa.obj x86\insnsb.obj x86\insnsn.obj \
x86\regs.obj x86\regvals.obj x86\regflags.obj \
x86\iflag.obj \
\
$(ZLIB)
# Files dependent on warnings.dat
WARNOBJ = asm\warnings.obj
WARNFILES = asm\warnings_c.h include\warnings.h doc\warnings.src
@ -99,10 +138,8 @@ OUTPUTOBJ = \
output\outdbg.obj output\outieee.obj output\outmacho.obj \
output\codeview.obj
# The source files for these objects are scanned for warnings
LIBOBJ_W = \
nasmlib\readnum.obj \
\
# Assembler-only library objects
LIBOBJ_ASM = \
asm\error.obj \
asm\floats.obj \
asm\directiv.obj \
@ -116,17 +153,6 @@ LIBOBJ_W = \
asm\segalloc.obj \
asm\rdstrnum.obj \
asm\srcfile.obj \
\
$(OUTPUTOBJ)
# The source files for these objects are NOT scanned for warnings;
# normally this will include all generated files.
# It is entirely possible that it may be necessary to move some of these
# files to LIBOBJ_W, notably $(OUTPUTOBJ)
LIBOBJ_NW = \
stdlib\snprintf.obj stdlib\vsnprintf.obj stdlib\strlcpy.obj \
stdlib\strnlen.obj stdlib\strrchrnul.obj \
\
asm\directbl.obj \
asm\pptok.obj \
asm\tokhash.obj \
@ -134,47 +160,17 @@ LIBOBJ_NW = \
\
macros\macros.obj \
\
nasmlib\ver.obj \
nasmlib\alloc.obj nasmlib\asprintf.obj \
nasmlib\crc32.obj nasmlib\crc64.obj nasmlib\md5c.obj \
nasmlib\string.obj nasmlib\nctype.obj \
nasmlib\file.obj nasmlib\mmap.obj nasmlib\ilog2.obj \
nasmlib\realpath.obj nasmlib\path.obj \
nasmlib\filename.obj nasmlib\rlimit.obj \
nasmlib\numstr.obj \
nasmlib\zerobuf.obj nasmlib\bsi.obj \
nasmlib\rbtree.obj nasmlib\hashtbl.obj \
nasmlib\raa.obj nasmlib\saa.obj \
nasmlib\strlist.obj \
nasmlib\perfhash.obj nasmlib\badenum.obj \
\
common\common.obj \
\
x86\insnsa.obj x86\insnsb.obj x86\insnsn.obj \
x86\regs.obj x86\regvals.obj x86\regflags.obj \
x86\iflag.obj \
\
$(WARNOBJ)
$(WARNOBJ) \
$(OUTPUTOBJ)
# Objects which are only used for the disassembler
LIBOBJ_DIS = \
disasm\disasm.obj disasm\sync.obj disasm\prefix.obj \
disasm\diserror.obj \
\
x86\insnsd.obj x86\regdis.obj
# Objects for the local copy of zlib. The variable ZLIB is set to
# $(ZLIBOBJ) if the internal version of zlib should be used.
ZLIBOBJ = \
zlib\adler32.obj \
zlib\crc32.obj \
zlib\infback.obj \
zlib\inffast.obj \
zlib\inflate.obj \
zlib\inftrees.obj \
zlib\zutil.obj
LIBOBJ = $(LIBOBJ_W) $(LIBOBJ_NW) $(ZLIB)
ALLOBJ_W = $(NASM) $(LIBOBJ_W)
LIBOBJ = $(LIBOBJ_COM) $(LIBOBJ_ASM) $(LIBOBJ_DIS)
ALLOBJ = $(PROGOBJ) $(LIBOBJ)
SUBDIRS = stdlib nasmlib include config output asm disasm x86 \
common zlib macros misc
@ -186,22 +182,26 @@ EDITORS = editors\nasmtok.el editors\nasmtok.json
#-- End File Lists --#
NASMLIB = libnasm.$(A)
NDISLIB = libndis.$(A)
ASMLIB = libasm.$(A)
DISLIB = libdis.$(A)
all: nasm$(X) ndisasm$(X)
nasm$(X): $(NASM) $(MANIFEST) $(NASMLIB)
$(CC) /Fe:$@ $(ALL_CFLAGS) $(NASM) $(NASMLIB) $(LIBS) \
nasm$(X): $(NASM) $(MANIFEST) $(ASMLIB) $(NASMLIB)
$(CC) /Fe:$@ $(ALL_CFLAGS) $(NASM) $(ASMLIB) $(NASMLIB) $(LIBS) \
$(ALL_LDFLAGS)
ndisasm$(X): $(NDISASM) $(MANIFEST) $(NDISLIB) $(NASMLIB)
$(CC) /Fe:$@ $(ALL_CFLAGS) $(NDISASM) $(NDISLIB) $(NASMLIB) $(LIBS) \
ndisasm$(X): $(NDISASM) $(MANIFEST) $(DISLIB) $(NASMLIB)
$(CC) /Fe:$@ $(ALL_CFLAGS) $(NDISASM) $(DISLIB) $(NASMLIB) $(LIBS) \
$(ALL_LDFLAGS)
$(NASMLIB): $(LIBOBJ)
$(NASMLIB): $(LIBOBJ_COM)
$(AR) $(ARFLAGS) /out:$@ $**
$(NDISLIB): $(LIBOBJ_DIS)
$(ASMLIB): $(LIBOBJ_ASM)
$(AR) $(ARFLAGS) /out:$@ $**
$(DISLIB): $(LIBOBJ_DIS)
$(AR) $(ARFLAGS) /out:$@ $**
# These are specific to certain Makefile syntaxes...
@ -227,7 +227,7 @@ PERLREQ_CLEANABLE = \
PERLREQ = $(PERLREQ_CLEANABLE)
INSDEP = x86\insns.xda x86\insns.pl x86\insns-iflags.ph x86\iflags.ph
INSDEP = x86\insns.xda x86\insns.pl x86\insns-iflags.ph x86\iflags.ph x86\insns-cc.ph
x86\insns.xda: x86\insns.dat x86\preinsns.pl $(DIRS)
$(RUNPERL) $(srcdir)\x86\preinsns.pl $(srcdir)\x86\insns.dat $@
@ -358,6 +358,9 @@ doc\warnings.src: asm\warnings.pl asm\warnings.dat
$(RUNPERL) $(srcdir)\asm\warnings.pl doc doc\warnings.src \
$(srcdir)\asm\warnings.dat
doc\perlbreq.src: tools\genperlbreq.pl $(DIRS)
$(RUNPERL) tools\genperlbreq.pl $(srcdir) doc\perlbreq.src
$(PERLREQ): $(DIRS)
perlreq: $(PERLREQ) $(PHONY)
@ -418,14 +421,31 @@ cleaner: clean
spotless: distclean cleaner
-del /f doc\Makefile
-del /f doc\msvc.mak
-del doc\*~
-del doc\*.bak
strip:
# Abuse doc/Makefile.in to build nasmdoc.pdf only
docs:
cd doc && $(MAKE) /f Makefile.in srcdir=. top_srcdir=.. \
# Abuse doc/Makefile.in to build nasmdoc.pdf only.
#
# doc/Makefile.in expects doc\warnings.src, doc\perlbreq.src and
# doc\pptok.src to already have been generated by the top-level build
# (as the Unix "doc" target does); build them here first.
#
# doc/Makefile.in is written for GNU make and relies on a few
# constructs nmake cannot parse at all ($^, $< outside an inference
# rule, and the GNU-only "-include *.dep" directive); tools/mkmsvcdocmak.pl
# rewrites those to their nmake-safe equivalents in a generated copy,
# doc\msvc.mak, which is what actually gets fed to nmake below.
#
# Building the documentation requires Ghostscript and the Roboto /
# Roboto Mono fonts to be installed and discoverable; see
# doc/source.src ("Optional Build Tools") for details.
docs: doc\warnings.src doc\perlbreq.src doc\pptok.src
$(RUNPERL) $(srcdir)\tools\mkmsvcdocmak.pl \
$(srcdir)\doc\Makefile.in doc\msvc.mak
cd doc && $(MAKE) /f msvc.mak srcdir=. top_srcdir=.. \
PERL=$(PERL) PDFOPT= nasmdoc.pdf
everything: all docs nsis

View file

@ -6,42 +6,57 @@
top_srcdir = .
srcdir = .
VPATH = $(srcdir)\asm;$(srcdir)\x86;asm;x86;$(srcdir)\macros;macros;$(srcdir)\output;$(srcdir)\lib;$(srcdir)\common;$(srcdir)\stdlib;$(srcdir)\nasmlib;$(srcdir)\disasm
VPATH = $(srcdir)/asm;$(srcdir)/x86;$(srcdir)/macros;$(srcdir)/output;
VPATH +=$(srcdir)/common;$(srcdir)/stdlib;$(srcdir)/nasmlib;
VPATH +=$(srcdir)/disasm;$(srcdir)/zlib;asm;x86;macros
prefix = C:\Program Files\NASM
exec_prefix = $(prefix)
bindir = $(prefix)\bin
mandir = $(prefix)\man
bindir = $(prefix)/bin
mandir = $(prefix)/man
CC = *wcl386
CC = *wcc386
DEBUG =
CFLAGS = -zq -6 -ox -wx -wcd=124 -ze -fpi $(DEBUG)
BUILD_CFLAGS = $(CFLAGS) $(%TARGET_CFLAGS)
INTERNAL_CFLAGS = -I$(srcdir) -I. -I$(srcdir)\include -I$(srcdir)\x86 -Ix86 -I$(srcdir)\asm -Iasm -I$(srcdir)\disasm -I$(srcdir)\output
BUILD_CFLAGS = $(CFLAGS) $(%TARGET_CFLAGS)
INTERNAL_CFLAGS = -I. -Iasm -Ix86 -Iinclude -I"$(srcdir)" -I"$(srcdir)/include" &
-I"$(srcdir)/asm" -I"$(srcdir)/x86" -I"$(srcdir)/disasm" -I"$(srcdir)/output" &
-I"$(srcdir)/zlib"
ALL_CFLAGS = $(BUILD_CFLAGS) $(INTERNAL_CFLAGS)
LD = *wlink
LD = *wlink
LDEBUG =
LDFLAGS = op q $(%TARGET_LFLAGS) $(LDEBUG)
LIBS =
STRIP = wstrip
PERL = perl
PERLFLAGS = -I$(srcdir)\perllib -I$(srcdir)
RUNPERL = $(PERL) $(PERLFLAGS)
PERL = perl
PERLFLAGS = -I$(srcdir)/perllib -I$(srcdir)
RUNPERL = $(PERL) $(PERLFLAGS)
!ifdef __LOADDLL__
!loaddll wcc wccd.dll
!loaddll wcc386 wccd386.dll
!loaddll wlib wlibd.dll
!loaddll wlink wlinkd.dll
!endif
.BEFORE
set COPYCMD=/y
@set INCLUDE=
@set COPYCMD=/y
@for %d in ($(SUBDIRS) $(XSUBDIRS)) do @if not exist %d mkdir %d
RM_F = -del /f
LN_S = copy
EMPTY = copy nul:
SIDE = %null Created by side effect
# rm is handled internally by WMAKE, so it does work even on non-Unix systems
RM_F = -rm -f
LN_S = copy
EMPTY = %create
SIDE = %null Created by side effect
PHONY = .SYMBOLIC
MAKENSIS = makensis
MAKENSIS = makensis
# Binary suffixes
O = obj
A = lib
X = .exe
O = obj
A = lib
X = .exe
# WMAKE errors out if a suffix is declared more than once, including
# its own built-in declarations. Thus, we need to explicitly clear the list
@ -53,168 +68,173 @@ X = .exe
# Needed to find C files anywhere but in the current directory
.c : $(VPATH)
.c.obj:
@set INCLUDE=
$(CC) -c $(ALL_CFLAGS) -fo=$^@ $[@
.c.obj: .AUTODEPEND
$(CC) $(ALL_CFLAGS) -fo=$^@ $[@
MANIFEST =
MANIFEST =
DIRS =
ZLIB = $(ZLIBOBJ)
ZLIB = $(ZLIBOBJ)
#-- Begin File Lists --#
# Edit in Makefile.in, not here!
NASM = asm\nasm.obj
NDISASM = disasm\ndisasm.obj
NASM = asm/nasm.obj
NDISASM = disasm/ndisasm.obj
PROGOBJ = $(NASM) $(NDISASM)
PROGS = nasm$(X) ndisasm$(X)
# Files dependent on extracted warnings
WARNOBJ = asm\warnings.obj
WARNFILES = asm\warnings_c.h include\warnings.h doc\warnings.src
OUTPUTOBJ = &
output\outform.obj output\outlib.obj &
output\nulldbg.obj output\nullout.obj &
output\outbin.obj output\outaout.obj output\outcoff.obj &
output\outelf.obj &
output\outobj.obj output\outas86.obj &
output\outdbg.obj output\outieee.obj output\outmacho.obj &
output\codeview.obj
# The source files for these objects are scanned for warnings
LIBOBJ_W = &
nasmlib\readnum.obj &
&
asm\error.obj &
asm\floats.obj &
asm\directiv.obj &
asm\pragma.obj &
asm\assemble.obj asm\labels.obj asm\parser.obj &
asm\preproc.obj asm\quote.obj &
asm\listing.obj asm\eval.obj asm\exprlib.obj asm\exprdump.obj &
asm\stdscan.obj &
asm\getbool.obj &
asm\strfunc.obj &
asm\segalloc.obj &
asm\rdstrnum.obj &
asm\srcfile.obj &
&
$(OUTPUTOBJ)
# The source files for these objects are NOT scanned for warnings;
# normally this will include all generated files.
# It is entirely possible that it may be necessary to move some of these
# files to LIBOBJ_W, notably $(OUTPUTOBJ)
LIBOBJ_NW = &
stdlib\snprintf.obj stdlib\vsnprintf.obj stdlib\strlcpy.obj &
stdlib\strnlen.obj stdlib\strrchrnul.obj &
&
asm\directbl.obj &
asm\pptok.obj &
asm\tokhash.obj &
asm\uncompress.obj &
&
macros\macros.obj &
&
nasmlib\ver.obj &
nasmlib\alloc.obj nasmlib\asprintf.obj &
nasmlib\crc32.obj nasmlib\crc64.obj nasmlib\md5c.obj &
nasmlib\string.obj nasmlib\nctype.obj &
nasmlib\file.obj nasmlib\mmap.obj nasmlib\ilog2.obj &
nasmlib\realpath.obj nasmlib\path.obj &
nasmlib\filename.obj nasmlib\rlimit.obj &
nasmlib\numstr.obj &
nasmlib\zerobuf.obj nasmlib\bsi.obj &
nasmlib\rbtree.obj nasmlib\hashtbl.obj &
nasmlib\raa.obj nasmlib\saa.obj &
nasmlib\strlist.obj &
nasmlib\perfhash.obj nasmlib\badenum.obj &
&
common\common.obj &
&
x86\insnsa.obj x86\insnsb.obj x86\insnsn.obj &
x86\regs.obj x86\regvals.obj x86\regflags.obj &
x86\iflag.obj &
&
$(WARNOBJ)
# Objects which are only used for the disassembler
LIBOBJ_DIS = &
disasm\disasm.obj disasm\sync.obj disasm\prefix.obj &
&
x86\insnsd.obj x86\regdis.obj
# Objects for the local copy of zlib. The variable ZLIB is set to
# $(ZLIBOBJ) if the internal version of zlib should be used.
ZLIBOBJ = &
zlib\adler32.obj &
zlib\crc32.obj &
zlib\infback.obj &
zlib\inffast.obj &
zlib\inflate.obj &
zlib\inftrees.obj &
zlib\zutil.obj
zlib/adler32.obj &
zlib/crc32.obj &
zlib/infback.obj &
zlib/inffast.obj &
zlib/inflate.obj &
zlib/inftrees.obj &
zlib/zutil.obj
LIBOBJ = $(LIBOBJ_W) $(LIBOBJ_NW) $(ZLIB)
ALLOBJ_W = $(NASM) $(LIBOBJ_W)
# Common library objects
LIBOBJ_COM = &
stdlib/snprintf.obj stdlib/vsnprintf.obj stdlib/strlcpy.obj &
stdlib/strnlen.obj &
&
nasmlib/ver.obj &
nasmlib/alloc.obj nasmlib/asprintf.obj &
nasmlib/crc32b.obj nasmlib/crc64.obj nasmlib/md5c.obj &
nasmlib/string.obj nasmlib/nctype.obj &
nasmlib/file.obj nasmlib/fileio.obj nasmlib/mmap.obj &
nasmlib/realpath.obj nasmlib/path.obj &
nasmlib/ilog2.obj nasmlib/numstr.obj &
nasmlib/rlimit.obj &
nasmlib/zerobuf.obj nasmlib/bsi.obj &
nasmlib/rbtree.obj nasmlib/hashtbl.obj &
nasmlib/raa.obj nasmlib/saa.obj &
nasmlib/strlist.obj &
nasmlib/perfhash.obj nasmlib/badenum.obj &
nasmlib/readnum.obj &
&
common/common.obj common/errstubs.obj common/files.obj &
&
x86/insnsa.obj x86/insnsb.obj x86/insnsn.obj &
x86/regs.obj x86/regvals.obj x86/regflags.obj &
x86/iflag.obj &
&
$(ZLIB)
# Files dependent on warnings.dat
WARNOBJ = asm/warnings.obj
WARNFILES = asm/warnings_c.h include/warnings.h doc/warnings.src
OUTPUTOBJ = &
output/outform.obj output/outlib.obj &
output/nulldbg.obj output/nullout.obj &
output/outbin.obj output/outaout.obj output/outcoff.obj &
output/outelf.obj &
output/outobj.obj output/outas86.obj &
output/outdbg.obj output/outieee.obj output/outmacho.obj &
output/codeview.obj
# Assembler-only library objects
LIBOBJ_ASM = &
asm/error.obj &
asm/floats.obj &
asm/directiv.obj &
asm/pragma.obj &
asm/assemble.obj asm/labels.obj asm/parser.obj &
asm/preproc.obj asm/quote.obj &
asm/listing.obj asm/eval.obj asm/exprlib.obj asm/exprdump.obj &
asm/stdscan.obj &
asm/getbool.obj &
asm/strfunc.obj &
asm/segalloc.obj &
asm/rdstrnum.obj &
asm/srcfile.obj &
asm/directbl.obj &
asm/pptok.obj &
asm/tokhash.obj &
asm/uncompress.obj &
&
macros/macros.obj &
&
$(WARNOBJ) &
$(OUTPUTOBJ)
# Objects which are only used for the disassembler
LIBOBJ_DIS = &
disasm/disasm.obj disasm/sync.obj disasm/prefix.obj &
disasm/diserror.obj &
&
x86/insnsd.obj x86/regdis.obj
LIBOBJ = $(LIBOBJ_COM) $(LIBOBJ_ASM) $(LIBOBJ_DIS)
ALLOBJ = $(PROGOBJ) $(LIBOBJ)
SUBDIRS = stdlib nasmlib include config output asm disasm x86 &
common zlib macros misc
XSUBDIRS = nsis win test doc editors
DEPDIRS = . $(SUBDIRS)
EDITORS = editors\nasmtok.el editors\nasmtok.json
EDITORS = editors/nasmtok.el editors/nasmtok.json
#-- End File Lists --#
what: .SYMBOLIC
what: $(PHONY)
@echo Please build "dos", "win32", "os2" or "linux386"
dos: .SYMBOLIC
@set TARGET_CFLAGS=-bt=DOS -I"$(%WATCOM)\h"
dos: $(PHONY)
@set TARGET_CFLAGS=-bt=DOS -I"$(%WATCOM)/h"
@set TARGET_LFLAGS=sys causeway
@%make all
win32: .SYMBOLIC
@set TARGET_CFLAGS=-bt=NT -I"$(%WATCOM)\h" -I"$(%WATCOM)\h\nt"
win32: $(PHONY)
@set TARGET_CFLAGS=-bt=NT -I"$(%WATCOM)/h" -I"$(%WATCOM)/h/nt"
@set TARGET_LFLAGS=sys nt
@%make all
os2: .SYMBOLIC
@set TARGET_CFLAGS=-bt=OS2 -I"$(%WATCOM)\h" -I"$(%WATCOM)\h\os2"
os2: $(PHONY)
@set TARGET_CFLAGS=-bt=OS2 -I"$(%WATCOM)/h" -I"$(%WATCOM)/h/os2"
@set TARGET_LFLAGS=sys os2v2
@%make all
linux386: .SYMBOLIC
@set TARGET_CFLAGS=-bt=LINUX -I"$(%WATCOM)\lh"
linux386: $(PHONY)
@set TARGET_CFLAGS=-bt=LINUX -I"$(%WATCOM)/lh"
@set TARGET_LFLAGS=sys linux
@%make all
all: perlreq nasm$(X) ndisasm$(X) .SYMBOLIC
all: perlreq nasm$(X) ndisasm$(X) $(PHONY)
# cd rdoff && $(MAKE) all
NASMLIB = nasm.lib
NDISLIB = ndisasm.lib
ASMLIB = asm.lib
DISLIB = dis.lib
nasm$(X): $(NASM) $(NASMLIB)
$(LD) $(LDFLAGS) name nasm$(X) libr {$(NASMLIB) $(LIBS)} file {$(NASM)}
nasm$(X): $(NASM) $(ASMLIB) $(NASMLIB)
$(LD) $(LDFLAGS) name nasm$(X) libr {$(ASMLIB) $(NASMLIB) $(LIBS)} file {$(NASM)}
ndisasm$(X): $(NDISASM) $(NDISLIB) $(NASMLIB)
$(LD) $(LDFLAGS) name ndisasm$(X) libr {$(NDISLIB) $(NASMLIB) $(LIBS)} file {$(NDISASM)}
ndisasm$(X): $(NDISASM) $(DISLIB) $(NASMLIB)
$(LD) $(LDFLAGS) name ndisasm$(X) libr {$(DISLIB) $(NASMLIB) $(LIBS)} file {$(NDISASM)}
nasm.lib: $(LIBOBJ)
wlib -q -b -n $@ $(LIBOBJ)
<<<<<<< HEAD
nasm.lib: $(LIBOBJ_COM)
wlib -q -b -n $@ $(LIBOBJ_COM)
ndisasm.lib: $(LIBOBJ_DIS)
asm.lib: $(LIBOBJ_ASM)
wlib -q -b -n $@ $(LIBOBJ_ASM)
dis.lib: $(LIBOBJ_DIS)
wlib -q -b -n $@ $(LIBOBJ_DIS)
# These are specific to certain Makefile syntaxes (what are they
# actually supposed to look like for wmake?)
WARNTIMES = $(WARNFILES:=.time)
WARNSRCS = $(LIBOBJ_NW:.obj=.c)
=======
nasm.lib: $(LIBOBJ)
*wlib -q -b -n $@ $<
ndisasm.lib: $(LIBOBJ_DIS)
*wlib -q -b -n $@ $<
>>>>>>> 61e7e23c94c8 (open-watcom: fix Open Watcom build make file)
#-- Begin Generated File Rules --#
# Edit in Makefile.in, not here!
@ -225,147 +245,147 @@ WARNSRCS = $(LIBOBJ_NW:.obj=.c)
# Perl-generated source files
PERLREQ_CLEANABLE = &
x86\insnsb.c x86\insnsa.c x86\insnsd.c x86\insnsi.h x86\insnsn.c &
x86\regs.c x86\regs.h x86\regflags.c x86\regdis.c x86\regdis.h &
x86\regvals.c asm\tokhash.c asm\tokens.h asm\pptok.h asm\pptok.c &
x86\iflag.c x86\iflaggen.h &
macros\macros.c &
asm\pptok.ph asm\directbl.c asm\directiv.h &
x86/insnsb.c x86/insnsa.c x86/insnsd.c x86/insnsi.h x86/insnsn.c &
x86/regs.c x86/regs.h x86/regflags.c x86/regdis.c x86/regdis.h &
x86/regvals.c asm/tokhash.c asm/tokens.h asm/pptok.h asm/pptok.c &
x86/iflag.c x86/iflaggen.h &
macros/macros.c &
asm/pptok.ph asm/directbl.c asm/directiv.h &
$(WARNFILES) &
version.h version.mac version.mak nsis\version.nsh
version.h version.mac version.mak nsis/version.nsh
PERLREQ = $(PERLREQ_CLEANABLE)
INSDEP = x86\insns.xda x86\insns.pl x86\insns-iflags.ph x86\iflags.ph
INSDEP = x86/insns.xda x86/insns.pl x86/insns-iflags.ph x86/iflags.ph x86/insns-cc.ph
x86\insns.xda: x86\insns.dat x86\preinsns.pl $(DIRS)
$(RUNPERL) $(srcdir)\x86\preinsns.pl $(srcdir)\x86\insns.dat $@
x86/insns.xda: x86/insns.dat x86/preinsns.pl $(DIRS)
$(RUNPERL) $(srcdir)/x86/preinsns.pl $(srcdir)/x86/insns.dat $@
x86\iflag.c: $(INSDEP)
$(RUNPERL) $(srcdir)\x86\insns.pl -fc &
x86\insns.xda x86\iflag.c
x86\iflaggen.h: $(INSDEP)
$(RUNPERL) $(srcdir)\x86\insns.pl -fh &
x86\insns.xda x86\iflaggen.h
x86\insnsb.c: $(INSDEP)
$(RUNPERL) $(srcdir)\x86\insns.pl -b &
x86\insns.xda x86\insnsb.c
x86\insnsa.c: $(INSDEP)
$(RUNPERL) $(srcdir)\x86\insns.pl -a &
x86\insns.xda x86\insnsa.c
x86\insnsd.c: $(INSDEP)
$(RUNPERL) $(srcdir)\x86\insns.pl -d &
x86\insns.xda x86\insnsd.c
x86\insnsi.h: $(INSDEP)
$(RUNPERL) $(srcdir)\x86\insns.pl -i &
x86\insns.xda x86\insnsi.h
x86\insnsn.c: $(INSDEP)
$(RUNPERL) $(srcdir)\x86\insns.pl -n &
x86\insns.xda x86\insnsn.c
x86/iflag.c: $(INSDEP)
$(RUNPERL) $(srcdir)/x86/insns.pl -fc &
x86/insns.xda x86/iflag.c
x86/iflaggen.h: $(INSDEP)
$(RUNPERL) $(srcdir)/x86/insns.pl -fh &
x86/insns.xda x86/iflaggen.h
x86/insnsb.c: $(INSDEP)
$(RUNPERL) $(srcdir)/x86/insns.pl -b &
x86/insns.xda x86/insnsb.c
x86/insnsa.c: $(INSDEP)
$(RUNPERL) $(srcdir)/x86/insns.pl -a &
x86/insns.xda x86/insnsa.c
x86/insnsd.c: $(INSDEP)
$(RUNPERL) $(srcdir)/x86/insns.pl -d &
x86/insns.xda x86/insnsd.c
x86/insnsi.h: $(INSDEP)
$(RUNPERL) $(srcdir)/x86/insns.pl -i &
x86/insns.xda x86/insnsi.h
x86/insnsn.c: $(INSDEP)
$(RUNPERL) $(srcdir)/x86/insns.pl -n &
x86/insns.xda x86/insnsn.c
# These files contains all the standard macros that are derived from
# the version number.
version.h: version version.pl
$(RUNPERL) $(srcdir)\version.pl h < $(srcdir)\version > version.h
$(RUNPERL) $(srcdir)/version.pl h < $(srcdir)/version > version.h
version.mac: version version.pl
$(RUNPERL) $(srcdir)\version.pl mac < $(srcdir)\version > version.mac
$(RUNPERL) $(srcdir)/version.pl mac < $(srcdir)/version > version.mac
version.sed: version version.pl
$(RUNPERL) $(srcdir)\version.pl sed < $(srcdir)\version > version.sed
$(RUNPERL) $(srcdir)/version.pl sed < $(srcdir)/version > version.sed
version.mak: version version.pl
$(RUNPERL) $(srcdir)\version.pl make < $(srcdir)\version > version.mak
nsis\version.nsh: version version.pl $(DIRS)
$(RUNPERL) $(srcdir)\version.pl nsis < $(srcdir)\version > nsis\version.nsh
$(RUNPERL) $(srcdir)/version.pl make < $(srcdir)/version > version.mak
nsis/version.nsh: version version.pl $(DIRS)
$(RUNPERL) $(srcdir)/version.pl nsis < $(srcdir)/version > nsis/version.nsh
# This source file is generated from the standard macros file
# `standard.mac' by another Perl script. Again, it's part of the
# standard distribution.
macros\macros.c: macros\macros.pl asm\pptok.ph version.mac &
$(srcdir)\macros\*.mac $(srcdir)\output\*.mac
$(RUNPERL) $(srcdir)\macros\macros.pl version.mac &
$(srcdir)\macros\*.mac $(srcdir)\output\*.mac
macros/macros.c: macros/macros.pl asm/pptok.ph version.mac &
$(srcdir)/macros/*.mac $(srcdir)/output/*.mac
$(RUNPERL) $(srcdir)/macros/macros.pl version.mac &
$(srcdir)/macros/*.mac $(srcdir)/output/*.mac
# These source files are generated from regs.dat by yet another
# perl script.
x86\regs.c: x86\regs.dat x86\regs.pl
$(RUNPERL) $(srcdir)\x86\regs.pl c &
$(srcdir)\x86\regs.dat > x86\regs.c
x86\regflags.c: x86\regs.dat x86\regs.pl
$(RUNPERL) $(srcdir)\x86\regs.pl fc &
$(srcdir)\x86\regs.dat > x86\regflags.c
x86\regdis.c: x86\regs.dat x86\regs.pl
$(RUNPERL) $(srcdir)\x86\regs.pl dc &
$(srcdir)\x86\regs.dat > x86\regdis.c
x86\regdis.h: x86\regs.dat x86\regs.pl
$(RUNPERL) $(srcdir)\x86\regs.pl dh &
$(srcdir)\x86\regs.dat > x86\regdis.h
x86\regvals.c: x86\regs.dat x86\regs.pl
$(RUNPERL) $(srcdir)\x86\regs.pl vc &
$(srcdir)\x86\regs.dat > x86\regvals.c
x86\regs.h: x86\regs.dat x86\regs.pl
$(RUNPERL) $(srcdir)\x86\regs.pl h &
$(srcdir)\x86\regs.dat > x86\regs.h
x86/regs.c: x86/regs.dat x86/regs.pl
$(RUNPERL) $(srcdir)/x86/regs.pl c &
$(srcdir)/x86/regs.dat > x86/regs.c
x86/regflags.c: x86/regs.dat x86/regs.pl
$(RUNPERL) $(srcdir)/x86/regs.pl fc &
$(srcdir)/x86/regs.dat > x86/regflags.c
x86/regdis.c: x86/regs.dat x86/regs.pl
$(RUNPERL) $(srcdir)/x86/regs.pl dc &
$(srcdir)/x86/regs.dat > x86/regdis.c
x86/regdis.h: x86/regs.dat x86/regs.pl
$(RUNPERL) $(srcdir)/x86/regs.pl dh &
$(srcdir)/x86/regs.dat > x86/regdis.h
x86/regvals.c: x86/regs.dat x86/regs.pl
$(RUNPERL) $(srcdir)/x86/regs.pl vc &
$(srcdir)/x86/regs.dat > x86/regvals.c
x86/regs.h: x86/regs.dat x86/regs.pl
$(RUNPERL) $(srcdir)/x86/regs.pl h &
$(srcdir)/x86/regs.dat > x86/regs.h
# Assembler token hash
asm\tokhash.c: x86\insns.xda x86\insnsn.c asm\tokens.dat asm\tokhash.pl &
perllib\phash.ph
$(RUNPERL) $(srcdir)\asm\tokhash.pl c &
x86\insnsn.c $(srcdir)\x86\regs.dat &
$(srcdir)\asm\tokens.dat > asm\tokhash.c
asm/tokhash.c: x86/insns.xda x86/insnsn.c asm/tokens.dat asm/tokhash.pl &
perllib/phash.ph
$(RUNPERL) $(srcdir)/asm/tokhash.pl c &
x86/insnsn.c $(srcdir)/x86/regs.dat &
$(srcdir)/asm/tokens.dat > asm/tokhash.c
# Assembler token metadata
asm\tokens.h: x86\insns.xda x86\insnsn.c asm\tokens.dat asm\tokhash.pl &
perllib\phash.ph
$(RUNPERL) $(srcdir)\asm\tokhash.pl h &
x86\insnsn.c $(srcdir)\x86\regs.dat &
$(srcdir)\asm\tokens.dat > asm\tokens.h
asm/tokens.h: x86/insns.xda x86/insnsn.c asm/tokens.dat asm/tokhash.pl &
perllib/phash.ph
$(RUNPERL) $(srcdir)/asm/tokhash.pl h &
x86/insnsn.c $(srcdir)/x86/regs.dat &
$(srcdir)/asm/tokens.dat > asm/tokens.h
# Preprocessor token hash
asm\pptok.h: asm\pptok.dat asm\pptok.pl perllib\phash.ph
$(RUNPERL) $(srcdir)\asm\pptok.pl h &
$(srcdir)\asm\pptok.dat asm\pptok.h
asm\pptok.c: asm\pptok.dat asm\pptok.pl perllib\phash.ph
$(RUNPERL) $(srcdir)\asm\pptok.pl c &
$(srcdir)\asm\pptok.dat asm\pptok.c
asm\pptok.ph: asm\pptok.dat asm\pptok.pl perllib\phash.ph
$(RUNPERL) $(srcdir)\asm\pptok.pl ph &
$(srcdir)\asm\pptok.dat asm\pptok.ph
doc\pptok.src: asm\pptok.dat asm\pptok.pl perllib\phash.ph
$(RUNPERL) $(srcdir)\asm\pptok.pl src &
$(srcdir)\asm\pptok.dat doc\pptok.src
asm/pptok.h: asm/pptok.dat asm/pptok.pl perllib/phash.ph
$(RUNPERL) $(srcdir)/asm/pptok.pl h &
$(srcdir)/asm/pptok.dat asm/pptok.h
asm/pptok.c: asm/pptok.dat asm/pptok.pl perllib/phash.ph
$(RUNPERL) $(srcdir)/asm/pptok.pl c &
$(srcdir)/asm/pptok.dat asm/pptok.c
asm/pptok.ph: asm/pptok.dat asm/pptok.pl perllib/phash.ph
$(RUNPERL) $(srcdir)/asm/pptok.pl ph &
$(srcdir)/asm/pptok.dat asm/pptok.ph
doc/pptok.src: asm/pptok.dat asm/pptok.pl perllib/phash.ph
$(RUNPERL) $(srcdir)/asm/pptok.pl src &
$(srcdir)/asm/pptok.dat doc/pptok.src
# Directives hash
asm\directiv.h: asm\directiv.dat nasmlib\perfhash.pl perllib\phash.ph
$(RUNPERL) $(srcdir)\nasmlib\perfhash.pl h &
$(srcdir)\asm\directiv.dat asm\directiv.h
asm\directbl.c: asm\directiv.dat nasmlib\perfhash.pl perllib\phash.ph
$(RUNPERL) $(srcdir)\nasmlib\perfhash.pl c &
$(srcdir)\asm\directiv.dat asm\directbl.c
asm/directiv.h: asm/directiv.dat nasmlib/perfhash.pl perllib/phash.ph
$(RUNPERL) $(srcdir)/nasmlib/perfhash.pl h &
$(srcdir)/asm/directiv.dat asm/directiv.h
asm/directbl.c: asm/directiv.dat nasmlib/perfhash.pl perllib/phash.ph
$(RUNPERL) $(srcdir)/nasmlib/perfhash.pl c &
$(srcdir)/asm/directiv.dat asm/directbl.c
# Editor token files
editors\nasmtok.el: editors\nasmtok.pl asm\tokhash.c asm\pptok.c &
asm\directiv.dat macros\macros.c editors\builtin.mac &
editors/nasmtok.el: editors/nasmtok.pl asm/tokhash.c asm/pptok.c &
asm/directiv.dat macros/macros.c editors/builtin.mac &
version.mak
$(RUNPERL) $(srcdir)\editors\nasmtok.pl -el $@ $(srcdir) $(objdir)
$(RUNPERL) $(srcdir)/editors/nasmtok.pl -el $@ $(srcdir) $(objdir)
editors\nasmtok.json: editors\nasmtok.pl asm\tokhash.c asm\pptok.c &
asm\directiv.dat macros\macros.c editors\builtin.mac &
editors/nasmtok.json: editors/nasmtok.pl asm/tokhash.c asm/pptok.c &
asm/directiv.dat macros/macros.c editors/builtin.mac &
version.mak
$(RUNPERL) $(srcdir)\editors\nasmtok.pl -json $@ $(srcdir) $(objdir)
$(RUNPERL) $(srcdir)/editors/nasmtok.pl -json $@ $(srcdir) $(objdir)
editors: $(EDITORS) $(PHONY)
asm\warnings_c.h: asm\warnings.pl asm\warnings.dat
$(RUNPERL) $(srcdir)\asm\warnings.pl c asm\warnings_c.h &
$(srcdir)\asm\warnings.dat
asm/warnings_c.h: asm/warnings.pl asm/warnings.dat
$(RUNPERL) $(srcdir)/asm/warnings.pl c asm/warnings_c.h &
$(srcdir)/asm/warnings.dat
include\warnings.h: asm\warnings.pl asm\warnings.dat
$(RUNPERL) $(srcdir)\asm\warnings.pl h include\warnings.h &
$(srcdir)\asm\warnings.dat
include/warnings.h: asm/warnings.pl asm/warnings.dat
$(RUNPERL) $(srcdir)/asm/warnings.pl h include/warnings.h &
$(srcdir)/asm/warnings.dat
doc\warnings.src: asm\warnings.pl asm\warnings.dat
$(RUNPERL) $(srcdir)\asm\warnings.pl doc doc\warnings.src &
$(srcdir)\asm\warnings.dat
doc/warnings.src: asm/warnings.pl asm/warnings.dat
$(RUNPERL) $(srcdir)/asm/warnings.pl doc doc/warnings.src &
$(srcdir)/asm/warnings.dat
$(PERLREQ): $(DIRS)
@ -375,57 +395,56 @@ warnings: $(WARNFILES) $(PHONY)
#-- End Generated File Rules --#
perlreq: $(PERLREQ) .SYMBOLIC
#-- Begin NSIS Rules --#
# Edit in Makefile.in, not here!
nsis\arch.nsh: nsis\getpearch.pl nasm$(X) $(DIRS)
$(PERL) $(srcdir)\nsis\getpearch.pl nasm$(X) > nsis\arch.nsh
nsis/arch.nsh: nsis/getpearch.pl nasm$(X) $(DIRS)
$(PERL) $(srcdir)/nsis/getpearch.pl nasm$(X) > nsis/arch.nsh
# Should only be done after "make everything".
# The use of redirection here keeps makensis from moving the cwd to the
# source directory.
nsis: nsis\nasm.nsi nsis\arch.nsh nsis\version.nsh
nsis: nsis/nasm.nsi nsis/arch.nsh nsis/version.nsh
$(MAKENSIS) -Dsrcdir=$(srcdir) -Dobjdir=$(objdir) - &
< $(srcdir)\nsis\nasm.nsi
< $(srcdir)/nsis/nasm.nsi
#-- End NSIS Rules --#
clean: .SYMBOLIC
clean: $(PHONY)
rm -f *.obj *.s *.i
rm -f asm\*.obj asm\*.s asm\*.i
rm -f x86\*.obj x86\*.s x86\*.i
rm -f lib\*.obj lib\*.s lib\*.i
rm -f macros\*.obj macros\*.s macros\*.i
rm -f output\*.obj output\*.s output\*.i
rm -f common\*.obj common\*.s common\*.i
rm -f stdlib\*.obj stdlib\*.s stdlib\*.i
rm -f nasmlib\*.obj nasmlib\*.s nasmlib\*.i
rm -f disasm\*.obj disasm\*.s disasm\*.i
rm -f asm/*.obj asm/*.s asm/*.i
rm -f x86/*.obj x86/*.s x86/*.i
rm -f lib/*.obj lib/*.s lib/*.i
rm -f macros/*.obj macros/*.s macros/*.i
rm -f output/*.obj output/*.s output/*.i
rm -f common/*.obj common/*.s common/*.i
rm -f stdlib/*.obj stdlib/*.s stdlib/*.i
rm -f nasmlib/*.obj nasmlib/*.s nasmlib/*.i
rm -f disasm/*.obj disasm/*.s disasm/*.i
rm -f zlib/*.obj zlib/*.s zlib/*.i
rm -f config.h config.log config.status
rm -f nasm$(X) ndisasm$(X) $(NASMLIB) $(NDISLIB)
distclean: clean .SYMBOLIC
distclean: clean $(PHONY)
rm -f config.h config.log config.status
rm -f Makefile *~ *.bak *.lst *.bin
rm -f output\*~ output\*.bak
rm -f test\*.lst test\*.bin test\*.obj test\*.bin
rm -f output/*~ output/*.bak
rm -f test/*.lst test/*.bin test/*.obj test/*.bin
cleaner: clean .SYMBOLIC
cleaner: clean $(PHONY)
rm -f $(PERLREQ)
rm -f *.man
rm -f nasm.spec
# cd doc && $(MAKE) clean
spotless: distclean cleaner .SYMBOLIC
rm -f doc\Makefile doc\*~ doc\*.bak
spotless: distclean cleaner $(PHONY)
rm -f doc/Makefile doc/*~ doc/*.bak
strip: .SYMBOLIC
strip: $(PHONY)
$(STRIP) *.exe
doc:
# cd doc && $(MAKE) all
# cd doc && $(MAKE) all
everything: all doc
@ -433,13 +452,13 @@ everything: all doc
# This build dependencies in *ALL* makefiles. Partially for that reason,
# it's expected to be invoked manually.
#
alldeps: perlreq .SYMBOLIC
$(PERL) syncfiles.pl Makefile.in Mkfiles\openwcom.mak
$(PERL) mkdep.pl -M Makefile.in Mkfiles\openwcom.mak -- . output lib
alldeps: perlreq $(PHONY)
$(PERL) syncfiles.pl Makefile.in Mkfiles/openwcom.mak
$(PERL) mkdep.pl -M Makefile.in Mkfiles/openwcom.mak -- . output lib
#-- Magic hints to mkdep.pl --#
# @object-ending: ".obj"
# @path-separator: "\"
# @path-separator: "/"
# @exclude: "config/config.h"
# @continuation: "&"
#-- Everything below is generated by mkdep.pl - do not edit --#

View file

@ -33,7 +33,7 @@ There are at least two ways to make it right.
at all.
2) Use "diff -up"
Use "diff -up" or "diff -uprN" to create patches.
Signing your work
@ -86,8 +86,10 @@ 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)
Long patch description:
Explain the problem you are fixing, the consequences of that problem,
and why your patch is the correct way to fix it.
Signed-off-by: Random J Developer <random@developer.example.org>
---

View file

@ -75,11 +75,11 @@ enum match_result {
static int64_t assemble(insn *instruction);
static int64_t insn_size(insn *instruction);
static int64_t calcsize(insn *, const struct itemplate *);
static int64_t calcsize(insn *);
static int64_t calcsize_speculative(const insn *, const struct itemplate *);
static int emit_prefixes(struct out_data *data, const insn *ins);
static void gencode(struct out_data *data, insn *ins);
static enum match_result find_match(const struct itemplate **tempp,
insn *instruction);
static enum match_result find_match(insn *instruction);
static enum match_result matches(const struct itemplate *, const insn *);
static opflags_t regflag(const operand *);
static int32_t regval(const operand *);
@ -634,8 +634,85 @@ static void out_reladdr(struct out_data *data, const struct operand *opx,
out(data);
}
/* Issue an error message on match failure */
static void no_match_error(enum match_result m, const insn *ins)
{
/* No match */
switch (m) {
case MERR_INVALOP:
nasm_holderr("invalid combination of opcode and operands");
break;
case MERR_OPSIZEINVAL:
nasm_holderr("invalid operand sizes for instruction");
break;
case MERR_OPSIZEMISSING:
nasm_holderr("operation size not specified");
break;
case MERR_OPSIZEMISMATCH:
nasm_holderr("mismatch in operand sizes");
break;
case MERR_BRNOTHERE:
nasm_holderr("broadcast not permitted on this operand");
break;
case MERR_BRNUMMISMATCH:
nasm_holderr("mismatch in the number of broadcasting elements");
break;
case MERR_MASKNOTHERE:
nasm_holderr("mask not permitted on this operand");
break;
case MERR_DECONOTHERE:
nasm_holderr("unsupported mode decorator for instruction");
break;
case MERR_BADCPU:
nasm_holderr("no instruction for this cpu level");
break;
case MERR_BADMODE:
nasm_holderr("instruction not supported in %d-bit mode", ins->bits);
break;
case MERR_ENCMISMATCH:
if (!ins->prefixes[PPS_REX]) {
nasm_holderr("instruction not encodable without explicit prefix");
} else {
nasm_holderr("instruction not encodable with %s prefix",
prefix_name(ins->prefixes[PPS_REX]));
}
break;
case MERR_BADBND:
case MERR_BADREPNE:
nasm_holderr("%s prefix is not allowed",
prefix_name(ins->prefixes[PPS_REP]));
break;
case MERR_REGSETSIZE:
nasm_holderr("invalid register set size");
break;
case MERR_REGSET:
nasm_holderr("register set not valid for operand");
break;
case MERR_WRONGIMM:
nasm_holderr("operand/operator invalid for this instruction");
break;
case MERR_BADZU:
nasm_holderr("{zu} not applicable to this instruction");
break;
case MERR_MEMZU:
nasm_holderr("{zu} invalid for non-register destination");
break;
case MERR_BADNF:
nasm_holderr("{nf} not available for this instruction");
break;
case MERR_REQNF:
nasm_holderr("{nf} required for this instruction");
break;
default:
if (m < MOK_GOOD)
nasm_holderr("invalid use of instruction");
break;
}
}
/* This is a real hack. The jcc8 or jmp8 byte code must come first. */
static enum match_result jmp_match(const struct itemplate *temp, const insn *ins)
static enum match_result
jmp_match(const insn *ins, const struct itemplate *temp)
{
const struct operand * const op0 = get_operand_const(ins, 0);
int64_t delta;
@ -676,34 +753,18 @@ static enum match_result jmp_match(const struct itemplate *temp, const insn *ins
* instruction size.
*
* Note that the instruction size is to be *subtracted* from the
* initial (beginning-of-instruction) delta value.
* initial (beginning-of-instruction) delta value, or *added* to the
* limiting value compared to.
*/
delta = op0->offset - ins->loc.offset;
if (delta - 2 < -128 || delta - 15 > 127) {
if (delta < -128 + 2 || delta > 127 + 15) {
/* This cannot be a byte-sized jump */
return MERR_INVALOP;
} else if (delta - 15 >= -128 && delta - 2 <= 127) {
} else if (delta >= -128 + 15 && delta <= 127 + 2) {
/* It is guaranteed to be a valid byte-sized jump, no need to test */
} else {
/*
* Need to do this the hard way.
*
* However, calcsize() can modify the instruction structure,
* but after a mismatch we have to revert to the original
* state, so make a copy here and hold error messages.
*/
int64_t isize;
insn tmpins;
errhold hold;
tmpins = *ins;
tmpins.dummy = true;
hold = nasm_error_hold_push();
isize = calcsize(&tmpins, temp);
if (nasm_error_hold_pop(hold, false) >= ERR_NONFATAL)
return MERR_INVALOP;
/* Borderline: need to do this the hard way... */
int64_t isize = calcsize_speculative(ins, temp);
if (isize < 0)
return MERR_INVALOP;
delta -= isize;
@ -810,13 +871,24 @@ static void out_eops(struct out_data *data, const extop *e)
/* This is totally just a wild guess what is reasonable... */
#define INCBIN_MAX_BUF (ZERO_BUF_SIZE * 16)
static void
list_add_template_info(const insn *ins)
{
char *buf;
(void)ins;
buf = nasm_asprintf(" ;;; used template %s:%d from insns.xda:%u",
nasm_insn_names[ins->opcode], ins->itempindex,
ins->itemp->xdaline);
lfmt->line(LIST_INFO, -1, buf);
nasm_free(buf);
}
static int64_t assemble(insn *instruction)
{
struct out_data data;
const struct itemplate *temp;
enum match_result m;
const int64_t start = instruction->loc.offset;
const int bits = instruction->bits;
if (instruction->opcode == I_none)
return 0;
@ -831,6 +903,7 @@ static int64_t assemble(insn *instruction)
const char *fname = instruction->eops->val.string.data;
FILE *fp;
size_t t = instruction->times; /* INCBIN handles TIMES by itself */
bool need_downlevel_times;
off_t base = 0;
off_t len;
const void *map = NULL;
@ -869,7 +942,6 @@ static int64_t assemble(insn *instruction)
}
lfmt->set_offset(data.loc.offset);
lfmt->uplevel(LIST_INCBIN, len);
if (!len)
goto end_incbin;
@ -881,6 +953,7 @@ static int64_t assemble(insn *instruction)
buf = nasm_malloc(blk);
}
need_downlevel_times = false;
while (t--) {
/*
* Consider these irrelevant for INCBIN, since it is fully
@ -893,6 +966,8 @@ static int64_t assemble(insn *instruction)
data.insoffs = 0;
data.inslen = 0;
lfmt->uplevel(LIST_INCBIN, len);
if (map) {
out_rawdata(&data, map, len);
} else if ((off_t)m == len) {
@ -903,31 +978,39 @@ static int64_t assemble(insn *instruction)
if (fseeko(fp, base, SEEK_SET) < 0 || ferror(fp)) {
nasm_nonfatal("`incbin': unable to seek on file `%s'",
fname);
goto end_incbin;
}
while (l > 0) {
m = fread(buf, 1, l < (off_t)blk ? (size_t)l : blk, fp);
if (!m || feof(fp)) {
/*
* This shouldn't happen unless the file
* actually changes while we are reading
* it.
*/
nasm_nonfatal("`incbin': unexpected EOF while"
" reading file `%s'", fname);
goto end_incbin;
t = 0; /* No more iterations */
} else {
while (l > 0) {
m = fread(buf, 1, l < (off_t)blk ? (size_t)l : blk, fp);
if (!m || feof(fp)) {
/*
* This shouldn't happen unless the file
* actually changes while we are reading
* it.
*/
nasm_nonfatal("`incbin': unexpected EOF while"
" reading file `%s'", fname);
t = 0; /* No more iterations */
break;
} else {
out_rawdata(&data, buf, m);
l -= m;
}
}
out_rawdata(&data, buf, m);
l -= m;
}
}
lfmt->downlevel(LIST_INCBIN);
if (t && !need_downlevel_times) {
lfmt->uplevel(LIST_TIMES, instruction->times);
need_downlevel_times = true;
}
}
end_incbin:
lfmt->downlevel(LIST_INCBIN);
if (instruction->times > 1) {
lfmt->uplevel(LIST_TIMES, instruction->times);
if (need_downlevel_times)
lfmt->downlevel(LIST_TIMES);
}
end_incbin:
if (ferror(fp)) {
nasm_nonfatal("`incbin': error while"
" reading file `%s'", fname);
@ -947,10 +1030,15 @@ static int64_t assemble(insn *instruction)
/* Pre-match instruction structure update */
insn_early_setup(instruction);
m = find_match(&temp, instruction);
m = find_match(instruction);
if (m >= MOK_GOOD) {
const struct itemplate * const temp = instruction->itemp;
/* Matches! */
if (list_option('X'))
list_add_template_info(instruction);
if (unlikely(itemp_has(temp, IF_OBSOLETE))) {
errflags warning;
const char *whathappened;
@ -982,7 +1070,7 @@ static int64_t assemble(insn *instruction)
whathappened, validity);
}
data.inslen = calcsize(instruction, temp);
data.inslen = calcsize(instruction);
/* This can happen if the instruction generated an error */
if (data.inslen <= 0)
@ -999,75 +1087,7 @@ static int64_t assemble(insn *instruction)
nasm_assert(data.loc.offset - start == data.inslen);
} else {
/* No match */
switch (m) {
case MERR_INVALOP:
default:
nasm_nonfatal("invalid combination of opcode and operands");
break;
case MERR_OPSIZEINVAL:
nasm_nonfatal("invalid operand sizes for instruction");
break;
case MERR_OPSIZEMISSING:
nasm_nonfatal("operation size not specified");
break;
case MERR_OPSIZEMISMATCH:
nasm_nonfatal("mismatch in operand sizes");
break;
case MERR_BRNOTHERE:
nasm_nonfatal("broadcast not permitted on this operand");
break;
case MERR_BRNUMMISMATCH:
nasm_nonfatal("mismatch in the number of broadcasting elements");
break;
case MERR_MASKNOTHERE:
nasm_nonfatal("mask not permitted on this operand");
break;
case MERR_DECONOTHERE:
nasm_nonfatal("unsupported mode decorator for instruction");
break;
case MERR_BADCPU:
nasm_nonfatal("no instruction for this cpu level");
break;
case MERR_BADMODE:
nasm_nonfatal("instruction not supported in %d-bit mode", bits);
break;
case MERR_ENCMISMATCH:
if (!instruction->prefixes[PPS_REX]) {
nasm_nonfatal("instruction not encodable without explicit prefix");
} else {
nasm_nonfatal("instruction not encodable with %s prefix",
prefix_name(instruction->prefixes[PPS_REX]));
}
break;
case MERR_BADBND:
case MERR_BADREPNE:
nasm_nonfatal("%s prefix is not allowed",
prefix_name(instruction->prefixes[PPS_REP]));
break;
case MERR_REGSETSIZE:
nasm_nonfatal("invalid register set size");
break;
case MERR_REGSET:
nasm_nonfatal("register set not valid for operand");
break;
case MERR_WRONGIMM:
nasm_nonfatal("operand/operator invalid for this instruction");
break;
case MERR_BADZU:
nasm_nonfatal("{zu} not applicable to this instruction");
break;
case MERR_MEMZU:
nasm_nonfatal("{zu} invalid for non-register destination");
break;
case MERR_BADNF:
nasm_nonfatal("{nf} not available for this instruction");
break;
case MERR_REQNF:
nasm_nonfatal("{nf} required for this instruction");
break;
}
no_match_error(m, instruction);
instruction->times = 1; /* Avoid repeated error messages */
}
}
@ -1236,7 +1256,6 @@ static int64_t len_extops(const extop *e)
static int64_t insn_size(insn *instruction)
{
const struct itemplate *temp;
enum match_result m;
int64_t isize = 0;
@ -1284,11 +1303,13 @@ static int64_t insn_size(insn *instruction)
/* Pre-matching setup */
insn_early_setup(instruction);
m = find_match(&temp, instruction);
if (m < MOK_GOOD)
m = find_match(instruction);
if (m < MOK_GOOD) {
no_match_error(m, instruction);
return -1; /* No match */
}
isize = calcsize(instruction, temp);
isize = calcsize(instruction);
debug_set_type(instruction);
isize = merge_resb(instruction, isize);
@ -1371,12 +1392,49 @@ static int ea_evex_flags(insn *ins, const struct operand *opy)
return 0;
}
/*
* Call calcsize() without modifying the source instruction, and without
* generating errors. This is used to answer the question "how long would
* this instruction be if it were to be generated at this point in the
* code." This is currently used by jmp_match() but may be used by other
* things in the future.
*
* Returns < 0 if generating the instruction would throw an error.
*/
static int64_t
calcsize_speculative(const insn *ins, const struct itemplate *itemp)
{
int64_t isize;
insn tmpins;
errhold hold;
tmpins = *ins;
tmpins.dummy = true;
tmpins.itemp = itemp;
hold = nasm_error_hold_push();
isize = calcsize(&tmpins);
if (nasm_error_hold_pop(hold, false) >= ERR_NONFATAL)
return -1;
return isize;
}
/* Common construct */
#define case3(x) case (x): case (x)+1: case (x)+2
#define case4(x) case3(x): case (x)+3
static int64_t calcsize(insn *ins, const struct itemplate * const temp)
/*
* calcsize() is assumed to be processing a *confirmed* instruction for
* the purpose of code generation: it can modify *ins, and will throw
* errors for invalid code. Use calcsize_speculative() if it is necessary
* to calculate the size of a *potential* instruction.
*/
static int64_t calcsize(insn *ins)
{
const struct itemplate * const temp = ins->itemp;
const int bits = ins->bits;
const uint8_t *codes = temp->code;
int64_t length = 0;
@ -1396,11 +1454,9 @@ static int64_t calcsize(insn *ins, const struct itemplate * const temp)
ins->evex = 0; /* Ensure EVEX is reset */
ins->vexreg = 0; /* No V register */
ins->vex_cm = 0; /* No implicit map */
ins->bits = bits; /* Execution mode (default asize) */
ins->itemp = temp; /* Instruction template */
eat = EA_SCALAR; /* Expect a scalar EA */
/* Default operand size */
/* Default operand size (prefixes are handled in the byte code) */
ins->op_size = bits != 16 ? 32 : 16;
nasm_zero(need_pfx);
@ -1445,7 +1501,7 @@ static int64_t calcsize(insn *ins, const struct itemplate * const temp)
if (opx->type & (BITS16 | BITS32 | BITS64))
length += (opx->type & BITS16) ? 2 : 4;
else
length += (bits == 16) ? 2 : 4;
length += (ins->op_size == 16) ? 2 : 4;
break;
case4(040):
@ -1472,7 +1528,7 @@ static int64_t calcsize(insn *ins, const struct itemplate * const temp)
if (opx->type & (BITS16 | BITS32 | BITS64))
length += (opx->type & BITS16) ? 2 : 4;
else
length += (bits == 16) ? 2 : 4;
length += (ins->op_size == 16) ? 2 : 4;
break;
case4(070):
@ -2411,7 +2467,7 @@ static void gencode(struct out_data *data, insn *ins)
if (opx->type & (BITS16 | BITS32))
size = (opx->type & BITS16) ? 2 : 4;
else
size = (bits == 16) ? 2 : 4;
size = (ins->op_size == 16) ? 2 : 4;
out_imm(data, opx, size, OUT_WRAP);
break;
@ -2447,7 +2503,7 @@ static void gencode(struct out_data *data, insn *ins)
if (opx->type & (BITS16 | BITS32 | BITS64))
size = (opx->type & BITS16) ? 2 : 4;
else
size = (bits == 16) ? 2 : 4;
size = (ins->op_size == 16) ? 2 : 4;
out_reladdr(data, opx, size);
break;
@ -2873,17 +2929,18 @@ static uint32_t op_evexflags(const operand * o, uint32_t mask)
return evexflags(o->decoflags, mask);
}
static enum match_result find_match(const struct itemplate **tempp,
insn *instruction)
static enum match_result find_match(insn *instruction)
{
const int bits = instruction->bits;
const struct itemplate_list *templist;
const struct itemplate *temp;
const struct itemplate *best = NULL;
const struct itemplate *best;
enum match_result m, merr;
int this_good;
int rex = instruction->prefixes[PPS_REX];
unsigned int n;
int n, i, besti;
instruction->itemp = best = NULL;
instruction->itempindex = besti = -1;
/* Impossible encoding request? */
if (bits != 64) {
@ -2892,31 +2949,29 @@ static enum match_result find_match(const struct itemplate **tempp,
}
merr = MERR_INVALOP;
best = NULL;
this_good = 0;
templist = &nasm_instructions[instruction->opcode];
n = templist->ntemp;
temp = templist->temp;
while (n--) {
for (i = 0; i < n; i++) {
m = matches(temp, instruction);
if (m > merr) {
best = temp;
besti = i;
merr = m;
this_good = 1;
if (merr == MOK_GOOD)
break;
} else if (m == merr) {
this_good++;
}
temp++;
}
if (merr >= MOK_FIRST)
merr = MOK_GOOD; /* Fuzzy match but valid */
*tempp = best;
if (merr >= MOK_FIRST) {
/* If this was a fuzzy match it is confirmed now */
merr = MOK_GOOD;
instruction->itemp = best;
instruction->itempindex = besti;
}
return merr;
}
@ -3042,7 +3097,7 @@ static enum match_result matches(const struct itemplate * const itemp,
/* "Default" operand size (from mode and prefixes only) */
op_size = ins->op_size;
if (itemp_has(itemp, IF_NWSIZE) && op_size == 32) {
if (bits == 64 && itemp_has(itemp, IF_NWSIZE) && op_size == 32) {
/* If this is an nw instruction, default to 64 bits in 64-bit mode */
op_size = bits;
}
@ -3082,18 +3137,23 @@ static enum match_result matches(const struct itemplate * const itemp,
/* Handle implied SHORT or NEAR */
if (unlikely(ttype & (NEAR|SHORT))) {
/* Treat BYTE as an alias for SHORT, ignoring size */
if (isize[i] == BITS8) {
itype[i] |= SHORT;
isize[i] = 0;
}
/* An explicit SHORT or BITS8 cancels NEAR; are synonyms */
if (itype[i] & SHORT) {
itype[i] &= ~NEAR;
}
/* NEAR is implicit unless otherwise specified */
if (!(itype[i] & (FAR|SHORT))) {
itype[i] |= ttype & NEAR;
}
if ((ttype & (NEAR|SHORT)) == (NEAR|SHORT)) {
/* Only a short form exists; allow both NEAR and SHORT */
/* Only a short form exists; this is specially coded */
if (!(itype[i] & (FAR|ABS)))
itype[i] |= NEAR|SHORT;
} else if ((itype[i] & SHORT) || isize[i] == BITS8) {
/* An explicit SHORT or BITS8 cancel NEAR; are synonyms */
itype[i] &= ~NEAR;
if (!isize[i])
isize[i] = BITS8;
} else if (!(itype[i] & (FAR|ABS|SHORT))) {
/* NEAR is implicit unless otherwise specified */
itype[i] |= ttype & NEAR;
}
}
@ -3102,20 +3162,18 @@ static enum match_result matches(const struct itemplate * const itemp,
/*
* If this is an *explicitly* sized immediate,
* allow it to match an extending pattern.
*
* NOTE: Open Watcom does not support 64-bit constants
* in switch statements; do not change this to a switch.
*/
switch (isize[i]) {
case BITS8:
if (isize[i] == BITS8) {
if (ttype & BYTEEXTMASK) {
isize[i] = tsize[i];
itype[i] |= BYTEEXTMASK;
}
break;
case BITS32:
} else if (isize[i] == BITS32) {
if (ttype & DWORDEXTMASK)
isize[i] = tsize[i];
break;
default:
break;
}
/*
@ -3338,7 +3396,7 @@ static enum match_result matches(const struct itemplate * const itemp,
* Check if special handling needed for relaxable jump
*/
if (itemp_has(itemp, IF_JMP_RELAX))
return jmp_match(itemp, ins);
return jmp_match(ins, itemp);
return MOK_GOOD;
}
@ -3449,8 +3507,7 @@ static int process_ea(operand *input, int rfield, opflags_t rflags,
input->type |= IP_REL;
}
if ((input->type & IP_REL) == IP_REL) {
if (input->segment == NO_SEG ||
(input->opflags & OPFLAG_RELATIVE)) {
if (!pass_first() && absolute_op(input)) {
nasm_warn(WARN_EA_ABSOLUTE,
"absolute address can not be RIP-relative");
input->type &= ~IP_REL;

View file

@ -22,6 +22,7 @@
#include "listing.h"
#include "labels.h"
#include "iflag.h"
#include "quote.h"
struct cpunames {
const char *name;
@ -178,34 +179,51 @@ static int get_bits(const char *value)
static enum directive parse_directive_line(char **directive, char **value)
{
char *p, *q, *buf;
char *p, *q, *eol, *buf;
char c;
buf = nasm_skip_spaces(*directive);
/*
* It should be enclosed in [ ].
* XXX: we don't check there is nothing else on the remainder of the
* line, except a possible comment.
*
* Strip off the comments. We should really strip the comments in
* generic code, not here. While we're at it, it would be better
* to pass the backend a series of tokens instead of a raw string,
* and actually process quoted strings for it, like of like argv
* is handled in C.
*/
if (*buf != '[')
return D_none;
q = strchr(buf, ']');
if (!q)
return D_corrupt;
q = buf;
while ((c = *q) != ']') {
switch (c) {
case '\0':
case ';':
return D_corrupt; /* No ] in directive */
case '\'':
case '\"':
case '`':
q = nasm_skip_string(q);
if (!*q++)
return D_corrupt;
break;
default:
q++;
break;
}
}
/*
* Strip off the comments. XXX: this doesn't account for quoted
* strings inside a directive. We should really strip the
* comments in generic code, not here. While we're at it, it
* would be better to pass the backend a series of tokens instead
* of a raw string, and actually process quoted strings for it,
* like of like argv is handled in C.
* Found the ] at the end of the directive. Make sure there isn't
* anything else at the end of the line, except a possible
* comment.
*/
p = strchr(buf, ';');
if (p) {
if (p < q) /* ouch! somewhere inside */
return D_corrupt;
*p = '\0';
eol = nasm_skip_spaces(q+1);
if (*eol != '\0' && *eol != ';') {
nasm_warn(WARN_DIRECTIVE_GARBAGE_EOL,
"garbage found on line after directive");
}
/* no brace, no trailing spaces */
@ -264,7 +282,7 @@ bool process_directives(char *directive)
switch (d) {
case D_none:
return D_none; /* Not a directive */
return false;
case D_corrupt:
nasm_nonfatal("invalid directive line");
@ -285,6 +303,12 @@ bool process_directives(char *directive)
default:
panic();
}
} else if (d < D_pseudo_ops) {
nasm_nonfatal("internal error: unimplemented directive [%s]",
directive);
break;
} else {
goto unknown;
}
break;
@ -364,6 +388,7 @@ bool process_directives(char *directive)
{
bool validid;
int64_t size = 0;
char *fullvalue = value; /* Including leading $ if present */
char *sizestr;
bool rn_error;
@ -371,7 +396,7 @@ bool process_directives(char *directive)
value++; /* skip escaping $ if present */
validid = nasm_isidchar(*value);
if (globl.dollarhex)
validid &= !nasm_isnumchar(*value);
validid &= !nasm_isnumstart(*value);
} else {
validid = nasm_isidstart(*value);
}
@ -387,7 +412,7 @@ bool process_directives(char *directive)
}
if (!validid) {
nasm_nonfatal("identifier expected after %s, got `%s'",
directive, value);
directive, fullvalue);
break;
}
@ -502,8 +527,9 @@ bool process_directives(char *directive)
push_warnings();
else if (!nasm_stricmp(value, "pop"))
pop_warnings();
} else {
set_warning_status(value);
}
set_warning_status(value);
break;
case D_CPU: /* [CPU] */
@ -603,13 +629,24 @@ bool process_directives(char *directive)
case D_PRAGMA:
process_pragma(value);
break;
}
case D_PREFIX:
case D_GPREFIX:
case D_SUFFIX:
case D_GSUFFIX:
case D_POSTFIX:
case D_GPOSTFIX:
case D_LPREFIX:
case D_LSUFFIX:
case D_LPOSTFIX:
set_label_mangle(d, value);
break;
}
/* A common error message */
if (bad_param) {
nasm_nonfatal("invalid parameter to [%s] directive", directive);
}
return d != D_none;
return true;
}

View file

@ -17,6 +17,12 @@
;; In the future, this will be turned into a general list of keywords
;; to be parsed in special contexts.
;;
;; #special tokens are used to separate different classes of tokens.
;; Make sure to add new tokens to the correct place. If a token is used
;; in both a directive and in pragmas, they should be in the directive
;; part of the list. Tokens used in pragmas *only* go at the end of the
;; list.
;;
; --- General configuration
#name directive
@ -25,10 +31,15 @@
#header directiv.h
; --- Special enum values
; These must be first in the list.
#special none = 0 ; Must be zero
#special unknown
#special corrupt
; --- True directives
; These tokens are accepted as directives by the global code or
; ignored if not implemented.
; --- Global directives
absolute
bits
@ -40,16 +51,29 @@ dollarhex
extern
float
global
static
list
section
segment
warning
sectalign
pragma
required
sectalign
section
segment
static
warning
; --- Common output directives/pragmas
prefix
suffix
postfix
gprefix
gsuffix
gpostfix
lprefix
lsuffix
lpostfix
; --- Pseudo-op list, for the benefit of %isdirective
; Tokens put in this part will be rejected as either directives or
; pragmas
#special pseudo_ops
db
dw
@ -71,6 +95,8 @@ incbin
equ
; --- Format-specific directives
; Tokens put in this part of the list will be forwarded to the
; backend ofmt->directive() method.
#special ofmt
export ; outcoff, outobj
group ; outobj
@ -83,22 +109,17 @@ osabi ; outelf
safeseh ; outcoff
uppercase ; outieee, outobj
; --- The following are tokens used in pragmas, not actual directives
; --- The following are tokens used in pragmas, not actual directives.
; They will not be accepted as directives.
#special pragma_tokens
; --- Assembler pragmas
prefix
suffix
gprefix
gsuffix
lprefix
lsuffix
limit
; --- Listing pragmas
options
; --- Backend pragmas
; --- Backend-specific pragmas
subsections_via_symbols ; macho
no_dead_strip ; macho
maxdump ; dbg

View file

@ -8,96 +8,28 @@
#include "compiler.h"
#include "nasmlib.h"
#include "error.h"
#include "files.h"
#include "listing.h"
#include "srcfile.h"
#include "strlist.h"
unsigned int debug_nasm; /* Debugging messages? */
unsigned int opt_verbose_info; /* Informational messages? */
struct error_format {
const char *beforeline; /* Before line number, if present */
const char *afterline; /* After line number, if present */
const char *beforemsg; /* Before actual message */
};
/* Common function body */
#define nasm_do_error(_sev,_flags) \
do { \
va_list ap; \
va_start(ap, fmt); \
if ((_sev) >= ERR_CRITICAL) \
nasm_verror_critical((_sev)|(_flags), fmt, ap); \
else \
nasm_verror((_sev)|(_flags), fmt, ap); \
va_end(ap); \
if ((_sev) >= ERR_FATAL) \
abort(); \
} while (0)
/*
* This is the generic function to use when the error type is not
* known a priori. For ERR_DEBUG and ERR_INFO the level can be
* included by
*/
void nasm_error(errflags flags, const char *fmt, ...)
{
nasm_do_error(flags & ERR_MASK, flags);
}
#define nasm_err_helpers(_type, _name, _sev) \
_type nasm_ ## _name ## f (errflags flags, const char *fmt, ...) \
{ \
nasm_do_error(_sev, flags); \
} \
_type nasm_ ## _name (const char *fmt, ...) \
{ \
nasm_do_error(_sev, 0); \
}
nasm_err_helpers(void, listmsg, ERR_LISTMSG)
nasm_err_helpers(void, note, ERR_NOTE)
nasm_err_helpers(void, nonfatal, ERR_NONFATAL)
nasm_err_helpers(fatal_func, fatal, ERR_FATAL)
nasm_err_helpers(fatal_func, critical, ERR_CRITICAL)
nasm_err_helpers(fatal_func, panic, ERR_PANIC)
/*
* Strongly discourage warnings without level by require flags on warnings.
* This means nasm_warn() is the equivalent of the -f variants of the
* other ones.
*
* This is wrapped in a macro to be able to elide it if the warning is
* disabled, hence the extra underscore.
*/
void nasm_warn_(errflags flags, const char *fmt, ...)
{
nasm_do_error(ERR_WARNING, flags);
}
/*
* nasm_info() and nasm_debug() takes mandatory enabling levels.
*/
void nasm_info_(unsigned int level, const char *fmt, ...)
{
if (info_level(level))
nasm_do_error(ERR_INFO, LEVEL(level));
}
void nasm_debug_(unsigned int level, const char *fmt, ...)
{
if (debug_level(level))
nasm_do_error(ERR_DEBUG, LEVEL(level));
}
fatal_func nasm_panic_from_macro(const char *func, const char *file, int line)
{
if (!func)
func = "<unknown>";
nasm_panic("internal error in %s at %s:%d\n", func, file, line);
}
fatal_func nasm_assert_failed(const char *msg, const char *func,
const char *file, int line)
{
if (!func)
func = "<unknown>";
nasm_panic("assertion %s failed in %s at %s:%d", msg, func, file, line);
}
enum error_formats {
ERRFMT_GNU,
ERRFMT_MSVC
};
static const struct error_format errfmts[] = {
{ ":", "", ": " }, /* ERRFMT_GNU */
{ "(", ")", " : " } /* ERRFMT_MSVC */
};
static const struct error_format *errfmt = &errfmts[ERRFMT_GNU];
static void usage(void);
/*
* Warning stack management. Note that there is an implicit "push"
@ -109,6 +41,7 @@ struct warning_stack {
uint8_t state[sizeof warning_state];
};
static struct warning_stack *warning_stack, *warning_state_init;
static struct strlist *warn_list;
/* Push the warning status onto the warning stack */
void push_warnings(void)
@ -135,16 +68,33 @@ void pop_warnings(void)
}
}
/* Call after the command line is parsed, but before the first pass */
void init_warnings(void)
/* Called after the command line is parsed, but before the first pass */
static void init_warnings(void)
{
push_warnings();
warning_state_init = warning_stack;
}
void error_init(void)
{
erropt.worst = 0;
init_warnings();
}
/* Call after each pass */
void reset_warnings(void)
/* Called before each pass. Buffer warnings if "final" is false. */
void error_pass_start(bool final)
{
nasm_assert(!warn_list);
erropt.worst = 0;
if (!final)
warn_list = strlist_alloc(false);
}
/*
* Called after the completion of each pass. This MUST preserve erropt.worst!
*/
static void reset_warnings(void)
{
struct warning_stack *ws = warning_stack;
@ -158,6 +108,12 @@ void reset_warnings(void)
memcpy(warning_state, ws->state, sizeof warning_state);
}
void error_pass_end(void)
{
strlist_free(&warn_list);
reset_warnings();
}
/*
* This is called when processing a -w or -W option, or a warning directive.
* Returns ok if the action was successful.
@ -258,10 +214,18 @@ bool set_warning_status(const char *value)
warning_state[i] |= mask;
break;
case WID_RESET:
{
uint8_t old;
if (warning_state_init)
old = warning_state_init->state[i];
else
old = warning_default[i];
warning_state[i] &= ~mask;
warning_state[i] |= warning_state_init->state[i] & mask;
warning_state[i] |= old & mask;
break;
}
}
}
if (!ok && value) {
@ -299,3 +263,504 @@ const char *error_pfx(errflags severity)
return "internal error: ";
}
}
static bool skip_this_pass(errflags severity)
{
errflags type = severity & ERR_MASK;
/*
* See if it's a pass-specific error or warning which should be skipped.
* We can never skip fatal errors as by definition they cannot be
* resumed from.
*/
if (type >= ERR_FATAL)
return false;
/*
* ERR_LISTMSG and ERR_NOTE messages are always skipped; the list
* file receives them anyway as this function is not consulted for
* sending to the list file.
*/
if (type <= ERR_NOTE)
return true;
/*
* This message is not applicable unless it is the last pass we
* are going to execute; this can be either the final
* code-generation pass or the single pass executed in
* preproc-only mode.
*/
return (severity & ERR_PASS2) && !pass_final_or_preproc();
}
/**
* check for suppressed message (usually warnings or notes)
*
* @param severity the severity of the warning or error
* @return true if we should abort error/warning printing
*/
static bool is_suppressed(errflags flags)
{
const errflags severity = flags & ERR_MASK;
const errflags level = WARN_IDX(flags);
if (severity >= ERR_FATAL) {
/* Fatal errors or higher can never be suppressed */
return false;
}
if (flags & erropt.never)
return true;
switch (severity) {
case ERR_WARNING:
if (!(warning_state[level] & WARN_ST_ENABLED))
return true;
break;
case ERR_INFO:
if (!info_level(level))
return true;
break;
case ERR_DEBUG:
if (!debug_level(level))
return true;
break;
default:
break;
}
/* Suppressed by the preprocessor? */
if (!(flags & ERR_PP_LISTMACRO))
return pp_suppress_error(flags);
return false;
}
/**
* Return the true error type (the ERR_MASK part) of the given
* severity, accounting for warnings that may need to be promoted to
* error.
*
* @param severity the severity of the warning or error
* @return true if we should error out
*/
static errflags pure_func true_error_type(errflags severity)
{
const uint8_t warn_is_err = WARN_ST_ENABLED|WARN_ST_ERROR;
int type;
type = severity & ERR_MASK;
if (type == ERR_WARNING) {
/* Promote warning to error? */
uint8_t state = warning_state[WARN_IDX(severity)];
if ((state & warn_is_err) == warn_is_err)
type = ERR_NONFATAL;
}
return type;
}
static const char no_file_name[] = "nasm"; /* What to print if no file name */
/*
* For fatal/critical/panic errors, kill this process.
*
* For FATAL errors doing cleanups, tidying up the list process,
* and so in is acceptable.
*
* For CRITICAL errors, minimize dependencies on memory allocation
* and/or having a system valid state.
*
* For PANIC, if abort_on_panic is set, abort without any other action.
*/
static_fatal_func die_hard(errflags true_type, errflags severity)
{
if (true_type < ERR_PANIC || !erropt.abort_on_panic) {
if (true_type < ERR_CRITICAL) {
/* FATAL shutdown, general cleanup actions are valid */
print_final_report(true);
lfmt->cleanup();
}
fflush(NULL);
close_output(true);
if (severity & ERR_USAGE)
usage();
/* Terminate immediately (exit closes any still open files) */
exit(true_type - ERR_FATAL + 1);
}
/*
* abort() shouldn't ever return, but be paranoid about this,
* plus it helps some compilers clue in to the fact that this
* function can never, ever return.
*/
while (1)
abort();
}
/*
* Returns the struct src_location appropriate for use, after some
* potential filename mangling.
*/
static struct src_location error_where(errflags severity)
{
struct src_location where;
if (severity & ERR_NOFILE) {
where.filename = NULL;
where.lineno = 0;
} else {
where = src_where_error();
if (!where.filename) {
enum filenames fn;
for (fn = FN_INFILE; fn <= FN_OUTFILE; fn++) {
const char *name = get_filename(fn);
if (name && *name) {
where.filename = name;
break;
}
}
where.lineno = 0;
}
}
return where;
}
/*
* error reporting for critical and panic errors: minimize
* the amount of system dependencies for getting a message out,
* and in particular try to avoid memory allocations.
*/
fatal_func nasm_verror_critical(errflags severity, const char *fmt, va_list args)
{
struct src_location where;
errflags true_type = severity & ERR_MASK;
static bool been_here = false;
while (unlikely(been_here))
abort(); /* Recursive critical error... just die */
been_here = true;
erropt.worst = true_type;
where = error_where(severity);
if (!where.filename)
where.filename = no_file_name;
fputs(error_pfx(severity), erropt.file);
fputs(where.filename, erropt.file);
if (where.lineno) {
fprintf(erropt.file, "%s%"PRId32"%s",
errfmt->beforeline, where.lineno, errfmt->afterline);
}
fputs(errfmt->beforemsg, erropt.file);
vfprintf(erropt.file, fmt, args);
fputc('\n', erropt.file);
die_hard(true_type, severity);
unreachable();
}
/**
* Stack of tentative error hold lists.
*/
struct nasm_errtext {
struct nasm_errtext *next;
char *msg; /* Owned by this structure */
struct src_location where; /* Owned by the srcfile system */
errflags severity;
errflags true_type;
int c_errno; /* Saved errno (for ERR_PERROR) */
};
struct nasm_errhold {
struct nasm_errhold *up;
struct nasm_errtext *head, **tail;
};
static struct strlist *warn_list;
static struct nasm_errhold *errhold_stack;
static void nasm_free_error(struct nasm_errtext *et)
{
nasm_free(et->msg);
nasm_free(et);
}
static void nasm_issue_error(struct nasm_errtext *et);
struct nasm_errhold *nasm_error_hold_push(void)
{
struct nasm_errhold *eh;
nasm_new(eh);
eh->up = errhold_stack;
eh->tail = &eh->head;
errhold_stack = eh;
return eh;
}
/* Pop an error hold. Returns the highest severity issued or dropped. */
errflags nasm_error_hold_pop(struct nasm_errhold *eh, bool issue)
{
struct nasm_errtext *et, *etmp;
errflags worst = 0;
/*
* Allow calling with a null argument saying no hold in the first place.
*/
if (!eh)
return worst;
/* This *must* be the current top of the errhold stack */
nasm_assert(eh == errhold_stack);
if (eh->head) {
if (issue) {
if (eh->up) {
/* Commit the current hold list to the previous level */
*eh->up->tail = eh->head;
eh->up->tail = eh->tail;
} else {
/* Issue errors */
list_for_each_safe(et, etmp, eh->head) {
if (et->true_type > worst)
worst = et->true_type;
nasm_issue_error(et);
}
}
} else {
/* Free the list, drop errors */
list_for_each_safe(et, etmp, eh->head) {
if (et->true_type > worst)
worst = et->true_type;
nasm_free_error(et);
}
}
}
errhold_stack = eh->up;
nasm_free(eh);
return worst;
}
/**
* common error reporting
* This is the common back end of the error reporting schemes currently
* implemented. It prints the nature of the warning and then the
* specific error message to erropt.file and may or may not return. It
* doesn't return if the error severity is a "panic" or "debug" type.
*
* @param severity the severity of the warning or error
* @param fmt the printf style format string
*/
void nasm_verror(errflags severity, const char *fmt, va_list args)
{
struct nasm_errtext *et;
int c_errno = errno;
errflags true_type = true_error_type(severity);
if (true_type >= ERR_CRITICAL) {
nasm_verror_critical(severity, fmt, args);
abort();
}
if (is_suppressed(severity))
return;
nasm_new(et);
et->c_errno = c_errno;
et->severity = severity;
et->true_type = true_type;
et->msg = nasm_vasprintf(fmt, args);
et->where = error_where(severity);
if (errhold_stack && true_type <= ERR_NONFATAL) {
/* It is a tentative error */
*errhold_stack->tail = et;
errhold_stack->tail = &et->next;
} else {
nasm_issue_error(et);
}
/*
* Don't do this before then, if we do, we lose messages in the list
* file, as the list file is only generated in the last pass.
*/
if (skip_this_pass(severity))
return;
if (!(severity & (ERR_HERE|ERR_PP_LISTMACRO)))
pp_error_list_macros(severity);
}
/*
* Actually print, list and take action on an error
*/
static void nasm_issue_error(struct nasm_errtext *et)
{
const char *pfx;
char warnsuf[64]; /* Warning suffix */
char linestr[64]; /* Formatted line number if applicable */
const errflags severity = et->severity;
const errflags true_type = et->true_type;
const struct src_location where = et->where;
const char *cerrsep = "";
const char *cerrmsg = "";
bool buffer = true_type < ERR_NONFATAL || (severity & ERR_HOLD);
if (severity & ERR_NO_SEVERITY)
pfx = "";
else
pfx = error_pfx(true_type);
*warnsuf = 0;
if (!(severity & (ERR_HERE|ERR_PP_LISTMACRO))) {
switch (severity & ERR_MASK) {
case ERR_WARNING:
{
const unsigned int level = WARN_IDX(severity);
snprintf(warnsuf, sizeof warnsuf, " [-w+%s%s]",
(true_type >= ERR_NONFATAL) ? "error=" : "",
warning_name[level]);
break;
}
case ERR_DEBUG:
snprintf(warnsuf, sizeof warnsuf, " [--debug=%u]", erropt.debug_nasm);
break;
case ERR_INFO:
snprintf(warnsuf, sizeof warnsuf, " [--info=%u]", erropt.verbose_info);
break;
default:
/* Not WARNING, DEBUG or INFO, not suppressible */
break;
}
if (severity & ERR_PERROR) {
cerrsep = ":";
cerrmsg = strerror(et->c_errno);
}
}
*linestr = 0;
if (where.lineno) {
snprintf(linestr, sizeof linestr, "%s%"PRId32"%s",
errfmt->beforeline, where.lineno, errfmt->afterline);
}
if (!skip_this_pass(severity)) {
const char *file = where.filename ? where.filename : no_file_name;
const char *here = "";
if (severity & ERR_HERE) {
here = where.filename ? " here" : " in an unknown location";
}
if (!warn_list)
buffer = false;
if (buffer) {
/*
* Buffer up warnings and held errors until we either get
* an error or we are on the code-generation pass.
*/
strlist_printf(warn_list, "%s%s%s%s%s%s%s%s%s",
file, linestr, errfmt->beforemsg,
pfx, et->msg, cerrsep, cerrmsg,
here, warnsuf);
} else {
/*
* Actually output an error. If we have buffered
* warnings, and this is a non-warning, output them now.
*/
if (warn_list) {
strlist_write(warn_list, "\n", erropt.file);
strlist_free(&warn_list);
}
fprintf(erropt.file, "%s%s%s%s%s%s%s%s%s\n",
file, linestr, errfmt->beforemsg,
pfx, et->msg, cerrsep, cerrmsg,
here, warnsuf);
}
}
/* Are we recursing from error_list_macros? */
if (severity & ERR_PP_LISTMACRO)
goto done;
/*
* Don't suppress this with skip_this_pass(), or we don't get
* pass1 or preprocessor warnings in the list file
*/
if (severity & ERR_HERE) {
if (where.lineno)
lfmt->error(severity, "%s%s at %s:%"PRId32"%s",
pfx, et->msg, where.filename, where.lineno, warnsuf);
else if (where.filename)
lfmt->error(severity, "%s%s in file %s%s",
pfx, et->msg, where.filename, warnsuf);
else
lfmt->error(severity, "%s%s in an unknown location%s",
pfx, et->msg, warnsuf);
} else {
lfmt->error(severity, "%s%s%s", pfx, et->msg, warnsuf);
}
if (skip_this_pass(severity))
goto done;
if (true_type >= ERR_FATAL) {
die_hard(true_type, severity);
} else if (!buffer) {
if (true_type > erropt.worst)
erropt.worst = true_type;
if (true_type >= ERR_NONFATAL)
erropt.never |= ERR_UNDEAD;
}
done:
nasm_free_error(et);
}
int set_error_format(const char *fmt)
{
if (!nasm_stricmp("vc", fmt) ||
!nasm_stricmp("msvc", fmt) ||
!nasm_stricmp("ms", fmt))
errfmt = &errfmts[ERRFMT_MSVC];
else if (!nasm_stricmp("gnu", fmt) ||
!nasm_stricmp("gcc", fmt))
errfmt = &errfmts[ERRFMT_GNU];
else
return -1;
return 0;
}
static void usage(void)
{
fprintf(erropt.file,
"Usage: %s [-@ response_file] [options...] [--] filename\n"
" For additional help:\n"
" %s -h [run|topics|all|-option]\n",
_progname, _progname);
}
void warn_dollar_hex(void)
{
nasm_warn(WARN_NUMBER_DEPRECATED_HEX,
"$ prefix for hexadecimal is deprecated");
}

View file

@ -210,6 +210,9 @@ static union label *find_label(const char *label, bool create, bool *created)
if (lptr || !create) {
if (created)
*created = false;
if (label_str)
nasm_free(label_str);
return lptr;
}
@ -262,14 +265,45 @@ static inline bool is_global(enum label_type type)
return type == LBL_GLOBAL || type == LBL_COMMON;
}
enum mangle_index {
LM_LPREFIX, /* Local variable prefix */
LM_LSUFFIX, /* Local variable suffix */
LM_GPREFIX, /* Global variable prefix */
LM_GSUFFIX /* GLobal variable suffix */
};
static const char *mangle_strings[] = {"", "", "", ""};
static bool mangle_string_set[ARRAY_SIZE(mangle_strings)];
/*
* Set a prefix or suffix
*/
void set_label_mangle(enum mangle_index which, const char *what)
void set_label_mangle(enum directive how, const char *what)
{
enum mangle_index which;
switch (how) {
case D_PREFIX:
case D_GPREFIX:
which = LM_GPREFIX;
break;
case D_SUFFIX:
case D_GSUFFIX:
case D_POSTFIX:
case D_GPOSTFIX:
which = LM_GSUFFIX;
break;
case D_LPREFIX:
which = LM_LPREFIX;
break;
case D_LSUFFIX:
case D_LPOSTFIX:
which = LM_LSUFFIX;
break;
default:
return;
}
if (mangle_string_set[which])
return; /* Once set, do not change */
@ -384,6 +418,7 @@ static bool declare_label_lptr(union label *lptr,
} else if (is_extern(oldtype) && is_global(type)) {
/* EXTERN or REQUIRED can be replaced with GLOBAL or COMMON */
lptr->defn.type = type;
lptr->defn.defined = 0;
/* Override special unconditionally */
if (special)

View file

@ -19,11 +19,24 @@
#define LIST_INDENT 40
#define LIST_HEXBIT 18
/*
* The options to enable by increasing levels of -L+ on the command line.
* Each string is inclusive of the previous level; there is no need to
* duplicate characters. "" *is* allowed to mean that a level should have
* no impact, e.g. because an option has been made obsolete or a level is
* reserved for future use.
*/
static const char * const list_plus_options[] = {
"bdefFmps", /* -L+ */
"ct", /* -L++ */
NULL
};
static const char xdigit[] = "0123456789ABCDEF";
#define HEX(a,b) (*(a)=xdigit[((b)>>4)&15],(a)[1]=xdigit[(b)&15])
uint64_t list_options, active_list_options;
uint64_t list_options, active_list_options, cmdline_list_options;
bool user_nolist;
static char listline[LIST_MAX_LEN];
@ -260,7 +273,7 @@ static void list_output(const struct out_data *data)
}
}
static void list_line(int type, int32_t lineno, const char *line)
static void list_line(enum list_type type, int32_t lineno, const char *line)
{
(void)type;
@ -279,20 +292,24 @@ static void list_line(int type, int32_t lineno, const char *line)
listlevel_e = listlevel;
}
static void list_uplevel(int type, int64_t size)
static void list_uplevel(enum list_type type, int64_t size)
{
if (!listfp)
return;
switch (type) {
case LIST_INCBIN:
suppress |= 1;
list_size(listoffset, "bin", size);
if (!list_option('c')) {
suppress |= 1;
list_size(listoffset, "bin", size);
}
break;
case LIST_TIMES:
suppress |= 2;
list_size(listoffset, "rep", size);
if (!list_option('t')) {
suppress |= 2;
list_size(listoffset, "rep", size);
}
break;
case LIST_INCLUDE:
@ -305,7 +322,7 @@ static void list_uplevel(int type, int64_t size)
}
}
static void list_downlevel(int type)
static void list_downlevel(enum list_type type)
{
if (!listfp)
return;
@ -349,36 +366,68 @@ static void list_set_offset(uint64_t offset)
listoffset = offset;
}
static void list_update_options(const char *str)
/*
* from_cmdline has the following effects:
* 1. It treats + as -L+... -> list_plus_options[] as opposed to a modifier;
* 2. It disallows the * modifier (= set to command line default);
* 3. It suppresses setting active_list_options (that will
* be done when list_init() is called.)
*
* As listing options are assumed non-critical, ignore errors
* to help forward compatibility.
*/
void list_update_options(const char *str, bool from_cmdline)
{
bool state = true;
unsigned char c;
uint64_t mask;
uint64_t setmask = LIST_ALL_OPTIONS_MASK;
uint64_t amask = from_cmdline ? 0 : setmask;
const char * const *cmdline_next_plus =
&list_plus_options[from_cmdline ? 0 : ARRAY_SIZE(list_plus_options)-1];
while ((c = *str++)) {
uint64_t mask = 0;
switch (c) {
case '+':
state = true;
if (*cmdline_next_plus)
list_update_options(*cmdline_next_plus++, true);
setmask = LIST_ALL_OPTIONS_MASK;
break;
case '-':
state = false;
setmask = 0;
break;
case '*':
if (!from_cmdline)
setmask = cmdline_list_options;
break;
case '!':
mask = LIST_ALL_OPTIONS_MASK;
break;
default:
mask = list_option_mask(c);
if (state)
list_options |= mask;
else
list_options &= ~mask;
break;
}
if (mask) {
list_options = (list_options & ~mask) | (setmask & mask);
active_list_options =
(active_list_options & ~mask) |
(setmask & amask & mask);
}
}
if (from_cmdline)
cmdline_list_options = list_options;
}
enum directive_result list_pragma(const struct pragma *pragma)
{
switch (pragma->opcode) {
case D_OPTIONS:
list_update_options(pragma->tail);
list_update_options(pragma->tail, false);
return DIRR_OK;
default:

View file

@ -10,6 +10,21 @@
#include "nasm.h"
/* List options implied by -L+ */
#define LIST_PLUS_OPTIONS "bdefFmps"
/* Listing type values flags */
enum list_type {
/* Flags for lfmt->line() */
LIST_READ,
LIST_MACRO,
LIST_INFO,
/* Flags for lfmt->uplevel() */
LIST_INCLUDE,
LIST_INCBIN,
LIST_TIMES
};
/*
* List-file generators should look like this:
*/
@ -46,7 +61,7 @@ struct lfmt {
* If a line number is provided, print it; if the line number is
* -1 then use the same line number as the previous call.
*/
void (*line)(int type, int32_t lineno, const char *line);
void (*line)(enum list_type type, int32_t lineno, const char *line);
/*
* Called to change one of the various levelled mechanisms in the
@ -62,12 +77,12 @@ struct lfmt {
* macro, so anything under that level won't be expanded unless
* it includes another file.
*/
void (*uplevel)(int type, int64_t size);
void (*uplevel)(enum list_type type, int64_t size);
/*
* Reverse the effects of uplevel.
*/
void (*downlevel)(int type);
void (*downlevel)(enum list_type type);
/*
* Called on a warning or error, with the error message.
@ -93,7 +108,7 @@ extern bool user_nolist;
* These are simple bitmasks of ASCII-64 mapping directly to option
* letters.
*/
extern uint64_t list_options, active_list_options;
extern uint64_t list_options, active_list_options, cmdline_list_options;
/*
* This maps the characters a-z, A-Z and 0-9 onto a 64-bit bitmask.
@ -107,13 +122,10 @@ extern uint64_t list_options, active_list_options;
* This isn't particularly efficient code, but just about every
* instance of it should be fed a constant, so the entire function can
* be precomputed at compile time. The only cases where the full
* computation is needed is when parsing the -L option or %pragma list
* options, neither of which is in any way performance critical.
*
* The character + represents ALL listing options except -Lw (flush
* after every line.)
* computation is needed is in list_update_options(), which is not
* performance critical.
*/
static inline const_func uint64_t list_option_mask_val(unsigned char x)
static inline const_func uint64_t list_option_mask(unsigned char x)
{
if (x >= 'a') {
if (x > 'z')
@ -134,13 +146,7 @@ static inline const_func uint64_t list_option_mask_val(unsigned char x)
return UINT64_C(1) << x;
}
static inline const_func uint64_t list_option_mask(unsigned char x)
{
if (x == '+')
return ~(list_option_mask_val('w') | 3);
else
return list_option_mask_val(x);
}
#define LIST_ALL_OPTIONS_MASK (~UINT64_C(3))
/* Return true if the listing engine is active and a certain option is set. */
static inline pure_func bool list_option(unsigned char x)
@ -160,6 +166,9 @@ static inline pure_func bool list_active(void)
return (active_list_options & 1);
}
/* Change listing options */
void list_update_options(const char *str, bool from_cmdline);
/* Pragma handler */
enum directive_result list_pragma(const struct pragma *);

1121
asm/nasm.c

File diff suppressed because it is too large Load diff

View file

@ -964,8 +964,10 @@ restart_parse:
while (i == TOKEN_SPECIAL || i == TOKEN_SIZE) {
switch (tokval.t_integer) {
case S_BYTE:
if (!setsize) /* we want to use only the first */
if (!setsize) { /* we want to use only the first */
result->opt |= OPTIM_NO_Jcc_RELAX | OPTIM_NO_JMP_RELAX;
op->type |= BITS8;
}
setsize = 1;
break;
case S_WORD:
@ -1014,9 +1016,12 @@ restart_parse:
op->type |= FAR;
break;
case S_NEAR:
/* This is not legacy behavior, even if it perhaps should be */
result->opt |= OPTIM_NO_Jcc_RELAX | OPTIM_NO_JMP_RELAX;
op->type |= NEAR;
break;
case S_SHORT:
result->opt |= OPTIM_NO_Jcc_RELAX | OPTIM_NO_JMP_RELAX;
op->type |= SHORT;
break;
case S_ABS:
@ -1101,7 +1106,7 @@ restart_parse:
* as if it had ended in a comma, but sets the COLON flag
* on the operand further down.
*/
} else if (mref || !far_jmp_ok) {
} else if (mref || (ok_reg && IS_SREG(value->type))) {
/* segment override? */
mref = true;
@ -1250,6 +1255,7 @@ restart_parse:
if (!(eclass & ~(EC_RELOC | EC_UNKNOWN))) {
/* It is an immediate */
bool size_was_specified = false;
op->offset = reloc_value(value);
op->segment = reloc_seg(value);
op->wrt = reloc_wrt(value);
@ -1263,6 +1269,27 @@ restart_parse:
op->type |= IMM_NORMAL;
set_imm_flags(op, result->opt);
/*
* Catch a missing size specifier when dealing with a label -
* which might result in non-intentional handling of only part
* of the label's address instead of the whole value.
*/
for(int j = 0 ; j <= opnum ; j++)
size_was_specified |= !!(result->oprs[j].xsize & SIZE_MASK);
/*
* Raise a 'label operation missing size specifier' error when:
* 1. No size specifier was mentioned up to this point.
* 2. One of the operands is a memory reference.
* 3. The current operand is a label and not a simple immediate.
*/
if (!size_was_specified && (op->opflags & OPFLAG_FORWARD)) {
for(int j = 0 ; j <= opnum ; j++) {
if ((result->oprs[j].type & OPTYPE_MASK) == MEMORY)
nasm_fatal("size wasn't specified, some data may be omitted");
}
}
/*
* Special hack: if the previous operand was a colon
* immediate operand with an explicit size, and this

View file

@ -287,17 +287,14 @@ static enum directive_result output_pragma_common(const struct pragma *pragma)
switch (pragma->opcode) {
case D_PREFIX:
case D_GPREFIX:
set_label_mangle(LM_GPREFIX, pragma->tail);
return DIRR_OK;
case D_SUFFIX:
case D_GSUFFIX:
set_label_mangle(LM_GSUFFIX, pragma->tail);
return DIRR_OK;
case D_POSTFIX:
case D_GPOSTFIX:
case D_LPREFIX:
set_label_mangle(LM_LPREFIX, pragma->tail);
return DIRR_OK;
case D_LSUFFIX:
set_label_mangle(LM_LSUFFIX, pragma->tail);
case D_LPOSTFIX:
set_label_mangle(pragma->opcode, pragma->tail);
return DIRR_OK;
default:
return DIRR_UNKNOWN;

View file

@ -148,23 +148,33 @@ static bool is_smac_param(enum token_type toktype)
}
/*
* This is tuned so struct Token should be 64 bytes on 64-bit
* systems and 32 bytes on 32-bit systems. It enables them
* to be nicely cache aligned, and the text to still be kept
* inline for nearly all tokens.
* This is tuned so struct Token should be 64 bytes on 64-bit systems
* and 32 bytes on 32-bit systems. It enables them to be nicely cache
* aligned, and the text to still be kept inline for nearly all
* tokens.
*
* We prohibit tokens of length > MAX_TEXT even though
* length here is an unsigned int; this avoids problems
* if the length is passed through an interface with type "int",
* and is absurdly large anyway.
* We prohibit tokens of length > MAX_TEXT even though length here is
* an unsigned int; this avoids problems if the length is passed
* through an interface with type "int", and is absurdly large anyway.
*
* Use INT_MAX >> 2 to try to at least try to avoid risking wraparound
* even in the fairly extreme case when "int" is incorrectly used and
* two lengths are added. That is still 512GB with a 32-bit int...
*
* Earlier versions of the source code incorrectly stated that
* examining the text string alone can be unconditionally valid. This
* is incorrect, as some token types strip parts of the string,
* e.g. indirect tokens.
*
* The pointer for out of line token strings are located at the end of
* the buffer to maximize the likelihood of incorrectly examining
* text.a or text.p.ptr giving a null-terminated empty string or a
* NULL pointer, respectively, rather than something more dangerous.
* It still not something that should happen.
*/
#define INLINE_TEXT (7*sizeof(char *)-sizeof(enum token_type)-sizeof(unsigned int)-1)
#define MAX_TEXT (INT_MAX-2)
#define INLINE_TEXT (7*sizeof(char *)-sizeof(enum token_type) \
-sizeof(unsigned int)-1)
#define MAX_TEXT (INT_MAX >> 2)
struct Token {
Token *next;
@ -1981,6 +1991,9 @@ static Token *free_Token(Token *t)
nasm_assert(t->type != TOKEN_FREE);
next = t->next;
if (t->len > INLINE_TEXT)
nasm_free(t->text.p.ptr);
nasm_zero(*t);
t->type = TOKEN_FREE;
t->next = freeTokens;
@ -2011,6 +2024,8 @@ static inline Token *alloc_Token(void)
static Token *free_Token(Token *t)
{
Token *next = t->next;
if (t->len > INLINE_TEXT)
nasm_free(t->text.p.ptr);
nasm_free(t);
return next;
}
@ -2024,7 +2039,7 @@ static inline void free_Blocks(void)
static Token *do_delete_Token(Token **tp)
{
if (tp)
if (tp && *tp)
return *tp = free_Token(*tp);
else
return NULL;
@ -2269,12 +2284,11 @@ static int ppscan(void *private_data, struct tokenval *tokval)
txt = tok_text(tline);
tokval->t_start = txt;
tokval->t_len = tline->len;
tokval->t_charptr = (char *)txt; /* Fix this */
tokval->t_charptr = (char *)txt; /* Fix needing const removal here */
switch (tline->type) {
default:
break;
return tokval->t_type = tline->type;
case TOKEN_ID:
if (txt[0] == '$') {
@ -2755,19 +2769,20 @@ restart:
return false;
}
/* param should be a natural number [0; INT_MAX] */
static int read_param_count(const char *str)
{
int result;
int64_t result;
bool err;
result = readnum(str, &err);
if (result < 0 || result > INT_MAX) {
result = 0;
nasm_nonfatal("parameter count `%s' is out of bounds [%d; %d]",
str, 0, INT_MAX);
} else if (err)
if (err || result < 0) {
nasm_nonfatal("unable to parse parameter count `%s'", str);
return 0;
} else if (result > nasm_limit[LIMIT_PARAMS]) {
nasm_nonfatal("parameter count `%s' is too large (max %"PRId64")",
str, nasm_limit[LIMIT_PARAMS]);
return 0;
}
return result;
}
@ -3166,7 +3181,7 @@ iftype:
t = tline = expand_smacro(tline);
while (tok_white(t) ||
(needtype == TOKEN_NUM && (tok_is(t, '-') | tok_is(t, '+'))))
(needtype == TOKEN_NUM && (tok_is(t, '-') || tok_is(t, '+'))))
t = t->next;
j = tok_is(t, needtype);
@ -3283,12 +3298,13 @@ list_smacro_def(enum preproc_token op, const Context *ctx, const SMacro *m)
if (m->nparam) {
/*
* Space for ( and either , or ) around each
* parameter, plus up to 5 flags + /ux
* Space for "(" at the beginning, then up to 5 flags "=&&!+"
* + "/ux" + terminal "," or ")" per parameter, plus the parameter
* name, if any.
*/
int i;
size += 1 + 8 * m->nparam;
size += 1 + (5+3+1) * m->nparam;
for (i = 0; i < m->nparam; i++)
size += m->params[i].name.len;
}
@ -3460,6 +3476,8 @@ static int parse_smacro_template(Token ***tpp, SMacro *tmpl)
cp = NULL;
break;
}
if (!cp) /* stop on invalid radix specifier */
break;
}
} else {
if (name)
@ -4672,8 +4690,16 @@ static int do_directive(Token *tline, Token **output, bool suppressed)
/* Emulate legacy behavior */
do_clear(CLEAR_DEFINE|CLEAR_MMACRO, false);
} else {
while ((t = skip_white(t)) && t->type == TOKEN_ID) {
while (tok_is(t, TOKEN_ID)) {
const char *txt = tok_text(t);
/*
* Advance to the next token, skipping whitespace
* and optional comma separators.
*/
while ((t = skip_white(t->next)) && tok_is(t, ','))
;
if (!nasm_stricmp(txt, "all")) {
do_clear(CLEAR_ALL, context);
} else if (!nasm_stricmp(txt, "define") ||
@ -4704,6 +4730,7 @@ static int do_directive(Token *tline, Token **output, bool suppressed)
} else {
nasm_nonfatal("invalid option to %s: %s", dname, txt);
t = NULL;
break;
}
}
}
@ -4943,6 +4970,13 @@ static int do_directive(Token *tline, Token **output, bool suppressed)
break;
case PP_RMACRO:
{
op = PP_MACRO;
nasm_warn(WARN_PP_RESERVED,
"reserved directive `%s', treating as '%s'",
dname, pp_directives[op + !casesense]);
}
/* fall through */
case PP_MACRO:
{
MMacro *def;
@ -4951,8 +4985,10 @@ static int do_directive(Token *tline, Token **output, bool suppressed)
def = new_mmacro();
def->casesense = casesense;
#if 0
if (op == PP_RMACRO)
def->max_depth = nasm_limit[LIMIT_MACRO_LEVELS];
#endif
if (!parse_mmacro_spec(tline, def, dname)) {
free_mmacro(def);
goto done;
@ -5188,7 +5224,8 @@ static int do_directive(Token *tline, Token **output, bool suppressed)
case PP_EXITREP:
{
MMacro *m = do_exit_macro(dname, false);
m->in_progress = 1; /* No more repeats */
if (m)
m->in_progress = 1; /* No more repeats */
break;
}
@ -6254,7 +6291,6 @@ static Token **parse_smacro_args(Token **tp, int *nparamp, const SMacro *m)
int brackets = 0;
int paren;
bool bracketed = false;
bool bad_bracket = false;
int i;
enum sparmflags flags;
const struct smac_param *mparm;
@ -6353,8 +6389,6 @@ static Token **parse_smacro_args(Token **tp, int *nparamp, const SMacro *m)
if (!skip) {
Token *tt;
bad_bracket |= bracketed && !brackets;
if (white) {
*pep = tt = new_White(NULL);
pep = &tt->next;
@ -6464,7 +6498,7 @@ static SMacro *expand_one_smacro(Token ***tpp)
*/
while (1) {
if (!m) {
nasm_warn(WARN_PP_MACRO_PARAMS_SINGLE|ERR_HOLD,
nasm_warn(WARN_PP_MACRO_PARAMS_SINGLE,
"single-line macro `%s' exists, "
"but not taking %d parameter%s",
mname, nparam, (nparam == 1) ? "" : "s");
@ -8166,6 +8200,94 @@ stdmac_find(const SMacro *s, Token **params, int nparam)
return make_tok_num(NULL, found);
}
static Token *
stdmac_env(const SMacro *s, Token **params, int nparam)
{
const char *env;
(void)s;
env = pp_getenv(params[0], false);
if (!env) {
if (nparam > 1)
return new_Token(NULL, tok_smac_param(1), "", 0);
env = ""; /* No fallback argument */
}
return make_tok_qstr(NULL, env);
}
static Token *
stdmac_limit(const SMacro *s, Token **params, int nparam)
{
const char *which_str, *limit;
enum get_limit_which which;
int64_t val = 0;
(void)s;
(void)nparam;
which_str = unquote_token(params[1]);
if (!*which_str || !nasm_stricmp(which_str, "current")) {
which = GET_LIMIT_CURRENT;
} else if (!strcmp(which_str, "*") ||
!nasm_stricmp(which_str, "reset") ||
!nasm_stricmp(which_str, "init")) {
which = GET_LIMIT_INIT;
} else if (!nasm_stricmp(which_str, "default")) {
which = GET_LIMIT_DEFAULT;
} else if (!nasm_stricmp(which_str, "unlimited") ||
!nasm_stricmp(which_str, "maximum") ||
!nasm_stricmp(which_str, "max")) {
which = GET_LIMIT_MAX;
} else {
nasm_nonfatal("invalid second argument `%s' to %s()",
which_str, s->name);
goto err;
}
limit = unquote_token(params[0]);
if (!*limit || !nasm_stricmp(limit, "unlimited"))
val = LIMIT_MAX_VAL;
else
val = nasm_get_limit(limit, which);
err:
return make_tok_num(NULL, val);
}
/*
* Given the currently default or command-line default listing options
*/
static Token *
get_list_options(uint64_t optmask)
{
static const char optchars[63] =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
char optbuf[65], *p;
unsigned int i;
p = optbuf;
for (i = 0; i < 62; i++) {
if (optmask & 4)
*p++ = optchars[i];
optmask >>= 1;
}
*p = '\0';
return make_tok_qstr_len(NULL, optbuf, p-optbuf);
}
static Token *
stdmac_list_options(const SMacro *s, Token **params, int nparam)
{
(void)s;
(void)params;
(void)nparam;
return get_list_options(active_list_options);
}
/*
* Wrapper around define_smacro() which also checks to see if it is
* a preprocessor directive, so that pp_op_may_be_function[] needs to
@ -8204,6 +8326,7 @@ static void pp_add_magic_simple(void)
{ "__?BITS?__", true, 0, 0, stdmac_bits },
{ "__?PTR?__", true, 0, 0, stdmac_ptr },
{ "__?DEFAULT?__", true, 0, 0, stdmac_default },
{ "__?LIST_OPTIONS?__", true, 0, 0, stdmac_list_options },
{ "%abs", false, 1, SPARM_EVAL, stdmac_abs },
{ "%chr", false, 1, SPARM_EVAL|SPARM_OPTIONAL|SPARM_VARADIC, stdmac_chr },
{ "%count", false, 1, SPARM_VARADIC, stdmac_count },
@ -8375,6 +8498,29 @@ static void pp_add_magic_miscfunc(void)
tmpl.params[1].def = make_tok_qstr_len(NULL, "", 0);
define_magic("%b2hs", false, &tmpl);
/* %limit() function */
nasm_zero(tmpl);
tmpl.nparam = 2;
tmpl.expand = stdmac_limit;
tmpl.recursive = true;
nasm_newn(tmpl.params, tmpl.nparam);
tmpl.params[0].flags = SPARM_STR|SPARM_CONDQUOTE;
tmpl.params[1].flags = SPARM_STR|SPARM_CONDQUOTE|SPARM_OPTIONAL;
define_magic("%limit", false, &tmpl);
/* %env() function */
for (i = 1; i <= 2; i++) {
nasm_zero(tmpl);
tmpl.nparam = i;
tmpl.expand = stdmac_env;
tmpl.recursive = true;
nasm_newn(tmpl.params, tmpl.nparam);
tmpl.params[0].flags = SPARM_STR|SPARM_CONDQUOTE;
if (i > 1)
tmpl.params[1].flags = SPARM_GREEDY;
define_magic("%env", false, &tmpl);
}
/* %find[i]() functions */
for (i = 0; i < 2; i++) {
static const char * const names[] = { "%findi", "%find" };
@ -8424,6 +8570,26 @@ static void pp_start_stdmac(void)
}
}
static void pp_add_limits_stdmac(void)
{
int i;
Token *t = NULL;
for (i = LIMIT_MAX-1; i > 0; i--) {
t = make_tok_qstr(t, nasm_limit_name(i));
t = make_tok_char(t, ',');
}
t = make_tok_qstr(t, nasm_limit_name(0));
define_smacro("__?NASM_LIMITS?__", true, t, NULL);
}
static void pp_add_list_options_default_stdmac(void)
{
define_smacro("__?LIST_OPTIONS_DEFAULT?__", true,
get_list_options(cmdline_list_options), NULL);
}
static void pp_reset_stdmac(enum preproc_mode mode)
{
int apass;
@ -8439,6 +8605,9 @@ static void pp_reset_stdmac(enum preproc_mode mode)
pp_add_stdmac(&nasm_stdmac_version);
pp_add_stdmac(ofmt->stdmac);
pp_add_limits_stdmac();
pp_add_list_options_default_stdmac();
do_predef = true;
/*
@ -8469,7 +8638,7 @@ static void pp_reset_stdmac(enum preproc_mode mode)
define_smacro("__?PASS?__", true, make_tok_num(NULL, apass), NULL);
}
void pp_reset(const char *file, enum preproc_mode mode,
void pp_reset(const char *file, char const* mapped_fname, enum preproc_mode mode,
struct strlist *dep_list)
{
cstk = NULL;
@ -8508,7 +8677,7 @@ void pp_reset(const char *file, enum preproc_mode mode,
nasm_fatalf(ERR_NOFILE, "unable to open input file `%s'%s%s",
file, errno ? " " : "", errno ? strerror(errno) : "");
}
src_set(0, file);
src_set(0, mapped_fname);
istk->where = src_where();
istk->lineinc = 1;
@ -8531,6 +8700,36 @@ void pp_init(enum preproc_opt opt)
nasm_newn(use_loaded, use_package_count);
}
static Include *pop_include_stack(void)
{
Include *i = istk;
if (i->fp)
fclose(i->fp);
if (i->conds) {
/*
* This should never happen for a builtin macro package,
* but if it does, at least get an error message out...
*/
nasm_fatal("expected `%%endif' before end of %s",
i->fp ? "file" : "macro package");
}
istk = i->next;
if (!i->nolist)
lfmt->downlevel(LIST_INCLUDE);
if (!i->noline) {
struct src_location whereto
= istk ? istk->where : src_nowhere();
if (ppdbg & PDBG_INCLUDE)
dfmt->debug_include(false, whereto, i->where);
src_update(whereto);
}
return i;
}
/*
* Get a line of tokens. If we popped the macro expansion/include stack,
* we return a pointer to the dummy token tok_pop; at that point if
@ -8698,25 +8897,8 @@ static Token *pp_tokline(void)
/*
* The current file/input has ended; work down the istk
*/
Include *i = istk;
Include *i = pop_include_stack();
if (i->fp)
fclose(i->fp);
if (i->conds)
nasm_fatal("expected `%%endif' before end of file");
istk = i->next;
if (!i->nolist)
lfmt->downlevel(LIST_INCLUDE);
if (!i->noline) {
struct src_location whereto
= istk ? istk->where : src_nowhere();
if (ppdbg & PDBG_INCLUDE)
dfmt->debug_include(false, whereto, i->where);
if (istk)
src_update(istk->where);
}
put_mmacro(&i->mstk.mstk);
put_mmacro(&i->mstk.mmac);
@ -8831,10 +9013,19 @@ void pp_cleanup_pass(void)
{
if (defining) {
if (defining->name) {
nasm_nonfatal("end of file while still defining macro `%s'",
nasm_nonfatal("end of input while still defining macro `%s'",
defining->name);
} else {
nasm_nonfatal("end of file while still in %%rep");
nasm_nonfatal("end of input while still in %%rep");
}
if (defining->refcnt != 0)
{
/* This can happen if a macro is ill formed without a correct ending
* and the macro is still referenced.
* In this case, we just set the refcnt to 0 to avoid a memory leak.
*/
defining->refcnt = 0;
}
free_mmacro(defining);
@ -8844,19 +9035,8 @@ void pp_cleanup_pass(void)
while (cstk)
ctx_pop();
free_macros();
while (istk) {
Include *i = istk;
istk = istk->next;
fclose(i->fp);
if (!istk && (ppdbg & PDBG_INCLUDE)) {
/* Signal closing the top-level input file */
dfmt->debug_include(false, src_nowhere(), i->where);
}
nasm_free(i);
}
while (cstk)
ctx_pop();
src_set_fname(NULL);
while (istk)
nasm_free(pop_include_stack());
if (ppdbg & PDBG_MMACROS)
debug_macro_output();
@ -9015,7 +9195,7 @@ make_tok_num_radix(Token *next, int64_t val, char radix, bool uns)
upper = !(radix & 0x20);
}
p += numstr(p, 64, uval, -1, base, upper);
p += numstr(p, sizeof(numbuf)-2, uval, -1, base, upper);
next = new_Token(next, TOKEN_NUM, numbuf, p - numbuf);
if (minus)

View file

@ -269,36 +269,35 @@ char *nasm_quote_cstr(const char *str, size_t *lenp)
* to indicate the lead marker of a quoted string. If it is '\"', then
* '`' is not a special character at all.
*/
enum unq_state {
st_start,
st_backslash,
st_byte, /* Byte numeric sequence */
st_ucs, /* \u or \U */
st_ctrl, /* \c */
st_done
};
size_t nasm_unquote_anystr(char *str, char **ep, const uint32_t badctl,
const char qstart)
{
unsigned char bq;
const unsigned char *p;
const unsigned char *escp = NULL;
unsigned char *q;
const unsigned char bq = *str;
const unsigned char *p = (unsigned char *)str;
unsigned char *q = (unsigned char *)str;
unsigned char c;
uint32_t ctlmask = 0; /* Mask of control characters seen */
enum unq_state {
st_start,
st_backslash,
st_hex,
st_oct,
st_ucs,
st_done
} state;
int ndig = 0;
uint32_t nval = 0;
p = q = (unsigned char *)str;
bq = *p++;
if (!bq)
return 0;
if (bq == (unsigned char)qstart) {
/* `...` string */
state = st_start;
/* `...` string or "..." with C unquoting */
enum unq_state state = st_start;
unsigned int base = 0; /* Base of numeric escape sequence */
uint64_t nval = 0; /* Accumulated value of numeric sequence */
unsigned int v;
int ndig = 0; /* Max digits of numeric sequence */
/* ndig < 0 means braced sequence */
const unsigned char *escp = NULL; /* Pointer to immediately after \ */
p++; /* Skip initial quote */
while (state != st_done) {
c = *p++;
@ -306,17 +305,18 @@ size_t nasm_unquote_anystr(char *str, char **ep, const uint32_t badctl,
case st_start:
if (c == '\\') {
state = st_backslash;
} else if ((c == '\0') | (c == bq)) {
} else if (c == '\0' || c == bq) {
state = st_done;
} else {
EMIT(c);
}
break;
break;
case st_backslash:
state = st_start;
escp = p; /* Beginning of argument sequence */
escp = p-1;
nval = 0;
switch (c) {
case 'a':
nval = 7;
@ -339,22 +339,33 @@ size_t nasm_unquote_anystr(char *str, char **ep, const uint32_t badctl,
case 't':
nval = 9;
break;
case '^':
state = st_ctrl;
break;
case 'u':
state = st_ucs;
base = 16;
ndig = 4;
break;
goto check_brace;
case 'U':
state = st_ucs;
base = 16;
ndig = 8;
break;
goto check_brace;
case 'v':
nval = 11;
break;
case 'x':
case 'X':
state = st_hex;
state = st_byte;
base = 16;
ndig = 2;
break;
goto check_brace;
case 'd': /* NASM extension: \d = decimal */
state = st_byte;
base = 10;
ndig = 3;
goto check_brace;
case '0':
case '1':
case '2':
@ -363,10 +374,19 @@ size_t nasm_unquote_anystr(char *str, char **ep, const uint32_t badctl,
case '5':
case '6':
case '7':
state = st_oct;
ndig = 2; /* Up to two more digits */
nval = c - '0';
break;
/* Back up both p and escp, as if there had been an "o" */
p = escp--;
/* fall through */
case 'o':
state = st_byte;
ndig = 3;
base = 8;
check_brace: /* Is this the start of a braced sequence? */
if (*p == '{') {
p++; /* Skip brace */
ndig = -1;
}
break;
case '\0':
nval = '\\';
p--; /* Reprocess; terminates string */
@ -379,31 +399,24 @@ size_t nasm_unquote_anystr(char *str, char **ep, const uint32_t badctl,
EMIT(nval);
break;
case st_oct:
if (c >= '0' && c <= '7') {
nval = (nval << 3) + (c - '0');
if (--ndig)
break; /* Might have more digits */
} else {
p--; /* Process this character again */
}
EMIT(nval);
state = st_start;
break;
case st_hex:
case st_byte:
case st_ucs:
if (nasm_isxdigit(c)) {
nval = (nval << 4) + numvalue(c);
if ((v = numvalue_chk(c)) < base) {
nval = (nval * base) + v;
if (--ndig)
break; /* Might have more digits */
break; /* Continue processing number, no output */
} else if (ndig < 0) {
/* End of braced sequence */
if (unlikely(c != '}'))
goto rewind;
} else {
p--; /* Process this character again */
p--; /* Reprocess terminating character */
if (unlikely(p == escp+1))
goto rewind; /* No digits at all received */
}
if (unlikely(p <= escp))
EMIT(escp[-1]);
else if (state == st_ucs)
/* Emit the output */
if (state == st_ucs)
EMIT_UTF8(nval);
else
EMIT(nval);
@ -411,6 +424,23 @@ size_t nasm_unquote_anystr(char *str, char **ep, const uint32_t badctl,
state = st_start;
break;
case st_ctrl:
if (!c)
goto rewind;
else if (c == '?')
c = 0177; /* DEL */
else
c &= 0x9f; /* Any thing else */
EMIT(c);
state = st_start;
break;
/* Rewind an entire sequence as invalid */
rewind:
p = escp; /* Start over at character following \ */
state = st_start;
break;
default:
panic();
}
@ -421,10 +451,11 @@ size_t nasm_unquote_anystr(char *str, char **ep, const uint32_t badctl,
* * any kind, including collapsing double quote marks.)
* We obviously can't get here if qstart == '\"'.
*/
while ((c = *p++) && (c != bq))
p++; /* Skip initial quote */
while ((c = *p++) && c != bq)
EMIT(c);
} else {
/* Not a quoted string, just return the input... */
/* Not a quoted string, just return the input */
while ((c = *p++))
EMIT(c);
}
@ -435,8 +466,11 @@ size_t nasm_unquote_anystr(char *str, char **ep, const uint32_t badctl,
if (ctlmask & badctl)
nasm_nonfatal("control character in string not allowed here");
if (ep)
if (ep) {
/* Point at the terminating character */
*ep = (char *)p - 1;
}
return (char *)q - str;
}
#undef EMIT
@ -471,11 +505,7 @@ char *nasm_skip_string(const char *str)
char bq;
const char *p;
char c;
enum unq_state {
st_start,
st_backslash,
st_done
} state;
enum unq_state state;
bq = str[0];
p = str+1;
@ -509,13 +539,20 @@ char *nasm_skip_string(const char *str)
case st_backslash:
/*
* Note: for the purpose of finding the end of the string,
* all successor states to st_backslash are functionally
* equivalent to st_start, since either a backslash or
* a backquote will force a return to the st_start state,
* and any possible multi-character state will terminate
* for any non-alphanumeric character.
* Note: for the purpose of finding the end of the
* string, all successor states to st_backslash except
* st_ctrl are functionally equivalent to st_start,
* since either a backslash or a backquote will force
* a return to the st_start state, and any possible
* multi-character state will terminate for any
* non-alphanumeric character.
*
* This state is necessary to prevent \` and \^` from
* being treated as a terminator, or \^\ from being treated
* as an escape (\^\` *is* an end of string terminator.)
*/
if (c == '^')
c = *p++;
state = c ? st_start : st_done;
break;

View file

@ -40,7 +40,7 @@ char *uncompress_stdmac(macros_t *sm)
zs.zalloc = nasm_z_alloc;
zs.zfree = nasm_z_free;
if (inflateInit2(&zs, 0) != Z_OK)
if (inflateInit2(&zs, 15) != Z_OK)
panic();
if (inflate(&zs, Z_FINISH) != Z_STREAM_END)

View file

@ -9,6 +9,11 @@ db-empty [on] no operand for data declaration
This is permitted, but often indicative of an error.
See \k{db}.
directive-garbage-eol [err] garbage after directive
Text was found after a directive. This is a warning so it can be
suppressed, because previous versions of NASM did not check for
this condition.
ea-absolute [on] absolute address cannot be RIP-relative
Warns that an address that is inherently absolute cannot
be generated with RIP-relative encoding using \c{REL},
@ -217,11 +222,20 @@ pp-open-string [on] unterminated string
Warns that a quoted string without a closing quotation
mark was encountered during preprocessing.
pp-rep-negative [on] regative \c{%rep} count
pp-rep-negative [on] negative \c{%rep} count
=negative-rep
Warns about a negative count given to the \c{%rep}
preprocessor directive.
pp-reserved [on] reserved unimplemented preprocessor directive
Warns that a preprocessor directive which was inadvertently
permitted in earlier versions of NASM without having been properly
implemented was seen in the source code. This currently applies to
the \i\c{%rmacro} (treated as \c{%macro}) and \i\c{%irmacro}
(treated as \c{%imacro}) directives. These directive names are
reserved and may be properly implemented in the future, changing
the meaning of the source code. directive is
pp-sel-range [on] \c{%sel()} argument out of range
Warns that the \c{%sel()} preprocessor function was passed
a value less than 1 or larger than the number of available
@ -254,6 +268,12 @@ pragma-unknown [off] unknown \c{%pragma} facility or directive
Warns about an unknown \c{%pragma} directive.
This is not yet implemented for most cases.
prefix-badmode-o64 [err] o64 prefix invalid in 16/32-bit mode
Warns that an \c{a64} prefix was specified in 16- or 32-bit
mode. If the error is demoted to a warning or suppressed, the
prefix is ignored by the assembler, but is likely to trigger
futher errors.
prefix-bnd [on] invalid \c{BND} prefix
=bnd
Warns about ineffective use of the \c{BND} prefix when the
@ -297,7 +317,7 @@ prefix-lock-xchg [on] superfluous \c{LOCK} prefix on \c{XCHG} instruction
prefix-opsize [on] invalid operand size prefix
Warns that an operand prefix (\c{o16}, \c{o32}, \c{o64},
\c{osp}) invalid for the specified instruction has been specified.
\c{osp}) is invalid for the specified instruction has been specified.
The operand prefix will be ignored by the assembler.
prefix-seg [on] segment prefix ignored in 64-bit mode

View file

@ -199,6 +199,7 @@ if ($what eq 'c') {
print $out " const char *name;\n";
print $out " enum warn_index warning;\n";
print $out "};\n\n";
printf $out "#define NUM_WARNINGS %d\n", $#warn_noall + 2;
printf $out "#define NUM_WARNING_ALIAS %d\n", scalar(keys %aliases);
printf $out "extern const char * const warning_name[%d];\n",
@ -206,10 +207,8 @@ if ($what eq 'c') {
printf $out "extern const char * const warning_help[%d];\n",
$#warnings + 2;
print $out "extern const struct warning_alias warning_alias[NUM_WARNING_ALIAS];\n";
printf $out "extern const uint8_t warning_default[%d];\n",
$#warn_noall + 2;
printf $out "extern uint8_t warning_state[%d];\n",
$#warn_noall + 2;
printf $out "extern const uint8_t warning_default[NUM_WARNINGS];\n",
printf $out "extern uint8_t warning_state[NUM_WARNINGS];\n",
print $out "\n#endif /* $guard */\n";
} elsif ($what eq 'doc') {
my %wsec = ('on' => [], 'off' => [], 'err' => [],

View file

@ -5,9 +5,10 @@ dnl Set debug flags and optimization flags depending on if
dnl --enable-debug is set or not. Some flags are set regardless...
dnl --------------------------------------------------------------------------
AC_DEFUN([PA_OPTION_DEBUG],
[PA_ARG_DISABLED([gdb], [disable gdb debug extensions],
[PA_ADD_LANGFLAGS([-g3])], [PA_ADD_LANGFLAGS([-ggdb3],[-g3])])
[PA_ADD_LANGFLAGS([-g3])
PA_ARG_DISABLED([gdb], [disable gdb debug extensions],,
[PA_ADD_LANGFLAGS([-ggdb])])
PA_ARG_ENABLED([debug], [optimize for debugging],
[PA_ADD_LANGFLAGS([-Og],[-O0])
[PA_ADD_LANGFLAGS([-Og],[-O0])
$1],
[$2])])

View file

@ -7,15 +7,24 @@ dnl but that could change in the future -- to force disabled by default,
dnl set to "no".
dnl --------------------------------------------------------------------------
AC_DEFUN([PA_OPTION_LTO],
[AC_BEFORE([$0],[AC_PROG_AR])dnl
AC_BEFORE([$0],[AC_PROG_RANLIB])dnl
PA_ARG_BOOL([lto],
[
dnl Careful here: AR or RANLIB may already have already been probed for.
dnl If not, do it now to prevent it from getting down further down.
dnl Do it unconditionally to avoid inconsistent behavior with or
dnl without --enable-lto.
AS_IF([test -z "$AR"], [AC_CHECK_TOOL(AR, ar)])
AS_IF([test -z "$RANLIB"], [AC_CHECK_TOOL(RANLIB, ranlib, :)])
PA_ARG_BOOL([lto],
[Try to enable link-time optimization for this compiler],
[m4_default([$1],[no])],
[PA_FIND_FLAGS([-flto=auto],[-flto])
PA_FIND_FLAGS([-ffat-lto-objects])
PA_FIND_FLAGS([-fuse-linker-plugin])
dnl Add here if there are any other toolchains that need special magic
AS_IF([test x$ac_compiler_gnu = xyes],
[AC_CHECK_TOOL(AR, [gcc-ar], [ar], [:])
AC_CHECK_TOOL(RANLIB, [gcc-ranlib], [ranlib], [:])])])])
[AC_CHECK_TOOL(CC_AR, gcc-ar)
AR="${CC_AR:-$AR}"
AC_CHECK_TOOL(CC_RANLIB, gcc-ranlib)
RANLIB="${CC_RANLIB:-$RANLIB}"])])])

View file

@ -15,6 +15,15 @@
*/
struct globalopt globl;
void reset_global_defaults(int bits)
{
globl.bits = bits;
globl.bnd = false;
globl.rel = 0;
globl.reldef = EAF_FS|EAF_GS;
globl.dollarhex = true;
}
/*
* Name of a register token, if applicable; otherwise NULL
*/

109
common/errstubs.c Normal file
View file

@ -0,0 +1,109 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/* Copyright 1996-2025 The NASM Authors - All Rights Reserved */
#include "compiler.h"
#include "nasmlib.h"
#include "error.h"
struct errinfo erropt;
/* Common function body */
#define nasm_do_error(_sev,_flags) \
do { \
const errflags nde_severity = (_sev); \
const errflags nde_flags = nde_severity | (_flags); \
va_list ap; \
va_start(ap, fmt); \
if (nde_severity >= ERR_CRITICAL) { \
nasm_verror_critical(nde_flags, fmt, ap); \
unreachable(); \
} else { \
nasm_verror(nde_flags, fmt, ap); \
if (nde_severity >= ERR_FATAL) \
unreachable(); \
} \
va_end(ap); \
} while (0)
/*
* This is the generic function to use when the error type is not
* known a priori. For ERR_DEBUG and ERR_INFO the level can be
* included by
*/
void nasm_error(errflags flags, const char *fmt, ...)
{
nasm_do_error(flags & ERR_MASK, flags);
}
#define nasm_err_helpers(_type, _name, _sev) \
_type nasm_ ## _name ## f (errflags flags, const char *fmt, ...) \
{ \
nasm_do_error(_sev, flags); \
} \
_type nasm_ ## _name (const char *fmt, ...) \
{ \
nasm_do_error(_sev, 0); \
}
nasm_err_helpers(void, listmsg, ERR_LISTMSG)
nasm_err_helpers(void, note, ERR_NOTE)
nasm_err_helpers(void, nonfatal, ERR_NONFATAL)
nasm_err_helpers(fatal_func, fatal, ERR_FATAL)
nasm_err_helpers(fatal_func, critical, ERR_CRITICAL)
nasm_err_helpers(fatal_func, panic, ERR_PANIC)
/*
* Strongly discourage warnings without level by require flags on warnings.
* This means nasm_warn() is the equivalent of the -f variants of the
* other ones.
*
* This is wrapped in a macro to be able to elide it if the warning is
* disabled, hence the extra underscore.
*/
void nasm_warn_(errflags flags, const char *fmt, ...)
{
nasm_do_error(ERR_WARNING, flags);
}
/*
* nasm_info() and nasm_debug() takes mandatory enabling levels.
*/
void nasm_info_(unsigned int level, const char *fmt, ...)
{
if (info_level(level))
nasm_do_error(ERR_INFO, LEVEL(level));
}
void nasm_debug_(unsigned int level, const char *fmt, ...)
{
if (debug_level(level))
nasm_do_error(ERR_DEBUG, LEVEL(level));
}
/*
* Convenience function for nasm_nonfatal(ERR_HOLD, ...)
*/
void nasm_holderr(const char *fmt, ...)
{
nasm_do_error(ERR_NONFATAL, ERR_NONFATAL|ERR_HOLD);
}
/*
* panic() and nasm_assert()
*/
fatal_func nasm_panic_from_macro(const char *func, const char *file, int line)
{
if (!func)
func = "<unknown>";
nasm_panic("internal error in %s at %s:%d\n", func, file, line);
}
fatal_func nasm_assert_failed(const char *msg, const char *func,
const char *file, int line)
{
if (!func)
func = "<unknown>";
nasm_panic("assertion %s failed in %s at %s:%d", msg, func, file, line);
}

76
common/files.c Normal file
View file

@ -0,0 +1,76 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/* Copyright 2026 The NASM Authors - All Rights Reserved */
#include "compiler.h"
#include "nasmlib.h"
#include "files.h"
#include "error.h"
/* These must match the constants in "files.h" */
static const char * const filename_names[FN_NFILES] = {
"input",
"output",
"error",
"list",
"dependency",
"map",
NULL, /* End of "real" filenames */
"debug mapped input",
"make mapped output"
};
const char *_filenames[FN_NFILES];
const char *copy_filename(enum filenames fn, const char *src)
{
return set_filename(fn, nasm_strdup(src));
}
const char *set_filename(enum filenames fn, char *src)
{
const char **dstp, *dst;
nasm_assert((size_t)fn < ARRAY_SIZE(_filenames));
dstp = &_filenames[fn];
dst = *dstp;
if (dst) {
nasm_fatal("more than one %s file specified: %s and %s",
filename_names[fn], dst, src);
}
return *dstp = src;
}
void check_overwrite_files(void)
{
enum filenames fi, fo; /* No fie or fum */
for (fi = FN_INFILE; fi < FN_OUTFILE; fi++) {
const char *inname = get_filename(fi);
if (!inname)
continue;
for (fo = FN_OUTFILE; fo < FN_NFILES_REAL; fo++) {
const char *outname = get_filename(fo);
if (outname && !nasm_compare_paths(inname, outname)) {
nasm_nonfatal("%s file would overwrite %s file `%s'",
filename_names[fo], filename_names[fi], inname);
}
}
}
}
void cleanup_filenames(void)
{
enum filenames fn;
for (fn = 0; fn < FN_NFILES; fn++) {
nasm_free((char *)_filenames[fn]);
_filenames[fn] = NULL;
}
}

View file

@ -25,6 +25,12 @@
#ifndef NASM_CONFIG_MSVC_H
#define NASM_CONFIG_MSVC_H
/* Needed for the _BitScanReverse()/_BitScanReverse64() intrinsics below;
not available prior to Visual Studio 2005. */
#if _MSC_VER >= 1400
# include <intrin.h>
#endif
/* Define to 1 if you have the <fcntl.h> header file. */
#define HAVE_FCNTL_H 1
@ -33,9 +39,25 @@
# define HAVE_INTTYPES_H 1
#endif
/* Define to 1 if you have the <intrin.h> header file. */
#if _MSC_VER >= 1400
# define HAVE_INTRIN_H 1
#endif
/* Define to 1 if you have the <io.h> header file. */
#define HAVE_IO_H 1
/* Define to 1 if you have the <stdarg.h> header file. */
#define HAVE_STDARG_H 1
/* Define to 1 if you have the <stdint.h> header file. */
#if _MSC_VER >= 1600
# define HAVE_STDINT_H 1
#endif
/* Define to 1 if you have the <stdio.h> header file. */
#define HAVE_STDIO_H 1
/* Define to 1 if you have the <stdlib.h> header file. */
#define HAVE_STDLIB_H 1
@ -48,6 +70,9 @@
/* Define to 1 if you have the <sys/types.h> header file. */
#define HAVE_SYS_TYPES_H 1
/* Define to 1 if you have the <wchar.h> header file. */
#define HAVE_WCHAR_H 1
/* Define to 1 if you have the `access' function. */
#define HAVE_ACCESS 1
#if _MSC_VER < 1400
@ -60,6 +85,13 @@
# define fileno _fileno
#endif
/* Define to 1 if you have the `isascii' function. */
#define HAVE_ISASCII 1
#define isascii __isascii
/* Define to 1 if you have the `iscntrl' function. */
#define HAVE_ISCNTRL 1
/* Define to 1 if you have the `snprintf' function. */
#define HAVE_SNPRINTF 1
#if _MSC_VER < 1900
@ -77,6 +109,25 @@
/* Define to 1 if you have the `_filelengthi64' function. */
#define HAVE__FILELENGTHI64 1
/* Define to 1 if you have the `_byteswap_ushort' intrinsic function. */
#define HAVE__BYTESWAP_USHORT 1
/* Define to 1 if you have the `_byteswap_ulong' intrinsic function. */
#define HAVE__BYTESWAP_ULONG 1
/* Define to 1 if you have the `_byteswap_uint64' intrinsic function. */
#define HAVE__BYTESWAP_UINT64 1
/* Define to 1 if you have the `_BitScanReverse' intrinsic function. */
#if _MSC_VER >= 1400
# define HAVE__BITSCANREVERSE 1
#endif
/* Define to 1 if you have the `_BitScanReverse64' intrinsic function. */
#if (defined(_M_X64) || defined(_M_ARM64)) && _MSC_VER >= 1400
# define HAVE__BITSCANREVERSE64 1
#endif
/* Define to 1 if you have the `_fseeki64' function. */
#define HAVE__FSEEKI64 1
@ -132,6 +183,18 @@
# define uintptr_t size_t
#endif
/* Define to 1 if the system has the type `uintmax_t'. */
#ifdef HAVE_STDINT_H
# define HAVE_UINTMAX_T 1
#else
/* Define to the widest unsigned integer type if <stdint.h> and <inttypes.h>
do not define. */
# define uintmax_t unsigned long long
#endif
/* Define to 1 if the system has the type `unsigned long long int'. */
#define HAVE_UNSIGNED_LONG_LONG_INT 1
/* Define to 1 if you have the `vsnprintf' function. */
#define HAVE_VSNPRINTF 1
#if _MSC_VER < 1400

View file

@ -91,10 +91,10 @@ AC_PROG_MAKE_SET
AC_PROG_INSTALL
AC_PROG_MKDIR_P
AC_CHECK_PROGS([NROFF], nroff, false)
AC_CHECK_PROGS([ASCIIDOC], asciidoc, false)
AC_CHECK_PROGS([XMLTO], xmlto, false)
AC_CHECK_PROGS([XZ], xz, false)
AC_CHECK_PROGS([PYTHON3], [python3 python], false)
dnl Check for progs needed for manpage generation
MANPAGES=manpages
@ -148,7 +148,7 @@ AC_SUBST([NSIS])
dnl Check for host compiler tools
AC_CHECK_TOOL(AR, ar)
AC_CHECK_TOOL(RANLIB, ranlib, :)
AC_CHECK_TOOL(STRIP, strip)
AC_CHECK_TOOL(STRIP, strip, :)
dnl
dnl NOTE: the tests for header files and library functions use constructs
@ -196,7 +196,6 @@ AC_CHECK_FUNCS(strcasecmp stricmp)
AC_CHECK_FUNCS(strncasecmp strnicmp)
AC_CHECK_FUNCS(strsep)
AC_CHECK_FUNCS(strnlen)
AC_CHECK_FUNCS(strrchrnul)
AC_CHECK_FUNCS(iscntrl)
AC_CHECK_FUNCS(isascii)
AC_CHECK_FUNCS(mempcpy)
@ -223,11 +222,11 @@ AC_CHECK_FUNCS(sysconf)
AC_CHECK_FUNCS([access _access faccessat])
PA_HAVE_FUNC(__builtin_expect,(1,1))
PA_HAVE_FUNC(__builtin_unreachable,())
PA_FUNC_SNPRINTF
PA_FUNC_VSNPRINTF
AC_CHECK_FUNCS([strlcpy])
AC_CHECK_FUNCS([strrchrnul])
dnl These types are POSIX-specific, and Windows does it differently...
AC_CHECK_TYPES([struct stat], [AC_CHECK_FUNCS([stat fstat])])
@ -244,7 +243,6 @@ AC_CHECK_DECLS(strnicmp)
AC_CHECK_DECLS(strsep)
AC_CHECK_DECLS(strlcpy)
AC_CHECK_DECLS(strnlen)
AC_CHECK_DECLS(strrchrnul)
dnl Check for missing types
AC_TYPE_UINTMAX_T
@ -373,5 +371,5 @@ dnl
PA_CHECK_BAD_STDC_INLINE
PA_C_TYPEOF
AC_CONFIG_FILES([Makefile doc/Makefile misc/Makefile test/Makefile])
AC_CONFIG_FILES([Makefile doc/Makefile misc/Makefile test/Makefile travis.mak])
AC_OUTPUT

View file

@ -109,35 +109,48 @@ static enum reg_enum whichreg(opflags_t regflags, int regval, uint32_t rex)
}
/*
* An implicit register operand
* An implicit register operand.
*/
/* Deal with OpenWatcom 64-bit switch() braindamage */
#ifdef __WATCOMC__
# define imp(op,rn) if (regflags == op) return rn
# define impdef(rn) return rn
#else
# define imp(op,rn) case op: return rn
# define impdef(rn) default: return rn
#endif
static enum reg_enum implicit_reg(opflags_t regflags)
{
switch (regflags) {
case REG_AL: return R_AL;
case REG_AX: return R_AX;
case REG_EAX: return R_EAX;
case REG_RAX: return R_RAX;
case REG_DL: return R_DL;
case REG_DX: return R_DX;
case REG_EDX: return R_EDX;
case REG_RDX: return R_RDX;
case REG_CL: return R_CL;
case REG_CX: return R_CX;
case REG_ECX: return R_ECX;
case REG_RCX: return R_RCX;
case FPU0: return R_ST0;
case XMM0: return R_XMM0;
case YMM0: return R_YMM0;
case ZMM0: return R_ZMM0;
case REG_ES: return R_ES;
case REG_CS: return R_CS;
case REG_SS: return R_SS;
case REG_DS: return R_DS;
case REG_FS: return R_FS;
case REG_GS: return R_GS;
case OPMASK0: return R_K0;
default: return 0;
#ifndef __WATCOMC__
switch (regflags)
#endif
{
imp(REG_AL,R_AL);
imp(REG_AX,R_AX);
imp(REG_EAX,R_EAX);
imp(REG_RAX,R_RAX);
imp(REG_DL,R_DL);
imp(REG_DX,R_DX);
imp(REG_EDX,R_EDX);
imp(REG_RDX,R_RDX);
imp(REG_CL,R_CL);
imp(REG_CX,R_CX);
imp(REG_ECX,R_ECX);
imp(REG_RCX,R_RCX);
imp(FPU0,R_ST0);
imp(XMM0,R_XMM0);
imp(YMM0,R_YMM0);
imp(ZMM0,R_ZMM0);
imp(REG_ES,R_ES);
imp(REG_CS,R_CS);
imp(REG_SS,R_SS);
imp(REG_DS,R_DS);
imp(REG_FS,R_FS);
imp(REG_GS,R_GS);
imp(OPMASK0,R_K0);
impdef(0);
}
}
@ -550,11 +563,14 @@ static int matches(const uint8_t *data, const struct prefix_info *prefix,
opx->segment |= SEG_SIGNED;
break;
case4(020):
case4(0300):
if (!is_hint_nop(*data))
return 0;
opx->offset = *data++;
opx->disp_size = 8;
break;
case4(020):
case4(024):
opx->offset = *data++;
opx->disp_size = 8;
@ -1500,7 +1516,7 @@ int32_t disasm(const uint8_t *dp, int32_t data_size,
slen += append_evex_reg_deco(output + slen, outbufsize - slen,
deco, &prefix);
} else if (t & IMMEDIATE) {
if (is_class(t, UNITY)) {
if (is_class(UNITY, t)) {
output[slen++] = '1';
} else if (o->segment & SEG_DFV) {
int fl;

View file

@ -87,4 +87,8 @@ const uint8_t *parse_prefixes(struct prefix_info *pf, const uint8_t *data,
_op; \
} while (0)
/* Error module */
void usage(void);
#endif

46
disasm/diserror.c Normal file
View file

@ -0,0 +1,46 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/* Copyright 1996-2025 The NASM Authors - All Rights Reserved */
/*
* diserror.c - stubs for the error functions for the disassembler
*/
#include "compiler.h"
#include "error.h"
#include "disasm.h"
void usage(void)
{
const char help[] =
"usage: ndisasm [-aihlruvw] [-b bits] [-o origin] [-s sync...]\n"
" [-e bytes] [-k start,bytes] [-p vendor] file\n"
" -a or -i activates auto (intelligent) sync\n"
" -b 16, -b 32 or -b 64 sets the processor mode\n"
" -u same as -b 32\n"
" -l same as -b 64\n"
" -w wide output (avoids continuation lines)\n"
" -h displays this text\n"
" -r or -v displays the version number\n"
" -e skips <bytes> bytes of header\n"
" -k avoids disassembling <bytes> bytes from position <start>\n"
" -p selects the preferred vendor instruction set (intel, amd, cyrix, idt)\n";
fputs(help, stderr);
}
void nasm_verror(errflags severity, const char *fmt, va_list val)
{
severity &= ERR_MASK;
vfprintf(stderr, fmt, val);
if (severity >= ERR_FATAL)
exit(severity - ERR_FATAL + 1);
}
fatal_func nasm_verror_critical(errflags severity, const char *fmt, va_list val)
{
nasm_verror(severity, fmt, val);
abort();
}
uint8_t warning_state[NUM_WARNINGS];

View file

@ -18,41 +18,12 @@
#include "sync.h"
#include "disasm.h"
const char *_progname;
static int bpl = 8; /* bytes per line of hex dump */
static const char *help =
"usage: ndisasm [-aihlruvw] [-b bits] [-o origin] [-s sync...]\n"
" [-e bytes] [-k start,bytes] [-p vendor] file\n"
" -a or -i activates auto (intelligent) sync\n"
" -b 16, -b 32 or -b 64 sets the processor mode\n"
" -u same as -b 32\n"
" -l same as -b 64\n"
" -w wide output (avoids continuation lines)\n"
" -h displays this text\n"
" -r or -v displays the version number\n"
" -e skips <bytes> bytes of header\n"
" -k avoids disassembling <bytes> bytes from position <start>\n"
" -p selects the preferred vendor instruction set (intel, amd, cyrix, idt)\n";
static void output_ins(uint64_t, const uint8_t *, int, const char *);
static void skip(uint32_t dist, FILE * fp);
void nasm_verror(errflags severity, const char *fmt, va_list val)
{
severity &= ERR_MASK;
vfprintf(stderr, fmt, val);
if (severity >= ERR_FATAL)
exit(severity - ERR_FATAL + 1);
}
fatal_func nasm_verror_critical(errflags severity, const char *fmt, va_list val)
{
nasm_verror(severity, fmt, val);
abort();
}
errflags errflags_never = 0;
static bool skip(off_t *posp, off_t dist, FILE *fp);
int main(int argc, char **argv)
{
@ -61,21 +32,27 @@ int main(int argc, char **argv)
char outbuf[256];
char *pname = *argv;
char *filename = NULL;
uint32_t nextsync, synclen, initskip = 0L;
int lenread;
int32_t lendis;
uint64_t nextsync, synclen;
size_t lenread;
bool autosync = false;
int bits = 16, b;
bool eof = false;
bool eof;
iflag_t prefer;
bool rn_error;
int64_t offset;
uint64_t offset, dataread, datamax;
off_t fileoffs, initskip;
FILE *fp;
_progname = argv[0];
reset_global_defaults(0);
nasm_ctype_init();
iflag_clear_all(&prefer);
offset = 0;
offset = 0;
datamax = UINT64_C(-1);
initskip = 0;
init_sync();
while (--argc) {
@ -90,7 +67,7 @@ int main(int argc, char **argv)
p++;
break;
case 'h':
fputs(help, stderr);
usage();
return 0;
case 'r':
case 'v':
@ -111,6 +88,23 @@ int main(int argc, char **argv)
bpl = 16;
p++;
break;
case 'z': /* max number of bytes to read */
v = p[1] ? p + 1 : --argc ? *++argv : NULL;
if (!v) {
fprintf(stderr, "%s: `-z' requires an argument\n",
pname);
return 1;
}
datamax = readnum(v, &rn_error);
if (rn_error) {
fprintf(stderr,
"%s: `-z' requires a numeric argument\n",
pname);
return 1;
}
p = ""; /* force to next argument */
break;
case 'b': /* bits */
v = p[1] ? p + 1 : --argc ? *++argv : NULL;
if (!v) {
@ -253,8 +247,8 @@ int main(int argc, char **argv)
}
if (!filename) {
fprintf(stderr, help, pname);
return 0;
usage();
return 1;
}
if (strcmp(filename, "-")) {
@ -269,8 +263,12 @@ int main(int argc, char **argv)
fp = stdin;
}
if (initskip > 0)
skip(initskip, fp);
reset_global_defaults(bits);
fileoffs = 0;
dataread = 0;
if (!skip(&fileoffs, initskip, fp))
return 1; /* EOF before header */
/*
* This main loop is really horrible, and wants rewriting with
@ -280,35 +278,42 @@ int main(int argc, char **argv)
q = p = buffer;
nextsync = next_sync(offset, &synclen);
do {
int32_t to_read = buffer + sizeof(buffer) - p;
lenread = 0;
eof = false;
while (lenread > 0 || (dataread < datamax && !eof && !feof(fp))) {
size_t to_read = buffer + sizeof(buffer) - p;
if ((nextsync || synclen) &&
to_read > nextsync - offset - (p - q))
to_read = nextsync - offset - (p - q);
if (to_read > datamax - dataread)
to_read = datamax - dataread;
lenread = 0;
if (to_read) {
lenread = fread(p, 1, to_read, fp);
if (lenread == 0)
eof = true; /* help along systems with bad feof */
} else
lenread = 0;
p += lenread;
if ((nextsync || synclen) &&
(uint32_t)offset == nextsync) {
dataread += lenread;
fileoffs += lenread;
p += lenread;
eof |= !lenread; /* help along systems with bad feof */
}
if ((nextsync || synclen) && offset == nextsync) {
if (synclen) {
fprintf(stdout, "%08"PRIX64" skipping 0x%"PRIX32" bytes\n",
fprintf(stdout, "%08"PRIX64" skipping 0x%"PRIX64" bytes\n",
offset, synclen);
offset += synclen;
skip(synclen, fp);
dataread += synclen;
eof |= skip(&fileoffs, synclen, fp);
}
q = p = buffer;
nextsync = next_sync(offset, &synclen);
}
while (p > q && (p - q >= INSN_MAX || lenread == 0)) {
lendis = disasm(q, INSN_MAX, outbuf, sizeof(outbuf),
bits, offset, autosync, &prefer);
if (!lendis || lendis > (p - q)
|| ((nextsync || synclen) &&
(uint32_t)lendis > nextsync - offset))
size_t lendis = disasm(q, INSN_MAX, outbuf, sizeof(outbuf),
bits, offset, autosync, &prefer);
if (!lendis || q + lendis > p ||
((nextsync || synclen) && lendis > nextsync - offset))
lendis = eatbyte(*q, outbuf, sizeof(outbuf), bits);
output_ins(offset, q, lendis, outbuf);
q += lendis;
@ -320,7 +325,7 @@ int main(int argc, char **argv)
p -= (q - buffer);
q = buffer;
}
} while (lenread > 0 || !(eof || feof(fp)));
}
if (fp != stdin)
fclose(fp);
@ -332,7 +337,8 @@ static void output_ins(uint64_t offset, const uint8_t *data,
int datalen, const char *insn)
{
int bytes;
fprintf(stdout, "%08"PRIX64" ", offset);
int addrwidth;
addrwidth = fprintf(stdout, "%08"PRIX64" ", offset);
bytes = 0;
while (datalen > 0 && bytes < bpl) {
@ -341,42 +347,57 @@ static void output_ins(uint64_t offset, const uint8_t *data,
datalen--;
}
fprintf(stdout, "%*s%s\n", (bpl + 1 - bytes) * 2, "", insn);
fprintf(stdout, "%*s %s\n", (bpl - bytes) << 1, "", insn);
while (datalen > 0) {
fprintf(stdout, " -");
fprintf(stdout, "%*s", addrwidth, "-");
bytes = 0;
while (datalen > 0 && bytes < bpl) {
fprintf(stdout, "%02X", *data++);
bytes++;
datalen--;
}
fprintf(stdout, "\n");
putchar('\n');
}
}
/*
* Skip a certain amount of data in a file, either by seeking if
* possible, or if that fails then by reading and discarding.
* Returns true if successful, false on EOF; updates posp.
*/
static void skip(uint32_t dist, FILE * fp)
static bool skip(off_t *posp, off_t dist, FILE *fp)
{
char buffer[256]; /* should fit on most stacks :-) */
if (!dist)
return true;
/*
* Got to be careful with fseek: at least one fseek I've tried
* doesn't approve of SEEK_CUR. So I'll use SEEK_SET and
* ftell... horrible but apparently necessary.
* doesn't approve of SEEK_CUR (WHICH ONE?). Weird...
*/
if (fseek(fp, dist + ftell(fp), SEEK_SET)) {
if (!fseeko(fp, *posp + dist, SEEK_SET)) {
*posp += dist;
} else {
off_t pos = ftello(fp);
if (pos != (off_t)-1) {
/* Possibly a partial seek? */
dist -= (pos - *posp);
*posp = pos;
}
while (dist > 0) {
uint32_t len = (dist < sizeof(buffer) ?
dist : sizeof(buffer));
if (fread(buffer, 1, len, fp) < len) {
perror("fread");
exit(1);
}
dist -= len;
static char junk_buf[BUFSIZ];
size_t len = sizeof junk_buf;
size_t skipped;
if (dist < (off_t)len)
len = dist;
skipped = fread(junk_buf, 1, len, fp);
dist -= skipped;
*posp += skipped;
if (skipped < len)
return false; /* EOF */
}
}
return true;
}

View file

@ -11,9 +11,6 @@
#include "nasmlib.h"
#include "sync.h"
#define SYNC_MAX_SHIFT 31
#define SYNC_MAX_SIZE (1U << SYNC_MAX_SHIFT)
/* initial # of sync points (*must* be power of two)*/
#define SYNC_INITIAL_CHUNK (1U << 12)
@ -24,12 +21,12 @@
static struct Sync {
uint64_t pos;
uint32_t length;
uint64_t length;
} *synx;
static uint32_t max_synx, nsynx;
static size_t max_synx, nsynx;
static inline void swap_sync(uint32_t dst, uint32_t src)
static inline void swap_sync(size_t dst, size_t src)
{
struct Sync t = synx[dst];
synx[dst] = synx[src];
@ -43,31 +40,35 @@ void init_sync(void)
nsynx = 0;
}
void add_sync(uint64_t pos, uint32_t length)
void add_sync(uint64_t pos, uint64_t length)
{
uint32_t i;
size_t i;
static bool synx_oom = false;
if (nsynx >= max_synx) {
if (max_synx >= SYNC_MAX_SIZE) /* too many sync points! */
struct Sync *xsynx;
size_t xmaxsynx = max_synx << 1;
if (synx_oom || xmaxsynx < max_synx ||
!(xsynx = realloc(synx, (xmaxsynx + 1) * sizeof(*synx)))) {
synx_oom = true;
return;
max_synx = (max_synx << 1);
synx = nasm_realloc(synx, (max_synx + 1) * sizeof(*synx));
}
}
nsynx++;
synx[nsynx].pos = pos;
synx[nsynx].length = length;
for (i = nsynx; i > 1; i /= 2) {
if (synx[i / 2].pos > synx[i].pos)
swap_sync(i / 2, i);
for (i = nsynx; i > 1; i >>= 1) {
if (synx[i >> 1].pos > synx[i].pos)
swap_sync(i >> 1, i);
}
}
uint64_t next_sync(uint64_t position, uint32_t *length)
uint64_t next_sync(uint64_t position, uint64_t *length)
{
while (nsynx > 0 && synx[1].pos + synx[1].length <= position) {
uint32_t i, j;
size_t i, j;
swap_sync(nsynx, 1);
nsynx--;

View file

@ -9,7 +9,7 @@
#define NASM_SYNC_H
void init_sync(void);
void add_sync(uint64_t position, uint32_t length);
uint64_t next_sync(uint64_t position, uint32_t *length);
void add_sync(uint64_t position, uint64_t length);
uint64_t next_sync(uint64_t position, uint64_t *length);
#endif

View file

@ -6,8 +6,6 @@
# UNIX Makefile for NASM documentation
#
@SET_MAKE@
PACKAGE_NAME = @PACKAGE_NAME@
PACKAGE_TARNAME = @PACKAGE_TARNAME@
@ -91,7 +89,7 @@ htmltarget=html/nasm00.html
html: $(HTMLAUX)
$(MKDIR_P) html
for f in $(HTMLAUX); do $(CP_UF) "$(srcdir)/$$f" html/; done
for f in $(HTMLAUX); do $(CP_F) "$(srcdir)/$$f" html/; done
$(MAKE) $(htmltarget)
RDSRC = $(RUNPERL) $(srcdir)/rdsrc.pl -I$(srcdir) -M$(@F).dep

View file

@ -11,6 +11,141 @@ evolving code simpler.
It is the production version of NASM since 2025.
\S{cl-3.02} Version 3.02
\b Fix build problems on C23 compilers using a pre-C23 version of
\c{<stdbool.h>} which defines \c{bool} as a macro in violation of the
C23 specification.
\b The immediate form of the \c{JMPE} instruction (opcode \c{0F B8})
has been changed to an absolute address, as in
the Itanium Architecture Software Developer's Manual, version 2.3,
Volume 4, page 4:249. Hopefully this won't break whatever virtual
environments use \c{JMPE}, but it is the closest thing there is to
an official specification for this opcode.
\> Being an \e{absolute} address, treat it equivalent to a \c{FAR}
jump and do not default to 64 bits in 64-bit mode.
\> That \c{JMPE} has apparently been wrong all these years is probably
as good of a hint as any how much it has been actually used, but it
\e{does} have the possibility of breaking virtual environments. In
that case, please file a bug report to
\W{https://bugs.nasm.us/}\c{https://bugs.nasm.us} with details about the
virtual environment, and we will figure out a suitable solution.
\b Various build fixes. Fix the documentation not building on MacOS
because of the \c{cp} utility lacking \c{-u} there. Also fix not
building generally due to wrong link formatting. Another fix was a
typo in \c{compiler.h} related to a C++ check.
\b Corrections to assembling encodings:
\> Fix \c{CMP} allowing \c{LOCK} which is illegal.
\> Correct multiple \c{AVX512} instructions such as \c{VCVTSD2SI},
\c{VCVTSD2USI}, \c{VCVTSS2SI}, \c{VCVTSS2USI}, \c{VCVTTSD2SI},
\c{VCVTTSD2USI}, \c{VCVTTSS2SI}, \c{VCVTTSS2USI}, \c{VGETEXPSH},
\c{VGETMANTSH}, \c{MOVDDUP}, \c{VMOVDDUP}.
\> Fixed other encodings or instruction formats for instructions \c{UWRMSR},
\c{CMPSD}, \c{VCMPSS}, \c{V4FMADDSS}, \c{V4FNMADDSS}, \c{VCVTDQ2PH},
\c{VCVTPD2PH}, \c{VCVTPH2UDQ}, \c{VCVTQQ2PH}, \c{VCVTUDQ2PH}, \c{VCVTUQQ2PH},
\c{VGETEXPSH}, \c{VGETMANTSH}, \c{VRCPPH}, \c{VRSQRTPH}, \c{VCVTPH2BF8},
\c{VCVTPH2BF8S}, \c{VCVTPH2HF8}, \c{VCVTPH2HF8S}.
\> Fixed typos in \c{VP4DPWSSD} mnemonic.
\> Fixed \c{BYTE} and \c{WORD} operands getting the same encoding on
arithmetic instructions such as \c{CMP}.
\> Fixed \c{PUSH} not assembling when used with a \c{DWORD} in 64-bit
mode. This is not a recommended syntax as the operand size is still
64 bits, but was permitted by earlier versions of NASM.
\> Fix parsing of \c{$}-escaped symbols in directives (\c{GLOBAL},
\c{STATIC}, \c{EXTERN}, \c{REQUIRED}, \c{COMMON}).
\b Corrections to disassembling:
\> Shift instructions with the unity operand were getting disassembled to a zero
operand instead of one.
\> \c{JMP}, \c{CALL} and \c{JMPE} disassembled incorrectly with the
register operands.
\b Whole bunch of minor fixes to operand sizes, operand size prefixes. Changes
mostly return the behavior known from 2.16.03.
\> \c{MOV [mem], label} would be accepted without size specifiers
which could cause unintended consequences. Raise an error if no
size was specified and one of the operands is a memory reference
and another operands is a label.
\> \c{JMP NEAR} is now the same as \c{JMP STRICT NEAR} as the
\c{STRICT} is redundant here. \c{JMP WORD} on the other hand is
up for optimization as \c{NEAR} and \c{WORD} relate to different
things - jump lengths and operation sizes respectively.
\> Using redundant (or not) but valid operands size prefixes was fixed on
instructions such as \c{IRET}, \c{PUSHF}, \c{POPF}, \c{PUSH} and \c{POP}.
\> Using an operand size prefix on a \c{JMP} or \c{CALL} instruction
could generate an invalid instruction. This appears to have been a
long-standing bug. Specifying the operand size by specifying the
size of the immediate explicitly (e.g. \c{JMP DWORD label}) has
always worked correctly, however.
\b Add support for C2y-style \c{\\o} escape sequences, braced escape
sequences, and as NASM extensions, decimal escape sequences
(\c{\\d}) and control-character escape sequences (\c{\\^}). See
\k{strings}.
\b Fix generation of the short opcodes for \c{ADD}, \c{OR}, \c{ADC},
\c{SBB}, \c{AND}, \c{SUB}, \c{XOR}, and \c{CMP AL,imm8}.
\b Fix truncation of the generated constant to 63 bits when invoking a
single-line macro when an argument is defined as \c{=/b} or
\c{=/ub}.
\b Add an \c{%env()} preprocessor function as a more robust and
flexible alternative to the \c{%!} construct. See \k{f_env}.
\b The maximum number of multi-line macro parameters is now a
configurable limit. See \k{opt-limit}.
\b The \c{--limit-} options and \c{%pragma limit} now accept the
keywords \c{default}, \c{maximum}, and \c{reset}. See
\k{opt-limit}.
\b Fix parsing of \c{seg:offs}-style \c{FAR} pointers in \c{EQU}.
\b Fix the \c{%clear} preprocessor directive hanging when given parameters.
\b The never properly implemented (or documented) preprocessor
directives \c{%rmacro} and \c{%irmacro} are now properly disabled; to
avoid breaking existing code, they fall back to \c{%macro} and
\c{%imacro} with a suitable warning.
\> Programmers should \e{not} rely on this behavior: in the future,
these directives might actually be (properly) implemented.
\b Fix a crash when \c{-M} directives were used in response files.
\b New listing option \c{-Lc} to include the contents of \c{INCBIN}
files, see \k{opt-L}.
\b New listing option \c{-Lt} to include the output from every
iteration of \c{TIMES} and \c{ALIGN} directives, see \k{opt-L}.
\b The \c{%pragma list options} directive now support resetting
options to their command-line default, see \k{opt-L}.
\b New predefined macros \c{__?LIST_OPTIONS?__} and
\c{__?LIST_OPTIONS_DEFAULT?__} to query the active and command-line
default listing options. See \k{opt-L}.
\S{cl-3.01} Version 3.01
\b A new \c{obj2} version of the \c{obj} output format, intended for
@ -36,10 +171,32 @@ It is the production version of NASM since 2025.
\b A new \c{--bits} option as convenience shorthand for \c{--before
"BITS ..."}. See \k{opt-bits}.
\b Add aliases \c{--suffix}, \c{--gsuffix} and \c{--lsuffix} for the
corresponding \c{postfix} options. See \k{opt-pfix}.
\b The options and pragmas for configuring external label mangling
were inconsistent, the former using the spelling \c{postfix} and
the latter \c{suffix}. Furthermore, these were also documented as
\e{directives} in addition to pragmas. Implement the already
documented directives (bracketed forms only) and allow both
\c{postfix} and \c{suffix} in all cases.
\b Define additional permissive patterns and fix some opcode bugs.
\> See \k{opt-pfix} and \k{mangling}.
\b Define additional permissive patterns and fix several opcode bugs.
\b Fix parsing of two-operand forms of x87 instructions.
\b Fix bogus "absolute address can not be RIP-relative" warning.
\b Hopefully fix building with OpenWatcom.
\b Generate a warning, promoted to error by default, on the use of
\c{o64} prefixes in 16- or 32-bit mode. If demoted to a warning or
suppressed the prefix is ignored, but likely will trigger
subsequent, harder to debug, error messages.
\b More consistent handling of jump and call instructions with
specified operand sizes.
\b Fix an operand size handling bug in the \c{CMPXCHG} instruction.
\S{cl-3.00} Version 3.00

View file

@ -402,26 +402,38 @@ global variables).
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
\IR{PREFIX} \c{[PREFIX]}
\IC{PREFIX}{GPREFIX} \c{[GPREFIX]}
\IC{PREFIX}{LPREFIX} \c{[LPREFIX]}
\IC{PREFIX}{SUFFIX} \c{[SUFFIX]}
\IC{PREFIX}{GSUFFIX} \c{[GSUFFIX]}
\IC{PREFIX}{LSUFFIX} \c{[LSUFFIX]}
\IC{PREFIX}{POSTFIX} \c{[POSTFIX]}
\IC{PREFIX}{GPOSTFIX} \c{[GPOSTFIX]}
\IC{PREFIX}{LPOSTFIX} \c{[LPOSTFIX]}
\c{PREFIX}, \c{GPREFIX}, \c{LPREFIX}, \c{POSTFIX}, \c{GPOSTFIX}, and
\c{LPOSTFIX} directives can prepend or append a string to a certain
\H{mangling} \I{PREFIX}\c{[[GL]PREFIX]}, \c{[[GL]SUFFIX]}: Mangling Symbols
\c{[PREFIX]}, \c{[GPREFIX]}, \c{[LPREFIX]}, \c{[SUFFIX]}, \c{[GSUFFIX]}, and
\c{[LSUFFIX]} directives can prepend or append a string to a certain
type of symbols, normally to fit specific ABI conventions
\b\c{PREFIX}|\c{GPREFIX}: Prepend the argument to all \c{EXTERN},
\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
\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{[SUFFIX]}, \c{[GSUFFIX]}, \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
\b\c{[LSUFFIX]}, \c{[LPOSTFIX]}: Append the argument to all other symbols
such as local labels and backend defined symbols.
These are macros implemented as pragmas, and using \c{%pragma} syntax
can be restricted to specific backends (see \k{pragma}):
These directives are also implemented as pragmas, and using
\c{%pragma} syntax can be restricted to specific backends (see
\k{pragma}):
\c %pragma macho lprefix L_
@ -443,13 +455,19 @@ naming scheme to chunk up sections into smaller subsections, each of
which may be eliminated. When the \c{subsections_via_symbols}
directive (\k{macho-ssvs}) is declared, each symbol is the start of a
separate block. The subsection is, then, defined to include sections
before the one that starts with a 'L'. \c{LPREFIX} is useful here to
before the one that starts with a 'L'. \c{[LPREFIX]} is useful here to
mark all local symbols with the 'L' prefix to be excluded to the meta
section. It converts local symbols compatible with the particular
toolchain. Note that local symbols declared with \c{STATIC}
(\k{static}) are excluded from the symbol mangling and also not marked
as global.
Earlier versions of NASM called the pragmas \i\c{suffix} and the
options \i\c{--postfix}, and did not implement directives at all
despite being so documented. Since NASM 3.01, the directive forms are
implemented, and directives, pragmas and options all support all
spellings.
\H{CPU} \i\c{CPU}: Defining CPU Dependencies

View file

@ -195,6 +195,8 @@
\IR{boolean or} boolean, OR
\IR{boolean xor} boolean, XOR
\IR{netbsd} NetBSD
\IA{.nolist}{nolist}
\IR{nolist} \c{.nolist}
\IR{nsis} NSIS
\IR{nullsoft scriptable installer} Nullsoft Scriptable Installer
\IA{.OBJ}{.obj}

View file

@ -442,7 +442,6 @@ quotes allows double quotes to appear within it and vice versa); the
contents of those are represented verbatim. Strings enclosed in
backquotes support C-style \c{\\}-escapes for special characters.
The following \i{escape sequences} are recognized by backquoted strings:
\c \' single quote (')
@ -463,6 +462,24 @@ The following \i{escape sequences} are recognized by backquoted strings:
\c \u1234 4 hexadecimal digits - Unicode character
\c \U12345678 8 hexadecimal digits - Unicode character
NASM 3.02 added the following additional sequences:
\c \o377 Up to 3 octal digits - literal byte (from C2y)
\c \d255 Up to 3 decimal digits - literal byte (NASM extension)
\c \^? ASCII DEL (\d127, \177)
\c \^X Convert X to a control character (e.g. \cA = \ca = \001)
Since NASM 3.02, the numeric escape sequences starting with \c{\\x},
\c{\\o}, \c{\\d} or \c{\\u} can have their argument enclosed in curly
braces to delimit their length, instead of terminating after a certain
number of digits or a non-digit another character:
\c \x{FF} Hexadecimal, literal byte
\c \o{377} Octal, literal byte
\c \d{255} Decimal, literal byte
\c \u{1234} Unicode character
\c \u{12345} Unicode character
All other escape sequences are reserved. Note that \c{\\0}, meaning a
\c{NUL} character (ASCII 0), is a special case of the octal escape
sequence.
@ -471,6 +488,8 @@ sequence.
\i{UTF-8}. For example, the following lines are all equivalent:
\c db `\u263a` ; UTF-8 smiley face
\c db `\U0000263a` ; UTF-8 smiley face
\c db `\u{263a}` ; UTF-8 smiley face
\c db `\xe2\x98\xba` ; UTF-8 smiley face
\c db 0E2h, 098h, 0BAh ; UTF-8 smiley face
@ -691,13 +710,13 @@ characters.
\S{expbor}: \i\c{||}: \i{Boolean OR} Operator
The \c{||} operator gives a boolean OR: it evaluates to 1 if both sides of
the expression are nonzero, otherwise 0.
The \c{||} operator gives a boolean OR: it evaluates to 1 if either side of
the expression is nonzero, otherwise 0.
\S{expbxor}: \i\c{^^}: \i{Boolean XOR} Operator
The \c{^^} operator gives a boolean XOR: it evaluates to 1 if any one side of
The \c{^^} operator gives a boolean XOR: it evaluates to 1 if exactly one side of
the expression is nonzero, otherwise 0.
@ -973,6 +992,7 @@ NASM has the capacity to define other special symbols beginning with
a double period: for example, \c{..start} is used to specify the
entry point in the \c{obj} output format (see \k{dotdotstart}),
\c{..imagebase} is used to find out the offset from a base address
of the current image in the \c{win64} output format (see \k{win64pic}).
of the current image in the \c{win64} output format (see \k{win64pic}),
\c{..symtab} is used to emit the COFF symbol table index (see \k{win32wrt}).
So just keep in mind that symbols beginning with a double period are
special.

View file

@ -645,13 +645,14 @@ It will get linked into the \c{.text} section anyway - see the info on
\W{https://github.com/MicrosoftDocs/win32/blob/docs/desktop-src/Debug/pe-format.md#grouped-sections-object-only}\c{Grouped Sections}.
\c section .text$1 align=16 comdat=1:FirstFnc
\c ... ; Code linked only if referenced from C
\c ... ; Code linked only if referenced from C
\c
\c section .text$1 align=16 comdat=1:SecondFnc
\c ... ; Code linked only if referenced from C
\c ... ; Code linked only if referenced from C
\c
\c section .rdata align=32 comdat=5:FirstFnc
\c ... ; Data linked only if the related code (FirstFnc) is linked
\c ... ; Data linked onlyif the related code
\c ; (FirstFnc) is linked
\c
The defaults assumed by NASM if you do not specify the above
@ -758,6 +759,33 @@ data for "safe exception handler table" causes no backward
incompatibilities and "safeseh" modules generated by NASM 2.03 and
later can still be linked by earlier versions or non-Microsoft linkers.
\S{win32wrt} \c{win32}: Special Symbol and WRT
The Microsoft linker may require symbol table indexes instead of absolute or
image relative addresses in some more modern structures, like those used for
exception handler control flow guard metadata (ehcont). This can be
accomplished by getting the symbol address with respect to the special
\c{..symtab} symbol. For instance:
\c __guard_ehcont_main: dd main.cont wrt ..symtab
\S{win32glob} \c{win32} Extensions to the \c{GLOBAL}, \c{EXTERN} and
\c{STATIC} Directives\I{GLOBAL, win32 extensions to}\I{EXTERN, win32
extensions to}\I{STATIC, win32 extensions to}
You can specify whether a symbol is a function by suffixing the name
with a colon and the word \i\c{function}. For example:
\c global hashlookup:function
\c static localfunc:function
\c extern extfunc:function
The linker may use this extra symbol information when generating tables of
valid indirect branch targets and such.
\S{codeview} Debugging formats for Windows
\I{Windows debugging formats}
@ -1414,6 +1442,15 @@ Declaring the type and size of global symbols is necessary when
writing shared library code. For more information, see
\k{picglobal}.
NASM supports the GNU indirect function symbol type using the keyword
\c{gnu_ifunc}. This marks the symbol as \c{STT_GNU_IFUNC} and causes the
dynamic loader to call the symbol as a resolver at runtime. For example:
\c global func_ifunc:function
\c
\c global func:gnu_ifunc
\c func equ func_ifunc
\S{elfextrn} \c{elf} Extensions to the \c{EXTERN} Directive\I{EXTERN,
elf extensions to}\I{EXTERN, elf extensions to}

View file

@ -146,6 +146,31 @@ running in preprocessor-only mode, to the output file (see \k{opt-E});
if necessary prefixed by a newly inserted \i\c{%line} directive.
\H{ppcaveats} \i{Preprocessor caveats}\I{caveats, preprocessor}
\S{ppcase} Case Insensitivity\I{case sensitivity, preprocessor}
The NASM preprocessor allows the user to create case-insensitive
macros using directives prefixed with \c{%i} for 'insensitive'
(\i\c{%idefine}, \i\c{%imacro}, etc.) However, this is limited by NASM
inherently not being aware of the character set used in either the
source code nor the output object code.
The primary intended use for case-insensitive macros is to override
NASM keywords or instructions. Therefore, \e{NASM case insensitivity
is limited to the ASCII character range only.} NASM does permit
non-ASCII characters (bytes with values above 127) in macros (and
labels), but treats them as opaque bytes that can only be matched
exactly.
In general, it is recommended to avoid using case insensitive macros
unless you have specific reasons to need them.
The same caveat applies to any other case-insensitive matching: the
\i\c{%ifidni} and \i\c{%elifidni} directives and the \i\c{%isidni()}
and \i\c{%findi()} functions.
\H{slmacro} \i{Single-Line Macros}
Single-line macros are expanded inline, much like macros in the C
@ -185,13 +210,13 @@ Otherwise it will be treated as an expansion. For example:
\c %define bar(a,b) ; two arguments, empty expansion
Macros defined with \c{%define} are \i{case sensitive}: after
Macros defined with \c{%define} are case sensitive: after
\c{%define foo bar}, only \c{foo} will expand to \c{bar}: \c{Foo} or
\c{FOO} will not. By using \c{%idefine} instead of \c{%define} (the
`i' stands for `insensitive') you can define all the case variants
of a macro at once, so that \c{%idefine foo bar} would cause
\c{foo}, \c{Foo}, \c{FOO}, \c{fOO} and so on all to expand to
\c{bar}.
\c{bar}. See however \k{ppcase}.
There is a mechanism which detects when a macro call has occurred as
a result of a previous expansion of the same macro, to guard against
@ -291,7 +316,7 @@ To have a reference to an embedded single-line macro resolved at the
time that the embedding macro is \e{defined}, as opposed to when the
embedding macro is \e{expanded}, you need a different mechanism to the
one offered by \c{%define}. The solution is to use \c{%xdefine}, or
it's \I{case sensitive}case-insensitive counterpart \c{%ixdefine}.
it's case-insensitive counterpart \c{%ixdefine}.
Suppose you have the following code:
@ -486,7 +511,7 @@ command-line using the `-u' option on the NASM command line: see
\S{assign} \i{Preprocessor Variables}: \i\c{%assign}
An alternative way to define single-line macros is by means of the
\c{%assign} command (and its \I{case sensitive}case-insensitive
\c{%assign} command (and its case-insensitive
counterpart \i\c{%iassign}, which differs from \c{%assign} in
exactly the same way that \c{%idefine} differs from \c{%define}).
@ -759,7 +784,7 @@ treats an empty argument list as a single empty argument.
\S{f_depend} \i\c\{%depend()} Function
he \c{%depend()} function takes a quoted string as argument, adds it
The \c{%depend()} function takes a quoted string as argument, adds it
to the output dependency list generated by the \c{-M} options (see
\k{opt-M}), and evaluates to the unchanged string.
@ -769,6 +794,31 @@ This is the function equivalent of the \c{%depend} directive, see
See also the \c{%pathsearch()} function (\k{f_pathsearch}).
\S{f_env} \i\c{%env()} Function
The \c{%env()} function takes an optionally quoted string as its first
argument, and if an environment variable with that name exists,
expands to a quoted string with the value of that environment
variable. If the environment variable does \e{not} exist, expands to
any additional arguments given, or to an empty quoted string if no
additional arguments are provided.
\c ; This example assumes USER=nasmuser and MISSING is undefined
\c
\c db %env(USER) ; db 'nasmuser'
\c db %env("USER") ; db 'nasmuser'
\c db %env("USER",0) ; db 'nasmuser'
\c db %env(MISSING) ; db ''
\c db %env("MISSING",0xff) ; db 0xff
\c db %env("MISSING",1,"2",3) ; db 1,"2",3
\c
\c ; This line generates a warning for "db" without data:
\c db %env("MISSING",) ; db
See also the \c{%ifenv} directive (\k{ifenv}) and the \c{%!}
construct (\k{getenv}).
\S{f_eval} \i\c{%eval()} Function
The \c{%eval()} function evaluates its argument as a numeric
@ -793,7 +843,7 @@ by an optional list. These are turned into quoted strings if
necessary, and then compared as if by the \i\c{%isidn()} or
\i\c{%isidni()} functions, respectively (see \k{ifidn}) \- the
\c{%find()} function compares case sensitively, and \c{%findi()} case
insensitively.
insensitively; see however \k{ppcase}.
The functions then expand to \c{0} if none of the strings in the list
match the first string, or the position in the list where the first
@ -863,6 +913,45 @@ Unlike the C \c{defined()} preprocessor construct, these functions are
valid anywhere in the source code, not just in \c{%if} expressions.
\S{f_limit} \i\c{%limit()} Function
The \c{%limit()} function takes as its first argument an optionally
quoted string which is matched against a resource limit as defined by
the \c{--limit-} command line option or the \c{%pragma limit}
directive (see \k{opt-limit}). The macro then expands to the value of
that limit, or \c{0} if no limit with that name is known in the
current version of NASM.
An optional second argument can be set to one of the following
optionally quoted strings:
\b \c{current}: the current value for the limit. This is also the result
if no second argument is specified.
\b \e{reset}: the initial value for the limit, set on the command line
or the default value if no such value is set; this is the value
that \c{%pragma limit} \e{limit-name} \c{reset} would set the limit
to.
\b \e{default}: the default value for the limit. This is the
value that \c{%pragma limit} \e{limit-name} \c{default} would set
the limit to.
\b \e{maximum}: the maximum permitted value for the limit. This is the
value that \c{%pragma limit} \e{limit-name} \c{maximum} would set
the limit to.
The value \c{unlimited} is represented by a very large positive
number. If the limit name is the empty string or \c{unlimited},
\c{%limit()} returns this value for comparison purposes.
The standard macro \c{__?NASM_LIMITS?__} expands to a comma-separated
list of quoted strings representing all limits defined in the current
version of NASM, see \k{nasm_limits}.
The \c{%limit()} function was introduced in NASM 3.02.
\S{f_map} \i\c{%map()} Function
The \c{%map()} function takes as its first parameter the name of a
@ -1577,7 +1666,7 @@ however, \c{%-1} will report an error if passed either of these,
because no inverse condition code exists.
\S{nolist} \i{Disabling Listing Expansion}\I\c{.nolist}
\S{nolist} \i{Disabling Listing Expansion}\i\c{.nolist}
When NASM is generating a listing file from your program, it will
generally expand multi-line macros by means of writing the macro
@ -1792,7 +1881,8 @@ to be assembled if and only if \c{text1} and \c{text2}, after
expanding single-line macros, are identical pieces of text.
Differences in white space are not counted.
\c{%ifidni} is similar to \c{%ifidn}, but is \i{case-insensitive}.
\c{%ifidni} is similar to \c{%ifidn}, but is case-insensitive; see
however \k{ppcase}.
For example, the following macro pushes a register or number on the
stack, and allows you to treat \c{IP} as a real register:
@ -1976,12 +2066,14 @@ this test, for example:
The conditional assembly construct \c{%ifenv} assembles the
subsequent code if and only if the environment variable referenced by
the \c{%!}\e{variable} directive exists.
the \c{%!}\e{variable} construct exists.
Just as for \c{%!}\e{variable} the argument should be written as a
string if it contains characters that would not be legal in an
Just as for \c{%!}\e{variable} the variable name must be written as a
quoted string if it contains characters that would not be legal in an
identifier. See \k{getenv}.
See also the the \c{%env()} function (\k{f_env}).
\S{if_caveat} Backwards Compatibility Caveat
@ -2720,6 +2812,9 @@ variable, for example:
\c %defstr C_colon %!'C:'
See also the \c{%ifenv} directive (\k{ifenv}) and the \c{%env()}
function (\k{f_env}).
\S{clear} \i\c\{%clear}: Clear All Macro Definitions

View file

@ -78,7 +78,7 @@ sub win32_gs_help() {
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);
my $e = File::Spec->catfile($p, $exe);
$gsp = $e if (-f $e && -x _);
}
}

View file

@ -102,43 +102,89 @@ sections of interest, avoiding excessively long listings.
Use this option to specify listing output details.
Supported options are:
\c{-L} options for general use are:
\b \c{-Lb} show builtin macro packages (standard and \c{%use})
\b \c{-Lb} show builtin macro packages (standard and \c{%use}, see \k{use})
\b \c{-Lc} list the data from \c{INCBIN} files (see \k{incbin})
\b \c{-Ld} show byte and repeat counts in decimal, not hex
\b \c{-Le} show the preprocessed input
\b \c{-Le} show the preprocessed output
\b \c{-Lf} ignore \c{.nolist} and force listing output
\b \c{-Lf} ignore \c{.nolist} (force output) (see \k{nolist})
\b \c{-LF} ignore \c{[LIST]} directives (see \k{LIST})
\b \c{-LF} ignore \c{[LIST -]} directives (force output) (see \k{LIST})
\b \c{-Lm} show multi-line macro calls with expanded parameters
\b \c{-Lp} output a list file in every pass, in case of errors
\b \c{-Lp} output a list file every pass, in case of errors
\b \c{-Ls} show all single-line macro definitions
\b \c{-Lw} flush the output after every line (very slow, mainly useful
to debug NASM crashes)
\b \c{-Lt} list the full output from \c{TIMES} and \c{ALIGN}
directives
\b \c{-L+} enable \e{all} listing options except \c{-Lw} (very verbose)
\b \c{-L+} equivalent to \c{-LbdefFmps}
\b \c{-L++} equivalent to \c{-L+} \c{-Lct}
\c{-L} options intended for the debugging of NASM itself (including
bug reporting), and not likely to be otherwise useful:
\b \c{-Lw} flush the output after every line (very slow!)
\b \c{-LX} list instruction pattern line numbers from \c{insns.xda}
\b \c{-L!} enable \e{all} listing options including debugging ones
For forward compatility reasons, an undefined flag will be
ignored. Thus, a new flag introduced in a newer version of NASM can be
specified without breaking older versions. Listing flags will always
be a single alphanumeric character and are case sensitive.
These options can be enabled or disabled at runtime using the
\c{%pragma list options} directive:
\c %pragma list options [+|-]flags...
\c %pragma list options [+|-|*]{!|flags}...
\c{+}, \c{-} and \c{*} adds, removes, or restores to the command-line
default the flags that follow.
For example, to turn on the \c{d} and \c{m} flags but disable the
\c{s} flag:
\c %pragma list options +dm -s
For forward compatility reasons, an undefined flag will be
ignored. Thus, a new flag introduced in a newer version of NASM can be
specified without breaking older versions. Listing flags will always
be a single alphanumeric character and are case sensitive.
The \c{+} and \c{++} shorthands available in on the command line are
not available when using \c{%pragma list options}; each listing option
needs to be specified explicitly, or \c{!} can be used to specify all
options.
Spaces, quotation marks, and commas in the argument are explicitly
ignored; thus, specifying the options as one or more quoted strings is
valid.
The built-in macros \i\c{__?LIST_OPTIONS?__} and
\i\c{__?LIST_OPTIONS_DEFAULT?__} contain the currently active and the
command-line default listing options, respectively, as quoted strings.
To save and restore the listing options, one can use:
\c %macro ...
\c %xdefine %%saved_list_options __?LIST_OPTIONS?__
\c %pragma list options ; ... changing the options
\c ; ... do stuff with special listing options ...
\c %pragma list options -! +%%saved_list_options
\c %endmacro
The statement:
\c %pragma list options -! +__?LIST_OPTIONS_DEFAULT?__
... is exactly equivalent to ...
\c %pragma list options *!
\S{opt-M} The \i\c{-M} Option: Generate \i{Makefile Dependencies}
@ -557,9 +603,13 @@ system calling conventions.
\c{--prefix} is an alias for \c{--gprefix}.
Starting with NASM 3.01, \c{--suffix}, \c{--gsuffix}, and
\c{--lsuffix} are accepted as aliases for the corresponding
\c{postfix} options.
See \k{mangling} for the equivalent directives and pragmas.
Earlier versions of NASM called the pragmas \i\c{suffix} and the
options \i\c{--postfix}, and did not implement directives at all
despite being so documented. Since NASM 3.01, the directive forms are
implemented, and directives, pragmas and options all support all
spellings.
\IR{--pragma} \c{--pragma} option
@ -606,8 +656,8 @@ form can be used for compatibility with older versions of NASM.
These options allows user to setup various maximum values after which
NASM will terminate with a fatal error rather than consume arbitrary
amount of compute time. Each limit can be set to a positive number or
\c{unlimited}.
amount of compute time. Each limit can be set to a positive number,
\c{unlimited}, \c{maximum}, or \c{default}.
\b\c{--limit-passes}: Number of maximum allowed passes. Default is
\c{unlimited}.
@ -633,6 +683,9 @@ expression length. Default is 8192 on most systems.
\b\c{--limit-lines}: Total number of source lines allowed to be
processed. Default is 2000000000.
\b\c{--limit-params}: Maximum number of multi-line macro
parameters. Default is 16383.
For example, set the maximum line count to 1000:
\c nasm --limit-lines 1000
@ -642,6 +695,14 @@ example:
\c %pragma limit lines 1000
Specifying the limit value as \c{*} or \c{reset} resets the limit to
the value specified on the command line or the default value, undoing
any previous \c{%pragma limit}.
See also the \c{%limit()} preprocessor function (\k{f_limit}) and the
\c{__?NASM_LIMITS?__} standard macro (\k{nasm_limits}).
\IR{--keep-all} \c{--keep-all} option
\S{opt-keep-all} The \i\c{--keep-all} Option

View file

@ -138,12 +138,3 @@ To build modified sources, you will need the tools described in
Some build system changes might not be possible without a POSIX
environment.
If you have modified the sources to change the embedded declarations
of warning classes, you may have to manually re-build the warning
catalog:
\c make warnings
This is not done automatically, as the tools do not have the ability
to automatically detect when it is necessary to do so.

View file

@ -184,6 +184,20 @@ clock:
\c __?UTC_TIME_NUM?__ 210042
\c __?POSIX_TIME?__ 1262293242
\H{nasm_limits} \i\c{__?NASM_LIMITS?__}: List of Resource Limits
The standard macro \c{__?NASM_LIMITS?__} is defined as a
comma-separated list of quoted strings corresponding to all resource
limits defined in the current version of NASM. It also indicates the
availability of the \c{%limit()} function and the keywords
\c{default}, \c{maximum}, and \c{reset} for \c{%pragma limit}.
See \k{opt-limit} and \c{f_limit}.
\c{__?NASM_LIMITS?__} is defined since NASM 3.02.
\H{has_ifdirective} \i\c{__?NASM_HAS_IFDIRECTIVE?__}: Directive
Probing Support
@ -213,6 +227,20 @@ For example, if the \c{altreg} package is included (see
See also the \c{%ifusable} and \c{%ifusing} directives, \k{ifusing}.
\H{list_options_macro} \i\c{__?LIST_OPTIONS?__}: Current Listing Options
Contains a quoted string with the listing options currently in
effect. See \k{opt-L}.
\H{list_options_default_macro} \i\c{__?LIST_OPTIONS_DEFAULT?__}:
Default Listing Options
Contains a quoted string with the listing options originally specified
by the user on the command line. See \k{opt-L}.
\H{pass_macro} \i\c{__?PASS?__}: Assembly Pass
The macro \c{__?PASS?__} is defined to be \c{1} on preparatory passes,

View file

@ -12,7 +12,7 @@ operation.
Near jumps are jumps within a single segment. Probably the most common way to
use them is through labels, as explained in \k{locallab}. \i\c{APX} added a near
jump instruction - \I\c{JMPABS}, that allows jumps to any \I{64-bit
jump instruction - \i\c{JMPABS}, that allows jumps to any \I{64-bit
immediate}64-bit address specified with an immediate operand. The instruction
works with absolute addresses and the syntax options are shown in
\k{jmpabs}.
@ -88,6 +88,29 @@ NASM allows this instruction to be specified either as:
The generated code is identical. The \c{ABS} is required regardless of
the \c{DEFAULT} setting.
\S{opt_jumps} Optimizing jump lengths and sizes
\i\c{JMP} lengths can be specified using keywords such as \i\c{SHORT} and
\i\c{NEAR}. The keyword used also has consequences in how many bytes will be
emitted in the final assembled instruction. It's worth to note the behavior of
\c{SHORT} and \c{NEAR} for example in 16 bit mode. If it's specifically required
to emit a 3 byte encoding of the jump instruction, then the \c{NEAR} version
shall always fulfill this requirement, even if the jump is made within a
\c{SHORT} distance (so up to a byte away). If the optimized version is expected
then it's best to not use a length specifier at all and let the assembler pick
the relevant version by itself.
Using size specifiers with jumps (and therefore with labels which are just
immediates) will be optimized down to the shortest possible encoding since the
size specifier is relevant to the operation size and not to the jump length.
\c 00000000 EB09 jmp label
\c 00000002 EB07 jmp SHORT label
\c 00000004 E90400 jmp NEAR label
\c 00000007 EB02 jmp BYTE label
\c 00000009 EB00 jmp WORD label
\c
\c label:
\H{shortnddnds} Compact \i{NDS}/\i{NDD} Operands
@ -97,7 +120,7 @@ operands. Semantically it works by passing another operand to the
instruction so that none of the source operands are modified as a
result of the operation.
Syntatically NASM allows both the obvious format mentioned above and a
Syntactically NASM allows both the obvious format mentioned above and a
\i{compact format} - compact meaning that if a user passes two
operands instead of three, one of them is simply copied to be used as
the source or destination. Thereby these instructions have exactly

View file

@ -4,6 +4,7 @@
%define __?BITS?__
%define __?PTR?__
%define __?DEFAULT?__
%define __?LIST_OPTIONS?__
%idefine %abs(=)
%idefine %chr(=+)
%idefine %count(+)
@ -14,6 +15,7 @@
%idefine %null(+)
%idefine %pathsearch()
%idefine %realpath()
%idefine %selbits(+)
%idefine %str(&+)
%idefine %strcat(&&+)
%idefine %strlen(&&)
@ -61,8 +63,13 @@
%idefine %substr(&&,=,=)
%idefine %ord(&&,=,=)
%idefine %b2hs(&&,&&)
%idefine %limit(&&,&&)
%idefine %env(&&)
%idefine %env(&&,+)
%idefine %findi(&&,+)
%idefine %find(&&,+)
%define __?NASM_LIMITS?__
%define __?LIST_OPTIONS_DEFAULT?__
%define __?PASS?__
%define __?SECT?__
%defalias __SECT__

View file

@ -10,9 +10,8 @@
tmp="$(mktemp -d)"
[ -n "$tmp" ] || exit 1
if [ -n "$1" ]; then
NASM="$1"
fi
NASM="${NASM:-../nasm}"
NASM="${1:-$NASM}"
: > "$tmp/junk.asm"
"$NASM" -f bin -o "$tmp/junk.bin" -Lsb -l "$tmp/junk.lst" "$tmp/junk.asm"

View file

@ -1,6 +1,6 @@
#!/usr/bin/perl
#
# Automatically produce some tables useful for a NASM major mode
# Automatically produce some tables useful for an emacs NASM major mode
#
use integer;
@ -317,7 +317,7 @@ sub write_output_el {
# Generate a list of all the token type lists.
print $out "\n(defconst nasm-token-lists\n";
print $out " \'(";
print $out make_lines(78, 4, map { "'nasm-$_" } sort keys(%tokens));
print $out make_lines(78, 4, map { "nasm-$_" } sort keys(%tokens));
print $out ")\n";
print $out " \"List of all ${whoami} token type lists.\")\n";
@ -367,10 +367,24 @@ sub write_output_json {
$ver{$vn} = $vv;
}
print $out $json->encode({
my $txt = $json->encode({
'$comment' => "NASM syntax information extracted from ${whoami}",
'tokens' => \%tokens, 'version' => \%ver});
print $out "\n";
# $json->encode() creates a single long line; break up the lines
# at least...
my @txt = split(/\,/, $txt);
my $last = shift @txt;
foreach my $t (@txt) {
if (length($last)+length($t) > 77) {
print $out $last, ",\n";
$last = $t;
} else {
$last .= ",$t";
}
}
print $out $last, "\n";
return 0;
}

View file

@ -177,23 +177,10 @@ int vsnprintf(char *, size_t, const char *, va_list);
size_t strlcpy(char *, const char *, size_t);
#endif
#if !defined(HAVE_STRCHRNUL) || !HAVE_DECL_STRCHRNUL
char * pure_func strrchrnul(const char *, int);
#endif
#if !defined(__cplusplus) || (__STDC_VERSION >= 202311L)
/* C++ and C23 have bool, false, and true as proper keywords */
#if !defined(__cplusplus) && (__STDC_VERSION__ < 202311L)
# ifdef HAVE_STDBOOL_H
/* If <stdbool.h> exists, include it explicitly to prevent it from
begin included later, causing the "bool" macro to be defined. */
# include <stdbool.h>
# ifdef bool
/* Force bool to be a typedef instead of a macro. What a "clever" hack
this is... */
typedef bool /* The macro definition of bool */
# undef bool
bool; /* No longer the macro definition */
# endif
# elif defined(HAVE___BOOL)
typedef _Bool bool;
# define false 0
@ -201,14 +188,10 @@ char * pure_func strrchrnul(const char *, int);
# else
/* This is a bit dangerous, because casting to this ersatz bool
will not produce the same result as the standard (bool) cast.
Instead, use the bool() constructor-style macro defined below. */
Instead, use the explicit construct !!x instead of relying on
implicit conversions or casts. */
typedef enum bool { false, true } bool;
# endif
/* This amounts to a C++-style conversion cast to bool. This works
because C ignores an argument-taking macro when used without an
argument and because bool was redefined as a typedef if it previously
was defined as a macro (see above.) */
# define bool(x) ((bool)!!(x))
#endif
/* Create a NULL pointer of the same type as the address of
@ -321,11 +304,11 @@ static inline void *mempset(void *dst, int c, size_t n)
* less likely to be taken.
*/
#ifdef HAVE___BUILTIN_EXPECT
# define likely(x) __builtin_expect(bool(x), true)
# define unlikely(x) __builtin_expect(bool(x), false)
# define likely(x) __builtin_expect(!!(x), true)
# define unlikely(x) __builtin_expect(!!(x), false)
#else
# define likely(x) bool(x)
# define unlikely(x) bool(x)
# define likely(x) (!!(x))
# define unlikely(x) (!!(x))
#endif
#ifdef HAVE___BUILTIN_PREFETCH
@ -482,4 +465,15 @@ static inline unsigned int watcom_switch_hack(uint64_t x)
# define default case BOGUS_CASE: default
#endif
#ifndef unreachable /* C23 defines as a macro in <stddef.h> */
# ifdef HAVE___BUILTIN_UNREACHABLE
# define unreachable() __builtin_unreachable()
# else
# define unreachable() do { abort(); } while(1)
# endif
#endif
/* This should be set from main() */
extern const char *_progname;
#endif /* NASM_COMPILER_H */

View file

@ -73,6 +73,12 @@ static inline unsigned int get_disp8_shift(const insn *ins)
/* MOVDDUP */
case DUP:
/*
* 128-bit vector case doesn't follow the same formula as 256- and
* 512-bit vectors.
*/
if (!vectlen)
return 3;
return vectlen + 4;
default:

View file

@ -28,6 +28,7 @@ void printf_func(2, 3) nasm_notef(errflags flags, const char *fmt, ...);
void printf_func(2, 3) nasm_warn_(errflags flags, const char *fmt, ...);
void printf_func(1, 2) nasm_nonfatal(const char *fmt, ...);
void printf_func(2, 3) nasm_nonfatalf(errflags flags, const char *fmt, ...);
void printf_func(1, 2) nasm_holderr(const char *fmt, ...);
fatal_func printf_func(1, 2) nasm_fatal(const char *fmt, ...);
fatal_func printf_func(2, 3) nasm_fatalf(errflags flags, const char *fmt, ...);
fatal_func printf_func(1, 2) nasm_critical(const char *fmt, ...);
@ -89,6 +90,7 @@ const char *error_pfx(errflags severity);
#define ERR_PP_PRECOND 0x00000400 /* for preprocessor use */
#define ERR_PP_LISTMACRO 0x00000800 /* from pp_error_list_macros() */
#define ERR_HOLD 0x00001000 /* this error/warning can be held */
#define ERR_PERROR 0x00002000 /* append strerror(errno) */
/*
* These codes define specific types of suppressible warning.
@ -113,14 +115,28 @@ const char *error_pfx(errflags severity);
#define WARN_INIT_ON WARN_ST_ENABLED
#define WARN_INIT_ERR (WARN_ST_ENABLED|WARN_ST_ERROR)
/* Options and status to/from the error module */
struct errinfo {
FILE *file; /* Error output file pointer */
errflags worst; /* Worst severity class encountered */
errflags never; /* Error flags to unconditionally suppress */
unsigned int debug_nasm; /* Debug message level */
unsigned int verbose_info; /* Info message level */
bool abort_on_panic; /* Call abort() on ERR_PANIC */
};
extern struct errinfo erropt;
int set_error_format(const char *fmt);
void error_init(void);
void error_pass_start(bool final);
void error_pass_end(void);
/* Process a warning option or directive */
bool set_warning_status(const char *value);
/* Warning stack management */
void push_warnings(void);
void pop_warnings(void);
void init_warnings(void);
void reset_warnings(void);
/*
* Tentative error hold for warnings/errors indicated with ERR_HOLD.
@ -146,10 +162,9 @@ errflags nasm_error_hold_pop(errhold hold, bool issue);
#include "warnings.h"
/* True if a warning is enabled, either as a warning or an error */
extern errflags errflags_never;
static inline bool warn_active(errflags warn)
{
if (warn & errflags_never)
if (warn & erropt.never)
return false;
return !!(warning_state[WARN_IDX(warn)] & WARN_ST_ENABLED);
@ -167,21 +182,19 @@ static inline bool warn_active(errflags warn)
#endif
/* Debug level checks */
extern unsigned int debug_nasm;
static inline bool debug_level(unsigned int level)
{
if (is_constant(level) && level > MAX_DEBUG)
return false;
return unlikely(level <= debug_nasm);
return unlikely(level <= erropt.debug_nasm);
}
/* Info level checks */
extern unsigned int opt_verbose_info;
static inline bool info_level(unsigned int level)
{
if (is_constant(level) && level > MAX_INFO)
return false;
return unlikely(level <= opt_verbose_info);
return unlikely(level <= erropt.verbose_info);
}
#ifdef HAVE_VARIADIC_MACROS
@ -229,5 +242,11 @@ static inline bool info_level(unsigned int level)
#endif
/* Callbacks from the error module */
void print_final_report(bool failure);
void close_output(bool failure);
bool pp_suppress_error(errflags flags);
void pp_error_list_macros(errflags flags);
#endif /* NASM_ERROR_H */

63
include/files.h Normal file
View file

@ -0,0 +1,63 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/* Copyright 2026 The NASM Authors - All Rights Reserved */
#ifndef NASM_FILES_H
#define NASM_FILES_H 1
#include "compiler.h"
#include "nasmlib.h" /* For nasm_assert() */
/*
* Primary file names set on the command line etc.
* Wrapped in accessors to make them as constant as possible.
*
* The order of the sections in this enum is critical!
*/
enum filenames {
/* Input filenames. FN_INFILE MUST be the first entry. */
FN_INFILE, /* Primary input file - MUST BE FIRST */
/*
* Section: Output filenames.
* FN_OUTFILE MUST be the first entry.
*/
FN_OUTFILE, /* Primary output file - MUST BE FIRST */
FN_ERRFILE, /* Error message file */
FN_LISTFILE, /* Listing file */
FN_DEPENDFILE, /* Dependency file */
FN_MAPFILE, /* Map file (outbin) */
/* Total number of "real" filenames. */
FN_NFILES_REAL,
/*
* Section: Virtual filenames.
* Strings that don't necessarily correspond directly to paths
* in the host filesystem.
*/
FN_MAPPED_INFILE, /* Debug mapped input file name */
FN_DEPEND_TARGET, /* Output target name per -MF, -MD, -MQ */
/* Total fixed filename count */
FN_NFILES
};
extern const char *_filenames[FN_NFILES];
static inline const char *get_filename(enum filenames fn)
{
nasm_assert((size_t)fn < ARRAY_SIZE(_filenames));
return _filenames[fn];
}
/*
* copy_filename() makes a private copy for the files subsystem,
* set_nocopy() expects an allocated string for the files subsystem to
* take over.
*/
const char *copy_filename(enum filenames fn, const char *src);
const char *set_filename(enum filenames fn, char *src);
void check_overwrite_files(void);
void cleanup_filenames(void);
#endif /* NASM_FILES_H */

View file

@ -20,6 +20,7 @@ struct itemplate {
decoflags_t deco[MAX_OPERANDS]; /* bit flags for operand decorators */
const uint8_t *code; /* the code it assembles to */
uint32_t iflag_idx; /* some flags referenced by index */
unsigned int xdaline; /* line # in insns.xda (for debug) */
};
/* Use this helper to test instruction template flags */

View file

@ -10,13 +10,6 @@
#include "compiler.h"
enum mangle_index {
LM_LPREFIX, /* Local variable prefix */
LM_LSUFFIX, /* Local variable suffix */
LM_GPREFIX, /* Global variable prefix */
LM_GSUFFIX /* GLobal variable suffix */
};
enum label_type {
LBL_none = -1, /* No label */
LBL_LOCAL = 0, /* Must be zero */
@ -39,7 +32,7 @@ void define_label(const char *label, int32_t segment, int64_t offset,
void backend_label(const char *label, int32_t segment, int64_t offset);
bool declare_label(const char *label, enum label_type type,
const char *special);
void set_label_mangle(enum mangle_index which, const char *what);
void set_label_mangle(enum directive which, const char *what);
int init_labels(void);
void cleanup_labels(void);
const char *local_scope(const char *label);

View file

@ -458,7 +458,7 @@ void pp_init(enum preproc_opt opt);
* of the pass, an error reporting function, an evaluator
* function, and a listing generator to talk to.
*/
void pp_reset(const char *file, enum preproc_mode mode,
void pp_reset(const char *file, const char* mapped_fname, enum preproc_mode mode,
struct strlist *deplist);
/*
@ -520,17 +520,6 @@ static inline char *nasm_skip_identifier(const char *str)
return (char *)p;
}
/*
* Data-type flags that get passed to listing-file routines.
*/
enum {
LIST_READ,
LIST_MACRO,
LIST_INCLUDE,
LIST_INCBIN,
LIST_TIMES
};
/*
* -----------------------------------------------------------
* Format of the `insn' structure returned from `parser.c' and
@ -898,6 +887,8 @@ typedef struct insn { /* an instruction itself */
const struct itemplate *itemp; /* Instruction template */
const struct operand *evex_brerop; /* BR/ER/SAE operand position */
struct operand oprs[MAX_OPERANDS]; /* the operands, defined as above */
int itempindex; /* For debug: instruction template index in insnsa.c */
} insn;
/* Instruction flags type: IF_* flags are defined in insns.h */
@ -968,11 +959,24 @@ enum nasm_limit {
LIMIT_MMACROS,
LIMIT_REP,
LIMIT_EVAL,
LIMIT_LINES
LIMIT_LINES,
LIMIT_PARAMS,
LIMIT_MAX /* Must be at end */
};
#define LIMIT_MAX LIMIT_LINES
extern int64_t nasm_limit[LIMIT_MAX+1];
extern enum directive_result nasm_set_limit(const char *, const char *);
#define LIMIT_MAX_VAL (INT64_MAX >> 1) /* Absolute maximum for any limit */
extern int64_t nasm_limit[LIMIT_MAX];
extern enum directive_result nasm_set_limit(const char *, const char *);
enum get_limit_which {
GET_LIMIT_CURRENT,
GET_LIMIT_INIT,
GET_LIMIT_DEFAULT,
GET_LIMIT_MAX
};
extern int64_t nasm_get_limit(const char *, enum get_limit_which);
extern const char *nasm_limit_name(enum nasm_limit);
/*
* The data structure defining an output format driver, and the
@ -1569,9 +1573,7 @@ struct globalopt {
bool dollarhex; /* $-prefixed hexadecimal numbers? */
};
extern struct globalopt globl;
extern const char *inname; /* primary input filename */
extern const char *outname; /* output filename */
void reset_global_defaults(int bits);
/*
* Switch to a different segment and return the current offset

View file

@ -102,6 +102,29 @@ char * safe_alloc nasm_strndup(const char *, size_t);
char * safe_alloc nasm_strcat(const char *one, const char *two);
char * safe_alloc end_with_null nasm_strcatn(const char *one, ...);
/*
* Replace a string in a string pointer variable with a nasm_strdup()
* copy of the argument on the right, freeing the contents of the
* previous contents of the variable if non-NULL.
*
* If *str is NULL, simply return the old value of *ptrp.
*/
char *nasm_strdupto(char **ptrp, const char *str);
/*
* Similar, but the new pointer must already have been heap allocated
* by the creating function.
*/
static inline char *nasm_strto(char **ptrp, char *str)
{
char *ptr = *ptrp;
if (!str)
return ptr;
if (ptr)
nasm_free(ptr);
return *ptrp = str;
}
/*
* nasm_[v]asprintf() are variants of the semi-standard [v]asprintf()
* functions, except that we return the pointer instead of a count.
@ -136,8 +159,25 @@ static inline size_t nasm_last_string_size(void)
return _nasm_last_string_size;
}
/* Statically assert the argument is a pointer without evaluating it */
#define nasm_assert_pointer(p) ((void)sizeof(*(p)))
/*
* All zero data buffer
*/
#define ZERO_BUF_SIZE 65536 /* Default value */
#if defined(BUFSIZ) && (BUFSIZ > ZERO_BUF_SIZE)
# undef ZERO_BUF_SIZE
# define ZERO_BUF_SIZE BUFSIZ
#endif
extern const uint8_t zero_buffer[ZERO_BUF_SIZE];
/*
* Statically assert the argument is a pointer without evaluating it.
* ? : requires that the types on both sides are compatible, and
* const volatile void * is compatible with any pointer type.
* Avoid a simple cast from NULL because it might make some compilers
* confused; a pointer to any object works there.
*/
#define nasm_assert_pointer(p) \
((void)sizeof(1 ? (p) : (const volatile void *)&zero_buffer))
#define nasm_new(p) ((p) = nasm_zalloc(sizeof(*(p))))
#define nasm_newn(p,n) ((p) = nasm_calloc((n), sizeof(*(p))))
@ -273,6 +313,22 @@ static inline unsigned int numvalue(unsigned char c)
return c >= 'a' ? c - 'a' + 10 : c - '0';
}
/* The same except returns -1U for non-digits, so it can be directly
* compared against the base used to test for validity. */
static inline unsigned int numvalue_chk(unsigned char c)
{
unsigned int v;
v = c - '0';
if (v < 10)
return v;
v = (c | 0x20) - 'a';
if (v < 26)
return v + 10;
return -1U;
}
/*
* Convert a string into a number, using NASM number rules. Sets
* `*error' to true if an error occurs, and false otherwise.
@ -335,9 +391,10 @@ static inline const char *nasm_digit_chars(bool ucase)
int32_t seg_alloc(void);
/*
* Add/replace or remove an extension to the end of a filename
* Add/replace or remove an extension to the end of a filename;
* returns a newly allocated buffer with the modified filename.
*/
const char *filename_set_extension(const char *inname, const char *extension);
char *filename_set_extension(const char *inname, const char *extension);
/*
* Utility macros...
@ -470,12 +527,8 @@ void nasm_set_binary_mode(FILE *f);
/* Probe for existence of a file */
bool nasm_file_exists(const char *filename);
#define ZERO_BUF_SIZE 65536 /* Default value */
#if defined(BUFSIZ) && (BUFSIZ > ZERO_BUF_SIZE)
# undef ZERO_BUF_SIZE
# define ZERO_BUF_SIZE BUFSIZ
#endif
extern const uint8_t zero_buffer[ZERO_BUF_SIZE];
/* Compare two pathnames */
int nasm_compare_paths(const char *a, const char *b);
/* Missing fseeko/ftello */
#ifndef HAVE_FSEEKO
@ -498,6 +551,9 @@ off_t nasm_file_size_by_path(const char *pathname);
bool nasm_file_time(time_t *t, const char *pathname);
void fwritezero(off_t bytes, FILE *fp);
/* Remove a file; explicitly defined to ignore a NULL or empty pathname */
int nasm_remove(const char *pathname);
/* Sign-extend a value to an arbitrary number of bits */
static inline int64_t const_func sext(int64_t value, unsigned int bits)
{

View file

@ -57,8 +57,8 @@ void saa_write8(struct SAA *s, uint8_t v);
void saa_write16(struct SAA *s, uint16_t v);
void saa_write32(struct SAA *s, uint32_t v);
void saa_write64(struct SAA *s, uint64_t v);
void saa_wleb128u(struct SAA *, int); /* write unsigned LEB128 value */
void saa_wleb128s(struct SAA *, int); /* write signed LEB128 value */
void saa_writeaddr(struct SAA *, uint64_t, size_t);
void saa_wleb128u(struct SAA *, uint64_t v); /* unsigned LEB128 value */
void saa_wleb128s(struct SAA *, int64_t v); /* signed LEB128 value */
void saa_writeaddr(struct SAA *, uint64_t, size_t); /* specific size integer */
#endif /* NASM_SAA_H */

View file

@ -6,8 +6,6 @@
# Makefile for various extra NASM programs and files
#
@SET_MAKE@
top_srcdir = @top_srcdir@
srcdir = @srcdir@
top_objdir = @top_builddir@

237
misc/nxdisasm.pl Executable file
View file

@ -0,0 +1,237 @@
#!/usr/bin/perl
#
# Script to extract section and symbol information from a compound
# binary object (PE, COFF, ELF...) using binutils and running them
# through ndisasm.
#
use strict;
use integer;
my @symbols; # Symbols by address
my @sections; # Sections by start address
# Find the last symbol list at an address <= the given address,
# and its index in the @symbols array
sub find_sym($) {
my($addr) = @_;
my $l = 0;
my $h = scalar @symbols - 1;
while ($l < $h) {
my $m = ($l+$h) >> 1;
my $a = $symbols[$m]->[0];
if ($a > $addr) {
$h = $m - 1;
} elsif ($a < $addr) {
$l = $m + 1;
} else {
$l = $m;
last;
}
}
return ($symbols[$l], $l);
}
# Print a symbolic string, possibly with an addend
sub sym_str($;$) {
my($addr, $sym) = @_;
if (!defined($sym)) {
return undef unless defined($addr);
my($sy, $sx) = find_sym($addr);
return undef unless defined($sy);
$sym = $sy->[1]->[0];
return undef unless defined($sym);
}
$addr -= $sym->{addr};
return '<'.$sym->{name}.'>' if ($addr == 0);
return sprintf('<%s%s0x%x>', $sym->{name},
$addr < 0 ? '-' : '+', abs($addr));
}
# Print a here marker for all symbols at this index and forward for
# all symbols with the same exact address; returns the following symbol
# list, if available
sub print_symbols($;$) {
my($addr, $sx) = @_;
my $sy;
if (defined($sx)) {
$sy = $symbols[$sx];
} else {
($sy, $sx) = find_sym($addr);
}
foreach my $sym (@{$sy->[1]}) {
my $str = sym_str($addr, $sym);
next unless (defined($str));
print '--- ', $str, ":\n";
}
$sx++;
return ($symbols[$sx], $sx);
}
my $OBJDUMP = $ENV{'OBJDUMP'} || 'objdump';
my $NDISASM = $ENV{'NDISASM'} || 'ndisasm';
sub parse_objdump($) {
my($file) = @_;
my %symhash; # Hash of symbol lists my address
open(my $od, '-|', $OBJDUMP, '-wht', $file) or return;
my $what = 0;
my $seq = 0;
while (defined(my $l = <$od>)) {
chomp $l;
if ($l =~ /^Sections:/) {
$what = 1;
} elsif ($l =~ /^SYMBOL TABLE:/) {
$what = 2;
} elsif ($what == 1 && $l =~ s/^\s*\d+\s+//) {
my @fields = split(/\s+/, $l, 7);
my %flags = map { $_ => 1 } split(/,\s*/, $fields[6]);
if ($flags{'CODE'} && $flags{'CONTENTS'} && $flags{'LOAD'}) {
my $size = hex $fields[1];
if ($size) {
push(@sections, { name => $fields[0],
size => $size,
addr => hex $fields[2],
lma => hex $fields[3],
offs => hex $fields[4],
seq => ++$seq });
}
}
} elsif ($what == 2) {
my $sym;
if ($l =~ /^([0-9a-f]+) (.{7}) (\S+)\s+([0-9a-f]+)\s+(\S+)/i) {
my $flags = $2;
my $sec = $3;
my $addr = hex $1;
my $size = hex $4;
my $name = $5;
if ($sec ne '*UND*' && $flags !~ /[WId]/ ) {
my $prio = 0;
$prio += 100 if ($flags =~ /^l/);
$prio += 200 if ($flags =~ /^[gu!]/);
$prio -= 50 if ($flags =~ /w/);
$prio += 400 if ($flags =~ /F$/);
$prio -= 90 if ($sec eq '*ABS*');
$sym = {
addr => $addr,
flags => $flags,
sec => $sec,
size => $size,
name => $name,
prio => $prio
};
}
} elsif ($l =~ /^\s*\[[\s\d]+\](?:\s+|\([^)]*\))*0x([0-9a-f]+)\s+(\S+)/i) {
$sym = { 'addr' => hex $1, 'name' => $2 }
}
if (defined($sym)) {
my $addr = $sym->{addr};
$sym->{seq} = ++$seq;
$symhash{$addr} = [] unless ($symhash{$addr});
push(@{$symhash{$addr}}, $sym);
}
}
}
close($od);
@sections = sort {
$a->{addr} <=> $b->{addr} ||
$a->{name} cmp $b->{name}
} @sections;
# Add fallback sections symbols if necessary
foreach my $sec (@sections) {
my $addr = $sec->{addr};
unless ($symhash{$addr}) {
$symhash{$addr} = [ { addr => $addr,
name => $sec->{name},
prio => -1000000000,
seq => ++$seq } ];
}
}
unless (exists($symhash{0})) {
$symhash{0} = [ ];
}
@symbols = map { [$_, $symhash{$_}] } sort { $a <=> $b } keys(%symhash);
foreach my $sl (@symbols) {
$sl->[1] = [sort {
$b->{prio} <=> $a->{prio} ||
$a->{name} cmp $b->{name} ||
$a->{sec} cmp $b->{sec}
} @{$sl->[1]}];
}
}
# Look for things which may be addresses in the disassembly and output
# the symbolic address if possible in that case.
sub postprocess_ndisasm($$) {
my($dis, $sec) = @_;
my $addr = $sec->{addr};
printf "=== section <%s> addr 0x%08x len 0x%x (%u):\n",
$sec->{name}, $addr, $sec->{size}, $sec->{size};
# First symbol in the section and its address
my($sy, $sx) = print_symbols($addr);
while (defined(my $l = <$dis>)) {
# print STDERR $l;
chomp $l;
if ($l =~ /^([0-9a-f]+)\s+([0-9a-f]+)\s+(.*)$/i) {
my $addr = hex $1;
my $ins = $3;
if (defined($sy) && $addr >= $sy->[0]) {
($sy, $sx) = print_symbols($addr, $sx);
}
while ($ins =~ s/([^+-])(0x[0-9a-f]+)/$1/i) {
my $ss = sym_str(hex $2);
$l .= ' '.$ss if (defined($ss));
}
}
print " ", $l, "\n";
}
}
# Run ndisasm on a specific section
sub disasm($@) {
my($file, @opts) = @_;
my $err = 0;
foreach my $sec (@sections) {
my $dis;
if (!open($dis, '-|', $NDISASM, '-i', '-e', $sec->{offs},
'-o', $sec->{addr}, '-z', $sec->{size}, @opts, $file)) {
$err++;
next;
}
postprocess_ndisasm($dis, $sec);
close($dis);
}
return $err;
}
my($file) = pop(@ARGV);
if ( ! -f $file ) {
die "$0: no input file: $file\n";
}
parse_objdump($file);
exit(disasm($file, @ARGV) != 0);

View file

@ -92,6 +92,7 @@ static void *nulldie(void *ptr)
fprintf(stderr, "%s: memory allocation error\n", progname);
exit(1);
abort(); /* This should never happen */
return NULL; /* make compiler happy */
}
static void *xmalloc(size_t size)
@ -110,7 +111,7 @@ static void *expand_buffer(void *buf, size_t *bufsizep, size_t datasize,
{
size_t bufsize = *bufsizep;
if (likely(bufsize < datasize))
if (likely(bufsize > datasize))
return buf;
if (bufsize < BUFSIZ)
@ -159,12 +160,12 @@ static void hexdump_data(unsigned int offset, const uint8_t *data,
printf(" %04x: ", i + offset);
for (j = 0; j < 16; j++) {
char sep = (j == 7) ? '-' : ' ';
if (i + j < field)
printf("%02x%c", data[i + j], sep);
else if (i + j < n)
printf("xx%c", sep); /* Beyond end of... */
else
if (i + j >= n)
printf(" "); /* No separator */
else if (i + j < field)
printf("%02x%c", data[i + j], sep);
else
printf("xx%c", sep); /* Beyond end of... */
}
printf(" : ");
for (j = 0; j < 16; j++) {

View file

@ -8,11 +8,10 @@ Name: nasm
Version: @@NASM_MANGLED_VER@@
Release: 0%{?dist}
License: BSD-2-Clause
Source: http://www.nasm.us/pub/nasm/releasebuilds/%{nasm_version}/nasm-%{nasm_version}.tar.xz
URL: http://www.nasm.us/
Source: https://www.nasm.us/pub/nasm/releasebuilds/%{nasm_version}/nasm-%{nasm_version}.tar.xz
URL: https://www.nasm.us/
BuildRoot: /tmp/rpm-build-nasm
Prefix: %{_prefix}
@@PERLBUILDREQS@@
BuildRequires: autoconf
BuildRequires: automake
BuildRequires: asciidoc
@ -23,6 +22,10 @@ BuildRequires: make
BuildRequires: gzip
BuildRequires: xz
BuildRequires: zlib-devel
BuildRequires: sed
BuildRequires: findutils
BuildRequires: coreutils
@@PERLBUILDREQS@@
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
Obsoletes: %{name}-rdoff < 2.16

View file

@ -147,6 +147,10 @@ OPTIONS
Prepend or append (respectively) the given argument to all global or
extern variables.
--debug-prefix-map 'BASE=DEST'::
Map file names beginning with 'BASE' to 'DEST' when encoding them in
output object files.
SYNTAX
------
This man page does not fully describe the syntax of *nasm*'s assembly language,

View file

@ -74,10 +74,8 @@ void *nasm_realloc(void *q, size_t size)
void nasm_free(void *q)
{
if (q){
if (q)
free(q);
q = NULL;
}
}
char *nasm_strdup(const char *s)
@ -101,6 +99,17 @@ char *nasm_strndup(const char *s, size_t len)
return memcpy(p, s, len);
}
char *nasm_strdupto(char **ptrp, const char *str)
{
char *ptr = *ptrp;
if (str) {
if (ptr)
nasm_free(ptr);
*ptrp = ptr = nasm_strdup(str);
}
return ptr;
}
char *nasm_strcat(const char *one, const char *two)
{
char *rslt;

View file

@ -1,77 +1,37 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/* Copyright 1996-2017 The NASM Authors - All Rights Reserved */
#include "file.h"
#include "compiler.h"
#include "nasmlib.h"
#include "error.h"
void nasm_read(void *ptr, size_t size, FILE *f)
{
size_t n = fread(ptr, 1, size, f);
if (ferror(f)) {
nasm_fatal("unable to read input: %s", strerror(errno));
} else if (n != size || feof(f)) {
nasm_fatal("fatal short read on input");
}
}
void nasm_write(const void *ptr, size_t size, FILE *f)
{
size_t n = fwrite(ptr, 1, size, f);
if (n != size || ferror(f) || feof(f))
nasm_fatal("unable to write output: %s", strerror(errno));
}
void fwriteint16_t(uint16_t data, FILE * fp)
{
data = htole16(data);
nasm_write(&data, 2, fp);
}
void fwriteint32_t(uint32_t data, FILE * fp)
{
data = htole32(data);
nasm_write(&data, 4, fp);
}
void fwriteint64_t(uint64_t data, FILE * fp)
{
data = htole64(data);
nasm_write(&data, 8, fp);
}
void fwriteaddr(uint64_t data, int size, FILE * fp)
{
data = htole64(data);
nasm_write(&data, size, fp);
}
void fwritezero(off_t bytes, FILE *fp)
{
size_t blksize;
#ifdef os_ftruncate
if (bytes >= BUFSIZ && !ferror(fp) && !feof(fp)) {
off_t pos = ftello(fp);
if (pos != (off_t)-1) {
off_t end = pos + bytes;
if (!fflush(fp) && !os_ftruncate(fileno(fp), end)) {
fseeko(fp, 0, SEEK_END);
pos = ftello(fp);
if (pos != (off_t)-1)
bytes = end - pos; /* This SHOULD be zero */
}
}
}
#ifdef HAVE_FCNTL_H
# include <fcntl.h>
#endif
#ifdef HAVE_SYS_STAT_H
# include <sys/stat.h>
#endif
#ifdef HAVE_IO_H
# include <io.h>
#endif
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
while (bytes > 0) {
blksize = (bytes < ZERO_BUF_SIZE) ? bytes : ZERO_BUF_SIZE;
#ifndef R_OK
# define R_OK 4 /* Classic Unix constant, same on Windows */
#endif
nasm_write(zero_buffer, blksize, fp);
bytes -= blksize;
}
}
#ifdef _WIN32
#ifdef S_ISREG
/* all good */
#elif defined(HAVE_S_ISREG)
/* exists, but not a macro */
# define S_ISREG S_ISREG
#elif defined(S_IFMT) && defined(S_IFREG)
# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
#elif defined(_S_IFMT) && defined(_S_IFREG)
# define S_ISREG(m) (((m) & _S_IFMT) == _S_IFREG)
#endif
/*
* On Windows, we want to use _wfopen(), as fopen() has a much smaller limit
@ -81,34 +41,48 @@ void fwritezero(off_t bytes, FILE *fp)
* let the Windows kernel know that we are not limited to PATH_MAX
* characters, but it breaks relative paths among other things, and
* apparently Windows 10 contains a registry option to override this
* limit anyway. One day maybe they will even implement UTF-8 as byte
* characters so we can use the standard file API even on this OS.
* limit anyway... but only for the wide character interfaces.
*/
#ifdef _WIN32
#include <wchar.h>
/*
* <windows.h> is needed for MultiByteToWideChar()/CompareStringOrdinal()
* (normally declared via <stringapiset.h>). Windows SDK headers like
* <stringapiset.h> are only guaranteed to work when pulled in through the
* normal <windows.h> pipeline, which sets up SDK-internal architecture
* macros (_X86_, _AMD64_, ...) derived from the compiler's own
* _M_IX86/_M_X64/etc; including such a leaf header directly can fail with
* a "No Target Architecture" #error from <winnt.h>.
*
* <windows.h> is deliberately *not* included from compiler.h: it #defines
* NEAR and FAR (as legacy no-op calling-convention keywords), which clash
* with NASM's own NEAR/FAR opflags bits from opflags.h. Keep the
* inclusion local to the few files, like this one, that actually need
* Windows API declarations, and define WIN32_LEAN_AND_MEAN to keep the
* exposed surface (winsock, GDI, shell, DDE, RPC, crypto, ...) minimal.
*/
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
os_filename os_mangle_filename(const char *filename)
typedef wchar_t *os_filename;
typedef wchar_t os_fopenflag;
static os_filename os_mangle_filename(const char *filename)
{
mbstate_t ps;
size_t wclen;
wchar_t *buf;
const char *p;
/*
* Note: mbsrtowcs() return (size_t)-1 on error, otherwise
* the length of the string *without* final NUL in wchar_t
* units. Thus we add 1 for the final NUL; the error value
* now becomes 0.
*/
memset(&ps, 0, sizeof ps); /* Begin in the initial state */
p = filename;
wclen = mbsrtowcs(NULL, &p, 0, &ps) + 1;
wclen = MultiByteToWideChar(CP_ACP, MB_ERR_INVALID_CHARS, filename,
-1, NULL, 0);
if (!wclen)
return NULL;
buf = nasm_malloc(wclen * sizeof(wchar_t));
/* wclen is in "characters" (UTF-16 code points) */
buf = nasm_malloc(wclen << 1);
memset(&ps, 0, sizeof ps); /* Begin in the initial state */
p = filename;
if (mbsrtowcs(buf, &p, wclen, &ps) + 1 != wclen || p) {
wclen = MultiByteToWideChar(CP_ACP, MB_ERR_INVALID_CHARS, filename,
-1, buf, wclen);
if (!wclen) {
nasm_free(buf);
return NULL;
}
@ -116,6 +90,139 @@ os_filename os_mangle_filename(const char *filename)
return buf;
}
static inline void os_free_filename(os_filename filename)
{
nasm_free(filename);
}
# define os_fopen _wfopen
# define os_access _waccess
# define os_remove _wremove
/*
* On Win32/64, we have to use the _wstati64() function. Note that
* we can't use _wstat64() without depending on a needlessly new
* version os MSVCRT.
*/
typedef struct _stati64 os_struct_stat;
# define os_stat _wstati64
# define os_fstat _fstati64
static inline void os_set_binary_mode(FILE *f) {
int ret = _setmode(_fileno(f), _O_BINARY);
if (ret == -1) {
nasm_fatalf(ERR_NOFILE, "unable to set file mode to binary: %s",
strerror(errno));
}
}
static inline int os_compare_paths(const os_filename a, const os_filename b)
{
return CompareStringOrdinal(a, -1, b, -1, TRUE);
}
#define os_compare_paths os_compare_paths
#else /* not _WIN32 */
typedef const char *os_filename;
typedef char os_fopenflag;
static inline os_filename os_mangle_filename(const char *filename)
{
return filename;
}
static inline void os_free_filename(os_filename filename)
{
(void)filename; /* Nothing to do */
}
static inline void os_set_binary_mode(FILE *f) {
(void)f;
}
# define os_fopen fopen
# define os_remove remove
#if defined(HAVE_FACCESSAT) && defined(AT_EACCESS)
static inline int os_access(os_filename pathname, int mode)
{
return faccessat(AT_FDCWD, pathname, mode, AT_EACCESS);
}
# define os_access os_access
#elif defined(HAVE_ACCESS)
# define os_access access
#endif
#ifdef HAVE_STRUCT_STAT
typedef struct stat os_struct_stat;
# ifdef HAVE_STAT
# define os_stat stat
# endif
# ifdef HAVE_FSTAT
# define os_fstat fstat
# endif
#else
struct dummy_struct_stat {
int st_mode;
int st_size;
};
typedef struct dummy_struct_stat os_struct_stat;
#endif
#endif /* Not _WIN32 */
#ifdef fileno
/* all good */
#elif defined(HAVE_FILENO)
/* exists, but not a macro */
# define fileno fileno
#elif defined(_fileno) || defined(HAVE__FILENO)
# define fileno _fileno
#endif
#ifndef S_ISREG
# undef os_stat
# undef os_fstat
#endif
/* Disable these functions if they don't support something we need */
#ifndef fileno
# undef os_fstat
# undef os_ftruncate
# undef HAVE_MMAP
#endif
/*
* If we don't have functional versions of these functions,
* stub them out so we don't need so many #ifndefs
*/
#ifndef os_stat
static inline int os_stat(os_filename osfname, os_struct_stat *st)
{
(void)osfname;
(void)st;
return -1;
}
#endif
#ifndef os_fstat
static inline int os_fstat(int fd, os_struct_stat *st)
{
(void)fd;
(void)st;
return -1;
}
#endif
#ifndef S_ISREG
static inline bool S_ISREG(int m)
{
(void)m;
return false;
}
#endif
void nasm_set_binary_mode(FILE *f)
@ -320,3 +427,55 @@ bool nasm_file_time(time_t *t, const char *pathname)
return false; /* No idea how to do this on this OS */
#endif
}
/*
* Delete a file (allows NULL as input -> do nothing)
*/
int nasm_remove(const char *pathname)
{
int rv;
os_filename osfname;
if (!pathname || !*pathname)
return 0;
osfname = os_mangle_filename(pathname);
if (!osfname)
return false;
rv = os_remove(osfname);
os_free_filename(osfname);
return rv;
}
/*
* Try to determine if two paths are the same. This test must not have
* false positives; false negatives are OK but (obviously) not ideal.
*/
#ifdef os_compare_paths
int nasm_compare_paths(const char *a, const char *b)
{
os_filename oa, ob;
/* A direct string comparison is usually quick */
int rv = strcmp(a, b);
if (!rv)
return rv;
oa = os_mangle_filename(a);
ob = os_mangle_filename(b);
rv = os_compare_paths(oa, ob);
os_free_filename(oa);
os_free_filename(ob);
return rv;
}
#else
int nasm_compare_paths(const char *a, const char *b)
{
return strcmp(a, b);
}
#endif

View file

@ -1,204 +0,0 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/* Copyright 1996-2022 The NASM Authors - All Rights Reserved */
#ifndef NASMLIB_FILE_H
#define NASMLIB_FILE_H
#include "compiler.h"
#include "nasmlib.h"
#include "error.h"
#include <errno.h>
#ifdef HAVE_FCNTL_H
# include <fcntl.h>
#endif
#ifdef HAVE_SYS_TYPES_H
#endif
#ifdef HAVE_SYS_STAT_H
# include <sys/stat.h>
#endif
#ifdef HAVE_IO_H
# include <io.h>
#endif
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#ifdef HAVE_SYS_MMAN_H
# include <sys/mman.h>
#endif
#ifndef R_OK
# define R_OK 4 /* Classic Unix constant, same on Windows */
#endif
/* Can we adjust the file size without actually writing all the bytes? */
#ifdef HAVE__CHSIZE_S
# define os_ftruncate(fd,size) _chsize_s(fd,size)
#elif defined(HAVE__CHSIZE)
# define os_ftruncate(fd,size) _chsize(fd,size)
#elif defined(HAVE_FTRUNCATE)
# define os_ftruncate(fd,size) ftruncate(fd,size)
#endif
/*
* On Windows, we want to use _wfopen(), as fopen() has a much smaller limit
* on the path length that it supports. Furthermore, we want to prefix the
* path name with \\?\ in order to let the Windows kernel know that
* we are not limited to PATH_MAX characters. Thus, we wrap all the functions
* which take filenames...
*/
#ifdef _WIN32
# include <wchar.h>
typedef wchar_t *os_filename;
typedef wchar_t os_fopenflag;
os_filename os_mangle_filename(const char *filename);
static inline void os_free_filename(os_filename filename)
{
nasm_free(filename);
}
# define os_fopen _wfopen
# define os_access _waccess
/*
* On Win32/64, we have to use the _wstati64() function. Note that
* we can't use _wstat64() without depending on a needlessly new
* version os MSVCRT.
*/
typedef struct _stati64 os_struct_stat;
# define os_stat _wstati64
# define os_fstat _fstati64
/*
* On Win32/64, freopen() and _wfreopen() fails when the mode string
* is with the letter 'b' that represents to set binary mode. On
* POSIX operating systems, the 'b' is ignored, without failure.
*/
#include <io.h>
#include <fcntl.h>
static inline void os_set_binary_mode(FILE *f) {
int ret = _setmode(_fileno(f), _O_BINARY);
if (ret == -1) {
nasm_fatalf(ERR_NOFILE, "unable to open file: %s",
strerror(errno));
}
}
#else /* not _WIN32 */
typedef const char *os_filename;
typedef char os_fopenflag;
static inline os_filename os_mangle_filename(const char *filename)
{
return filename;
}
static inline void os_free_filename(os_filename filename)
{
(void)filename; /* Nothing to do */
}
static inline void os_set_binary_mode(FILE *f) {
(void)f;
}
# define os_fopen fopen
#if defined(HAVE_FACCESSAT) && defined(AT_EACCESS)
static inline int os_access(os_filename pathname, int mode)
{
return faccessat(AT_FDCWD, pathname, mode, AT_EACCESS);
}
# define os_access os_access
#elif defined(HAVE_ACCESS)
# define os_access access
#endif
#ifdef HAVE_STRUCT_STAT
typedef struct stat os_struct_stat;
# ifdef HAVE_STAT
# define os_stat stat
# endif
# ifdef HAVE_FSTAT
# define os_fstat fstat
# endif
#else
struct dummy_struct_stat {
int st_mode;
int st_size;
};
typedef struct dummy_struct_stat os_struct_stat;
#endif
#endif /* Not _WIN32 */
#ifdef S_ISREG
/* all good */
#elif defined(HAVE_S_ISREG)
/* exists, but not a macro */
# define S_ISREG S_ISREG
#elif defined(S_IFMT) && defined(S_IFREG)
# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
#elif defined(_S_IFMT) && defined(_S_IFREG)
# define S_ISREG(m) (((m) & _S_IFMT) == _S_IFREG)
#endif
#ifdef fileno
/* all good */
#elif defined(HAVE_FILENO)
/* exists, but not a macro */
# define fileno fileno
#elif defined(_fileno) || defined(HAVE__FILENO)
# define fileno _fileno
#endif
#ifndef S_ISREG
# undef os_stat
# undef os_fstat
#endif
/* Disable these functions if they don't support something we need */
#ifndef fileno
# undef os_fstat
# undef os_ftruncate
# undef HAVE_MMAP
#endif
/*
* If we don't have functional versions of these functions,
* stub them out so we don't need so many #ifndefs
*/
#ifndef os_stat
static inline int os_stat(os_filename osfname, os_struct_stat *st)
{
(void)osfname;
(void)st;
return -1;
}
#endif
#ifndef os_fstat
static inline int os_fstat(int fd, os_struct_stat *st)
{
(void)fd;
(void)st;
return -1;
}
#endif
#ifndef S_ISREG
static inline bool S_ISREG(int m)
{
(void)m;
return false;
}
#endif
#endif /* NASMLIB_FILE_H */

91
nasmlib/fileio.c Normal file
View file

@ -0,0 +1,91 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/* Copyright 1996-2017 The NASM Authors - All Rights Reserved */
#include "compiler.h"
#include "nasmlib.h"
#include "error.h"
void nasm_read(void *ptr, size_t size, FILE *f)
{
size_t n = fread(ptr, 1, size, f);
if (ferror(f)) {
nasm_fatal("unable to read input: %s", strerror(errno));
} else if (n != size || feof(f)) {
nasm_fatal("fatal short read on input");
}
}
void nasm_write(const void *ptr, size_t size, FILE *f)
{
size_t n = fwrite(ptr, 1, size, f);
if (n != size || ferror(f) || feof(f))
nasm_fatal("unable to write output: %s", strerror(errno));
}
void fwriteint16_t(uint16_t data, FILE * fp)
{
data = htole16(data);
nasm_write(&data, 2, fp);
}
void fwriteint32_t(uint32_t data, FILE * fp)
{
data = htole32(data);
nasm_write(&data, 4, fp);
}
void fwriteint64_t(uint64_t data, FILE * fp)
{
data = htole64(data);
nasm_write(&data, 8, fp);
}
void fwriteaddr(uint64_t data, int size, FILE * fp)
{
data = htole64(data);
nasm_write(&data, size, fp);
}
/* Can we adjust the file size without actually writing all the bytes? */
#ifdef HAVE_IO_H
# include <io.h>
#endif
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#ifdef HAVE__CHSIZE_S
# define os_ftruncate(fd,size) _chsize_s(fd,size)
#elif defined(HAVE__CHSIZE)
# define os_ftruncate(fd,size) _chsize(fd,size)
#elif defined(HAVE_FTRUNCATE)
# define os_ftruncate(fd,size) ftruncate(fd,size)
#endif
void fwritezero(off_t bytes, FILE *fp)
{
size_t blksize;
#ifdef os_ftruncate
if (bytes >= BUFSIZ && !ferror(fp) && !feof(fp)) {
off_t pos = ftello(fp);
if (pos != (off_t)-1) {
off_t end = pos + bytes;
if (!fflush(fp) && !os_ftruncate(fileno(fp), end)) {
fseeko(fp, 0, SEEK_END);
pos = ftello(fp);
if (pos != (off_t)-1)
bytes = end - pos; /* This SHOULD be zero */
}
}
}
#endif
while (bytes > 0) {
blksize = (bytes < ZERO_BUF_SIZE) ? bytes : ZERO_BUF_SIZE;
nasm_write(zero_buffer, blksize, fp);
bytes -= blksize;
}
}

View file

@ -1,33 +0,0 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/* Copyright 1996-2017 The NASM Authors - All Rights Reserved */
/*
* nasmlib.c library routines for the Netwide Assembler
*/
#include "compiler.h"
#include "nasmlib.h"
#include "error.h"
/*
* Add/modify a filename extension, assumed to be a period-delimited
* field at the very end of the filename. Returns a newly allocated
* string buffer.
*/
const char *filename_set_extension(const char *inname, const char *extension)
{
const char *q = inname;
char *p;
size_t elen = strlen(extension);
size_t baselen;
q = strrchrnul(inname, '.'); /* find extension or end of string */
baselen = q - inname;
p = nasm_malloc(baselen + elen + 1);
memcpy(p, inname, baselen);
memcpy(p+baselen, extension, elen+1);
return p;
}

View file

@ -1,13 +1,26 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/* Copyright 1996-2017 The NASM Authors - All Rights Reserved */
#include "file.h"
#include "nasmlib.h"
/* ----------------------------------------------------------------------- *
* Unix-style memory mapping, using mmap().
* ----------------------------------------------------------------------- */
#if defined(HAVE_FILENO) && defined(HAVE_MMAP)
#ifdef HAVE_FCNTL_H
# include <fcntl.h>
#endif
#ifdef HAVE_SYS_STAT_H
# include <sys/stat.h>
#endif
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#ifdef HAVE_SYS_MMAN_H
# include <sys/mman.h>
#endif
/*
* System page size
*/

View file

@ -29,7 +29,8 @@ int numstr(char *buf, size_t buflen, uint64_t n,
char *p;
int len;
if (base < 2 || base > NUMSTR_MAXBASE)
if (unlikely(base < 2) || unlikely(base > NUMSTR_MAXBASE) ||
unlikely(!buflen))
return -1;
if (moredigits)

View file

@ -69,37 +69,39 @@
# define leaveonclean 0
# define leave_leading 1
#elif PATHSTYLE == PATH_VMS
/*
* VMS filenames may have ;version at the end. Assume we should count that
* as part of the filename anyway.
*/
# define separators ":]"
# define curdir "[]"
# define postext ";"
#else
/* No idea what to do here, do nothing. Feel free to add new ones. */
# define curdir ""
#endif
#ifndef extsep
# define extsep '.'
#endif
/*
* This is an inline, because most compilers can greatly simplify this
* for a fixed string, like we have here.
*/
static inline bool pure_func ismatch(const char *charset, char ch)
{
const char *p;
for (p = charset; *p; p++) {
if (ch == *p)
return true;
if (charset && *charset) {
const char *p;
for (p = charset; *p; p++) {
if (ch == *p)
return true;
}
}
return false;
}
static const char * pure_func first_filename_char(const char *path)
static inline const char * pure_func first_filename_char(const char *path)
{
#ifdef separators
const char *p = path + strlen(path);
const char *p = strchr(path, '\0');
while (p > path) {
if (ismatch(separators, p[-1]))
@ -178,3 +180,51 @@ char *nasm_catfile(const char *dir, const char *file)
return p;
#endif
}
/*
* Add/modify a filename extension. Returns a newly allocated
* string buffer. If the extension is not an empty string, the first
* character is replaced by the appropriate extsep for the filesystem.
*/
char *filename_set_extension(const char *inname, const char *extension)
{
const char *nulp, *ep, *p;
char *outname, *q;
size_t elen = strlen(extension);
size_t baselen;
ep = nulp = strchr(inname, '\0');
for (p = nulp-1; p >= inname; p--) {
char c = *p;
if (c == extsep) {
/* Found the beginning of an existing extension */
ep = p;
break;
}
if (ismatch(separators, c)) {
/* Found the beginning of the file name */
ep = p+1;
break;
}
#ifdef postext
if (ismatch(postext, c)) {
/* Found the beginning of a character sequence
that should be stripped off; keep searching from here */
ep = p;
continue;
}
#endif
}
baselen = ep - inname;
q = outname = nasm_malloc(baselen + elen + 1);
q = mempcpy(q, inname, baselen);
if (!elen) {
*q = '\0';
} else {
*q++ = extsep;
memcpy(q, extension+1, elen); /* Includes final null */
}
return outname;
}

View file

@ -8,19 +8,12 @@
#include "compiler.h"
#include "nctype.h"
#include "nasmlib.h"
#include "nasm.h"
#include "error.h"
#include "nasm.h" /* For globl.dollarhex */
#define lib_isnumchar(c) (nasm_isalnum(c) || (c) == '$' || (c) == '_')
void warn_dollar_hex(void)
{
nasm_warn(WARN_NUMBER_DEPRECATED_HEX,
"$ prefix for hexadecimal is deprecated");
}
int64_t readnum(const char *str, bool *error)
{
const char *r = str, *q;

View file

@ -3,6 +3,7 @@
#include "compiler.h"
#include "nasmlib.h"
#include "ilog2.h"
#include "saa.h"
/* Aggregate SAA components smaller than this */
@ -299,55 +300,57 @@ void saa_writeaddr(struct SAA *s, uint64_t v, size_t len)
saa_wbytes(s, &v, len);
}
/* write unsigned LEB128 value to SAA */
void saa_wleb128u(struct SAA *psaa, int value)
/*
* Write an LEB128 value to an SAA. Each byte contains 7 bits of
* payload in littleendian order, with the topmost bit indicating
* continuation.
*
* For the signed format, the sign bit needs to be included, even if
* it zero, so may generate an encoding that would be invalid for
* the unsigned format, e.g 127:
*
* unsigned: 7F
* signed: FF 00
*
* Thus, the >> 6 instead of >> 7 in the exit test for the signed
* version.
*/
void saa_wleb128u(struct SAA *s, uint64_t value)
{
char temp[64], *ptemp;
uint8_t buf[sizeof(value)*2]; /* Very conservative allocation :) */
uint8_t *p = buf;
uint8_t byte;
int len;
ptemp = temp;
len = 0;
do {
while (1) {
byte = value & 127;
value >>= 7;
if (value != 0) /* more bytes to come */
byte |= 0x80;
*ptemp = byte;
ptemp++;
len++;
} while (value != 0);
saa_wbytes(psaa, temp, len);
}
/* write signed LEB128 value to SAA */
void saa_wleb128s(struct SAA *psaa, int value)
{
char temp[64], *ptemp;
uint8_t byte;
bool more, negative;
int size, len;
ptemp = temp;
more = 1;
negative = (value < 0);
size = sizeof(int) * 8;
len = 0;
while (more) {
byte = value & 0x7f;
value >>= 7;
if (negative)
/* sign extend */
value |= -(1 << (size - 7));
/* sign bit of byte is second high order bit (0x40) */
if ((value == 0 && !(byte & 0x40)) ||
((value == -1) && (byte & 0x40)))
more = 0;
else
byte |= 0x80;
*ptemp = byte;
ptemp++;
len++;
if (!value) {
*p++ = byte;
break;
}
byte |= 0x80;
*p++ = byte;
}
saa_wbytes(psaa, temp, len);
saa_wbytes(s, buf, p-buf);
}
/* write a signed LEB128 value to SAA */
void saa_wleb128s(struct SAA *s, int64_t value)
{
uint8_t buf[sizeof(value)*2]; /* Very conservative allocation :) */
uint8_t *p = buf;
uint8_t byte;
int64_t sign = value >> 63;
while (1) {
byte = value & 127;
if ((value >> 6) == sign) {
*p++ = byte;
break;
}
value >>= 7;
byte |= 0x80;
*p++ = byte;
}
saa_wbytes(s, buf, p-buf);
}

View file

@ -11,6 +11,7 @@
#include "nasm.h"
#include "nasmlib.h"
#include "files.h"
#include "error.h"
#include "preproc.h"
#include "saa.h"
@ -25,7 +26,6 @@ static void cv8_linenum(const char *filename, int32_t linenumber,
static void cv8_deflabel(char *name, int32_t segment, int64_t offset,
int is_global, char *special);
static void cv8_typevalue(int32_t type);
static void cv8_output(int type, void *param);
static void cv8_cleanup(void);
const struct dfmt df_cv8 = {
@ -39,7 +39,7 @@ const struct dfmt df_cv8 = {
NULL, /* .debug_mmacros */
null_debug_directive, /* .debug_directive */
cv8_typevalue, /* .debug_typevalue */
cv8_output, /* .debug_output */
NULL, /* .debug_output */
cv8_cleanup, /* .cleanup */
NULL /* pragma list */
};
@ -47,6 +47,12 @@ const struct dfmt df_cv8 = {
/*******************************************************************************
* dfmt callbacks
******************************************************************************/
struct sect_lines
{
struct SAA *lines;
uint32_t num_lines;
};
struct source_file;
struct source_file {
@ -59,8 +65,7 @@ struct source_file {
uint32_t filetbl_off;
uint32_t sourcetbl_off;
struct SAA *lines;
uint32_t num_lines;
struct sect_lines *sects;
unsigned char md5sum[MD5_HASHBYTES];
};
@ -108,8 +113,6 @@ struct cv8_state {
int symbol_sect;
int type_sect;
uint32_t text_offset;
struct source_file *source_files, **source_files_tail;
const char *last_filename;
struct source_file *last_source_file;
@ -117,9 +120,6 @@ struct cv8_state {
unsigned num_files;
uint32_t total_filename_len;
unsigned total_lines;
struct SAA *symbols;
struct cv8_symbol *last_sym;
unsigned num_syms[SYMTYPE_MAX];
@ -143,62 +143,68 @@ static void cv8_init(void)
cv8_state.symbol_sect = coff_make_section(".debug$S", sect_flags);
cv8_state.type_sect = coff_make_section(".debug$T", sect_flags);
cv8_state.text_offset = 0;
cv8_state.source_files = NULL;
cv8_state.source_files_tail = &cv8_state.source_files;
cv8_state.num_files = 0;
cv8_state.total_filename_len = 0;
cv8_state.total_lines = 0;
cv8_state.symbols = saa_init(sizeof(struct cv8_symbol));
cv8_state.last_sym = NULL;
}
static struct source_file *register_file(const char *filename);
static struct coff_Section *find_section(int32_t segto);
static int find_section(int32_t segto);
static void cv8_linenum(const char *filename, int32_t linenumber,
int32_t segto)
{
struct coff_Section *s;
struct linepair *li;
struct source_file *file;
struct sect_lines *sl;
int i;
file = register_file(filename);
s = find_section(segto);
if (s == NULL)
i = find_section(segto);
if (i == -1)
return;
if ((s->flags & IMAGE_SCN_MEM_EXECUTE) == 0)
if ((coff_sects[i]->flags & IMAGE_SCN_MEM_EXECUTE) == 0)
return;
li = saa_wstruct(file->lines);
li->file_offset = cv8_state.text_offset;
sl = &register_file(filename)->sects[i];
if (!sl->lines)
sl->lines = saa_init(sizeof(struct linepair));
li = saa_wstruct(sl->lines);
li->file_offset = coff_sects[i]->len;
li->linenumber = linenumber;
file->num_lines++;
cv8_state.total_lines++;
sl->num_lines++;
}
static void cv8_deflabel(char *name, int32_t segment, int64_t offset,
int is_global, char *special)
{
struct cv8_symbol *sym;
struct coff_Section *s;
int i;
(void)special;
s = find_section(segment);
if (s == NULL)
/* Skip macro-local labels */
if (name[0] == '.' && name[1] == '.' && name[2] == '@' && name[3] >= '0' && name[3] <= '9')
return;
i = find_section(segment);
if (i == -1)
return;
/* MS linker errors on relocations to .pdata section, so skip such symbols */
if (!strcmp(coff_sects[i]->name, ".pdata"))
return;
sym = saa_wstruct(cv8_state.symbols);
if (s->flags & IMAGE_SCN_MEM_EXECUTE)
if (coff_sects[i]->flags & IMAGE_SCN_MEM_EXECUTE)
sym->type = is_global ? SYMTYPE_PROC : SYMTYPE_CODE;
else
sym->type = is_global ? SYMTYPE_GDATA : SYMTYPE_LDATA;
@ -261,17 +267,6 @@ static void cv8_typevalue(int32_t type)
}
}
static void cv8_output(int type, void *param)
{
struct coff_DebugInfo *dinfo = param;
(void)type;
if (dinfo->section && dinfo->section->name &&
!strncmp(dinfo->section->name, ".text", 5))
cv8_state.text_offset += dinfo->size;
}
static void build_symbol_table(struct coff_Section *const sect);
static void build_type_table(struct coff_Section *const sect);
@ -283,15 +278,19 @@ static void cv8_cleanup(void)
struct coff_Section *symbol_sect = coff_sects[cv8_state.symbol_sect];
struct coff_Section *type_sect = coff_sects[cv8_state.type_sect];
cv8_state.outfile.name = nasm_realpath(outname);
cv8_state.outfile.name = nasm_realpath(get_filename(FN_OUTFILE));
cv8_state.outfile.namebytes = strlen(cv8_state.outfile.name) + 1;
build_symbol_table(symbol_sect);
build_type_table(type_sect);
list_for_each_safe(file, ftmp, cv8_state.source_files) {
int i;
nasm_free(file->fullname);
saa_free(file->lines);
for (i = 0; i < coff_nsects; i++)
if (file->sects[i].lines)
saa_free(file->sects[i].lines);
nasm_free(file->sects);
nasm_free(file);
}
hash_free(&cv8_state.file_hash);
@ -375,7 +374,7 @@ static struct source_file *register_file(const char *filename)
file->filename = filename;
file->fullname = fullpath;
file->fullnamelen = strlen(fullpath);
file->lines = saa_init(sizeof(struct linepair));
file->sects = nasm_calloc(coff_nsects, sizeof(*file->sects));
*cv8_state.source_files_tail = file;
cv8_state.source_files_tail = &file->next;
calc_md5(fullpath, file->md5sum);
@ -390,25 +389,21 @@ static struct source_file *register_file(const char *filename)
return file;
}
static struct coff_Section *find_section(int32_t segto)
static int find_section(int32_t segto)
{
int i;
for (i = 0; i < coff_nsects; i++) {
struct coff_Section *sec;
for (i = 0; i < coff_nsects; i++)
if (segto == coff_sects[i]->index)
return i;
sec = coff_sects[i];
if (segto == sec->index)
return sec;
}
return NULL;
return -1;
}
static void register_reloc(struct coff_Section *const sect,
char *sym, uint32_t addr, uint16_t type)
int reloc_sect, char *sym, uint32_t addr, uint16_t type)
{
struct coff_Reloc *r;
struct coff_Section *sec;
uint32_t i;
r = *sect->tail = nasm_malloc(sizeof(struct coff_Reloc));
@ -420,14 +415,9 @@ static void register_reloc(struct coff_Section *const sect,
r->symbase = SECT_SYMBOLS;
r->type = type;
r->symbol = 0;
for (i = 0; i < (uint32_t)coff_nsects; i++) {
sec = coff_sects[i];
if (!strcmp(sym, sec->name)) {
return;
}
r->symbol += 2;
}
r->symbol = reloc_sect * 2;
if (reloc_sect < coff_nsects)
return;
saa_rewind(coff_syms);
for (i = 0; i < coff_nsyms; i++) {
@ -531,52 +521,58 @@ static void write_linenumber_table(struct coff_Section *const sect)
const uint32_t line_field_len = 8;
int i;
uint32_t field_length = 0;
size_t field_base;
struct source_file *file;
struct coff_Section *s;
for (i = 0; i < coff_nsects; i++) {
if (!strncmp(coff_sects[i]->name, ".text", 5))
break;
}
uint32_t field_length;
size_t field_base;
struct source_file *file;
struct coff_Section *s;
unsigned num_files = 0;
unsigned total_lines = 0;
if (i == coff_nsects)
return;
s = coff_sects[i];
list_for_each(file, cv8_state.source_files)
if (file->sects[i].num_lines) {
num_files++;
total_lines += file->sects[i].num_lines;
}
if (!total_lines)
continue;
field_length = 12;
field_length += (cv8_state.num_files * file_field_len);
field_length += (cv8_state.total_lines * line_field_len);
s = coff_sects[i];
section_write32(sect, 0x000000F2);
section_write32(sect, field_length);
field_length = 12;
field_length += (num_files * file_field_len);
field_length += (total_lines * line_field_len);
field_base = sect->len;
section_write32(sect, 0); /* SECREL, updated by relocation */
section_write16(sect, 0); /* SECTION, updated by relocation*/
section_write16(sect, 0); /* pad */
section_write32(sect, s->len);
section_write32(sect, 0x000000F2);
section_write32(sect, field_length);
register_reloc(sect, ".text", field_base,
win64 ? IMAGE_REL_AMD64_SECREL : IMAGE_REL_I386_SECREL);
field_base = sect->len;
section_write32(sect, 0); /* SECREL, updated by relocation */
section_write16(sect, 0); /* SECTION, updated by relocation*/
section_write16(sect, 0); /* pad */
section_write32(sect, s->len);
register_reloc(sect, ".text", field_base + 4,
win64 ? IMAGE_REL_AMD64_SECTION : IMAGE_REL_I386_SECTION);
register_reloc(sect, i, NULL, field_base,
win64 ? IMAGE_REL_AMD64_SECREL : IMAGE_REL_I386_SECREL);
list_for_each(file, cv8_state.source_files) {
struct linepair *li;
register_reloc(sect, i, NULL, field_base + 4,
win64 ? IMAGE_REL_AMD64_SECTION : IMAGE_REL_I386_SECTION);
/* source mapping */
section_write32(sect, file->sourcetbl_off);
section_write32(sect, file->num_lines);
section_write32(sect, file_field_len + (file->num_lines * line_field_len));
list_for_each(file, cv8_state.source_files) {
struct linepair *li;
/* the pairs */
saa_rewind(file->lines);
while ((li = saa_rstruct(file->lines))) {
section_write32(sect, li->file_offset);
section_write32(sect, li->linenumber |= 0x80000000);
/* source mapping */
section_write32(sect, file->sourcetbl_off);
section_write32(sect, file->sects[i].num_lines);
section_write32(sect, file_field_len + (file->sects[i].num_lines * line_field_len));
/* the pairs */
saa_rewind(file->sects[i].lines);
while ((li = saa_rstruct(file->sects[i].lines))) {
section_write32(sect, li->file_offset);
section_write32(sect, li->linenumber |= 0x80000000);
}
}
}
}
@ -685,10 +681,10 @@ static uint32_t write_symbolinfo_symbols(struct coff_Section *sect)
section_wbytes(sect, sym->name, strlen(sym->name) + 1);
register_reloc(sect, sym->name, field_base,
register_reloc(sect, coff_nsects, sym->name, field_base,
win64 ? IMAGE_REL_AMD64_SECREL :
IMAGE_REL_I386_SECREL);
register_reloc(sect, sym->name, field_base + 4,
register_reloc(sect, coff_nsects, sym->name, field_base + 4,
win64 ? IMAGE_REL_AMD64_SECTION :
IMAGE_REL_I386_SECTION);
}
@ -751,12 +747,14 @@ static void build_symbol_table(struct coff_Section *const sect)
{
section_write32(sect, 0x00000004);
write_filename_table(sect);
align4_table(sect);
write_sourcefile_table(sect);
align4_table(sect);
write_linenumber_table(sect);
align4_table(sect);
if (cv8_state.source_files) {
write_filename_table(sect);
align4_table(sect);
write_sourcefile_table(sect);
align4_table(sect);
write_linenumber_table(sect);
align4_table(sect);
}
write_symbolinfo_table(sect);
align4_table(sect);
}

View file

@ -232,6 +232,7 @@
#define STT_COMMON 5 /* Symbol is a common data object */
#define STT_TLS 6 /* Symbol is thread-local data object */
#define STT_NUM 7 /* Number of defined types */
#define STT_GNU_IFUNC 10 /* Symbol is indirect code object */
/* Symbol visibilities */
#define STV_DEFAULT 0 /* Default symbol visibility rules */

View file

@ -12,6 +12,7 @@
#include "nasm.h"
#include "nasmlib.h"
#include "files.h"
#include "error.h"
#include "saa.h"
#include "raa.h"
@ -25,7 +26,7 @@ struct Piece {
int type; /* 0 = absolute, 1 = seg, 2 = sym */
int32_t offset; /* relative offset */
int number; /* symbol/segment number (4=bss) */
int32_t bytes; /* size of reloc or of absolute data */
int32_t bytes; /* size of reloc or of absolute data */
bool relative; /* relative address? */
};
@ -80,6 +81,8 @@ static void as86_sect_write(struct Section *, const uint8_t *,
static void as86_init(void)
{
char *module_name;
stext.data = saa_init(1L);
stext.datalen = 0L;
stext.head = stext.last = NULL;
@ -101,7 +104,9 @@ static void as86_init(void)
strslen = 0;
/* as86 module name = input file minus extension */
as86_add_string(filename_set_extension(inname, ""));
module_name = filename_set_extension(get_filename(FN_MAPPED_INFILE), "");
as86_add_string(module_name);
nasm_free(module_name);
}
static void as86_cleanup(void)

View file

@ -49,6 +49,7 @@
#include "nasm.h"
#include "nasmlib.h"
#include "files.h"
#include "error.h"
#include "saa.h"
#include "stdscan.h"
@ -543,7 +544,7 @@ static void bin_cleanup(void)
for (h = 63; h; h--)
fputc('-', rf);
fprintf(rf, "\n\nSource file: %s\nOutput file: %s\n\n",
inname, outname);
get_filename(FN_INFILE), get_filename(FN_OUTFILE));
if (map_control & MAP_ORIGIN) { /* Display program origin. */
fprintf(rf, "-- Program origin ");
@ -1294,6 +1295,8 @@ bin_directive(enum directive directive, char *args)
else if (!nasm_stricmp(p, "stderr"))
rf = stderr;
else { /* Must be a filename. */
copy_filename(FN_MAPFILE, p);
check_overwrite_files();
rf = nasm_open_write(p, NF_TEXT);
if (!rf) {
nasm_nonfatal("unable to open map file `%s'", p);

View file

@ -15,6 +15,7 @@
#include "nasm.h"
#include "nasmlib.h"
#include "ilog2.h"
#include "files.h"
#include "error.h"
#include "saa.h"
#include "raa.h"
@ -74,6 +75,9 @@ bool win32, win64;
static int32_t imagebase_sect;
#define WRT_IMAGEBASE "..imagebase"
static int32_t symtab_sect;
#define WRT_SYMTAB "..symtab"
/*
* Some common section flags by default
*/
@ -192,6 +196,8 @@ static void coff_gen_init(void)
coff_strs = saa_init(1);
strslen = 0;
def_seg = seg_alloc();
symtab_sect = seg_alloc()+1;
backend_label(WRT_SYMTAB, symtab_sect, 0);
}
static void coff_cleanup(void)
@ -210,6 +216,11 @@ static void coff_cleanup(void)
coff_sects[i]->head = coff_sects[i]->head->next;
nasm_free(r);
}
while (coff_sects[i]->symidx_reloc_head) {
struct coff_SymIdxReloc * const ir = coff_sects[i]->symidx_reloc_head;
coff_sects[i]->symidx_reloc_head = ir->next;
nasm_free(ir);
}
nasm_free(coff_sects[i]->name);
nasm_free(coff_sects[i]->comdat_name);
nasm_free(coff_sects[i]);
@ -539,16 +550,18 @@ static void coff_deflabel(char *name, int32_t segment, int64_t offset,
int pos, section;
struct coff_Symbol *sym;
if (special)
nasm_nonfatal("COFF format does not support any"
" special symbol types");
nasm_debug(2, " coff_deflabel: %s, seg=%"PRIx32", off=%"PRIx64", is_global=%d, %s, coff_nsyms=%"PRIu32"\n",
name, segment, offset, is_global, special, coff_nsyms);
if (name[0] == '.' && name[1] == '.' && name[2] != '@') {
if (strcmp(name,WRT_IMAGEBASE))
if (strcmp(name,WRT_IMAGEBASE) && strcmp(name, WRT_SYMTAB))
nasm_nonfatal("unrecognized special symbol `%s'", name);
return;
}
if (is_global == 3) /* discard special-retry from pass two. */
return;
if (segment == NO_SEG)
section = -1; /* absolute symbol */
else {
@ -598,6 +611,20 @@ static void coff_deflabel(char *name, int32_t segment, int64_t offset,
else
sym->value = (sym->section == 0 ? 0 : offset);
if (special) {
special = nasm_skip_spaces(special);
while (*special) {
const char *wend = nasm_skip_word(special);
size_t wlen = wend - special;
if (wlen == 8 && !nasm_strnicmp(special, "function", 8))
sym->type = 0x20; /* DT_FCN */
else
nasm_nonfatal("unrecognised symbol type `%*.*s' on `%s'",
(int)wlen, (int)wlen, special, name);
special = nasm_skip_spaces(wend);
}
}
/*
* define the references from external-symbol segment numbers
* to these symbol records.
@ -649,6 +676,49 @@ static int32_t coff_add_reloc(struct coff_Section *sect, int32_t segment,
return 0;
}
/* Helper for coff_out handling wrt ..symtab addressing. */
static uint32_t coff_out_get_symbol_idx(int32_t tsegment, int64_t offset)
{
/* No better way of doing this? */
int section;
if (tsegment == NO_SEG) {
section = -1;
} else {
for (section = 0; section < coff_nsects; section++)
if (tsegment == coff_sects[section]->index)
break;
section++;
}
/* Do symbol table lookup (unless it is external). */
if (section <= coff_nsects) {
uint32_t n, symidx = UINT32_MAX;
saa_rewind(coff_syms);
for (n = 0; n < coff_nsyms; n++) {
struct coff_Symbol *sym = saa_rstruct(coff_syms);
nasm_try_static_assert(sizeof(sym->value) == sizeof(int32_t));
if (sym->section == section && sym->value == (int32_t)offset) {
if (sym->type & 0x30) /* N_TMASK */
return n; /* Prefer symbol with non-NULL type. */
if (symidx == UINT32_MAX)
symidx = n;
}
}
if (symidx == UINT32_MAX)
nasm_nonfatal("wrt ..symtab: Unable to find symbol for %s:%#" PRIx64,
section > 0 ? coff_sects[section - 1]->name : "ABS", offset);
return symidx;
}
/* External symbols. */
if (tsegment != NO_SEG)
return raa_read(bsym, tsegment);
nasm_nonfatal("wrt ..symtab: Unable to find symbol for %#"PRIx32":%#" PRIx64,
tsegment, offset);
return UINT32_MAX;
}
static void coff_out(const struct out_data *out)
{
OUT_LEGACY(out,segto,data,type,size,segment,wrt);
@ -656,7 +726,7 @@ static void coff_out(const struct out_data *out)
uint8_t mydata[8], *p;
int i;
if (wrt != NO_SEG && !win64) {
if (wrt != NO_SEG && wrt != symtab_sect && !win64) {
wrt = NO_SEG; /* continue to do _something_ */
nasm_nonfatal("WRT not supported by COFF output formats");
}
@ -716,7 +786,25 @@ static void coff_out(const struct out_data *out)
coff_sect_write(s, data, size);
} else if (type == OUT_ADDRESS) {
int asize = abs((int)size);
if (!win64) {
if (wrt == symtab_sect) {
/* Emit internal fixup since the table starts with sections and
stuff that can be added to after this statement. */
struct coff_SymIdxReloc *ir;
nasm_new(ir);
ir->offset = s->len;
ir->size = (uint8_t)asize;
ir->symbol = coff_out_get_symbol_idx(segment, out->toffset);
ir->next = s->symidx_reloc_head;
s->symidx_reloc_head = ir;
nasm_assert((unsigned)asize <= sizeof(mydata));
coff_sect_write(s, mydata, asize);
if (asize > 4)
nasm_warn(WARN_OTHER, "zero extending 'wrt "WRT_SYMTAB
"' (32-bit) to %u-bit", asize * 8);
else if (asize < 4)
nasm_warn(WARN_OTHER, "truncating 'wrt "WRT_SYMTAB
"' (32-bit) to %u-bit", asize * 8);
} else if (!win64) {
if (asize != 4 && (segment != NO_SEG || wrt != NO_SEG)) {
nasm_nonfatal("COFF format does not support non-32-bit"
" relocations");
@ -900,6 +988,8 @@ coff_directives(enum directive directive, char *value)
{
static int sxseg=-1;
int i;
int32_t ignseg;
int64_t ignoff;
if (!win32) /* Only applicable for -f win32 */
return DIRR_UNKNOWN;
@ -907,6 +997,8 @@ coff_directives(enum directive directive, char *value)
if (!value)
return DIRR_OK;
lookup_label(value, &ignseg, &ignoff); /* prevent extern elimination */
if (sxseg == -1) {
for (i = 0; i < coff_nsects; i++)
if (!strcmp(".sxdata",coff_sects[i]->name))
@ -1102,6 +1194,15 @@ static void coff_write(void)
*/
for (i = 0; i < coff_nsects; i++)
if (coff_sects[i]->data) {
/* Apply symbol table index fixups before writing */
struct coff_SymIdxReloc *ir;
for (ir = coff_sects[i]->symidx_reloc_head; ir; ir = ir->next) {
uint8_t mydata[4];
setu32(mydata, ir->symbol + initsym);
saa_fwrite(coff_sects[i]->data, ir->offset,
mydata, ir->size >= 4 ? 4 : ir->size);
}
saa_fpwrite(coff_sects[i]->data, ofile);
coff_write_relocs(coff_sects[i]);
@ -1241,7 +1342,7 @@ static void coff_write_symbols(void)
if (reproducible)
memset(filename, 0, 18);
else
strncpy(filename, inname, 18);
strncpy(filename, get_filename(FN_MAPPED_INFILE), 18);
nasm_write(filename, 18, ofile);
/*

View file

@ -13,6 +13,7 @@
#include "nasm.h"
#include "nasmlib.h"
#include "files.h"
#include "outform.h"
#include "outlib.h"
#include "insns.h"
@ -36,8 +37,8 @@ static void dbg_init(void)
{
dbgsect = NULL;
fprintf(ofile, "NASM Output format debug dump\n");
fprintf(ofile, "input file = %s\n", inname);
fprintf(ofile, "output file = %s\n", outname);
fprintf(ofile, "input file = %s\n", get_filename(FN_INFILE));
fprintf(ofile, "output file = %s\n", get_filename(FN_OUTFILE));
init_seg = seg_alloc();
}

View file

@ -10,6 +10,7 @@
#include "nasm.h"
#include "nasmlib.h"
#include "files.h"
#include "error.h"
#include "saa.h"
#include "raa.h"
@ -508,16 +509,27 @@ static void elf64_init(void)
elf_init();
}
static void elf_populate_dirs(void)
{
const char * const infile = get_filename(FN_MAPPED_INFILE);
char *cur_path = nasm_realpath(infile);
char *dir_name = nasm_dirname(cur_path);
strlcpy(elf_module, infile, sizeof(elf_module));
strlcpy(elf_dir, dir_name, sizeof(elf_dir));
nasm_free(dir_name);
nasm_free(cur_path);
}
static void elf_init(void)
{
static const char * const reserved_sections[] = {
".shstrtab", ".strtab", ".symtab", ".symtab_shndx", NULL
};
const char * const *p;
const char * cur_path = nasm_realpath(inname);
strlcpy(elf_module, inname, sizeof(elf_module));
strlcpy(elf_dir, nasm_dirname(cur_path), sizeof(elf_dir));
elf_populate_dirs();
sects = NULL;
nsects = sectlen = 0;
syms = saa_init((int32_t)sizeof(struct elf_symbol));
@ -886,6 +898,8 @@ static void elf_deflabel(char *name, int32_t segment, int64_t offset,
case 9:
if (!nasm_strnicmp(spcword, "protected", wlen))
sym->other = STV_PROTECTED;
else if (!nasm_strnicmp(spcword, "gnu_ifunc", wlen))
type = STT_GNU_IFUNC;
else
ok = false;
break;
@ -1883,7 +1897,7 @@ static void elf_write(void)
ehdr.com.e_ident[EI_ABIVERSION] = elf_abiver;
ehdr.com.e_type = htole16(ET_REL);
ehdr.com.e_machine = htole16(efmt->e_machine);
ehdr.com.e_version = htole16(EV_CURRENT);
ehdr.com.e_version = htole32(EV_CURRENT);
if (!efmt->elf64) {
ehdr.ehdr32.e_shoff = htole32(sizeof ehdr);

View file

@ -71,7 +71,7 @@ void ofmt_list(const struct ofmt *deffmt, FILE * fp)
for (i = 0; i < ARRAY_SIZE(ofmt_aliases); i++) {
if (!ofmt_aliases[i].shortname)
continue;
fprintf(fp, " %-20s Legacy alias for \"%s\"\n",
fprintf(fp, " %-20s Alias for \"%s\"\n",
ofmt_aliases[i].shortname,
ofmt_aliases[i].ofmt->shortname);
}

View file

@ -320,6 +320,13 @@ static const struct ofmt_alias ofmt_aliases[] = {
#ifdef OF_MACHO32
{ "macho", &of_macho32 },
#endif
#ifdef OF_OBJ
{ "omf", &of_obj },
#endif
#ifdef OF_OBJ2
{ "omf2", &of_obj2 },
{ "os2", &of_obj2 },
#endif
#ifdef OF_WIN32
{ "win", &of_win32 },
#endif

View file

@ -45,6 +45,7 @@
#include "nasmlib.h"
#include "asmutil.h"
#include "error.h"
#include "files.h"
#include "ver.h"
#include "outform.h"
@ -178,7 +179,7 @@ static void ieee_unqualified_name(char *, char *);
*/
static void ieee_init(void)
{
strlcpy(ieee_infile, inname, sizeof(ieee_infile));
strlcpy(ieee_infile, get_filename(FN_MAPPED_INFILE), sizeof(ieee_infile));
any_segs = false;
fpubhead = NULL;
fpubtail = &fpubhead;

View file

@ -14,6 +14,7 @@
#include "nasmlib.h"
#include "ilog2.h"
#include "labels.h"
#include "files.h"
#include "error.h"
#include "saa.h"
#include "raa.h"
@ -324,7 +325,7 @@ static int32_t macho_gotpcrel_sect;
static void macho_init(void)
{
module_name = inname;
module_name = get_filename(FN_MAPPED_INFILE);
sects = NULL;
sectstail = &sects;

View file

@ -17,6 +17,7 @@
#include "error.h"
#include "stdscan.h"
#include "eval.h"
#include "files.h"
#include "ver.h"
#include "outform.h"
@ -656,7 +657,7 @@ static const char *get_default_class(const char *segment)
static void obj_init(void)
{
strlcpy(obj_infile, inname, sizeof(obj_infile));
strlcpy(obj_infile, get_filename(FN_MAPPED_INFILE), sizeof(obj_infile));
first_seg = seg_alloc();
any_segs = false;
fpubhead = NULL;
@ -710,6 +711,7 @@ static void obj_cleanup(void)
nasm_free(pubtmp->name);
nasm_free(pubtmp);
}
nasm_free(segtmp->name);
nasm_free(segtmp->segclass);
nasm_free(segtmp->overlay);
nasm_free(segtmp);
@ -1736,6 +1738,10 @@ obj_directive(enum directive directive, char *value)
*/
continue;
}
if (grp->nentries >= GROUP_MAX) {
nasm_nonfatal("too many segments in a group");
return DIRR_ERROR;
}
for (seg = seghead; seg; seg = seg->next)
if (!strcmp(seg->name, p))
break;

View file

@ -457,6 +457,7 @@ struct coff_Section {
int32_t namepos; /* Offset of name into the strings table */
int32_t pos, relpos;
int64_t pass_last_seen;
struct coff_SymIdxReloc *symidx_reloc_head;
/* comdat-related members */
char *comdat_name;
@ -478,6 +479,13 @@ struct coff_Reloc {
int16_t type;
};
struct coff_SymIdxReloc {
struct coff_SymIdxReloc *next;
uint32_t symbol; /* symbol number */
uint32_t offset; /* byte offset into the secetion. */
uint32_t size; /* the size of the area to fix up */
};
struct coff_Symbol {
char name[9];
int32_t strpos; /* string table position of name */

View file

@ -1,19 +0,0 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/* Copyright 2017 The NASM Authors - All Rights Reserved */
#include "compiler.h"
#ifndef HAVE_STRRCHRNUL
char * pure_func strrchrnul(const char *s, int c)
{
char *p;
p = strrchr(s, c);
if (!p)
p = strchr(s, '\0');
return p;
}
#endif

11
templates/template.h Normal file
View file

@ -0,0 +1,11 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/* Copyright 1996-20xx The NASM Authors - All Rights Reserved */
#ifndef FILENAME_H
#define FILENAME_H
#include "compiler.h"
/* Code goes here */
#endif /* FILENAME_H */

View file

@ -1,5 +1,3 @@
@SET_MAKE@
.SUFFIXES: .bin .bin16 .bin32 .bin64 .o .o64 .aout .aoutb .obj .obj64 \
.mo32 .mo64 .dbg .i .od .ox .ith .srec .exe .lst \
.asm .pl
@ -13,13 +11,13 @@ NASM = ../nasm$(X)
NDISASM = ../ndisasm$(X)
OMFDUMP = ../misc/omfdump$(X)
LISTOPT = -L+
NASMOPT = -DSRC -Ox -I../misc $(LISTOPT) $(OPT)
NASMOPT = -DSRC -Ox -I../misc -I../travis/pushimm -I../travis/macroerr -I../travis/incbin $(LISTOPT) $(OPT)
PERL = perl
TESTS = $(wildcard *.asm)
RM_F = rm -f
RM_RF = rm -rf
.PHONY: tools nasm ndisasm ffmpegtest x264test
.PHONY: tools nasm ndisasm ffmpegtest x264test dav1dtest intel-ipsec-mbtest isa-ltest isa-l_cryptotest cryptography-primitivestest
tools:
$(MAKE) -C .. all
@ -35,6 +33,21 @@ ffmpegtest:
x264test:
bash projtest.sh '$(NASM)' $@
dav1dtest:
bash projtest.sh '$(NASM)' $@
intel-ipsec-mbtest:
bash projtest.sh '$(NASM)' $@
isa-ltest:
bash projtest.sh '$(NASM)' $@
isa-l_cryptotest:
bash projtest.sh '$(NASM)' $@
cryptography-primitivestest:
bash projtest.sh '$(NASM)' $@
%.bin: %.asm $(NASM)
$(NASM) $(NASMOPT) -f bin -o $@ -MD $@.dep -l $@.lst $<
@ -103,15 +116,6 @@ x264test:
all:
golden: performtest.pl $(TESTS)
$(PERL) performtest.pl --golden --nasm='$(NASM)' $(TESTS)
test: performtest.pl $(NASM) $(TESTS)
$(PERL) performtest.pl --nasm='$(NASM)' $(TESTS)
diff: performtest.pl $(NASM) $(TESTS)
$(PERL) performtest.pl --diff --nasm='$(NASM)' $(TESTS)
clean:
$(RM_F) *.com *.o *.o64 *.aout *.obj *.win32 *.win64 *.exe *.lst *.bin
$(RM_F) *.bin *.bin16 *.bin32 *.bin64
@ -119,7 +123,8 @@ clean:
$(RM_F) *.aoutb
$(RM_RF) testresults
$(RM_F) elftest elftest64
$(RM_RF) ffmpegtest x264test
$(RM_RF) ffmpegtest x264test dav1dtest
$(RM_RF) intel-ipsec-mbtest isa-ltest isa-l_cryptotest cryptography-primitivestest
spotless: clean
$(RM_RF) golden

View file

@ -4,34 +4,119 @@
%define treg tmm %+ %1
%define treg2 tmm %+ %2
%define treg3 tmm %+ %3
%define zreg zmm %+ %1
ldtilecfg [rsi]
sttilecfg [rdi]
ldtilecfg [rsi] ;AMX_TILE
sttilecfg [rdi] ;AMX_TILE
tilezero treg
tilezero treg ;AMX_TILE
tileloadd treg, [rax]
tileloadd treg, [rax,rdx]
tileloadd treg, [rax,rdx*2]
tileloadd treg, [rax] ;AMX_TILE
tileloadd treg, [rax+rdx] ;AMX_TILE
tileloadd treg, [rax+rdx*2] ;AMX_TILE
tileloaddt1 treg, [rax]
tileloaddt1 treg, [rax,rdx]
tileloaddt1 treg, [rax,rdx*2]
tileloaddt1 treg, [rax] ;AMX_TILE
tileloaddt1 treg, [rax+rdx] ;AMX_TILE
tileloaddt1 treg, [rax+rdx*2] ;AMX_TILE
tdpbf16ps treg, treg2, treg3
tdpbssd treg, treg2, treg3
tdpbusd treg, treg2, treg3
tdpbsud treg, treg2, treg3
tdpbuud treg, treg2, treg3
tdpfp16ps treg, treg2, treg3
tcmmimfp16ps treg, treg2, treg3
tcmmrlfp16ps treg, treg2, treg3
tileloaddrs treg, [rax] ;AMX-MOVRS
tileloaddrs treg, [rax+rdx] ;AMX-MOVRS
tileloaddrs treg, [rax+rdx*2] ;AMX-MOVRS
tilestored [rax], treg
tilestored [rax,rdx], treg
tilestored [rax,rdx*2], treg
tileloaddrst1 treg, [rax] ;AMX-MOVRS
tileloaddrst1 treg, [rax+rdx] ;AMX-MOVRS
tileloaddrst1 treg, [rax+rdx*2] ;AMX-MOVRS
tilerelease
tdpbf16ps treg, treg2, treg3 ;AMX-BF16
tdpbssd treg, treg2, treg3 ;AMX_INT8
tdpbusd treg, treg2, treg3 ;AMX_INT8
tdpbsud treg, treg2, treg3 ;AMX_INT8
tdpbuud treg, treg2, treg3 ;AMX_INT8
tdpfp16ps treg, treg2, treg3 ;AMX-FP16
tcmmimfp16ps treg, treg2, treg3 ;AMX-COMPLEX
tcmmrlfp16ps treg, treg2, treg3 ;AMX-COMPLEX
; TMMULTF32PS was retagged 'NEVER' (no longer implemented), but keep the
; test case and suppress the resulting warning, like the AMX-TRANSPOSE
; instructions below.
[warning -obsolete-removed]
tmmultf32ps treg, treg2, treg3 ;AMX_TF32
[warning *obsolete-removed]
tdpbf8ps treg, treg2, treg3 ;AMX-FP8
tdpbhf8ps treg, treg2, treg3 ;AMX-FP8
tdphbf8ps treg, treg2, treg3 ;AMX-FP8
tdphf8ps treg, treg2, treg3 ;AMX-FP8
tcvtrowd2ps zreg, treg, eax ;AMX-AVX512
tcvtrowd2ps zreg, treg, %1 ;AMX-AVX512
tcvtrowps2bf16h zreg, treg, eax ;AMX-AVX512
tcvtrowps2bf16h zreg, treg, %1 ;AMX-AVX512
tcvtrowps2bf16l zreg, treg, eax ;AMX-AVX512
tcvtrowps2bf16l zreg, treg, %1 ;AMX-AVX512
tcvtrowps2phh zreg, treg, eax ;AMX-AVX512
tcvtrowps2phh zreg, treg, %1 ;AMX-AVX512
tcvtrowps2phl zreg, treg, eax ;AMX-AVX512
tcvtrowps2phl zreg, treg, %1 ;AMX-AVX512
tilemovrow zreg, treg, eax ;AMX-AVX512
tilemovrow zreg, treg, %1 ;AMX-AVX512
; All the 16 AMX-TRANSPOSE instructions were removed from the 59th edition of
; "Intel Architecture Instruction Set Extensions and Future Features Programming Reference"
; September 2025, 319433-059
; Similar to PCOMMIT, they are tagged as 'NEVER'
[warning -obsolete-removed]
t2rpntlvwz0 treg, [rax] ;AMX-TRANSPOSE
t2rpntlvwz0 treg, [rax+rdx] ;AMX-TRANSPOSE
t2rpntlvwz0 treg, [rax+rdx*2] ;AMX-TRANSPOSE
t2rpntlvwz0t1 treg, [rax] ;AMX-TRANSPOSE
t2rpntlvwz0t1 treg, [rax+rdx] ;AMX-TRANSPOSE
t2rpntlvwz0t1 treg, [rax+rdx*2] ;AMX-TRANSPOSE
t2rpntlvwz1 treg, [rax] ;AMX-TRANSPOSE
t2rpntlvwz1 treg, [rax+rdx] ;AMX-TRANSPOSE
t2rpntlvwz1 treg, [rax+rdx*2] ;AMX-TRANSPOSE
t2rpntlvwz1t1 treg, [rax] ;AMX-TRANSPOSE
t2rpntlvwz1t1 treg, [rax+rdx] ;AMX-TRANSPOSE
t2rpntlvwz1t1 treg, [rax+rdx*2] ;AMX-TRANSPOSE
ttransposed treg, treg ;AMX-TRANSPOSE
t2rpntlvwz0rs treg, [rax] ;AMX-TRANSPOSE + AMX-MOVRS
t2rpntlvwz0rs treg, [rax+rdx] ;AMX-TRANSPOSE + AMX-MOVRS
t2rpntlvwz0rs treg, [rax+rdx*2] ;AMX-TRANSPOSE + AMX-MOVRS
t2rpntlvwz0rst1 treg, [rax] ;AMX-TRANSPOSE + AMX-MOVRS
t2rpntlvwz0rst1 treg, [rax+rdx] ;AMX-TRANSPOSE + AMX-MOVRS
t2rpntlvwz0rst1 treg, [rax+rdx*2] ;AMX-TRANSPOSE + AMX-MOVRS
t2rpntlvwz1rs treg, [rax] ;AMX-TRANSPOSE + AMX-MOVRS
t2rpntlvwz1rs treg, [rax+rdx] ;AMX-TRANSPOSE + AMX-MOVRS
t2rpntlvwz1rs treg, [rax+rdx*2] ;AMX-TRANSPOSE + AMX-MOVRS
t2rpntlvwz1rst1 treg, [rax] ;AMX-TRANSPOSE + AMX-MOVRS
t2rpntlvwz1rst1 treg, [rax+rdx] ;AMX-TRANSPOSE + AMX-MOVRS
t2rpntlvwz1rst1 treg, [rax+rdx*2] ;AMX-TRANSPOSE + AMX-MOVRS
ttdpbf16ps treg, treg2, treg3 ;AMX-TRANSPOSE + AMX-BF16
ttdpfp16ps treg, treg2, treg3 ;AMX-TRANSPOSE + AMX-FP16
ttcmmimfp16ps treg, treg2, treg3 ;AMX-TRANSPOSE + AMX-COMPLEX
ttcmmrlfp16ps treg, treg2, treg3 ;AMX-TRANSPOSE + AMX-COMPLEX
tconjtcmmimfp16ps treg, treg2, treg3 ;AMX-TRANSPOSE + AMX-COMPLEX
tconjtfp16 treg, treg ;AMX-TRANSPOSE + AMX-COMPLEX
ttmmultf32ps treg, treg2, treg3 ;AMX-TRANSPOSE + AMX_TF32
[warning *obsolete-removed]
tilestored [rax], treg ;AMX_TILE
tilestored [rax,rdx], treg ;AMX_TILE
tilestored [rax,rdx*2], treg ;AMX_TILE
tilerelease ;AMX_TILE
%endmacro
%assign n 0

View file

@ -0,0 +1,20 @@
BITS 64
vbcstnebf16ps xmm1, [rax]
vbcstnebf16ps ymm1, [rax]
vbcstnebf162ps xmm1, [rax]
vbcstnebf162ps ymm1, [rax]
vbcstnesh2ps xmm1, [rax]
vbcstnesh2ps ymm1, [rax]
vcvtneebf162ps xmm1, oword [rbx]
vcvtneebf162ps ymm1, yword [rcx]
vcvtneeph2ps xmm1, oword [rbx]
vcvtneeph2ps ymm1, yword [rcx]
vcvtneobf162ps xmm1, oword [rbx]
vcvtneobf162ps ymm1, yword [rcx]
vcvtneoph2ps xmm1, oword [rbx]
vcvtneoph2ps ymm1, yword [rcx]
cpu latevex
vcvtneps2bf16 xmm1, xmm2
vcvtneps2bf16 xmm1, ymm2
vcvtneps2bf16 xmm1, oword [rbx]
vcvtneps2bf16 xmm1, yword [rbx]

20
test/avx-ne-convert.asm Normal file
View file

@ -0,0 +1,20 @@
BITS 32
vbcstnebf16ps xmm1, [eax]
vbcstnebf16ps ymm1, [eax]
vbcstnebf162ps xmm1, [eax]
vbcstnebf162ps ymm1, [eax]
vbcstnesh2ps xmm1, [eax]
vbcstnesh2ps ymm1, [eax]
vcvtneebf162ps xmm1, oword [ebx]
vcvtneebf162ps ymm1, yword [ecx]
vcvtneeph2ps xmm1, oword [ebx]
vcvtneeph2ps ymm1, yword [ecx]
vcvtneobf162ps xmm1, oword [ebx]
vcvtneobf162ps ymm1, yword [ecx]
vcvtneoph2ps xmm1, oword [ebx]
vcvtneoph2ps ymm1, yword [ecx]
cpu latevex
vcvtneps2bf16 xmm1, xmm2
vcvtneps2bf16 xmm1, ymm2
vcvtneps2bf16 xmm1, oword [ebx]
vcvtneps2bf16 xmm1, yword [ebx]

Some files were not shown because too many files have changed in this diff Show more