0. Contents

1. About
2. Commandline Options
Options -0, -1, -2, ..., -10
Option -bin
Option -coff
Option -djgpp
Option -e
Option -elf
Option -elf64
Option -eq
Option -Fd
Option -FPi
Option -Fw
Options -Gc, -Gd, -Gr, -Gz
Option -m
Option -mz
Option -nc
Options -nd, -nt
Option -nm
Option -pe
Option -win64
Option -zc
Option -Zd
Option -zf
Option -Zg
Option -Zi
Options -zlc and -zld
Options -zlf, -zlp and zls
Option -Zm
Option -Zne
Option -zt
Option -Zv8
Option -zze
Option -zzs
3. Syntax Extensions
3.1 Directive INCBIN
3.2 FASTCALL Register Calling Convention
3.3 IDs enclosed in Back Quotes
3.4 Floating-Point Immediates in Instructions
3.5 Directive OPTION FIELDALIGN
3.6 Directive OPTION PROCALIGN
3.7 Directive OPTION MZ
3.8 Directive OPTION ELF
3.9 Directive OPTION WIN64
3.10 Directive OPTION FRAME
3.11 Directive OPTION RENAMEKEYWORD
3.12 Directive OPTION DLLIMPORT
3.13 Directive OPTION CODEVIEW
3.14 Directive OPTION STACKBASE
3.15 Directives PUSHCONTEXT / POPCONTEXT ALIGNMENT
3.16 Directives .X64 and .X64p
3.17 Attribute LABEL for first Macro Parameter
3.18 Member Argument for IF[N]DEF and .ERR[N]DEF
3.19 Initialization of Data Items of Type MMWORD/XMMWORD
3.20 Optional Array Size for LABEL Directive
3.21 Optional Name Argument for Simplified Segment Directives
3.22 Segment Attribute COMDAT
3.23 Attribute VARARGML for last Macro Parameter
3.24 Miscellaneous
3.24.1 Numeric constant __JWASM__
3.24.2 Operating System Argument for .MODEL
3.24.3 Accepted Parameters for IF[N]DEF Directive
3.24.4 Visibility of Procedures
3.24.5 Non-RIP-Relative Addressing in 64-Bit
4. Instruction Sets
5. Code Generation Differences
5.1 Forward References in Macro Expressions
6. Output Formats
6.1 OMF Output Format
6.2 COFF Output Format
6.3 Win64 Output Format
6.4 Binary Output Format
6.5 PE Output Format
7. Masm Bugs fixed in JWasm
8. Optional Features
9. Known Bugs and missing Features
10. License
Appendix A. Reserved Words
Appendix B. Source Samples
Appendix C. Errors and Warnings
Appendix D. Differences between Masm 6 and Masm 8
Appendix E. Restrictions of precommpiled 16-bit Binary JWASMR.EXE
Appendix F. Additional Features of JWasm's Debug Version

1. About

This document lists the differences between JWasm and Masm, as far as the user interface is concerned.

When Masm is mentioned, then usually Masm v8.00 is meant, unless stated otherwise. Masm v8.00 also was the first Masm version supporting 64-bit (ML64.EXE).

The Masm documentation itself can be found on numerous places in the web, in plain text, HTML, PDF and Windows Help format. However, it's usually just the documentation that came whith Masm v6.1 - hence a bit outdated nowadays ( the changes from Masm v6 to Masm v8 are listed in Appendix D ).

2. Commandline Options

Entering 'JWasm -?' or 'JWasm -h' will make JWasm display the options it understands. A lot of them exist in both Masm and JWasm, but some are valid for JWasm only; OTOH, a few options are missing in JWasm.

Options are usually entered via the command line. Additionally, when starting, JWasm will search for environment variable JWASM and handle it similar to the way Masm handles variable ML. Hence it is also possible to enter options via this method.

The options specific to JWasm - and also the options which are handled somewhat differently by JWasm compared to Masm - will be handled in the following chapters.

One major difference should be mentioned here: JWasm does never launch a linker on its own ( which Masm does unless option -c is given ). This makes a few Masm options useless for JWasm, and hence they are not implemented; see Chapter Known Bugs and missing Features for details.

Options -0, -1, -2, ..., -10: Select Cpu

Option [0|1|..|10] selects cpu/instruction set. Most values correspond to cpu directives:

0.8086
1.186
2.286
3.386
4.486
5.586
6.686
7.686 and .MMX (P2)
8.686, .MMX and SSE instructions (P3)
9.686, .MMX, SSE and SSE2 instructions (P4)
10.x64 (x86-64 cpu)

Option -bin: Select Output Format Binary

Option -bin selects output format BINary. The output module's default file extension will be changed from .OBJ to .BIN.

For more information, see Binary Output Format.

Chapter Output Formats lists all available output formats.

Option -coff: Select Output Format COFF

Option -coff selects output format COFF. The most common use for -coff is to produce modules for 32-bit Windows. However, it's not mandatory that the output will be 32-bit with -coff; depending on what cpu is selected when the .MODEL directive will be parsed, the output may be 32- or 64-bit.

For more information about COFF, see COFF Output Format.

Chapter Output Formats lists all available output formats.

Option -djgpp: Select Output Format for DJGPP (optional)

Option -djgpp selects Djgpp's variant of COFF as output format. Since it is rarely used nowadays, this option isn't activated in the precompiled binaries. See Optional Features how to enable it.

Chapter Output Formats lists all available output formats.

Option -e: Set error limit

Allows to set the number of errors after which the assembly process is aborted. The default value is 50.

Option -elf: Select 32-bit Output Format ELF

Option -elf selects output format ELF. JWasm will produce an object module in 32-bit Elf format.

Use OPTION ELF to set values in the ELF header.

Chapter Output Formats lists all available output formats.

Option -elf64: Select 64-bit Output Format ELF

Option -elf64 selects output format ELF64. JWasm will produce an object module in 64-bit Elf format. Additionally, this option will set cpu to x86-64 and model to FLAT.

Use OPTION ELF to set values in the ELF header.

Chapter Output Formats lists all available output formats.

Option -eq: Suppress Error Messages on Screen

Option -eq will suppress displaying error messages on the screen. They are still written into an error file.

Option -Fd: Write Import Definitions

Option -Fd makes JWasm write import definitions in a format understood by Open Watcom's Wlink and JWlink. Such definitions will tell the linker how to resolve the external reference; no import library is needed. This option is only useful in conjunction with OPTION DLLIMPORT (chapter 3.12). Syntax is:
-Fd[=file_name]
If the optional <file_name> argument is given, the import definitions will be written into a file of this name. This is the only way for Open Watcom's Wlink to pass the information.

If JWlink is used, the <file_name> argument may be omitted. Then JWasm will write the import definitions directly into the object module's linker directive section (section ".drectve"). This works for output formats COFF and ELF only. See sample Win32_7 how to use JWasm and JWlink to create a Windows binary without import libs.

Option -FPi: Activate Floating-Point Emulation

Option -FPi activates "inline FP instructions with emulation". This will make JWasm create fixups for floating-point instructions if code is 16bit. If supported by the linker or the OS, the FP instructions can then be replaced by calls to an FP emulator if no coprocessor exists.

Option -Fw: Set Error File Name

Option -Fw will set the file name for warning and error messages. As default, these messages are written to a file with a name equal to the assembly source, but with extension .ERR. Syntax is:
-Fw file_name

Options -Gc, -Gd, -Gr, -Gz: Set Default Calling Convention

The default calling convention set by these options are:

-Gc Pascal
-Gd C(decl)
-Gr Fastcall
-Gz Stdcall

Option -m: Select Memory Model

Option -m generates a line containing a .MODEL directive to select a memory model. Syntax is:
-m[t|s|m|c|l|h|f]
where the value behind 'm' means:
t = tiny
s = small
m = medium
c = compact
l = large
h = huge
f = flat
This option is ignored if a 64-bit output format (-win64 or -elf64) is active.

Option -mz: Select Output Format MZ

Option -mz selects output format MZ. This will write a binary in DOS MZ format. The module's default file extension will be changed from .OBJ to .EXE. All symbols in the module must resolve internally, no externals are allowed. Some values in the "MZ" header can be adjusted by directive OPTION MZ (see below).

As in all binary formats, the listing will contain a binary map; see Binary Output Format for more details.

Chapter Output Formats lists all available output formats.

Option -nc: Set Code Class Name

Option -nc sets the code segment's class name if simplified segment directives are used (default:CODE). Syntax is:
-nc=name
where <name> will be the code segment's class name.

Options -nd and -nt: Set DATA and CODE Segment Names

Options -nd and -nt will set the name of the data/code segments if simplified segment directives are used. Syntax is:
-nt=name_of_code
-nd=name_of_data
The default names are _TEXT for code and _DATA for data.

Option -nm: Set Module Name

Option -nm sets the module name. Syntax is:
-nm=module_name
The default value for <module_name> is the name of the source file without extension.

Option -pe: Create a PE Binary

Option -pe will make JWasm create a binary in Windows PE format (32- and 64-bit). The output module's default file extension will be changed from .OBJ to .EXE.

For more details about the PE format see PE Output Format.

Chapter Output Formats lists all available output formats.

Option -win64: Select Output Format Win64

Option -win64 makes JWasm produce an object module in PE32+ format, the 64-bit format used for Win64 binaries.

Option -win64 will also set cpu to x86-64, model to FLAT and default calling convention to FASTCALL. This is to make JWasm compatible with Masm64 (ML64.EXE).

With OPTION WIN64, parameters specific to Win64 may be set.

For more information about Win64, see Win64 Output Format.

Chapter Output Formats lists all available output formats.

Option -zc: Set Name Decoration for C

This option sets the name decoration for the C ( aka CDECL ) calling convention. There are two variants:
-zc[m|w]
-zcm is the default, C names are decorated with an underscore prefix. This is also the way Masm does it. The other variant, -zcw, omits the prefix altogether. This is the usual "decoration" in Unix/Linux.

Option -Zd: Emit Line Number Debugging Info

Option -Zd generates line number debug information for OMF and COFF output format. For other formats, this option is ignored. Line number information allows a debugger to trace the binary on the source code level. Debuggers that have been verified to work with this option:

MS CodeView OMF 16-bit, Windows and DOS
CDB, NTSD COFF 32- and 64-bit, Windows
WinDbg COFF 32- and 64-bit, Windows
MS Visual Studio 2008 COFF 32-bit[1], Windows
MS Visual Studio 2010 COFF 32-bit[1], Windows
OW WD/WDW OMF/COFF 16- and 32-bit, Windows and DOS
PellesC IDE COFF 32-bit[1], Windows
Borland TD/TDW/TD32 OMF 16- and 32-bit, Windows and DOS
[1]: the 64-bit version of this software should also be able to debug 64-bit debuggees.

Option -zf: Select FASTCALL Type

Option -zf selects the FASTCALL calling convention type for 16- and 32-bit code. Syntax is:
-zf[0|1]
The default value 0 is MS VC style, while value 1 activates the Open Watcom fastcall type.

Option -Zg: Masm-compatible Code Generation

Option -Zg makes JWasm try an exact copy of Masm's code generation, which results in the following changes:

Option -Zi: Emit Symbolic Debugging Info

Option -Zi generates symbolic debugging info in CodeView V4 style for OMF and COFF output format. For other formats, this option is accepted, but ignored. Note that -Zi will always enable -Zd ( line number information ). Debuggers which have been verified to work with this option:

MS CodeView 16-bit, Windows and DOS
MS CDB or NTSD 32- and 64-bit, Windows
MS WinDbg 32- and 64-bit, Windows
MS Visual Studio 2008 32-bit[1], Windows
MS Visual Studio 2010 32-bit[1], Windows
Open Watcom WD/WDW 16- and 32-bit, Windows and DOS
Pelles C IDE 32-bit[1], Windows
[1]: the 64-bit version of this software should also be able to debug 64-bit debuggees.

Usually both the assembler and the linker must be told that symbolic debugging information is to be generated ( with MS link, the linker option is /DEBUG ).

The -Zi option accepts an optional numeric argument to control the volume of information that is emitted. The values currently accepted are:

0Just global symbols will be written.
1Global & local symbols will be written. No user-defined types are included. Usually this reduction does no harm, but may decrease linking time - if lots of modules are to be linked, the effect may be quite significant.
2This is the default. Global & local symbols and user-defined types are written.
3Additionally to 2, symbolic constants (equates) will be written.

Also see OPTION CODEVIEW for additional switches to control symbolic debugging output.

Options -zlc and -zld: Control Content of OMF Output Module

Options -zlc and -zld do reduce size of the OMF output module. They might be useful if lots of - small - modules are to be assembled and put into a static library. Also, the OMF coment records written if -zlc or -zld is NOT set may not be accepted by all linkers.

Option -zlc:
suppresses writing OMF coment records about data in Code segments. These records may help a disassembler to produce nicer listings.
Option -zld:
suppresses writing an OMF coment record for each Code segment telling the linker that far calls to targets in the same segments should be optimized. This is more or less a feature for 16-bit code only.

Options -zlf, -zlp and -zls: Control Content of COFF Output Module

Options -zlf, -zlp and -zls do reduce size of the COFF output module. They might be useful if lots of - small - modules are to be assembled and put into a static library.

OptionMeaning
-zlf suppresses the @file entry in the COFF symbol table. This entry is usually used for debugging purposes only and hence a - pretty small - amount of space can be saved.
-zlp suppresses static (=private) procedures to be included into the COFF symbol table - as long as they aren't referenced absolutely. Such procedures aren't needed for the linking process. However, since the linker has no knowledge of them then, they will also disappear from the linker-generated map-file.
-zls suppresses the auxiliary entries for sections in the COFF symbol table. These entries may not be needed in all cases and thus a little space is saved.

Option -Zm: Enable Masm v5 Compatibility

Option -Zm (or setting OPTION M510) will do:
- set OPTION OLDSTRUCTS
- set OPTION DOTNAME
- set OPTION SETIF2:TRUE
- set OPTION OFFSET:SEGMENT (if no model is set)
- set OPTION NOSCOPED (if no model with language specifier is set)
- allow to define data items behind code labels
- allow "invalid" use of REP/REPE/REPNE instruction prefixes
- change precedence of [] and () operator from 1 to 9. Hence expression -5[bx] is parsed as (-5)[bx], while without -Zm it is parsed as -(5[bx]), which generates an error.
Other Masm v5.1 compatibility options aren't implemented yet.

Option -Zne: Disable JWasm Syntax Extensions

Option -Zne will disable syntax extensions which aren't supported by Masm. Currently these are:
- directive INCBIN
- calling convention FASTCALL
- IDs enclosed in backquotes
- floating-point immediate operands in instructions
- directive OPTION FIELDALIGN
- directive OPTION PROCALIGN
- directive OPTION MZ
- directive OPTION ELF
- directive OPTION WIN64
- directive OPTION FRAME
- directive OPTION RENAMEKEYWORD
- directive OPTION DLLIMPORT
- directive OPTION CODEVIEW
- directive OPTION STACKBASE
- directives PUSHCONTEXT / POPCONTEXT ALIGNMENT
- attribute LABEL for first macro parameter
- member argument for IF[N]DEF and .ERR[N]DEF directives
- integer initializer values for items of type [X]MMWORD
- optional name argument for .DATA, .DATA? and .CONST directives
- forward references in arguments for INVOKEd procedures
- overrides inside square brackets for base/index registers
- Optional Array Size for LABEL Directive
Some directives aren't touched by this option, although Masm won't accept them:
.X64 and .X64p
INVOKE in 64-bit mode
runtime conditional directives .IF, .REPEAT, .WHILE in 64-bit mode
If these directives are to be disabled, it must be done with OPTION NOKEYWORD.

Option -zt: Set Name Decoration for STDCALL

Option -zt will fine-tune name decoration for STDCALL symbols. Syntax is:
-zt[0|1|2]
where value 0 will disable name decoration, value 1 will just add an underscore prefix and value 2 - which is the default - will emit full STDCALL name decoration as expected by most linkers.

Option -zt0 will make object modules compatible to ALINK + Win32.lib. It may also ease adding assembly modules to Borland's C++Builder or Delphi projects.

Option -Zv8: Enable Masm v8 Procedure Visibility

Option -Zv8 changes handling of procedure visibility to the way done by Masm v8+. See Visibility of Procedures for details.

Option -zze: Disable Export Name Decoration

Option -zze suppresses name decoration for procedures with the EXPORT attribute (exported name only).

Option -zzs: Avoid Wlink COFF Incompatibility

Option -zzs is kind of a workaround for a Wlink incompatibility. It's useful to be set if 1) the source module has a starting address, 2) output format is COFF AND 3) Wlink is to be used as linker.

3. Syntax Extensions

This chapter describes the syntax extensions of JWasm compared to Masm v8.

3.1 Directive INCBIN

This directive allows to include the contents of a file into the object module. Syntax is
INCBIN filename [, starting offset[, max size]]
<filename> should be enclosed in <> or double quotes.

3.2 FASTCALL Register Calling Convention

In 16- and 32-bit mode, one may use either the Microsoft or the Watcom register calling convention. It's selected by option -zf.

The Microsoft FASTCALL convention uses registers AX, DX and BX in 16-bit for the first 3 parameters, and registers ECX and EDX in 32-bit for the first 2 parameters which are small enough to fit into a register.

The Open Watcom fastcall convention uses up to four registers ( E/AX, E/DX, E/BX, E/CX ).

In 64-bit mode, FASTCALL means the standard Windows 64 ABI if output format is not ELF. For -elf64, there is no FASTCALL support implemented yet.

To make FASTCALL the default calling convention, there are 3 ways:

3.3 IDs enclosed in Back Quotes

IDs can be enclosed in back quotes (`) and thus they can contain characters not allowed in "normal" IDs. However, there is at least one case where IDs in back quotes won't be recognized: if the expansion operator (%) is located at position 0 in a line.

Example using back quotes:

Module 1:

    `functionname.with.dots` PROC C PUBLIC a1:dword

Module 2:

    `functionname.with.dots` PROTO C :dword
    .code
    INVOKE `functionname.with.dots`, 1

Since IDs in back quotes are not 100% compatible with "normal" IDs, it might be considered to use the ALIAS directive instead. Be aware that, since the alias handling is a linker task, it is necessary to define both names, the alias name and the target name, as public.

3.4 Floating-Point Immediates in Instructions

Floating-point immediate values are accepted as instruction operands. As default, the type is a REAL4, which has a magnitude of 32 bits:
 
        mov eax, 1.0

With type coercion, it's also possible to define a 64-bit "double", although it's probably useful in 64-bit code only:

 
        mov rax, real8 ptr 1.0

Additionally, operators LOW32 and HIGH32 accept a floating-point constant as argument. In this case, the constant is assumed to have format REAL8. Thus it's possible to pass a double constant directly as a procedure argument in 32-bit code:

 
       push HIGH32 1.0
       push LOW32 1.0
       call WorkWithReal8Value

3.5 Directive OPTION FIELDALIGN

OPTION FIELDALIGN sets the default value for structure alignment. The default value is 1 or the value set by cmdline switch -Zp. Syntax is:
OPTION FIELDALIGN: [1|2|4|8|16|32]
The current default value can be saved/restored with directives PUSHCONTEXT / POPCONTEXT ALIGNMENT,

3.6 Directive OPTION PROCALIGN

With OPTION PROCALIGN parameter it's possible to automatically align procedures. Syntax is:
OPTION PROCALIGN: [1|2|4|8|16|32]
The default value is 1. The current value can be saved/restored with directives PUSHCONTEXT / POPCONTEXT ALIGNMENT,

Example:

    .386
    .model flat, stdcall
    option PROCALIGN:16
    .code

proc1 PROC
    ret
proc1 endp

proc2 PROC
    ret
proc2 endp

    end

The listing shows that start address of proc2 is aligned to 16 (=10h):

00000000                        proc1 PROC
00000000                            ret
00000000  C3                *   retn
00000001                        proc1 endp

00000010                        proc2 PROC
00000010                            ret
00000010  C3                *   retn
00000011                        proc2 endp

Note: to ensure that the procedures are aligned in the final binary as it is supposed by the OPTION PROCALIGN value, the alignment of the current code segment must be at least the value of OPTION PROCALIGN.

3.7 Directive OPTION MZ

Directive OPTION MZ allows to fine-tune the values written to the MZ header if output format MZ (see -mz cmdline option) is selected. For other output formats, this option has no effect. The syntax for the directive is:
OPTION MZ:[start_fixups][:header_align][:heap_min][:heap_max]
The parameters are:

start_fixupsoffset within the header where segment fixups will start. The size of the header will always be at least this value, even if there are no fixups at all. Default - and minimum - value is 1Eh.
header_alignalignment of the header (including segment fixups). Value must be a power of 2, 10h is the default and minimum.
heap_minthe additional space (in paragraphs) which is needed by the binary to run. Default is the total of the sizes of the uninitialized BSS and STACK segments.
heap_maxspace (in paragraphs) which the binary would like to have. Default is FFFFh.

3.8 Directive OPTION ELF

Directive OPTION ELF allows to fine-tune the values written to the ELF header if output format ELF (see -elf or -elf64) is selected. For other output formats, this option has no effect. The syntax for the directive is:
OPTION ELF:osabi
The only argument <osabi> will be copied to the ELF header field EI_OSABI. It's a numeric constant, and according to the elf specs some valid values are:

0ELFOSABI_NONE unspecified
1ELFOSABI_HPUX HP-UX
2ELFOSABI_NETBSD NetBSD
3ELFOSABI_LINUX Linux, default
6ELFOSABI_SOLARISSun Solaris
7ELFOSABI_AIX IBM AIX
9ELFOSABI_FREEBSDFreeBSD
12ELFOSABI_OPENBSDOpenBSD

3.9 Directive OPTION WIN64

Directive OPTION WIN64 allows to set parameters for the Win64 output format if this format (see -win64 cmdline option) is selected. For other output formats, this option has no effect. The syntax for the directive is:
OPTION WIN64: switches
accepted values for switches are:

Store Register Arguments [ bit 0 ]:
- 0: the "home locations" (also sometimes called "shadow space") of the first 4 register parameters are uninitialized. This is the default setting.
- 1: register contents of the PROC's first 4 parameters (RCX, RDX, R8 and R9 ) will be copied to the "home locations" within a PROC's prologue.

INVOKE Stack Space Reservation [bit 1]:
- 0: for each INVOKE the stack is adjusted to reserve space for the parameters required for the call. After the call, the space is released again. This is the default setting.
- 1: the maximum stack space required by all INVOKEs inside a procedure is computed by the assembler and reserved once on the procedure's entry. It's released when the procedure is exited. If INVOKEs are to be used outside of procedures, the stack space has to be reserved manually!
Note: an assembly time variable, @ReservedStack, is created internally when this option is set. It will reflect the value computed by the assembler. It should also be mentioned that when this option is on, and a procedure contains no INVOKEs at all, then nevertheless the minimal amount of 4*8 bytes is reserved on the stack.
Warning: You should have understood exactly what this option does BEFORE you're using it. Using PUSH/POP instruction pairs to "save" values across an INVOKE is VERBOTEN if this option is on.

3.10 Directive OPTION FRAME

This option affects 64-bit only. It allows to make JWasm automatically generate prologues and epilogues for procedures with the FRAME attribute. Thus the code complies to the rules of Win64 SEH (Structured Exception Handling). Syntax is
OPTION FRAME:<AUTO | NOAUTO>
AUTO will enable this feature, NOAUTO (which is default) disables it.

The unwind information which is generated is "complete", that is, it contains the ".endprologue" pseudo-op already. To allow to save all non-volatile registers in the prologue, the "USES" phrase is more capable in this mode and will accept XMM registers to be saved and restored.

3.11 Directive OPTION RENAMEKEYWORD

This option allows to rename a keyword, so it can be used under a different name. Syntax:
OPTION RENAMEKEYWORD:<current_name>=new_name
current_name is the current name of the keyword and must be enclosed in angle brackets. new_name must be a valid identifier. If a keyword is to be renamed, it should be done at the beginning of the source, and a keyword shouldn't be renamed multiple times. Since v2.11, a keyword may be renamed temporarily and multiple times.

3.12 Directive OPTION DLLIMPORT

a) Using OPTION DLLIMPORT

This option makes the assembler assume that all PROTOs that follow this directive represent functions located in a dll. Syntax:
OPTION DLLIMPORT:<dll_name> | NONE
<dll_name> must be enclosed in angle brackets. Argument NONE will switch back to the default mode.

b) Code Generation Effects

The effects of setting this options are subtle and useful only for MS Windows applications: if the function described by the prototype is called via INVOKE, slightly more efficient code than normal is generated, because the function's address in the IAT is used. Example:
INVOKE GetModuleHandle, NULL
code generation with OPTION DLLIMPORT:
 
        push NULL
        call DWORD PTR [_imp__GetModuleHandle@4]
code generation without OPTION DLLIMPORT:
 
        push NULL
        call _GetModuleHandle@4
        ...
    _GetModuleHandle@4:
        jmp DWORD PTR [_imp__GetModuleHandle@4]  ;stub added by the linker

c) OPTION DLLIMPORT in Conjunction with -Fd Switch

Optionally, by using cmdline option -Fd, JWasm will write the import information received through OPTION DLLIMPORT lines to either a file or directly into the object module (COFF and ELF only). Example:
 
        .386
        .model flat,stdcall
        option dllimport:<kernel32>
    GetModuleHandleA proto :dword
    ExitProcess proto :dword
        option dllimport:none
        .code
        invoke GetModuleHandleA, 0
        invoke ExitProcess, 0
        end
JWasm -coff -Fd=lnk.rsp sample.asm
After the assembly step, file lnk.rsp will contain:
import '_ExitProcess@4' kernel32.ExitProcess
import '_GetModuleHandleA@4' kernel32.GetModuleHandleA
Both Open Watcom's Wlink and JWlink will be able to directly use this information and hence, as a result, no further Windows import libraries are needed in the link step:
Wlink format windows pe file sample.obj @lnk.rsp
JWlink may even go one step further - it's able to read import definitions contained in a COFF or ELF module's linker directive section ( named ".drectve" ). Therefore one can omit the filename argument for -Fd. Sample Win32_7 demonstrates the usage.

d) OPTION DLLIMPORT in Conjunction with -pe Switch

If output format PE is selected, using OPTION DLLIMPORT is the only way to resolve external references; see PE Output Format for more information.

3.13 Directive OPTION CODEVIEW

The OPTION CODEVIEW directive allows to fine-tune the generation of symbolic debugging information. It has no effect at all if commandline option -Zi isn't set. Syntax:
OPTION CODEVIEW:switches

There is currently only one switch :

[bit 0]: If 1, create symbols with indices S_[L|G]THREAD32 instead of S_[L|G]DATA32 for data items that are stored in segments with class 'TLS'. This allows the debugger to display the correct value of static TLS ( Thread Local Storage ) variables. Example:

    option codeview:1

_TLS segment dword alias(".tls") public 'TLS'
tvar DD -1      ;codeview symbol tvar will be S_LTHREAD32
_TLS ends

3.13 Directive OPTION STACKBASE

The OPTION STACKBASE directive allows to change the way how stack variables - defined by the PROC and LOCAL directives - are accessed. Syntax is:
OPTION STACKBASE:register
register will be the index register that is used for accessing the stack variables. The "natural" register for accessing these variables is the [E|R]BP register ( the "frame pointer"). With OPTION STACKBASE one might set any index register as frame pointer.

OPTION STACKBASE will additionally define assembly-time variable @StackBase. The assembler will add the value of this variable to the effective address of stack variables. @StackBase can be modified just like any userdefined variable - however, it is initialized to zero by the PROC directive. The purpose for the introduction of @StackBase is to make it feasible to use the "volatile" stack-pointer (ESP/RSP) register as base for accessing stack variables.

Finally, OPTION STACKBASE will define another assembly-time variable: @ProcStatus. This variable is read-only and will allow to query information about the current procedure's status. The information that is returned by @ProcStatus is:

BitMeaning if bit is 1
0inside prologue of current procedure.
1inside epilogue of current procedure.
2"frame-pointer omission" is on for procedure
7prologue of current procedure isn't created yet

3.15 Directives PUSHCONTEXT / POPCONTEXT ALIGNMENT

The PUSHCONTEXT / POPCONTEXT directives understand new qualifier ALIGNMENT, which saves/restores current values of FIELDALIGN and PROCALIGN options.

Note: in JWasm v2.00-2.09, PUSHCONTEXT / POPCONTEXT ALL did include these alignment values. Since JWasm v2.10, this is no longer true; this behavior is more Masm-compatible.

3.16 Directives .X64 and .X64p

These directives select a 64-bit (x86-64) cpu. In contrast to .X64, .X64p will allow to use privileged instructions.

The .X64 directive isn't needed usually, because for output formats WIN64 (see -win64) and ELF64 (see -elf64), .X64 is the default.

The .X64p directive is useful for mixed-model binaries or system software (see example DOS64 ).

When the cpu is set to 64-bit, the SEGMENT directive accepts a new 'size' value: USE64. It tells the assembler that this segment's offset is 64-bit wide and uses 64-bit instructions.

The SYSCALL calling convention is renamed to SYSCALL_ when 64-bit is on, because there exists a SYSCALL instruction mnemonic in this mode.

3.17 Attribute LABEL for first Macro Parameter

The LABEL attribute for the first macro parameter allows access to a label which is assigned to the macro. Syntax is:

<macro_name> MACRO <param_name>:LABEL [,<param_name>[, ...]]

The LABEL attribute is accepted for the first parameter only. A macro with such a parameter can be invoked in the following way:

<label> <macro_name> [<argument>, ...]

Example:

 
    foo macro lbl:LABEL, first, second
    lbl  db first
         dw second
    endm

    .data

    data1 foo 1,1000
    data2 foo 2,2000

Note that a code label ( that is, a label followed by a colon or double-colon ) is parsed BEFORE the macro is evaluated, hence such a label will have been defined already when the macro "runs".

3.18 Member Argument for IF[N]DEF and .ERR[N]DEF Directives

Since v2.07, JWasm's implementation of IF[N]DEF - and .ERR[N]DEF - will additionally accept a struct member as argument. This syntax requires a fully qualified name:

 
      IFDEF <struct_name>.<member_name>

3.19 Initialization of Data Items with Type MMWORD/XMMWORD

For data items of types MMWORD or XMMWORD, JWasm will accept integer values for initialization:

 
    vmm1  MMWORD  1122334455667788h
    vxmm1 XMMWORD 112233445566778899AABBCCDDEEFFh

Masm will accept just floating-point initializers for data items of type [X]MMWORD. It's even worse, since floating-point initializers are silently ignored for data items with sizes != 4, 8 and 10; since XMMWORD has size 16, it's impossible to initialize such an item directly. JWasm copies this Masm behavior, but to allow to initialize a XMMWORD with a floating-point value, one may use type coercion:

 
    vxmm1 XMMWORD real4 ptr 1.0   ;bytes 4-15 will be 0
    vxmm2 XMMWORD real8 ptr 1.0   ;bytes 8-15 will be 0

Variants that work in both JWasm and Masm, and also allow to initialize the full XMMWORD are:

 
    vxmm1 LABEL XMMWORD
      real4 1.0, 2.0, 3.0, 4.0
    vxmm2 LABEL XMMWORD
      real8 1.0, 2.0

3.20 Optional Array Size for LABEL Directive

The LABEL directive accepts an optional array size argument:
myarray LABEL word : 10 ; myarray is assumed to be an array of 10 words
    dw 1,2,3,4,5,6,7,8,9,10

Please note that the array size argument defines the array's number of elements, not the array's size in bytes.

This extension allows to define large initialized arrays, not restricted by line size limits. The SIZEOF and LENGTHOF operators will return the same values as if the array had been defined via the DUP operator.

The array size argument may be a forward reference:

myarray LABEL word : size_myarray / sizeof word
    dw 1,2,3,4,5,6,7,8,9,10
size_myarray equ $ - myarray

3.21 Optional Name Argument for Simplified Segment Directives

Masm allows an optional argument for simplified segment directives .CODE, .FARDATA and .FARDATA?. This is to set the name of the segment that is to be opened. JWasm will also accept the name argument for those directives; additionally, it's accepted for .DATA, .DATA? and .CONST directives.

3.22 Segment Attribute COMDAT

With segment attribute COMDAT one may define COMDAT sections. A COMDAT section is a section that can be defined by more than one object file. A COMDAT section must contain at least one symbol, the COMDAT symbol. The syntax to define the section is:

 
    segname SEGMENT COMDAT( selection [, assoc_segment ] ) ...

The selection argument tells the linker what to do if multiple definitions of a COMDAT symbol are found; the accepted values are:
ValueDescription
1no duplicatesIf the symbol is already defined, the linker issues a "multiply defined symbol" error.
2any Any section that defines the same COMDAT symbol can be linked; the rest are removed.
3same size The linker chooses an arbitrary section among the definitions for this symbol. If all definitions are not the same size, a "multiply defined symbol" error is issued.
4exact match The linker chooses an arbitrary section among the definitions for this symbol. If all definitions do not match exactly, a "multiply defined symbol" error is issued.
5associative The section is linked if a certain other COMDAT section ( see the assoc_segment in the syntax description ) is linked.
6largest The linker chooses the largest definition from among all of the definitions for this symbol. If multiple definitions have this size, the choice between them is arbitrary.

Currently support for COMDAT is restricted to COFF.

JWasm won't do anything special with COMDAT sections; in future releases this may change: cmdline options similar to the Microsoft VC compiler options -Gf or -Gy may be added.

To create an object module that places each function in its own COMDAT section ( as it is done by MS VC if the -Gy option is given ), it is recommended to use COMDAT in conjunction with ALIAS:

 
    _TEXT_proc1 segment flat comdat(1) alias(".text")
    proc1 proc c
        ...
    proc1 endp
    _TEXT1_proc1 ends

    _TEXT_proc2 segment flat comdat(1) alias(".text")
    proc2 proc c private
        ...
    proc2 endp
    _TEXT2_proc2 ends

    _TEXT_proc3 segment flat comdat(1) alias(".text")
    proc3 proc c
        ...
    proc3 endp
    _TEXT_proc3 ends

3.23 Attribute VARARGML for last Macro Parameter

VARARGML has mostly the same effects as attribute VARARG; the difference is that VARARGML will make the assembler concat lines if the last character on the line is a comma.

3.24 Miscellaneous

3.24.1 Numeric constant __JWASM__
3.24.2 Operating System Argument for .MODEL
3.24.3 Accepted Parameters for IF[N]DEF Directive
3.24.4 Visibility of Procedures
3.24.5 Non-RIP-Relative Addressing in 64-Bit

3.24.1 Numeric constant __JWASM__

__JWASM__ is a predefined symbol, its value is the current JWasm version * 100, that is, for v1.9 the value is 190. The predefined text equate @Version won't contain JWasm's version, for compatibility reasons it has value <800> (since v2.06, previously the value was <615>).

3.24.2 Operating System Argument for .MODEL

The .MODEL directive has an optional "operating system" argument. Masm accepts value OS_DOS only, JWasm accepts values OS_DOS and OS_OS2. This setting will affect the generated code of directives .STARTUP and .EXIT for 16-bit memory models.

3.24.3 Accepted Parameters for IF[N]DEF Directive

Masm's IF[N]DEF directive accepts user-defined symbols and registers, but fails for instructions, directives and other reserved words. JWasm's IF[N}DEF implementation accepts those symbols as well. OTOH, JWasm is a bit more picky and will display a warning if more than one item is found behind the directive - Masm just takes the first and silently skips the rest.

Also see Member Argument for IF[N]DEF and .ERR[N]DEF Directives.

3.24.4 Visibility of Procedures

When a PROTO or EXTERNDEF directive for a symbol is located in a module before a matching PROC directive, the visibility of this Procedure ( "public" vs "private", or "external" vs. "static" ) is handled differently in Masm v6 or 7 and Masm v8 or newer:

Since Masm v8, a PROTO or EXTERNDEF for a symbol which is later defined as a PROC will make the procedure public, no matter what a possible visibility attribute of the PROC itself - or the default one set with OPTION PROC - is telling.

OTOH, with Masm v6/7, both the visibility attribute of the PROC directive and the current default setting of OPTION PROC will affect the symbol's visibility.

                Masm6 Masm8 JWasm JWasm+Zv8
      -------------------------------------
      On,E,P            x             x
      On,E,Pn           x             x
      On,E,Pp     x     x      x      x
      Op,E,P      x     x      x      x
      Op,E,Pn     x     x             x
      Op,E,Pp     x     x      x      x

      On = OPTION PROC:PRIVATE
      Op = OPTION PROC:PUBLIC
      E  = PROTO or EXTERNDEF before PROC
      P  = PROC without visibility attribute
      Pn = PROC with PRIVATE visibility attribute
      Pp = PROC with PUBLIC visibility attribute
      x  = procedure will be public
As default, JWasm more or less copies the Masm v6/7 behavior. The difference is that an explicite visibility attribute behind PROC has the highest priority for JWasm. However, since v2.04, there's an additional cmdline option -Zv8 which will make JWasm behave like Masm v8+.

It should be noted that without a PROTO/EXTERNDEF before PROC, there are no differences between Masm v6, v8 and JWasm, and the -Zv8 switch also has no effect then.

3.24.5 Non-RIP-Relative Addressing in 64-Bit

In 64-bit a RIP-relative addressing mode was introduced. This mode is used as default for direct addressing, because it allows to access all code or data labels with a 32-bit displacement. However, for constant address locations this mode is not appropriate and won't be used:

 
     mov al, gs:[1000h]
     mov al, gs:[100000000h]

If a constant address is to be accessed without segment prefixes - note that in 64-bit, only segment registers FS and GS can be used as segment prefixes - one has to use the FLAT keyword in JWasm:

 
     mov al, FLAT:[1000h]           ;invalid for Masm
     mov al, FLAT:[100000000h]      ;invalid for Masm

This syntax differs from Masm's, because Masm won't accept FLAT. In 64-bit Masm, the syntax for accessing constant addresses is instead:

 
     mov al, [1000h]               ;invalid for JWasm
     mov al, [100000000h]          ;invalid for JWasm

The code that will be generated won't show any differences:

  
0000000000000000: 65 8A 04 25 10 00 00 00              mov al,byte ptr gs:[00000010h]
0000000000000008: 65 A0 00 00 00 00 01 00 00 00        mov al,byte ptr gs:[0000000100000000h]
0000000000000012: 8A 04 25 10 00 00 00                 mov al,byte ptr ds:[00000010h]
0000000000000019: A0 00 00 00 00 01 00 00 00           mov al,byte ptr ds:[0000000100000000h]

4. Instruction Sets

JWasm supports all instructions sets supported by Masm v8. These are

- the instructions implemented by 8086, 80186, 80286, 80386, 80486.
- the Pentium and Pentium Pro instructions.
- the MMX and K3D instruction set extensions.
- the SSE, SSE2, SSE3 and SSSE3 instruction set extensions.
- the Intel VMX instruction set extension ( since JWasm v2.09 ).
- the x86-64 64-bit instruction set ( implemented by ML64 ).
Additionally supported are
- SSE4.1 and SSE4.2 instruction sets ( since JWasm v2.01 ).
- AVX instruction set ( since JWasm v2.06 ).

With Masm, SSE4.1 and SSE4.2 require Masm v9; AVX requires Masm v10.

5. Code Generation Differences

JWasm might generate slightly different code than Masm on some occasions. Commandline option -Zg should eliminate most of these differences. However, some differences are due to fixed Masm bugs (see below), in which case option -Zg won't have any effect.

For a few instructions, the encoding differs between Masm versions.

Example:

    cmp al,dl

is encoded 38 D0 in Masm v6, but 3A C2 in Masm v8. In such cases, JWasm will prefer to copy the encoding of Masm v8.

5.1 Forward References in Macro Expressions

Like Masm, JWasm usually evaluates expressions in preprocessor directives during the first pass only. However, due to different jump optimization strategies of Masm and JWasm, the results may differ. This is very unlikely to impose a problem, but it is mentioned here for completeness. An example (found in README.TXT of Masm v6.14):

 
      Label1:
           JMP Label2
      Label2:

      REPEAT Label2 - Label1
           INC AX
      ENDM

Masm will - incorrectly - repeat the loop 10 times, although the result of expression Label2 - Label1 is 2 only. OTOH, JWasm will repeat the loop 2 times only, because it's using an "optimistic" strategy concerning forward references.

6. Output Formats

The format of the assembler's output is selected by commandline options. These are:

-omfIntel's "relocatable Object Module Format", including 32-bit MS extensions.
It's the default.
-coff(MS) COFF object module format, supports flat memory models only.
It's usually used for 32-bit Windows modules.
-elf32-Bit ELF ("Executable and Linkable Format") object modules.
-elf6464-bit ELF object modules.
-win6464-bit format for Win64 object modules. COFF variant with 64-bit extensions.
-djgppCOFF variant used by DJGPP. Not active in precompiled binaries.
-binraw binary format.
-mzDOS MZ binary format.
-pe32- and 64-bit PE binaries.
The formats selected by -bin, -mz and -pe are binary formats, hence the output is not supposed to be fed to a linker.

6.1 OMF Output Format

The OMF format fully supports the segmented architecture of the x86 cpu. The specification has been extended around 1990 to support 32-bit, including the FLAT memory model. However, since it's a bit old now, there's no support of some of the new relocations introduced for 64-bit. The OMF object module consists of records of certain types. JWasm writes those records in the following order:
TypeDescription
THEADR1Marks the start of an object module, contains the name of the source file.
COMENT, class A1h1MS extension; tells linker the CodeView version number. Emitted if -Zi option is active.
COMENT, class E9hnBorland-style auto-dependency record(s). Emitted if -Zd or -Zi options are active.
COMENT, class 9Eh1MS extension; directs the linker to use a "standardized" segment ordering. Emitted if the .DOSSEG directive is found in the source.
COMENT, class 9FhnDefault library search name(s). Emitted if INCLUDELIB directives are used.
LNAMESnDefines names for segments and groups ( optionally also for externals, communals and publics ).
SEGDEFnDefines segment(s).
COMENT, class FEhnTells WLink to do FARCALL optimization for a specific segment. Suppressed with -zld.
GRPDEFnDefines group(s).
EXTDEFnDefines external(s).
COMENT, class A8hnDefines weak external(s). Emitted if EXTERN directive is used with "altname".
COMDEFnDefines communal(s).
ALIASnDefines alias(es).
PUBDEFnDefines public(s).
COMENT, class A0hnDefines export(s). Emitted if the EXPORT attribute is used in a PROC directive.
COMENT, class A2h1Link Pass Separator. Emitted if no entry point is defined in this object module.
LEDATAnData record; defines segment content(s).
FIXUPPnContains information to make the linker resolve references between object modules.
LINNUMnLine number information. Emitted if -Zd or -Zi option is active.
COMENT, class FDhnTells disassembler that a code segment contains data. Suppressed with -zlc.
MODEND1Marks the end of the object module; optionally defines the entry point.
LEDATA, FIXUPP and LINNUM records usually are intermixed; a FIXUPP and/or a LINNUM record appears immediately after the LEDATA record to which it refers.
Since v2.11, multiple THEADR records are written if cmdline options -Zd or -Zi are set and line number information is written for more than one source file; this conforms to MASM behavior.

6.2 COFF Output Format

The COFF object module format is suitable for flat, non-segmented memory models. In most cases the COFF format is used for 32-bit code. However, it's possible to create a 64-bit COFF module if the current cpu is .x64 when the .MODEL directive is parsed ( note that -win64 is the usual way to create modules for 64-bit Windows ). To some extent 16-bit code is also supported with COFF, although OMF will always be the better choice then.

6.3 Win64 Output Format

6.3.1 Win64 Basics

This output format, that is selected with the -win64 commandline option, is a variant of the COFF output format. It's commonly used to create object modules for 64-bit Windows. The default calling convention is the Win64 FASTCALL implementation.

6.3.2 Directive INVOKE in Win64

Unlike the 64-bit version of Masm, which doesn't support INVOKE anymore, JWasm still does; however, please be aware of some peculiarities:

6.3.3 Win64 Structured Exception Handling (SEH)

SEH in Win64 differs significantly from the implementation in Win32. It's very well possible to ignore Win64 SEH for assembly. However, if an assembly routine wants to comply to these rules, a thorough understanding of the Win64 ABI is necessary. Masm ( the 64-bit version ) supplies some "primitives" for SEH support (.ALLOCSTACK, .PUSHREG, .SAVEREG, ...), along with a new FRAME attribute for the PROC directive. These features are also supported by JWasm. See sample Win64_3 how the "primitives" are to be used for SEH support.

The big disadvantage is that using the FRAME keyword in Masm "disables" most of the other high level features combined with PROC (function parameters, locals and registers saved with USES) because no function prologues and epilogues are generated anymore. Additionally, the implementation at least in Masm v8 seems to be a bit buggy, at least in Masm v8. Because of this and to ease the usage of SEH in Win64 there is a new directive implemented in JWasm:

 
        OPTION FRAME:AUTO

If this option is set, JWasm will create Win64 SEH-compatible prologues and epilogues. If the option is off, JWasm will behave Masm-compatible, that is, FRAME found in a PROC directive will disable automatic prologue/epilogue generation. See sample Win64_3e how this option is supposed to be used.

As for the PROC syntax: The Masm documentation states that FRAME can be used in combination with USES and procedure parameters and must be located behind all parameters. However, this syntax isn't accepted by any Masm version. The only syntax which Masm will accept without being confused is FRAME as the one and only parameter for PROC. Therefore JWasm doesn't follow the Masm documentation in this point: the optional FRAME keyword is expected *before* the procedure parameters. The syntax in JWasm is:

 
    procname PROC [public] FRAME[:exc_handler] [USES <reglist>] [parameters]

The SEH "primitives" will generate some additional data in segments .pdata and .xdata. This data is somewhat hidden, but JWasm will display the corresponding data definitions in the listing if option -Sg is set.

Finally, JWasm's default behavior of INVOKE isn't fully SEH-compatible, because the stack pointer is temporarily changed to make room for arguments. To make INVOKE comply to SEH, OPTION WIN64 INVOKE Stack Space Reservation has to be used.

6.4 Binary Output Format

If the binary output format has been selected, the contents of the file are just the raw data bytes emitted by the assembler, no header, relocations or symbol tables are generated. All references have to be resolved internally.

The binary format is most useful for bootloaders or DOS COM files, but may be used to create any binary format. See sample Win32_5, that demonstrates how the binary format is used to create a Win32 application.

If a listing file is produced, a binary map will be added, which shows the file and memory layout of the image:

 
                                    .model tiny

                                    .data

00000000  0D0A48656C6C6F2C20    str1    db 13,10,"Hello, world!",13,10,'$'

00000000                            .code

                                    org 100h

00000100                        start:

00000100  B409                      mov ah, 09h
00000102  BA0000                    mov dx, offset str1
00000105  CD21                      int 21h
00000107  B8004C                    mov ax, 4c00h
0000010A  CD21                      int 21h

                                    end start


Binary Map:

Segment                  Pos(file)      VA  Size(fil) Size(mem)
---------------------------------------------------------------
_TEXT                           0      100         C         C
_DATA                           C      10C        12        12
---------------------------------------------------------------
                                                  1E        1E

Note that bytes with "undefined contents" at the start and the end of the output file are skipped and won't become part of the binary.

6.5 PE Output Format

The ( Windows ) PE output format ( both 32- and 64-bit ) is a binary format - there's no link step supposed to follow the assembly step. Hence all references must be resolved internally, no external references are possible. Since the Windows ABI is implemented as a set of dlls that export function names, it's necessary to provide a mechanism to call such external functions - in the PE format this is achieved with the help of directive OPTION DLLIMPORT; it allows to attach a module name to function prototypes used by the assembly source and consequently give the assembler the means to resolve all references without the help of a linker.

The PE format requires a .MODEL FLAT directive in the source code. This directive will trigger the creation of the internal PE-header section, the value of the cpu at this time will determine whether a 32- or 64-bit PE binary is to be written.

As in all binary formats, the listing will contain a binary map; see Binary Output Format for more details.

If -pe is set, a few sections will be created internally:

-.hdr$1 : section will contain the DOS MZ-stub.
-.hdr$2 : section will contain the PE header
-.hdr$3 : section will contain the PE object table

The default values in the PE header are
Field32-bit Value64-bit Value (if different)
Signature "PE"
Machine 14Ch 8664h
Timestamp date & time
Size OptionalHeader 0E0h0F0h
Characteristics 10Fh12Fh
Magic 10Bh20Bh
LinkerVersion5.1
ImageBase400000h
SectionAlignment1000h
FileAlignment200h
OSVersion4.0
ImageVersion0.0
SubsystemVersion4.0
Win32Version0
Checksum0
Subsystem2 (=Console)
DllCharacteristics0
SizeOfStack100000h,1000h
SizeOfHeap100000h,1000h
LoaderFlags0

To change the default values in the PE header there are two options. First, a predefined assembly-time variable @pe_file_flags will map the value of field Characteristics - changing the value of @pe_file_flags will also change the value in the header field. The other fields in the PE header are only accessible by setting the appropriate values in section .hdr$2. Fields not listed in the table above are set internally by the assembler to ensure data integrity and cannot be modified from within the assembly source.

If the PE binary is to use resources, a .rsrc section has to be created which is to contain them. Defining the resources manually works and is doable, but it might become tedious if a lot of resource items are to be defined. Therefore tool res2inc is supplied, which allows to convert a compiled resource file (.RES) to an assembly include file.

If a dll is created with -pe, one has to mark all procedures that are to be exported with the EXPORT attribute. If the exported names are to be undecorated, use the -zze cmdline option.

Sample Win64_8 shows how a 64-bit Windows binary is created with -pe. It also shows how to define resources in .rsrc manually and how to modify default values of PE header fields.

7. Masm bugs fixed in JWasm

#DescriptionFixed Masm Version
1the infamous "invoke" bug: if an argument for invoke has to be expanded (from BYTE or WORD to DWORD, for example ), bad code was generated. 9
2PROTOs contained twice in the source caused an EXTDEF entry to be generated in the object module. -
3"TYPE xmm0" will return 10 in Masm v6 and v7 - the correct value is 16. 8
4a nested structure might cause a GPF in Masm if the embedded STRUCT's starting offset has to be adjusted due to alignment. -
5defining huge arrays in Masm is very slow and might even cause a deadlock if COFF has been selected as output format. -
6for Masm v6 and v7, if an array > 64 kB is defined and output format OMF is selected, the array's size will be mod 0x10000 only. 8
7Masm doesn't flag invalid numbers in struct/array initializer strings. -
8if an ALIAS is defined somewhere in the source and the symbol table is listed, a 'General Failure' error occurs in Masm if output format is OMF. -
9Type "coerces" for DWORD data items defined in a 32bit segment are ignored by Masm, i.e., "dd far16 ptr <symbol>" will generate a near32 fixup instead of a far16 one. -
10if the ALIGN directive has to add 5 bytes in 32bit code segments, Masm includes an "add eax,0" opcode, which isn't a no-op because flags are modified. -
11silent truncation of immediate constants: Masm v6 and v7 will accept line "mov [word_variable],12345h" without error. 8
12preprocessed output with option -EP may erroneously contain text macros and macro function calls if the macros are located in the initialization string of a structured variable. -
13Masm generates wrong code if a conditional jump is coupled with a type coercion which modifies offset magnitude. Examples: "jz near32 ptr ..." in 16bit code or "jz near16 ptr ..." in 32bit code). -
14if the arguments given to Masm end with an option which expects a parameter (i.e. "ml -c -Fo"), a 'General Failure' may occur. -
15floating-point data items in Masm can be followed by any suffix (example: REAL4 1.0foo, 2.0bar). JWasm won't accept this. -
16If a local is defined inside a macro, Masm will create a unique name for it. The name is constructed by using '??' as prefix, followed by a hexadecimal number with 4 digits. There is no check for overflow, however, so if the total of locals in all macros exceeds 65536, strange errors will occur. -
17If a weak external is defined for -coff with the ALIAS directive, an invalid fixup - and also a strange entry in the module's symbol table - is created. -
18If a section contains more than 0xffff relocations in COFF, the number of relocations that is stored in the object module is just the value of the lower 16-bit half of the relocation count. 8
19If a symbolic constant (=equate) is made public in OMF format, Masm will store the symbol's value in a 16-bit record if it is in the range -32768 ... 65535. If the symbol is referenced in another module as a 32-bit number, it is always zero-extended, never sign-extended; hence values -1 ... -32768 will become 65535 ... 32768. -
20if data labels become public by the -Zf option ( and not by the PUBLIC directive ), their names are not decorated. Also, if format is COFF, they won't become true publics, they're just included in the symbol table with class "static", -
It's slightly dangerous to fix old Masm bugs, since some code might work only if the bugs exists. So no, JWasm won't achieve 100% Masm compatibility.

8. Optional Features

There exist some features that are not activated in the precompiled binaries. To enable these options, the JWasm source must be recompiled with one or more switches set in the command line:

Support for Djgpp's variant of COFF

This option is enabled with switch -DDJGPP_SUPPORT. The generated JWasm binary will accept an additional output format (-djgpp) to be set in the commandline, that makes the assembler generate COFF modules compatible with DJGPP.

Support for Assembly Source generated by Intel C++ compiler

This option is enabled with switch -DDOTNAMEX. It will make the assembler accept names that contain dots if the name starts with a dot or an underscore. Note that this behavior is not compatible with standard Masm syntax.

9. Known Bugs and missing Features

a) Bugs which are known but not fixed yet:

There are currently no known bugs.

b) Features which aren't implemented yet:

- directives PAGE, TITLE, SUBTITLE, SUBTTL. the directives are ignored and a warning (level 4) is displayed.
- the following parameters of the OPTION directive:
- OLDMACROS
- EXPR16
- READONLY
- optional parameter NONUNIQUE for structures is ignored.
- commandline option -AT (Enable tiny model).
- commandline options -Sp, -Ss and -St (set page length, subtitle and title).
- commandline option -H (set max external name length).
- commandline option -Ta (Assemble non-.ASM file).
- commandline option -Zd for ELF output format.
- commandline option -Zi for ELF output format.

If there's ever a problem with one of the missing features, it's very likely that it's related to OPTION OLDMACROS. This option makes Masm 6 emulate two Masm 5.1 peculiarities:

- macro arguments may be separated by spaces
- ampersands (&) inside the macro must match the current level of macro nesting.

c) Missing features which most likely won't be implemented:

- syntax "mm(n)" and "xmm(n)" (supported by Masm v6 and v7 only)
- commandline option -Bl, -F, -Fe, -Fm and -link: since JWasm doesn't launch a linker, those options are useless.
- commandline options -Fr and -FR (generate browser info).
- commandline option -Sc (generate timings in listing).
- commandline option -errorReport (Report internal assembler errors to Microsoft).

10. License

This manual was written by Andreas Grech ( aka Japheth ).

It may be redistributed as long as it is free of charge.

Appendix A. JWasm Reserved Words

Reserved Words are case-insensitive. Besides the items listed below all instruction mnemonics are also Reserved Words.

Registers 16- and 32-bit Modes

8-bit registers AL CL DL BL AH CH DH BH
16-bit registers AX CX DX BX SP BP SI DI
32-bit registers EAX ECX EDX EBX ESP EBP ESI EDI
Segment registers ES CS SS DS FS GS
Floating-point registers ST ST(1) ST(2) ST(3) ST(4) ST(5) ST(6) ST(7)
MMX registers MM0 MM1 MM2 MM3 MM4 MM5 MM6 MM7
SSE registers XMM0 XMM1 XMM2 XMM3 XMM4 XMM5 XMM6 XMM7
AVX registers YMM0 YMM1 YMM2 YMM3 YMM4 YMM5 YMM6 YMM7
Control registers CR0 CR2 CR3 CR4
Debug registers DR0 DR1 DR2 DR3 DR6 DR7
Test registers[1] TR3 TR4 TR5 TR6 TR7
[1]: invalid in 64-bit mode.

Additional Registers in 64-bit Mode

8-bit registers SPL BPL SIL DIL
R8B R9B R10B R11B R12B R13B R14B R15B
16-bit registers R8W R9W R10W R11W R12W R13W R14W R15W
32-bit registers R8D R9D R10D R11D R12D R13D R14D R15D
64-bit registers RAX RCX RDX RBX RSP RBP RSI RDI
R8 R9 R10 R11 R12 R13 R14 R15
SSE registers XMM8 XMM9 XMM10 XMM11 XMM12 XMM13 XMM14 XMM15
AVX registers YMM8 YMM9 YMM10 YMM11 YMM12 YMM13 YMM14 YMM15
Control registers CR8

Types

BYTE
SBYTE
WORD
SWORD
DWORD
SDWORD
REAL4
FWORD
QWORD
SQWORD
REAL8
TBYTE
REAL10
OWORD
YMMWORD
NEAR
FAR
NEAR16
NEAR32
FAR16
FAR32
MMWORD
XMMWORD

Unary Operators

.TYPE
HIGH
HIGH32
HIGHWORD
IMAGEREL[1]
LENGTH
LENGTHOF
LOW
LOW32
LOWWORD
LROFFSET
MASK
OFFSET
OPATTR
SECTIONREL[1]
SEG
SHORT
SIZE
SIZEOF
THIS
TYPE
WIDTH
[1]: not for OMF output format.

Binary Operators

EQ
NE
GE
GT
LE
LT
MOD
PTR
DUP
SHL[1]
SHR[1]
AND[1]
OR[1]
XOR[1]
[1]: these keywords are also instructions.

Directives

.8086
.186
.286
.286C
.286P
.386
.386C
.386P
.486
.486P
.586
.586P
.686
.686P
.K3D
.MMX
.XMM
.X64
.X64P
.8087
.287
.387
.NO87
.CREF
.LIST
.LISTALL
.LISTIF, .LFCOND
.NOCREF, .XCREF
.NOLIST, .XLIST
.NOLISTIF, .SFCOND
.TFCOND
PAGE
SUBTITLE, SUBTTL
TITLE
.LISTMACRO, .XALL
.LISTMACROALL, .LALL
.NOLISTMACRO, .SALL
.ALPHA
.DOSSEG, DOSSEG
.SEQ
.CODE
.STACK
.DATA
.DATA?
.FARDATA
.FARDATA?
.CONST
.IF
.REPEAT
.WHILE
.BREAK
.CONTINUE
.ELSE
.ELSEIF
.ENDIF
.ENDW
.UNTIL
.UNTILCXZ
.EXIT
.STARTUP
.MODEL
.RADIX
.SAFESEH
.ERR
.ERR1
.ERR2
.ERRE
.ERRNZ
.ERRDIF
.ERRDIFI
.ERRIDN
.ERRIDNI
.ERRB
.ERRNB
.ERRDEF
.ERRNDEF
COMMENT
IF
IFE
IF1
IF2
IFDIF
IFDIFI
IFIDN
IFIDNI
IFB
IFNB
IFDEF
IFNDEF
ELSE
ELSEIF
ELSEIFE
ELSEIF1
ELSEIF2
ELSEIFDIF
ELSEIFDIFI
ELSEIFIDN
ELSEIFIDNI
ELSEIFB
ELSEIFNB
ELSEIFDEF
ELSEIFNDEF
ENDIF
FOR, IRP
FORC, IRPC
REPEAT, REPT
WHILE
MACRO
EXITM
ENDM
GOTO
PURGE
INCLUDE
TEXTEQU
CATSTR
SUBSTR
INSTR
SIZESTR
DB
DW
DD
DF
DQ
DT
STRUCT, STRUC
UNION
TYPEDEF
RECORD
COMM
EXTERN, EXTRN
EXTERNDEF
PUBLIC
PROTO
PROC
ENDP
LOCAL
LABEL
INVOKE
ORG
ALIGN
EVEN
SEGMENT
ENDS
GROUP
ASSUME
ALIAS
ECHO, %OUT
END
EQU
INCBIN
INCLUDELIB
NAME
OPTION
POPCONTEXT
PUSHCONTEXT

Additional Directives in 64-bit Mode

.ALLOCSTACK
.ENDPROLOG
.PUSHFRAME
.PUSHREG
.SAVEREG
.SAVEXMM128
.SETFRAME

Other Reserved Words

ADDR
FLAT
VARARG
FRAME[1]
C
SYSCALL[2]
STDCALL
PASCAL
FORTRAN
BASIC
FASTCALL
[1]: in 64-bit mode only.
[2]: in 64-bit, calling convention SYSCALL is renamed to SYSCALL_, since in this mode there exists a SYSCALL instruction.

Appendix B. Source Samples

Win64_3 - SEH Support in Win64
Win64_3e - SEH Support in Win64 (JWasm specific)
DOS64 - Switch to Long Mode and Back
Win32_5 - Create a Win32 Binary with -bin
Win32_7 - Usage of OPTION DLLIMPORT and -Fd Switch
Win64_8 - Create a Win64 Binary with -pe

Win64_3 - SEH Support in Win64


;--- This sample shows how to use SEH primitives. It doesn't use hll
;--- directives. Thus this source can be assembled by both JWasm 
;--- and Masm64.
;---
;--- to assemble enter:
;---   JWasm -win64 Win64_3.asm
;--- or:
;---   ml64 -c Win64_3.asm
;---
;--- to link the binary enter:
;---   Link Win64_3.obj

    option casemap:none

    includelib kernel32.lib
    includelib user32.lib

HINSTANCE typedef QWORD
HWND      typedef QWORD
HMENU     typedef QWORD
HICON     typedef QWORD
HBRUSH    typedef QWORD
HCURSOR   typedef QWORD
WPARAM    typedef QWORD
LPARAM    typedef QWORD
LPSTR     typedef QWORD
LPVOID    typedef QWORD
UINT      typedef DWORD

NULL           equ 0
WS_OVERLAPPEDWINDOW equ 0CF0000h
CW_USEDEFAULT  equ 80000000h
SW_SHOWDEFAULT equ 10
SW_SHOWNORMAL  equ 1
IDC_ARROW      equ 32512
IDI_APPLICATION equ 32512
WM_DESTROY     equ 2
CS_VREDRAW     equ 1
CS_HREDRAW     equ 2
COLOR_WINDOW   equ 5

proto_WNDPROC typedef proto :HWND,:QWORD,:WPARAM,:LPARAM
WNDPROC typedef ptr proto_WNDPROC

WNDCLASSEXA struct 8
cbSize          DWORD   ?
style           DWORD   ?
lpfnWndProc     WNDPROC ?
cbClsExtra      DWORD   ?
cbWndExtra      DWORD   ?
hInstance       HINSTANCE ?
hIcon           HICON   ?
hCursor         HCURSOR ?
hbrBackground   HBRUSH  ?
lpszMenuName    LPSTR   ?
lpszClassName   LPSTR   ?
hIconSm         HICON   ?
WNDCLASSEXA ends

POINT   struct
x   SDWORD  ?
y   SDWORD  ?
POINT   ends

MSG struct 8
hwnd    HWND    ?
message DWORD   ?
wParam  WPARAM  ?
lParam  LPARAM  ?
time    DWORD   ?
pt      POINT   <>
MSG ends

GetModuleHandleA proto :LPSTR
GetCommandLineA  proto
ExitProcess      proto :UINT
LoadIconA        proto :HINSTANCE, :LPSTR
LoadCursorA      proto :HINSTANCE, :LPSTR
RegisterClassExA proto :ptr WNDCLASSEXA
CreateWindowExA  proto :DWORD, :LPSTR, :LPSTR, :DWORD, :SDWORD, :SDWORD, :SDWORD, :SDWORD, :HWND, :HMENU, :HINSTANCE, :LPVOID
ShowWindow       proto :HWND, :SDWORD
UpdateWindow     proto :HWND
GetMessageA      proto :ptr MSG, :HWND, :SDWORD, :SDWORD
TranslateMessage proto :ptr MSG
DispatchMessageA proto :ptr MSG
PostQuitMessage  proto :SDWORD
DefWindowProcA   proto :HWND, :UINT, :WPARAM, :LPARAM

;WinMain proto :HINSTANCE, :HINSTANCE, :LPSTR, :UINT

    .data

ClassName db "SimpleWinClass",0
AppName  db "Our First Window",0

    .data?

hInstance HINSTANCE ?
CommandLine LPSTR ?

    .code

WinMainCRTStartup proc FRAME
    push   rbp
    .pushreg rbp
    mov    rbp,rsp
    .setframe rbp, 0
    .endprolog

    sub    rsp,32
    mov    ecx,NULL
    call   GetModuleHandleA
    mov    hInstance, rax
    call   GetCommandLineA
    mov    CommandLine, rax
    mov    rcx, hInstance
    mov    rdx, NULL
    mov    r8, CommandLine
    mov    r9d, SW_SHOWDEFAULT
    call   WinMain
    mov    ecx, eax
    call   ExitProcess
    align 4
WinMainCRTStartup endp

WinMain proc FRAME

    push  rbp
    .pushreg rbp
    mov   rbp,rsp
    .setframe rbp, 0
    .endprolog
    sub   rsp, sizeof WNDCLASSEXA + sizeof MSG + sizeof HWND + 12*8

hInst     equ <[rbp+10h]>
hPrevInst equ <[rbp+18h]>
CmdLine   equ <[rbp+20h]>
CmdShow   equ <[rbp+28h]>

wc   equ <[rbp - sizeof WNDCLASSEXA].WNDCLASSEXA>
msg  equ <[rbp - sizeof WNDCLASSEXA - sizeof MSG].MSG>
hwnd equ <[rbp - sizeof WNDCLASSEXA - sizeof MSG - sizeof HWND]>

    mov   hInst, rcx  ;store param1 in shadow space

    mov   wc.cbSize, SIZEOF WNDCLASSEXA
    mov   wc.style, CS_HREDRAW or CS_VREDRAW
;   mov   rax, OFFSET WndProc  ;using LEA is preferable
    lea   rax, [WndProc]
    mov   wc.lpfnWndProc, rax
    mov   wc.cbClsExtra, NULL
    mov   wc.cbWndExtra, NULL
    mov   wc.hInstance, rcx
    mov   wc.hbrBackground, COLOR_WINDOW+1
    mov   wc.lpszMenuName, NULL
;    mov   rax, OFFSET ClassName  ;using LEA is preferable
    lea   rax, [ClassName]
    mov   wc.lpszClassName, rax
    mov   ecx, NULL
    mov   edx, IDI_APPLICATION
    call  LoadIconA
    mov   wc.hIcon, rax
    mov   wc.hIconSm, rax
    mov   ecx, NULL
    mov   edx, IDC_ARROW
    call  LoadCursorA
    mov   wc.hCursor,rax
    lea   rcx, wc
    call  RegisterClassExA
    mov   ecx, NULL
    lea   rdx, [ClassName]
    lea   r8, [AppName]
    mov   r9d, WS_OVERLAPPEDWINDOW
    mov   dword ptr [rsp+4*8], CW_USEDEFAULT
    mov   dword ptr [rsp+5*8], CW_USEDEFAULT
    mov   dword ptr [rsp+6*8], CW_USEDEFAULT
    mov   dword ptr [rsp+7*8], CW_USEDEFAULT
    mov   qword ptr [rsp+8*8], NULL
    mov   qword ptr [rsp+9*8], NULL
    mov   rax, hInst
    mov   [rsp+10*8], rax
    mov   qword ptr [rsp+11*8], NULL
    call  CreateWindowExA
    mov   hwnd,rax
    mov   rcx, hwnd
    mov   edx, SW_SHOWNORMAL
    call  ShowWindow
    mov   rcx, hwnd
    call  UpdateWindow
;--- message loop
@@:
        lea rcx, msg
        mov rdx, NULL
        mov r8, 0
        mov r9, 0
        call GetMessageA
        and rax, rax
        jz @F
        lea rcx, msg
        call TranslateMessage
        lea rcx, msg
        call DispatchMessageA
        jmp @B
@@:
    mov   rax, msg.wParam
    add   rsp, sizeof WNDCLASSEXA + sizeof MSG + sizeof HWND + 12*8
    pop   rbp
    ret
    align 4
WinMain endp

WndProc proc FRAME

    sub   rsp, 4*8
    .allocstack 4*8
    .endprolog

    cmp edx, WM_DESTROY
    jnz @F
    mov ecx, NULL
    call PostQuitMessage
    xor rax,rax
    jmp exit
@@:
    call DefWindowProcA
exit:
    add rsp, 4*8
    ret
    align 4
WndProc endp

end

Win64_3e - SEH Support in Win64 (JWasm specific)


;--- SEH support in Win64. Unlike Win64_3, 
;--- this version uses hll directives, so it cannot be assembled
;--- with Masm64. Also, OPTION FRAME:AUTO is used.
;---
;--- to create the binary enter:
;---   JWasm -win64 Win64_3e.asm
;---   Link Win64_3e.obj

    option casemap:none
    option frame:auto    ;generate SEH-compatible prologues and epilogues

    includelib kernel32.lib
    includelib user32.lib

HINSTANCE typedef QWORD
HWND      typedef QWORD
HMENU     typedef QWORD
HICON     typedef QWORD
HBRUSH    typedef QWORD
HCURSOR   typedef QWORD
WPARAM    typedef QWORD
LPARAM    typedef QWORD
LPSTR     typedef QWORD
LPVOID    typedef QWORD
UINT      typedef DWORD

NULL           equ 0
WS_OVERLAPPEDWINDOW equ 0CF0000h
CW_USEDEFAULT  equ 80000000h
SW_SHOWDEFAULT equ 10
SW_SHOWNORMAL  equ 1
IDC_ARROW      equ 32512
IDI_APPLICATION equ 32512
WM_DESTROY     equ 2
CS_VREDRAW     equ 1
CS_HREDRAW     equ 2
COLOR_WINDOW   equ 5

proto_WNDPROC typedef proto :HWND,:QWORD,:WPARAM,:LPARAM
WNDPROC typedef ptr proto_WNDPROC

WNDCLASSEXA struct 8
cbSize          DWORD   ?
style           DWORD   ?
lpfnWndProc     WNDPROC ?
cbClsExtra      DWORD   ?
cbWndExtra      DWORD   ?
hInstance       HINSTANCE ?
hIcon           HICON   ?
hCursor         HCURSOR ?
hbrBackground   HBRUSH  ?
lpszMenuName    LPSTR   ?
lpszClassName   LPSTR   ?
hIconSm         HICON   ?
WNDCLASSEXA ends

POINT   struct
x   SDWORD  ?
y   SDWORD  ?
POINT   ends

MSG struct 8
hwnd    HWND    ?
message DWORD   ?
wParam  WPARAM  ?
lParam  LPARAM  ?
time    DWORD   ?
pt      POINT   <>
MSG ends

GetModuleHandleA proto :LPSTR
GetCommandLineA  proto
ExitProcess      proto :UINT
LoadIconA        proto :HINSTANCE, :LPSTR
LoadCursorA      proto :HINSTANCE, :LPSTR
RegisterClassExA proto :ptr WNDCLASSEXA
CreateWindowExA  proto :DWORD, :LPSTR, :LPSTR, :DWORD, :SDWORD, :SDWORD, :SDWORD, :SDWORD, :HWND, :HMENU, :HINSTANCE, :LPVOID
ShowWindow       proto :HWND, :SDWORD
UpdateWindow     proto :HWND
GetMessageA      proto :ptr MSG, :HWND, :SDWORD, :SDWORD
TranslateMessage proto :ptr MSG
DispatchMessageA proto :ptr MSG
PostQuitMessage  proto :SDWORD
DefWindowProcA   proto :HWND, :UINT, :WPARAM, :LPARAM

WinMain proto :HINSTANCE, :HINSTANCE, :LPSTR, :UINT

    .data

ClassName db "SimpleWinClass",0
AppName  db "Our First Window",0

    .data?

hInstance HINSTANCE ?
CommandLine LPSTR ?

    .code

WinMainCRTStartup proc FRAME

    invoke GetModuleHandleA, NULL
    mov    hInstance, rax
    invoke GetCommandLineA
    mov    CommandLine, rax
    invoke WinMain, hInstance, NULL, CommandLine, SW_SHOWDEFAULT
    invoke ExitProcess, eax

WinMainCRTStartup endp

WinMain proc FRAME hInst:HINSTANCE, hPrevInst:HINSTANCE, CmdLine:LPSTR, CmdShow:UINT

    local wc:WNDCLASSEXA
    local msg:MSG
    local hwnd:HWND

    mov   hInst, rcx
    mov   wc.cbSize, SIZEOF WNDCLASSEXA
    mov   wc.style, CS_HREDRAW or CS_VREDRAW
    lea   rax, [WndProc]
    mov   wc.lpfnWndProc, rax
    mov   wc.cbClsExtra, NULL
    mov   wc.cbWndExtra, NULL
    mov   wc.hInstance, rcx
    mov   wc.hbrBackground, COLOR_WINDOW+1
    mov   wc.lpszMenuName, NULL
    lea   rax, [ClassName]
    mov   wc.lpszClassName, rax
    invoke LoadIconA, NULL, IDI_APPLICATION
    mov   wc.hIcon, rax
    mov   wc.hIconSm, rax
    invoke LoadCursorA, NULL, IDC_ARROW
    mov   wc.hCursor,rax
    invoke RegisterClassExA, addr wc
    invoke CreateWindowExA, NULL, ADDR ClassName, ADDR AppName,\
           WS_OVERLAPPEDWINDOW, CW_USEDEFAULT,\
           CW_USEDEFAULT, CW_USEDEFAULT,CW_USEDEFAULT, NULL, NULL,\
           hInst, NULL
    mov   hwnd,rax
    invoke ShowWindow, hwnd, SW_SHOWNORMAL
    invoke UpdateWindow, hwnd
    .while (1)
        invoke GetMessageA, ADDR msg, NULL, 0, 0
        .break .if (!rax)
        invoke TranslateMessage, ADDR msg
        invoke DispatchMessageA, ADDR msg
    .endw
    mov   rax, msg.wParam
    ret
WinMain endp

WndProc proc FRAME hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM

    .if ( edx == WM_DESTROY )
        invoke PostQuitMessage, NULL
        xor rax,rax
    .else
        invoke DefWindowProcA, rcx, edx, r8, r9
    .endif
    ret
WndProc endp

end WinMainCRTStartup

DOS64 - Switch to Long Mode and Back


;--- DOS program which switches to long-mode and back.
;--- Note: requires at least JWasm v2.
;--- Also: needs a 64bit cpu in real-mode to run.
;--- Parts of the source are based on samples supplied by
;--- sinsi and Tomasz Grysztar in the FASM forum.
;--- To create the binary enter:
;---  JWasm -mz DOS64.asm

    .x64p

;--- 16bit start/exit code

_TEXT16 segment use16 para public 'CODE'

    assume ds:_TEXT16
    assume es:_TEXT16

GDTR label fword        ; Global Descriptors Table Register
    dw 4*8-1            ; limit of GDT (size minus one)
    dd offset GDT       ; linear address of GDT
IDTR label fword        ; Interrupt Descriptor Table Register
    dw 256*16-1         ; limit of IDT (size minus one)
    dd 0                ; linear address of IDT
nullidt label fword
    dw 3FFh
    dd 0
  
    align 8
GDT dq 0                    ; null descriptor
    dw 0FFFFh,0,9A00h,0AFh  ; 64-bit code descriptor
    dw 0FFFFh,0,9A00h,000h  ; compatibility mode code descriptor
    dw 0FFFFh,0,9200h,000h  ; compatibility mode data descriptor

wPICMask dw 0   ; variable to save/restore PIC masks

start16:
    push cs
    pop ds
    mov ax,cs
    movzx eax,ax
    shl eax,4
    add dword ptr [GDTR+2], eax ; convert offset to linear address
    mov word ptr [GDT+2*8+2], ax
    mov word ptr [GDT+3*8+2], ax
    shr eax,16
    mov byte ptr [GDT+2*8+4], al
    mov byte ptr [GDT+3*8+4], al

    mov ax,ss
    mov dx,es
    sub ax,dx
    mov bx,sp
    shr bx,4
    add bx,ax
    mov ah,4Ah
    int 21h         ; free unused memory
    push cs
    pop es
    mov ax,ss
    mov dx,cs
    sub ax,dx
    shl ax,4
    add ax,sp
    push ds
    pop ss
    mov sp,ax       ; make a TINY model, CS=SS=DS=ES

    smsw ax
    test al,1
    jz @F
    mov dx,offset err1
    mov ah,9
    int 21h
    mov ah,4Ch
    int 21h
err1 db "Mode is V86. Need REAL mode to switch to LONG mode!",13,10,'$'
@@:
    xor edx,edx
    mov eax,80000001h   ; test if long-mode is supported
    cpuid
    test edx,20000000h
    jnz @F
    mov dx,offset err2
    mov ah,9
    int 21h
    mov ah,4Ch
    int 21h
err2 db "No 64bit cpu detected.",13,10,'$'
@@:
    mov bx,1000h
    mov ah,48h
    int 21h
    jnc @F
    mov dx,offset err3
    mov ah,9
    int 21h
    mov ah,4Ch
    int 21h
err3 db "Out of memory",13,10,'$'
@@:
    add ax,100h-1   ; align to page boundary
    mov al,0
    mov es,ax

;--- setup page directories and tables

    sub di,di
    mov cx,4096
    sub eax,eax
    rep stosd       ; clear 4 pages

    sub di,di
    mov ax,es
    movzx eax,ax
    shl eax,4
    mov cr3,eax             ; load page-map level-4 base

    lea edx, [eax+5000h]
    mov dword ptr [IDTR+2], edx

    or eax,111b
    add eax, 1000h
    mov es:[di+0000h],eax   ; first PDP table
    add eax, 1000h
    mov es:[di+1000h],eax   ; first page directory
    add eax, 1000h
    mov es:[di+2000h],eax   ; first page table
    mov di,3000h            ; address of first page table
    mov eax,0 + 111b
    mov cx,256              ; number of pages to map (1 MB)
@@:
    stosd
    add di,4
    add eax,1000h
    loop @B

;--- setup ebx/rbx with linear address of _TEXT

    mov bx,_TEXT
    movzx ebx,bx
    shl ebx,4
    add [llg], ebx

;--- create IDT

    mov di,5000h
    mov cx,32
    mov edx, offset exception
    add edx, ebx
make_exc_gates:
    mov eax,edx
    stosw
    mov ax,8
    stosw
    mov ax,8E00h
    stosd
    xor eax, eax
    stosd
    stosd
    add edx,4
    loop make_exc_gates
    mov cx,256-32
make_int_gates:
    mov eax,offset interrupt
    add eax, ebx
    stosw
    mov ax,8
    stosw
    mov ax,8E00h
    stosd
    xor eax, eax
    stosd
    stosd
    loop make_int_gates

    mov di,5000h
    mov eax, ebx
    add eax, offset clock
    mov es:[di+80h*16+0],ax ; set IRQ 0 handler
    shr eax,16
    mov es:[di+80h*16+6],ax

    mov eax, ebx
    add eax, offset keyboard
    mov es:[di+81h*16+0],ax ; set IRQ 1 handler
    shr eax,16
    mov es:[di+81h*16+6],ax

;--- clear NT flag

    pushf
    pop ax
    and ah,0BFh
    push ax
    popf

;--- reprogram PIC: change IRQ 0-7 to INT 80h-87h, IRQ 8-15 to INT 88h-8Fh

    cli
    in al,0A1h
    mov ah,al
    in al,21h
    mov [wPICMask],ax
    mov al,10001b       ; begin PIC 1 initialization
    out 20h,al
    mov al,10001b       ; begin PIC 2 initialization
    out 0A0h,al
    mov al,80h          ; IRQ 0-7: interrupts 80h-87h
    out 21h,al
    mov al,88h          ; IRQ 8-15: interrupts 88h-8Fh
    out 0A1h,al
    mov al,100b         ; slave connected to IRQ2
    out 21h,al
    mov al,2
    out 0A1h,al
    mov al,1            ; Intel environment, manual EOI
    out 21h,al
    out 0A1h,al
    in al,21h
    mov al,11111100b    ; enable only clock and keyboard IRQ
    out 21h,al
    in al,0A1h
    mov al,11111111b
    out 0A1h,al

    mov eax,cr4
    or eax,1 shl 5
    mov cr4,eax         ; enable physical-address extensions (PAE)

    mov ecx,0C0000080h  ; EFER MSR
    rdmsr
    or eax,1 shl 8      ; enable long mode
    wrmsr

    lgdt [GDTR]
    lidt [IDTR]

    mov cx,ss
    movzx ecx,cx        ; get base of SS
    shl ecx,4
    movzx esp,sp
    add ecx, esp        ; ECX=linear address of current SS:ESP

    mov eax,cr0
    or eax,80000001h
    mov cr0,eax         ; enable paging + pmode

    db 66h, 0EAh        ; jmp 0008:oooooooo
llg dd offset long_start
    dw 8

;--- switch back to real-mode and exit

backtoreal:
    cli

    mov eax,cr0
    and eax,7FFFFFFFh   ; disable paging
    mov cr0,eax

    mov ecx,0C0000080h  ; EFER MSR
    rdmsr
    and ah,not 1h       ; disable long mode (EFER.LME=0)
    wrmsr

    mov ax,24           ; set SS,DS and ES to 64k data
    mov ss,ax
    mov ds,ax
    mov es,ax

    mov eax,cr0         ; switch to real mode
    and al,0FEh
    mov cr0, eax

    db 0eah             ; clear instruction cache, CS=real-mode seg
    dw $+4
    dw _TEXT16

    mov ax,STACK        ; SS=real-mode seg
    mov ss, ax
    mov sp,4096

    push cs             ; DS=real-mode _TEXT16 seg
    pop ds

    lidt [nullidt]      ; IDTR=real-mode compatible values

    mov eax,cr4
    and al,not 20h      ; disable physical-address extensions (PAE)
    mov cr4,eax

;--- reprogram PIC: change IRQ 0-7 to INT 08h-0Fh, IRQ 8-15 to INT 70h-77h

    mov al,10001b       ; begin PIC 1 initialization
    out 20h,al
    mov al,10001b       ; begin PIC 2 initialization
    out 0A0h,al
    mov al,08h          ; IRQ 0-7: back to ints 8h-Fh
    out 21h,al
    mov al,70h          ; IRQ 8-15: back to ints 70h-77h
    out 0A1h,al
    mov al,100b         ; slave connected to IRQ2
    out 21h,al
    mov al,2
    out 0A1h,al
    mov al,1            ; Intel environment, manual EOI
    out 21h,al
    out 0A1h,al
    in al,21h

    mov ax,[wPICMask]   ; restore PIC masks
    out 21h,al
    mov al,ah
    out 0A1h,al

    sti
    mov ax,4c00h
    int 21h

_TEXT16 ends

;--- here's the 64bit code segment.
;--- since 64bit code is always flat but the DOS mz format is segmented,
;--- there are restrictions, because the assembler doesn't know the
;--- linear address where the 64bit segment will be loaded:
;--- + direct addressing with constants isn't possible (mov [0B8000h],rax)
;---   since the rip-relative address will be calculated wrong.
;--- + 64bit offsets (mov rax, offset <var>) must be adjusted by the linear
;---   address where the 64bit segment was loaded (is in rbx).
;---
;--- rbx must preserve linear address of _TEXT

_TEXT segment para use64 public 'CODE'

    assume ds:FLAT, es:FLAT

long_start:

    xor eax,eax
    mov ss,eax
    mov esp,ecx
    sti             ; now interrupts can be used
    call WriteStrX
    db "Hello 64bit",10,0
nextcmd:
    mov r8b,0       ; r8b will be filled by the keyboard irq routine
nocmd:
    cmp r8b,0
    jz nocmd
    cmp r8b,1       ; ESC?
    jz esc_pressed
    cmp r8b,13h     ; 'r'?
    jz r_pressed
    call WriteStrX
    db "unknown key ",0
    mov al,r8b
    call WriteB
    call WriteStrX
    db 10,0
    jmp nextcmd

;--- 'r' key: display some register contents

r_pressed:
    call WriteStrX
    db 10,"cr0=",0
    mov rax,cr0
    call WriteQW
    call WriteStrX
    db 10,"cr2=",0
    mov rax,cr2
    call WriteQW
    call WriteStrX
    db 10,"cr3=",0
    mov rax,cr3
    call WriteQW
    call WriteStrX
    db 10,"cr4=",0
    mov rax,cr4
    call WriteQW
    call WriteStrX
    db 10,"cr8=",0
    mov rax,cr8
    call WriteQW
    call WriteStrX
    db 10,0
    jmp nextcmd

;--- ESC: back to real-mode

esc_pressed:
    jmp [bv]
bv  label fword
    dd offset backtoreal
    dw 16

;--- screen output helpers

;--- scroll screen up one line
;--- rsi = linear address start of last line
;--- rbp = linear address of BIOS area (0x400)
scroll_screen:
    cld
    mov edi,esi
    movzx eax,word ptr [rbp+4Ah]
    push rax
    lea rsi, [rsi+2*rax]
    mov cl, [rbp+84h]
    mul cl
    mov ecx,eax
    rep movsw
    pop rcx
    mov ax,0720h
    rep stosw
    ret

WriteChr:
    push rbp
    push rdi
    push rsi
    push rbx
    push rcx
    push rdx
    push rax
    mov edi,0B8000h
    mov ebp,400h
    cmp byte ptr [rbp+63h],0B4h
    jnz @F
    xor di,di
@@:
    movzx ebx, word ptr [rbp+4Eh]
    add edi, ebx
    movzx ebx, byte ptr [rbp+62h]
    mov esi, edi
    movzx ecx, byte ptr [rbx*2+rbp+50h+1] ;ROW
    movzx eax, word ptr [rbp+4Ah]
    mul ecx
    movzx edx, byte ptr [rbx*2+rbp+50h]  ;COL
    add eax, edx
    mov dh,cl
    lea edi, [rdi+rax*2]
    mov al, [rsp]
    cmp al, 10
    jz newline
    mov [rdi], al
    mov byte ptr [rdi+1], 07
    inc dl
    cmp dl, byte ptr [rbp+4Ah]
    jb @F
newline:
    mov dl, 00
    inc dh
    cmp dh, byte ptr [rbp+84h]
    jbe @F
    dec dh
    call scroll_screen
@@:
    mov [rbx*2+rbp+50h],dx
    pop rax
    pop rdx
    pop rcx
    pop rbx
    pop rsi
    pop rdi
    pop rbp
    ret

WriteStr:   ;write string in rdx
    push rsi
    mov rsi, rdx
    cld
@@:
    lodsb
    and al,al
    jz @F
    call WriteChr
    jmp @B
@@:
    pop rsi
    ret

WriteStrX:  ;write string at rip
    push rsi
    mov rsi, [rsp+8]
    cld
@@:
    lodsb
    and al,al
    jz @F
    call WriteChr
    jmp @B
@@:
    mov [rsp+8],rsi
    pop rsi
    ret

WriteQW:        ;write QWord in rax
    push rax
    shr rax,32
    call WriteDW
    pop rax
WriteDW:
    push rax
    shr rax,16
    call WriteW
    pop rax
WriteW:
    push rax
    shr rax,8
    call WriteB
    pop rax
WriteB:     ;write Byte in al
    push rax
    shr rax,4
    call WriteNb
    pop rax
WriteNb:
    and al,0Fh
    add al,'0'
    cmp al,'9'
    jbe @F
    add al,7
@@:
    jmp WriteChr

;--- exception handler

exception:
excno = 0
    repeat 32
    push excno
    jmp @F
    excno = excno+1
    endm
@@:
    call WriteStrX
    db 10,"Exception ",0
    pop rax
    call WriteB
    call WriteStrX
    db " errcode=",0
    mov rax,[rsp+0]
    call WriteQW
    call WriteStrX
    db " rip=",0
    mov rax,[rsp+8]
    call WriteQW
    call WriteStrX
    db 10,0
@@:
    jmp $

;--- clock and keyboard interrupts

clock:
    push rbp
    mov ebp,400h
    inc dword ptr [rbp+6Ch]
    pop rbp
interrupt:              ; handler for all other interrupts
    push rax
    mov al,20h
    out 20h,al
    pop rax
    iretq

keyboard:
    push rax
    in al,60h
    test al,80h
    jnz @F
    mov r8b, al
@@:
    in al,61h           ; give finishing information
    out 61h,al          ; to keyboard...
    mov al,20h
    out 20h,al          ; ...and interrupt controller
    pop rax
    iretq

_TEXT ends

;--- 4k stack, used in both modes

STACK segment use16 para stack 'STACK'
    db 4096 dup (?)
STACK ends

    end start16

Win32_5 - Create a Win32 Binary with -bin


;--- Win32 "hello world" console application.
;--- Uses JWasm's bin output format, so no linker needed.
;--- assemble: JWasm -bin -Fo Win32_5.exe Win32_5.ASM

    .386
    option casemap:none

    .nolist
    include winnt.inc   ;include PE image definitions
    .list

STD_OUTPUT_HANDLE equ -11

IMAGEBASE equ 400000h

PEHDR segment dword FLAT

;--- define the DOS "MZ" header

    org IMAGEBASE

    IMAGE_DOS_HEADER <"ZM", 80h, 1, 0,4,0,-1,0,200h,0,0,0,0,0,<0>,0,0,<0>,IMAGEREL PEHdr>

    db 0Eh         ;push cs
    db 1Fh         ;pop ds
    db 0BAh,0Eh,0  ;mov dx,text
    db 0B4h,09h    ;mov ah,9
    db 0CDh,21h    ;int 21h
    db 0B8h,01h,4Ch;mov ax,4c01h
    db 0CDh,21h    ;int 21h
    db "This program cannot be run in DOS mode",13,10,'$'

    org IMAGEBASE+80h

;--- define the Win32 "PE" header

PEHdr label byte
    db "PE",0,0
    IMAGE_FILE_HEADER <IMAGE_FILE_MACHINE_I386, num_sections, 0, 0, 0, sizeof IMAGE_OPTIONAL_HEADER32,
        IMAGE_FILE_RELOCS_STRIPPED or IMAGE_FILE_EXECUTABLE_IMAGE or IMAGE_FILE_32BIT_MACHINE or IMAGE_FILE_LOCAL_SYMS_STRIPPED>

    IMAGE_OPTIONAL_HEADER32 { 10Bh, ;magic
        6,0,                        ;linker major, minor
        1000h,1000h,0,              ;sizeof code, initialized data, uninitialized data
        IMAGEREL mainCRTStartup,    ;entry point
        IMAGEREL start_text, IMAGEREL start_rdata,  ;baseof code, data
        IMAGEBASE,    ;imagebase
        1000h,200h,   ;section alignment, file alignment
        4,0,          ;OS major, minor
        0,0,          ;Image major, minor
        4,0,          ;Subsys major, minor
        0,            ;win32 version
        3000h,        ;sizeof image
        1000h,        ;sizeof header
        0,            ;checksum
        IMAGE_SUBSYSTEM_WINDOWS_CUI,
        0,            ;dll characteristics
        100000h,1000h,;stack res,com
        100000h,1000h,;heap res, com
        0,            ;loader flags
        16,           ;number of directories
        <<0,0>,       ;exports
        < IMAGEREL start_idata, SECTIONREL endof_idata >, ;imports
        <0,0>,<0,0>,     ;resource, exception
        <>,<>,<>,<>,     ;security, baserelocs, debug, architecture
        <>,<>,<>,<>,     ;globalptr, tls, load_config, bound_import
        <>,<>,<>,<>>}    ;iat, delay_import, com descriptor, reserved

;--- define the section table

sectiontable label byte
    IMAGE_SECTION_HEADER <".text", <sizeof_text>, IMAGEREL start_text, sizeof_text,
        200h, 0, 0, 0, 0, 060000020h >
    IMAGE_SECTION_HEADER <".rdata", <SECTIONREL endof_idata + sizeof_const>, IMAGEREL start_rdata, SECTIONREL endof_idata + sizeof_const,
        400h, 0, 0, 0, 0, 040000040h >
num_sections equ ( $ -  sectiontable ) / sizeof IMAGE_SECTION_HEADER

    org IMAGEBASE+200h   ;forces physical size of header to 200h and sets VA to 400200h

PEHDR ends

;--- the ALIGNx segments are needed because
;--- section alignment and file alignment are different

ALIGN1 segment dword public FLAT 'DATA'
    org 0E00h   ; change pc to RVA 1000h
ALIGN1 ends

_TEXT segment dword public FLAT 'CODE'
_TEXT ends

ALIGN2 segment dword public FLAT 'DATA'
    org 0E00h   ; change pc to RVA 2000h
ALIGN2 ends

_IDATA segment dword public FLAT 'DATA'
start_rdata label byte
start_idata label byte
;--- import descriptors go here
_IDATA ends
_IDATA$1 segment dword public FLAT 'DATA'
    IMAGE_IMPORT_DESCRIPTOR <<0>,0,0,0,0>
;--- ILT entries go here
_IDATA$1 ends
_IDATA$2 segment dword public FLAT 'DATA'
    dd 0    ;--- end of last ILT
;--- IAT entries go here
_IDATA$2 ends
_IDATA$3 segment dword public FLAT 'DATA'
    dd 0    ;--- end of last IAT
;--- import name strings go here
_IDATA$3 ends
_IDATA$4 segment dword public FLAT 'DATA'
endof_idata equ $
_IDATA$4 ends

CONST segment dword public FLAT 'DATA'
start_const label byte
CONST ends

DefineImpDll macro name
_IDATA segment
    IMAGE_IMPORT_DESCRIPTOR <<IMAGEREL name&ILT>,0,0,IMAGEREL name, IMAGEREL name&IAT>
_IDATA ends
_IDATA$1 segment
ifdef ImportDefined
    dd 0  ;terminate previous ILT
endif
name&ILT label dword
_IDATA$1 ends
_IDATA$2 segment
ifdef ImportDefined
    dd 0  ;terminate previous IAT
endif
name&IAT label dword
_IDATA$2 ends
_IDATA$3 segment
name db @CatStr(!",name, !"),0
    align 4
_IDATA$3 ends
ImportDefined equ 1
    endm

DefineImport macro name
_IDATA$1 segment
    dd IMAGEREL n&name
_IDATA$1 ends
_IDATA$2 segment
lp&name typedef ptr pr&name
name    lp&name IMAGEREL n&name
_IDATA$2 ends
_IDATA$3 segment
n&name dw 0
    db @CatStr(!",name, !"),0
    align 4
_IDATA$3 ends
    endm

prWriteConsoleA typedef proto stdcall :dword, :dword, :dword, :dword, :dword
prGetStdHandle  typedef proto stdcall :dword
prExitProcess   typedef proto stdcall :dword

    DefineImpDll kernel32
    DefineImport ExitProcess
    DefineImport WriteConsoleA
    DefineImport GetStdHandle

if 0 ;if further dlls are to be imported
prMessageBoxA   typedef proto stdcall :dword, :dword, :dword, :dword

    DefineImpDll user32
    DefineImport MessageBoxA
endif

CONST segment

string  db 13,10,"hello, world.",13,10

sizeof_const equ $ - start_const

CONST ends

_TEXT segment

    assume ds:FLAT,es:FLAT

start_text label near

;--- start of program

main proc

local dwWritten:dword
local hConsole:dword

    invoke  GetStdHandle, STD_OUTPUT_HANDLE
    mov     hConsole,eax

    invoke  WriteConsoleA, hConsole, addr string, sizeof string, addr dwWritten, 0

    xor     eax,eax
    ret
main endp

;--- entry

mainCRTStartup proc c

    invoke  main
    invoke  ExitProcess, eax

mainCRTStartup endp

sizeof_text equ $ - start_text

    org 200h    ;align size of _TEXT to next 512 byte boundary

_TEXT ends

    end

Win32_7 - Usage of OPTION DLLIMPORT and -Fd Switch


;--- Win32_7 - Shows how to use OPTION DLLIMPORT and switch -Fd.
;---           No import libraries are needed in the link step.
;---
;--- assemble: JWasm -coff -Fd Win32_7.ASM
;--- link:     JWlink format windows pe f Win32_7.OBJ

    .386
    .model FLAT, stdcall
    option casemap:none

STD_OUTPUT_HANDLE equ -11

   option dllimport:<kernel32>
WriteConsoleA proto :dword, :dword, :dword, :dword, :dword
GetStdHandle  proto :dword
ExitProcess   proto :dword
   option dllimport:<user32>
MessageBoxA   proto :dword, :dword, :dword, :dword
   option dllimport:<none>

    .const

msg db 13,10,"hello, world.",13,10
    db 0

    .code

main proc

local   written:dword

    invoke  GetStdHandle, STD_OUTPUT_HANDLE
    mov ebx, eax
    invoke  WriteConsoleA, ebx, addr msg, sizeof msg,
                addr written, 0
    invoke  MessageBoxA, 0, addr msg, 0, 0
    ret

main endp

;--- entry

start:

    invoke  main
    invoke  ExitProcess, 0

    end start

Win64_8 - Create a Win64 Binary with -pe


;--- create a 64-bit binary with -pe cmdline option
;---
;---   JWasm -pe Win64_8.asm

    .x64                ; -pe requires to set cpu, model & language
    .model flat, fastcall

    option casemap:none
    option frame:auto   ; generate SEH-compatible prologues and epilogues
    option win64:3      ; init shadow space, reserve stack at PROC level

;--- resource IDs
IDR_MENU1   equ 100
IDR_BITMAP1 equ 101
IDM_EXIT    equ 1000

NULL      equ 0
LPSTR     typedef ptr
LPVOID    typedef ptr
UINT      typedef dword
BOOL      typedef dword

;--- winbase definitions
HINSTANCE typedef ptr

;--- winuser definitions
HWND      typedef ptr
HMENU     typedef ptr
HICON     typedef ptr
HBRUSH    typedef ptr
HCURSOR   typedef ptr
HDC       typedef ptr
HBITMAP   typedef ptr
WPARAM    typedef ptr
LPARAM    typedef qword

WS_OVERLAPPEDWINDOW equ 0CF0000h
CW_USEDEFAULT  equ 80000000h
SW_SHOWDEFAULT equ 10
SW_SHOWNORMAL  equ 1
IDC_ARROW      equ 32512
IDI_APPLICATION equ 32512
CS_VREDRAW     equ 1
CS_HREDRAW     equ 2
COLOR_WINDOW   equ 5

WM_DESTROY     equ 2
WM_PAINT       equ 000Fh
WM_COMMAND     equ 0111h

proto_WNDPROC typedef proto :HWND,:qword,:WPARAM,:LPARAM
WNDPROC typedef ptr proto_WNDPROC

WNDCLASSEXA struct 8
cbSize          dword   ?
style           dword   ?
lpfnWndProc     WNDPROC ?
cbClsExtra      dword   ?
cbWndExtra      dword   ?
hInstance       HINSTANCE ?
hIcon           HICON   ?
hCursor         HCURSOR ?
hbrBackground   HBRUSH  ?
lpszMenuName    LPSTR   ?
lpszClassName   LPSTR   ?
hIconSm         HICON   ?
WNDCLASSEXA ends

POINT   struct
x   sdword  ?
y   sdword  ?
POINT   ends

MSG struct 8
hwnd    HWND    ?
message dword   ?
wParam  WPARAM  ?
lParam  LPARAM  ?
time    dword   ?
pt      POINT   <>
MSG ends

RECT struct
left    sdword  ?
top     sdword  ?
right   sdword  ?
bottom  sdword  ?
RECT ends

PAINTSTRUCT struct 8
hdc         HDC  ?
fErase      BOOL ?
rcPaint     RECT <>
fRestore    BOOL ?
fIncUpdate  BOOL ?
rgbReserved byte 32 dup (?)
PAINTSTRUCT ends

;--- wingdi definitions

DIB_RGB_COLORS  equ 0
SRCCOPY         equ 00CC0020h

HGDIOBJ  typedef ptr

BITMAPINFOHEADER struct
biSize          dword   ?
biWidth         sdword  ?
biHeight        sdword  ?
biPlanes        word    ?
biBitCount      word    ?
biCompression   dword   ?
biSizeImage     dword   ?
biXPelsPerMeter sdword  ?
biYPelsPerMeter sdword  ?
biClrUsed       dword   ?
biClrImportant  dword   ?
BITMAPINFOHEADER ends

    option dllimport:<kernel32>
GetModuleHandleA proto :LPSTR
GetCommandLineA  proto
ExitProcess      proto :UINT

    option dllimport:<user32>
BeginPaint       proto :HWND, :ptr PAINTSTRUCT
CreateWindowExA  proto :dword, :LPSTR, :LPSTR, :dword, :sdword, :sdword, :sdword, :sdword, :HWND, :HMENU, :HINSTANCE, :LPVOID
DefWindowProcA   proto :HWND, :UINT, :WPARAM, :LPARAM
DestroyWindow    proto :HWND
DispatchMessageA proto :ptr MSG
EndPaint         proto :HWND, :ptr PAINTSTRUCT
GetClientRect    proto :HWND, :ptr RECT
GetMessageA      proto :ptr MSG, :HWND, :sdword, :sdword
LoadBitmapA      proto :HINSTANCE, :LPSTR
LoadCursorA      proto :HINSTANCE, :LPSTR
LoadIconA        proto :HINSTANCE, :LPSTR
PostQuitMessage  proto :sdword
RegisterClassExA proto :ptr WNDCLASSEXA
ShowWindow       proto :HWND, :sdword
TranslateMessage proto :ptr MSG
UpdateWindow     proto :HWND

    option DLLIMPORT:<gdi32>
BitBlt             proto :HDC, :dword, :dword, :dword, :dword, :HDC, :dword, :dword, :dword
CreateCompatibleDC proto :HDC
DeleteDC           proto :HDC
GetDIBits          proto :HDC, :HBITMAP, :dword, :dword, :ptr, :ptr BITMAPINFO, :dword
SelectObject       proto :HDC, :HGDIOBJ
    option dllimport:none

WinMain proto :HINSTANCE, :HINSTANCE, :LPSTR, :UINT

    .data

ClassName db "SimpleWinClass",0
AppName  db "Bitmap rendering",0

    .data?

hInstance HINSTANCE ?
hBitmap   HBITMAP ?
CommandLine LPSTR ?

    .code

WinMainCRTStartup proc FRAME

    invoke GetModuleHandleA, NULL
    mov    hInstance, rax
    invoke GetCommandLineA
    mov    CommandLine, rax
    invoke WinMain, hInstance, NULL, CommandLine, SW_SHOWDEFAULT
    invoke ExitProcess, eax

WinMainCRTStartup endp

WinMain proc FRAME hInst:HINSTANCE, hPrevInst:HINSTANCE, CmdLine:LPSTR, CmdShow:UINT

    local wc:WNDCLASSEXA
    local msg:MSG
    local hwnd:HWND

    invoke LoadBitmapA, hInst, IDR_BITMAP1
    mov   hBitmap, rax

    mov   wc.cbSize, sizeof WNDCLASSEXA
    mov   wc.style, CS_HREDRAW or CS_VREDRAW
    lea   rax, [WndProc]
    mov   wc.lpfnWndProc, rax
    mov   wc.cbClsExtra, NULL
    mov   wc.cbWndExtra, NULL
    mov   rcx, hInst
    mov   wc.hInstance, rcx
    mov   wc.hbrBackground, COLOR_WINDOW+1
    mov   wc.lpszMenuName, IDR_MENU1
    lea   rax, [ClassName]
    mov   wc.lpszClassName, rax
    invoke LoadIconA, NULL, IDI_APPLICATION
    mov   wc.hIcon, rax
    mov   wc.hIconSm, rax
    invoke LoadCursorA, NULL, IDC_ARROW
    mov   wc.hCursor,rax
    invoke RegisterClassExA, addr wc
    invoke CreateWindowExA, NULL, ADDR ClassName, ADDR AppName,
           WS_OVERLAPPEDWINDOW, CW_USEDEFAULT,
           CW_USEDEFAULT, CW_USEDEFAULT,CW_USEDEFAULT, NULL, NULL,
           hInst, NULL
    mov   hwnd,rax
    invoke ShowWindow, hwnd, SW_SHOWNORMAL
    invoke UpdateWindow, hwnd
    .while (1)
        invoke GetMessageA, ADDR msg, NULL, 0, 0
        .break .if (!eax)
        invoke TranslateMessage, ADDR msg
        invoke DispatchMessageA, ADDR msg
    .endw
    mov   rax, msg.wParam
    ret
WinMain endp

WndProc proc FRAME hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM

local hdc2:HDC
local ps:PAINTSTRUCT
local rect:RECT
local bmi:BITMAPINFOHEADER

    .if edx == WM_DESTROY
        invoke PostQuitMessage, NULL
        xor rax,rax
    .elseif edx == WM_COMMAND
        .if wParam == IDM_EXIT
            invoke DestroyWindow, hWnd
        .endif
        xor eax, eax
    .elseif edx == WM_PAINT
        invoke BeginPaint, hWnd, addr ps
        invoke CreateCompatibleDC, ps.hdc
        mov hdc2, rax
        invoke SelectObject, hdc2, hBitmap
        mov bmi.biSize, sizeof BITMAPINFOHEADER
        mov bmi.biBitCount, 0
        invoke GetDIBits, hdc2, hBitmap, 0, 0, 0, addr bmi, DIB_RGB_COLORS
        invoke GetClientRect, hWnd, addr rect
        mov r8d, rect.right
        sub r8d, bmi.biWidth
        jnc @F
        xor r8d, r8d
@@:
        shr r8d, 1
        mov r9d, rect.bottom
        sub r9d, bmi.biHeight
        jnc @F
        xor r9d, r9d
@@:
        shr r9d, 1
        invoke BitBlt, ps.hdc, r8d, r9d, bmi.biWidth, bmi.biHeight, hdc2, 0, 0, SRCCOPY
        invoke DeleteDC, hdc2
        invoke EndPaint, hWnd, addr ps

        xor eax,eax
    .else
        invoke DefWindowProcA, rcx, edx, r8, r9
    .endif
    ret
WndProc endp

if 1 ;for -pe

RT_BITMAP equ 2
RT_MENU   equ 4

;--- menu resource flags
MF_POPUP   equ 10h
MF_END     equ 80h

IMAGE_RESOURCE_DIRECTORY struct
Characteristics      dword ?
TimeDateStamp        dword ?
MajorVersion         word  ?
MinorVersion         word  ?
NumberOfNamedEntries word  ?
NumberOfIdEntries    word  ?
IMAGE_RESOURCE_DIRECTORY ends

IMAGE_RESOURCE_DIRECTORY_ENTRY struct
union
r0      record NameIsString:1, NameOffset:31
Name_   dword   ?
Id      word    ?
ends
union
OffsetToData dword   ?
r1           record	DataIsDirectory:1, OffsetToDirectory:31
ends
IMAGE_RESOURCE_DIRECTORY_ENTRY ends

IMAGE_RESOURCE_DATA_ENTRY struct
OffsetToData dword ?
Size_        dword ?
CodePage     dword ?
Reserved     dword ?
IMAGE_RESOURCE_DATA_ENTRY ends

    option dotname

.rsrc segment dword FLAT public read 'RSRC'

;--- define menu IDR_MENU1 and bitmap IDR_BITMAP1

;--- root level: enum the resource types
      IMAGE_RESOURCE_DIRECTORY <0,0,0,0,0,2>
      IMAGE_RESOURCE_DIRECTORY_ENTRY < <RT_BITMAP>, <SECTIONREL bms   + 80000000h> >
      IMAGE_RESOURCE_DIRECTORY_ENTRY < <RT_MENU>,   <SECTIONREL menus + 80000000h> >

;--- second level: enum the IDs of resource type X
bms   IMAGE_RESOURCE_DIRECTORY <0,0,0,0,0,1>
      IMAGE_RESOURCE_DIRECTORY_ENTRY < <IDR_BITMAP1>, <SECTIONREL bm1   + 80000000h> >
menus IMAGE_RESOURCE_DIRECTORY <0,0,0,0,0,1>
      IMAGE_RESOURCE_DIRECTORY_ENTRY < <IDR_MENU1>,   <SECTIONREL menu1 + 80000000h> >

;--- third level: enum the languages of ID X
bm1   IMAGE_RESOURCE_DIRECTORY <0,0,0,0,0,1>
      IMAGE_RESOURCE_DIRECTORY_ENTRY < <409h>, <SECTIONREL bm1_l1> >
menu1 IMAGE_RESOURCE_DIRECTORY <0,0,0,0,0,1>
      IMAGE_RESOURCE_DIRECTORY_ENTRY < <409h>, <SECTIONREL m1_l1> >

;--- last level: define the resource data
;--- data for menu IDR_MENU1, language 409h
m1_l1 IMAGE_RESOURCE_DATA_ENTRY <IMAGEREL m1_l1_data, size_m1_l1, 0, 0>
m1_l1_data dw 0,0	;menu header
    dw MF_POPUP or MF_END, '&','F','i','l','e',0
    dw MF_END, IDM_EXIT,   'E','&','x','i','t',0
size_m1_l1 equ $ - m1_l1_data
    align 4

;--- data for bitmap IDR_BITMAP1
bm1_l1 IMAGE_RESOURCE_DATA_ENTRY <IMAGEREL bm1_l1_data, size_bm1_l1, 0, 0>
bm1_l1_data label word
    incbin <Win32_8.bmp>,14	;skip bitmap file header
size_bm1_l1 equ $ - ( bm1_l1_data )

.rsrc ends

;--- set /subsystem:windows
;--- the PE header is stored in section .hdr$2
    option dotname
.hdr$2 segment dword FLAT public 'HDR'
    org 5Ch ;position to IMAGE_NT_HEADER64.OptionalHeader.Subsystem
    dw 2    ;2=subsystem windows
.hdr$2 ends

endif

end WinMainCRTStartup

Appendix C. Errors and Warnings

The warning and error numbers emitted by JWasm differ from Masm's. However, the texts of the messages are pretty much identical.
As in Masm, the first digit shows the severity of the issue: range 1xxx reports a fatal error ( assembly process is stopped ), range 2xxx indicates an error ( assembly process continues, but no object module will be created ) and 4xxx are warnings.
x029 Multiple base registers not allowed In 16-bit code, one cannot use both BX and BP in indirect addressing; in 32/64-bit code, ESP/RSP can only appear once in indirect addressing.
x030 Instruction or register not accepted in current CPU mode
x031 Invalid addressing mode with current CPU setting
x032 Cannot use TRn-TRn with current CPU setting The TRx special registers were restricted to 80386 and 80486 cpus.
x033 Must be index or base register
x034 Multiple index registers not allowed
x035
x036 Scale factor must be 1, 2, 4 or 8
x037 Cannot be used as index register: <register> Index registers are restricted. In 16-bit mode, only SI and DI can be index registers. In 32-bit mode, all general-purpose registers except ESP can be index registers.
x038 Base and index register differ in size
x039 Expecting comma
x040 ORG needs a constant or local offset
x041 POP CS is not allowed
x042 Only MOV can use special register The special registers CRx, DRx and TRx can only be moved to/from general purpose registers.
x043 Cannot use SHORT with CALL Distance of CALL operands must be NEAR or FAR.
x044 Only SHORT jump distance is allowed Some jump instructions accept short distances only (JCXZ, JECXZ, LOOPx).
x045 Syntax error
x046 Prefix must be followed by an instruction
x047 Syntax error: Unexpected colon
x048 Operands must be the same size: <size op1> - <size op2>
x049 Invalid instruction operands
x050 Jump distance not possible in current CPU mode Jcc instructions won't accept type coercions that increase the jump distance (i.e. "jz NEAR PTR label") if current cpu is < 80386.
x051 Immediate data out of range
x052 Can not use short or near modifiers with this instruction
x053 Jump out of range by <num> byte(s) A short distance must be in the range -128 to +127.
x054 Displacement out of range: <displacement>
x055 Initializer value too large
x056 Symbol already defined: <symbol>
x057 Offset magnitude too large for specified size
x058 Magnitude of offset exceeds 16 bit
x059 Operand 2 too big
x060 Operand 1 too small
x061 Line too long Size of a line ( after concatenation) is restricted to 600.
x062 Too many tokens in a line The number of tokens in a line is restricted to 150.
x063
x064 Operand is expected
x065 Constant expected A constant (numeric) value is expected in the current context. Note that a label - more exactly: the offset part of a label's address - is not a constant value, since the final value is calculated by the linker ( or the OS loader ) only.
x066 Constant operand is expected The expression evaluator accepts a constant only in the current context.
x067 .ELSE clause already occured in this .IF block An .IF block may contain 0 or 1 .ELSE clauses and it must be the last clause before .ENDIF.
x068 Multiple overrides
x069 Segment, group or segment register expected The operand before the colon operator (:) must be a segment, group or segment register.
x070 Identifier too long Identifer names are restricted to 247. This is a hard limit for OMF output format. For other formats, the limit may be extended by adjusting and recompiling the source code.
x071 Invalid operand size for instruction
x072 Not supported: <directive> Message is displayed if one of the follwing options is specified: OPTION READONLY, OPTION EXPR16, OPTION OLDMACROS. Those are currently not supported.
x073 Size not specified, assuming: <type> this is a warning. <type> may be BYTE, WORD or DWORD. The message may occur if an immediate value is written to an untyped memory reference:

 
       mov [ebx], 1

JWasm makes a guess and displays the warning, while Masm will display an error in such cases.

x074 Floating-point initializer ignored
x075 Only SHORT and NEAR jump distance is allowed Conditional jump (Jcc) instruction destination cannot be far.
x076 Initializer magnitude too large for specified size
x077 Segment attribute is defined already: <attribute>
x078 Segment definition changed: %s, %s
x079 Class name too long Segment class names are restricted to 255 in size.
x080 Block nesting error: %s
x081 Segment attribute is unknown: %s
x082 Must be in segment block Instructions and directives that generate code or data must be inside a segment block.
x083 Segment not defined: <segment>
x084 Colon is expected
x085 Invalid qualified type: %s
x086 Qualified type is expected
x087
x088 Library name is missing
x089 Cannot access label through segment registers: <label>
x090 Line too long after expansion: <line>
x091 Language type must be specified
x092 PROC, MACRO or macro loop directive must precede LOCAL
x093 Cannot nest procedures
x094 VARARG requires C calling convention
x095 Multiple .MODEL directives, .MODEL ignored
x096 Model is not declared Without a model, simplified segment directives ( .CODE, .DATA, .CONST, .DATA?, .STACK, .FARDATA and .FARDATA? ) and directives .STARTUP, .EXIT cannot be used.
x097 Backquote missing: `<identifier>
x098 COMMENT delimiter expected
x099 END directive required at end of file
x100 Nesting level too deep
x101 Macro nesting level too deep
x102 Symbol not defined : <symbol>
x103
x104 No filename specified.
x105 Out of Memory This is a fatal error. With the 8086-version of jwasm, JWASMR, you'll see this error if you try to assemble something that contains a few thousand symbols. The 32- or 64-bit versions of jwasm should always have enough memory on modern machines.
x106 Cannot open file: "<file>" [<error code>] Error code ENOENT means "file not found". Other error codes are displayed as numbers
x107 Cannot close file: <file> [<error code>]
x108 File write error: <file> [<error code>] Usually happens if output media is read-only or full.
x109 Invalid command-line option: <option>
x110 Internal error in <source file>(<line>) This error shouldn't be seen in the release version. It's displayed if the internal assert() function is called, which usually is done when a "virtually impossible" error condition has occurred.
x111 Expecting closing square bracket
x112 Expecting file name
x113 Too many errors Use commandline option -e to set the max. number of errors that are displayed
x114 forced error <message> Generic "forced error" message
x115 forced error: Value not equal to 0: <value> <text> Error emitted by the .ERRNZ directive.
x116 forced error: Value equal to 0: <value> <text> Error emitted by the .ERRE directive.
x117 forced error: symbol defined: <symbol> Error emitted by the .ERRDEF directive.
x118 forced error: symbol not defined: <symbol> Error emitted by the .ERRNDEF directive.
x119 forced error: string blank : <string> Error emitted by the .ERRB directive.
x120 forced error: string not blank : <string> Error emitted by the .ERRNB directive.
x121 forced error: strings not equal : <string> : <string> Error emitted by the .ERRDIF and .ERRDIFI directives.
x122 forced error: strings equal : <string> : <string> Error emitted by the .ERRIDN and .ERRIDNI directives.
x123 <file>(<line>): Included by Additional error information if error occured in an include file.
x124 <file>(<line>)[<macro>]: Macro called from Additional error information if error occured inside a macro.
x125 <file>(<line>): iteration <iteration>: Macro called from Additional error information if error occured inside a loop macro (FOR, FORC, REPEAT, ...).
x126 <file>(<line>): Main line code Additional error information if error occured inside an include file or a macro.
x127 Extending jump
x128 Directive ignored: %s
x129 number must be a power of 2
x130 Incompatible with segment alignment: %s
x131 Segment expected: %s
x132 Incompatible CPU mode for 32-bit segment
x133 Far call is converted to near call.
x134 CPU option %s is not valid for selected CPU.
x135 Segment '%s' is in another group already
x136 Symbol type conflict: %s
x137 Conflicting parameter definition: %s
x138 PROC and PROTO calling convention conflict
x139 Non-benign %s redefinition: %s
x140 Too many bits in RECORD: %s
x141 Statement not allowed inside structure definition
x142 Unmatched block nesting: %s
x143 Symbol redefinition: %s
x144 Text item required
x145 INVOKE argument type mismatch: argument %u
x146 Too few arguments to INVOKE: %s
x147 VARARG parameter must be last
x148 LABEL parameter must be first
x149 Too many arguments in macro call: %s This is a warning. Macro is invoked with more arguments than expected.
x150 Missing operator in expression
x151 Unexpected literal found in expression: %s Literals enclosed in <> or {} are items processed by the preprocessor or to initialize "structured" data items. If they're used otherwise, this error will occur.
x152 Initializer must be a string or single item: %s
x153 Too many initial values for structure: %s
x154 Too many initial values for array: %s
x155 String or text literal too long
x156 PROLOGUE must be macro function The user-defined prologue macro must be a macro function, that is, there must be an EXITM somewhere inside that returns a literal.
x157 EPILOGUE must be macro procedure: %s The user-defined epilogue macro must be a macro procedure, that is, there must NOT be an EXITM somewhere inside that returns a literal.
x158 Reserved word expected
x159 INVOKE requires prototype for procedure
x160 Invalid type for data declaration: %s
x161 Operand must be RECORD type or field
x162 Unmatched macro nesting
x163 Empty (null) string
x164 No segment information to create fixup: %s
x165 Register value overwritten by INVOKE
x166 Missing quotation mark in string
x167 Divide by zero in expression
x168 General Failure
x169 Cannot have implicit far jump or call to near label
x170 Invalid use of register
x171 Distance invalid for current segment
x172 Initializer magnitude too large: %s
x173 Cannot add two relocatable labels
x174 Cannot define as public or external: <symbol_name> Text macros, macros, stack variables, structure fields or segment/groups cannot be public or external.
x175 Positive value expected
x176 FAR not allowed in FLAT model COMM variables
x177 Too many arguments to INVOKE
x178 Directive must appear inside a macro
x179 Invalid type expression
x180 Cannot declare scoped code label as PUBLIC: <label>
x181 Invalid radix tag
x182 Instruction operand must have size The instruction allows operands with more than just one size, and the wanted size cannot be guessed from the current operands.
x183 Use of register assumed to ERROR
x184 Instructions and initialized data not supported in <seg_type> segments <seg_type> may be BSS or AT. Such segments don't have data.
x185 Literal expected after '='
x186 No 4k Page-aligned segments in MS386 OMF A 4K page-aligned segment isn't compatible with MS OMF format, it's a Phar Lab extension. This warning won't appear in the standard version.
x187
x188 Operand must be relocatable
x189 Constant or relocatable label expected
x190 [ELSE]IF2/.ERR2 not allowed, single-pass assembler
x191 Expression too complex for UNTILCXZ
x192 Operands must be in same segment
x193 Invalid use of external symbol: <symbol_name>
x194 For -coff leading underscore required for start label: <start_label>
x195 Invalid command-line value, default is used: %s
x196 Unknown fixup type: %u at <segment>.<offset>
x197 Unsupported fixup type for <format>: <type>
x198 Invalid fixup type for <format> <type> at location <segment>.<offset>
x199 Syntax error in control-flow directive
x200 Invalid .model parameter for flat model
x201 Output format doesn't support externals: <symbol> In formats BIN and MZ all references must be local to the module.
x202 Invalid start label for -bin
x203 No start label defined Warning, format MZ only: MZ-binaries usually have a start label. In some cases (i.e. overlays) a missing start label may be ok.
x204 No stack defined Warning, format MZ only: MZ-binaries usually have a stack. In some cases (i.e. overlays) a missing stack may be ok.
x205 Invalid alignment - value must be 2^n (n=4..15)
x206 Index value past end of string: <value> The index argument of SUBSTR or INSTR is beyond the string argument length
x207 Count value too large
x208 Count must be positive or zero
x209 Syntax error: <item> The parser found an item that has no meaning in the current context
x210
x211
x212 Must use floating-point initializer
x213 ORG directive not allowed in unions
x214 Struct alignment must be 1, 2, 4, 8, 16 or 32
x215 Structure cannot be instanced A structure that has size 0 or that contains an ORG directive cannot be instanced.
x216 Missing angle bracket or brace in literal
x217 Nondigit in number: <number>
x218 16bit fixup for 32bit label: %s
x219 Too many macro placeholders The number of parameters and locals for a macro must not exceed 256
x220 Missing macro argument: %s, parameter %u
x221 Doesn't work with 32-bit segments: <directive> Directives .STARTUP and .EXIT work for 16-bit only.
x222 Segment exceeds 64k limit: %s In MZ format, 16-bit segments are restricted to 64k.
x223 Not supported with OMF format: %s
x224 Not supported with current output format: %s The directive or feature isn't supported by all formats. For example, segment-related directives or attributes won't make much sense for flat formats like COFF or ELF.
x225 Unknown default prologue argument: %s
x226 LOADDS ignored in flat model
x227 Missing right parenthesis in expression
x228 Invalid operand for <operator>: <operand>
x229 Structure improperly initialized: %s
x230 Expected: %s
x231 Invalid data initializer
x232 Expected data label Some operators ( LENGTH, SIZE ) work with data labels only.
x233 Expression must be a code address
x234 -n Option needs a valid name parameter
x235 Constant value too large: <value> the value of the constant doesn't fit in 64 or - if it is a number to be assigned to a symbolic constant - 32 bits.
x236 Text macro was used before definition this is a warning only. However, using text macros before they have been defined will force JWasm to do a full second pass, which increases assembly time.
x237 Offset size incompatible with current segment
x238 Instruction form requires 80386
x239 Group/Segment offset size conflict: <group offset> - <segment offset> Segments within a group must all have the same offset size.
x240 Assembly passes reached: <passes> Although this is a warning only it usually indicates a severe problem. The assembler is very probably unable to calculate "final" values of all labels and has to be terminated by pressing Ctrl-C.
x241 Filename parameter must be enclosed in <> or quotes The INCBIN directive requires delimiters for its filename.
x242 Start address on END directive ignored with .STARTUP
x243 Invalid symbol type in expression: <symbol> The expression evaluator has encountered a symbol that is meaningless in expressions, for example a (text) macro.
x244 Missing right parenthesis
x245 Directive must be in control block .ELSE, .ELSEIF and .ENDIF are valid inside .IF-blocks, .BREAK, .CONTINUE may occur inside .WHILE- or .REPEAT-blocks, .ENDW needs a preceding .WHILE and .UNTIL needs a preceding .REPEAT.
x246 Expected: memory model the .MODEL directive needs at least one parameter, the memory model.
x247 Type is wrong size for register
x248 IF[n]DEF expects a plain symbol as argument this is a warning. Masm accepts any expression as argument for directives [ELSE]IF[N]DEF, but the result probably isn't always what has been expected.
x249 Jump destination must specify a label
x250 Ignored: <attribute> An attribute or parameter of a directive was found, but not handled. See Known Bugs and missing Features for details about what features aren't implemented yet.
x251 Missing argument for cmdline option
x252 Invalid coprocessor register
x253 Registers AH-DH may not be used with SPL-DIL or R8-R15 64-bit only.
x254 .ENDPROLOG found before EH directives 64-bit only.
x255 Missing FRAME in PROC, no unwind code will be generated 64-bit only.
x256 Bad alignment for offset in unwind code 64-bit only.
x257 Nonzero value expected
x258 Size of prolog too big, must be < 256 bytes 64-bit only.
x259 Missing .ENDPROLOG: %s 64-bit only.
x260 .SAFESEH argument must be a PROC
x261 Directive ignored without -%s switch
x262 ELF GNU extensions (8/16-bit relocations) used This is a warning only. The extensions are not "official", but the GNU linker LD will understand them.
x263 Syntax error in expression
x264 Macro label not defined: %s The target of a GOTO must be within the very same macro.
x265 Procedure argument or local not referenced: %s This warning is displayed only if at least -W3 is specified.
x266 Group definition too large, truncated: <group_name> The size of the OMF record that is to define a group would exceed 4 kB. However, to see this error you'll have to define a group that is to comprise more than 1000 segments,
x267 COMM variable exceeds 64K: <variable> in 16-bit, the size of a COMM variable is restricted to 64 kB.
x268 Must be public or external: %s Names that are to be known by the linker must be public or external.
x269 parameter/local name is reserved word: %s This is a warning. The names of macro parameters or locals have highest priority and hence the reserved word will become inaccessible within the macro.
x270 real or BCD number not allowed
x271 structure field expected
x272 Constant value too large: <value> the value of the constant doesn't fit in 64 or - if it is a number to be assigned to a symbolic constant - 32 bits.
x273 ELSE clause already occured in this IF block An IF block may contain 0 or 1 ELSE clauses and it must be the last clause before ENDIF.
x274 Illegal use of segment register
x275 Group exceeds 64K: <group> MZ format only: a group that contains 16-bit segments cannot be larger than 64 kB, because the group must fit into a physical segment.
x276 EXPORT must be FAR: <symbol> A 16-bit procedure that is to be exported must be declared with the FAR distance attribute.

Appendix D. Differences between Masm 6 and Masm 8

This is not strictly JWasm-related, but since a lot of documentation that can be found about Masm still refers to Masm v6 or Masm v6.1 only, it's useful to list the differences.

Appendix E. Restrictions of precompiled 16-bit Binary JWASMR.EXE

JWASMR lacks some features of the other precompiled binaries: Since the JWasm source is available, one may enable this or that feature if really needed, though.

Appendix F. Additional Features of JWasm's Debug Version

Note: there are no precompiled debug versions of JWasm available. Such versions have to be created from the source code. See the comments in the makefiles how to do that.

The debug version offers the following additional commandline options:
-af Display all files used in assembly process
-ce Cause an exception
-dm Display all messages
-dr Display reserved words
-drh Display reserved words hash table
-ds Display global symbols
-dsh Display global symbols hash table
-dt Display debug trace
-ls Display preprocessed line storage
-nbp Disable back-patching
-nfp Do full subsequent passes ( disables "fastpass" )
-pm=<n> Stop assembly after n passes
-sp Skip preprocessor step