mirror of
https://github.com/netwide-assembler/nasm
synced 2026-08-26 16:23:04 -04:00
Compare commits
267 commits
nasm-3.01r
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fbdc88565c | ||
|
|
b2734a91bd | ||
|
|
9248a85f97 | ||
|
|
63abf28933 | ||
|
|
6393f99455 | ||
|
|
8317d7ae2f | ||
|
|
5d727e1253 | ||
|
|
56200857e2 | ||
|
|
186be201d5 | ||
|
|
c68bf5ef57 | ||
|
|
ace0078261 | ||
|
|
e2f38a8aed | ||
|
|
18c778c590 | ||
|
|
339ee194fc | ||
|
|
1c3d3dc554 | ||
|
|
86c6b34bd3 | ||
|
|
75024b8109 | ||
|
|
c0b64a692b | ||
|
|
87968c3596 | ||
|
|
620dd315ee | ||
|
|
851460a10b | ||
|
|
c577f357d1 | ||
|
|
87e9a45891 | ||
|
|
c138d532fb | ||
|
|
081a097909 | ||
|
|
eee1384bf5 | ||
|
|
6de2898d8d | ||
|
|
5422294119 | ||
|
|
5d8ec1742c | ||
|
|
941aa2ba16 | ||
|
|
fe6bb359e4 | ||
|
|
1ac35569b1 | ||
|
|
6ca6b03467 | ||
|
|
629cf75c3d | ||
|
|
1891551544 | ||
|
|
70dae61029 | ||
|
|
35016d4880 | ||
|
|
c95b04bc7d | ||
|
|
28bf46e532 | ||
|
|
73abe9374b | ||
|
|
7f69cf689c | ||
|
|
3cc3654e08 | ||
|
|
c460d1112f | ||
|
|
386f5d44f7 | ||
|
|
844f409f8d | ||
|
|
8890d723d0 | ||
|
|
dad1d8ca42 | ||
|
|
720a32672c | ||
|
|
9d94cac7ae | ||
|
|
9000d56aec | ||
|
|
4a56d66ed9 | ||
|
|
47f1cd8ede | ||
|
|
27500eee7f | ||
|
|
9969b34454 | ||
|
|
06f9a1855e | ||
|
|
8fe7600cde | ||
|
|
640c7e0f5b | ||
|
|
096c82e141 | ||
|
|
4d18bdd318 | ||
|
|
5b9dce55cb | ||
|
|
6051380c34 | ||
|
|
cdfe73e4b9 | ||
|
|
7bc82e7daf | ||
|
|
44245e4684 | ||
|
|
7b4e77dae2 | ||
|
|
e47a62ed4d | ||
|
|
20cf91df63 | ||
|
|
24263bc4c1 | ||
|
|
139986238a | ||
|
|
3f269f2dc8 | ||
|
|
a55b5930b3 | ||
|
|
414ea824d9 | ||
|
|
6950581b35 | ||
|
|
cfcfe9e701 | ||
|
|
3a33d83610 | ||
|
|
90ba5bbc23 | ||
|
|
2b37c0ad75 | ||
|
|
1fc631a173 | ||
|
|
19125b6d46 | ||
|
|
08a369628e | ||
|
|
f0c3b0e6c7 | ||
|
|
5e6a181fec | ||
|
|
6f830c1c74 | ||
|
|
022586090d | ||
|
|
0c9baa8f3a | ||
|
|
9052efaa63 | ||
|
|
8d1f35b78f | ||
|
|
7b267445b6 | ||
|
|
018406b870 | ||
|
|
6015afc6d7 | ||
|
|
ed8864e342 | ||
|
|
d832776ccb | ||
|
|
6d8ea837c6 | ||
|
|
d2541cb884 | ||
|
|
dee2d13f2c | ||
|
|
1c9e16a03f | ||
|
|
05ad1e46b2 | ||
|
|
c8be7b7a3f | ||
|
|
3ad8e6c533 | ||
|
|
251b9c6825 | ||
|
|
06d2606b06 | ||
|
|
f1e4e6fe16 | ||
|
|
f216d5b65d | ||
|
|
5b4d5cf2a7 | ||
|
|
dc68633fa3 | ||
|
|
93bb528742 | ||
|
|
471073c0d0 | ||
|
|
6e8cdf8d59 | ||
|
|
35ffac3ea0 | ||
|
|
de7a94e884 | ||
|
|
0114c92101 | ||
|
|
ea675d0af7 | ||
|
|
3ee140842f | ||
|
|
ccb73b72b2 | ||
|
|
113191195b | ||
|
|
aa12d3381a | ||
|
|
498afdba1b | ||
|
|
b5235c49f0 | ||
|
|
8c3f3fbe36 | ||
|
|
3cb6231581 | ||
|
|
97db0b96c2 | ||
|
|
e1e03770f7 | ||
|
|
c8ea2d906d | ||
|
|
d7c7de072f | ||
|
|
d1e9ce5ab0 | ||
|
|
4bcfe7a838 | ||
|
|
31ae053886 | ||
|
|
207b3727c7 | ||
|
|
21904008f5 | ||
|
|
8058e5df17 | ||
|
|
00fe1077dc | ||
|
|
fe5235ffc9 | ||
|
|
444ef5a122 | ||
|
|
4afd70f404 | ||
|
|
a9e46d4572 | ||
|
|
a8d44ce956 | ||
|
|
e856c2e1dd | ||
|
|
ab0cb6afcb | ||
|
|
b41191e29d | ||
|
|
6f8dc8116f | ||
|
|
55e064dccb | ||
|
|
cf770c08e8 | ||
|
|
2ac469c93e | ||
|
|
6251fc5908 | ||
|
|
93c8f343d9 | ||
|
|
6b0e02de3a | ||
|
|
447bb02e1d | ||
|
|
b1ee0338a3 | ||
|
|
e63209628f | ||
|
|
c8ce9504ca | ||
|
|
0894bdae30 | ||
|
|
fcb49f5dd6 | ||
|
|
4b37759129 | ||
|
|
0dd578ce68 | ||
|
|
8d4733962e | ||
|
|
9fdc7eab6e | ||
|
|
8ccb56cb10 | ||
|
|
1e494b46c1 | ||
|
|
c8fa17205b | ||
|
|
b1909cf39b | ||
|
|
89e1d6203a | ||
|
|
5606bdb335 | ||
|
|
fe9586f201 | ||
|
|
a4c5b2829c | ||
|
|
7f92d306a9 | ||
|
|
5de64ecd20 | ||
|
|
e7aa83c68e | ||
|
|
2aab21b3fb | ||
|
|
fbacd59cce | ||
|
|
99898edfc1 | ||
|
|
b4f74befce | ||
|
|
5bb69e6c8b | ||
|
|
320bc224b5 | ||
|
|
ddcf4d4f99 | ||
|
|
f0dc7c220d | ||
|
|
e68a08cd7d | ||
|
|
f4defff3ea | ||
|
|
2fe0c39bdc | ||
|
|
c2344472c2 | ||
|
|
7c6bcd9589 | ||
|
|
9dbff83e77 | ||
|
|
f7a4d8fd1b | ||
|
|
724efa686f | ||
|
|
ef587a2566 | ||
|
|
85cd46de67 | ||
|
|
14f887fb4e | ||
|
|
184f8485b5 | ||
|
|
ed23d3ba34 | ||
|
|
8744226309 | ||
|
|
1ef93d643d | ||
|
|
627ec8b865 | ||
|
|
3910b58e96 | ||
|
|
bbff2d7ec6 | ||
|
|
0058d91bec | ||
|
|
89682def9b | ||
|
|
3f188d7222 | ||
|
|
5c224e169e | ||
|
|
d9c93e06ae | ||
|
|
22a9118f1e | ||
|
|
ff7a315acb | ||
|
|
795daf3d2d | ||
|
|
5dfcfc8cab | ||
|
|
b8c2a63286 | ||
|
|
f4f7d18c06 | ||
|
|
c0e4def0fe | ||
|
|
94c6ecda5b | ||
|
|
ca178f80d8 | ||
|
|
acfeb7df6c | ||
|
|
94923e1382 | ||
|
|
e19c989bd5 | ||
|
|
4709cfe493 | ||
|
|
ca67f50341 | ||
|
|
bf16907c9d | ||
|
|
1a907c27a5 | ||
|
|
94dd4d30a7 | ||
|
|
1b939ecf3d | ||
|
|
9503778d6e | ||
|
|
fc56538bce | ||
|
|
efe066ef40 | ||
|
|
ab8787a1fa | ||
|
|
f520436a7a | ||
|
|
e86773d70b | ||
|
|
44ec97993a | ||
|
|
9ba21c1e50 | ||
|
|
746e7c9efa | ||
|
|
dfb3b0013e | ||
|
|
0bc4333150 | ||
|
|
44e89ba9b6 | ||
|
|
587ed5e36d | ||
|
|
e9fac2faa6 | ||
|
|
3e925ee75c | ||
|
|
5d655306f9 | ||
|
|
e20b3087cc | ||
|
|
8f1cd30fcb | ||
|
|
a7457e66cf | ||
|
|
2c71e67762 | ||
|
|
c0aec6969b | ||
|
|
5a6b276b89 | ||
|
|
4cdb62ffb6 | ||
|
|
7e82d9d1e3 | ||
|
|
a16571a705 | ||
|
|
b8e256a475 | ||
|
|
f87fb5c957 | ||
|
|
b453f9e8ea | ||
|
|
35ef2e2d1a | ||
|
|
69c25535ae | ||
|
|
ddf85b55ed | ||
|
|
3d96ea651a | ||
|
|
a8a1dc2b0c | ||
|
|
9b101e9316 | ||
|
|
0c8379825e | ||
|
|
29a5aabd7a | ||
|
|
013db3d446 | ||
|
|
378ee0e9c5 | ||
|
|
62b610ad86 | ||
|
|
43f9a71fc0 | ||
|
|
a684942de0 | ||
|
|
420313da8c | ||
|
|
be03f169b9 | ||
|
|
51dce26137 | ||
|
|
a398a41f0a | ||
|
|
019615f85f | ||
|
|
292d852f55 | ||
|
|
5a5057ad95 | ||
|
|
e027b5919f | ||
|
|
ae9335a0b9 | ||
|
|
c08b4edca1 |
19790 changed files with 256427 additions and 11682 deletions
112
.github/workflows/test.yml
vendored
112
.github/workflows/test.yml
vendored
|
|
@ -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
7
.gitignore
vendored
|
|
@ -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
|
||||
|
|
|
|||
4
AUTHORS
4
AUTHORS
|
|
@ -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
|
||||
|
|
|
|||
139
Makefile.in
139
Makefile.in
|
|
@ -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
|
||||
|
|
|
|||
142
Mkfiles/msvc.mak
142
Mkfiles/msvc.mak
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 --#
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
---
|
||||
|
|
|
|||
391
asm/assemble.c
391
asm/assemble.c
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
649
asm/error.c
649
asm/error.c
|
|
@ -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");
|
||||
}
|
||||
|
|
|
|||
37
asm/labels.c
37
asm/labels.c
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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
1121
asm/nasm.c
File diff suppressed because it is too large
Load diff
31
asm/parser.c
31
asm/parser.c
|
|
@ -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
|
||||
|
|
|
|||
11
asm/pragma.c
11
asm/pragma.c
|
|
@ -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;
|
||||
|
|
|
|||
312
asm/preproc.c
312
asm/preproc.c
|
|
@ -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)
|
||||
|
|
|
|||
171
asm/quote.c
171
asm/quote.c
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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' => [],
|
||||
|
|
|
|||
|
|
@ -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])])
|
||||
|
|
|
|||
|
|
@ -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}"])])])
|
||||
|
|
|
|||
|
|
@ -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
109
common/errstubs.c
Normal 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
76
common/files.c
Normal 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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
|
|||
10
configure.ac
10
configure.ac
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
46
disasm/diserror.c
Normal 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];
|
||||
173
disasm/ndisasm.c
173
disasm/ndisasm.c
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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--;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
163
doc/changes.src
163
doc/changes.src
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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}
|
||||
|
|
|
|||
30
doc/lang.src
30
doc/lang.src
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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}
|
||||
|
|
|
|||
117
doc/preproc.src
117
doc/preproc.src
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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 _);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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__
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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
63
include/files.h
Normal 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 */
|
||||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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
237
misc/nxdisasm.pl
Executable 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);
|
||||
|
|
@ -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++) {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
4
nasm.txt
4
nasm.txt
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
329
nasmlib/file.c
329
nasmlib/file.c
|
|
@ -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
|
||||
|
|
|
|||
204
nasmlib/file.h
204
nasmlib/file.h
|
|
@ -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
91
nasmlib/fileio.c
Normal 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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 = ®ister_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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
115
output/outcoff.c
115
output/outcoff.c
|
|
@ -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);
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 = §s;
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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
11
templates/template.h
Normal 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 */
|
||||
|
|
@ -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
|
||||
|
|
|
|||
127
test/amx.asm
127
test/amx.asm
|
|
@ -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
|
||||
|
|
|
|||
20
test/avx-ne-convert-64.asm
Normal file
20
test/avx-ne-convert-64.asm
Normal 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
20
test/avx-ne-convert.asm
Normal 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
Loading…
Add table
Add a link
Reference in a new issue