Sommaire

BONJOUR
Musique "Invention BWV784" J.S. BACH 1685-1750

Assembeur X86 MASM32


MASM32 Home Page

* The MASM32 SDK *

Index Download Installation Forum License History Myths Why

The MASM32 SDK Version 11

Description
The MASM32 SDK version 11 is a working development environment for programmers who are interested in either learning or writing 32 bit Microsoft assembler (MASM). The installation is an automated process that installs the correct directory tree structure on the local drive of your choice.

Note that MASM32 will not install on a network drive. MASM32 comes with its own runtime library written fully in assembler and an extensive range of macros for improved high level emulation and faster development. It builds its own IMPORT libraries for the Windows API functions and supplies its own include files for a very large number of API functions.

The default editor in MASM32 has been fully recoded from scratch in MASM and it is smaller, faster and more powerful with two (2) separate scripting engines, a legacy version to maintain backwards compatibility of existing scripts and a completely new one that is much faster and more powerful than its predecessor.

New CHM documentation and a wider range of "Create New" project types directly supported by the new script engine from the editor place a wider range of project types at your fingertips. There is also a new format PLUGIN system for the default editor as well as the old one for backwards compatibility.

UNICODE Support
The MASM32 SDK has a completely new include file system that supports either ASCII or UNICODE by the inclusion of an equate, __UNICODE__ . Two new macro systems support UNICODE text that can be used in much the same manner as embedded ASCII text.

DEP Compatibility
The MASM32 SDK has been rebuilt to ensure it is fully compatible with the Data Execution Prevention safety feature in later versions of Windows.

OS Version
The MASM32 SDK requires Win2000 or higher Windows versions. The Installation is not designed to run on Win9x or ME.

Features
1. The most up to date version of Ray Filiatreault's floating point library and tutorial.
2. A completely new dedicated time and date library written by Greg Lyon.
3. The MASM32 library with over 200 procedures for writing general purpose high performance code.
4. A new dynamic array system for variable length string and binary data with both a macro and procedural interface.
5. The include files and libraries have been upgraded to include VISTA / Win7 with additional equates and structures.
6. A specialised linker, resource compiler and assembler from Pelle's tool set with working examples.
7. An extensive range of example code ranging from simple examples to more complex code design.
8. Prebuilt scripts in the editor for creating working templates for assembler projects.
9. A very easy to use console interface for developing algorithms, test code and experimental ideas in code.
More ......

Target Users
The MASM32 SDK is targeted at experienced programmers who are familiar with writing software in 32 bit versions of Windows using the API interface and who are familiar with at least some direct mnemonic programming in assembler. It is not well suited for beginner programmers due to the advanced technical nature of programming in assembler and beginners are advised to start with a compiler first to learn basic concepts like addressing, programming logic, control flow and similar.

Help Files
The help file system has been upgraded to CHM format so that MASM32 can be used on Windows versions that no longer support Winhelp help files.

Application
MASM is routinely capable of building complete executable files, dynamic link libraries and separate object modules and libraries to use with the Microsoft Visual C development environment as well as MASM. It is an esoteric tool that is not for the faint of heart and it is reasonably complex to master but in skilled hands it has performance that is beyond the best of modern compilers when properly written which makes it useful for performance critical tasks.

Things To Get
For both space and copyright reasons the MASM32 SDK does not include reference material from either the Intel Corporation or the Microsoft Corporation but both make the best comprehensive reference material available as free downloads. With the Intel Corporation you would obtain the PIV set of manuals or later for compete mnemonic and architecture reference and with the Microsoft Corporation you can either use their online MSDN reference or download an appropriate PLATFORMSDK or its successor for you own version of Windows. If you can still find it it is useful to have the very old WIN32.HLP file on yur computer even if you have to download the Winhelp engine to use it on OS versions like Vista as it is a lot faster to load than the later CHM format help files and works with the F1 help key system built into the default editor.

Warning
Not for the faint of heart. If MASM is beyond you, take up server side scripting.

Copyright (c) The MASM32 SDK 1998 - 2012 All Rights Reserved


Notes sur le langage C

MASM32 est un ensemble d'outils de développement et de bibliothèques pour l'écriture de programmes 32 bits en assembleur.

MASM32 vous est recommandé par le Monde de Gigi

Taille : 4.78 Mo

Langue : Anglais

OS : Windows 2000 et plus

Licence : Freeware

Site de l'éditeur : http://www.le-monde-de-gigi.com/go/?url=http://www.masm32.com

MASM32 est un ensemble d'outils de développement et de bibliothèques contenant Microsoft MASM et un éditeur de liens. L'assembleur est un langage ("dit de bas niveau") de tres haute technicité qui permet d'écrire des programmes très rapide et de petite taille. Cette dernière version vous permettra d'exploiter toute la puissance de ce langage malheureusement laissé un peu à l'abandon.

Certes, il n'est pas aisé d'écrire des programmes en assembleur et seuls les plus courageux réussiront à tirer le meilleur de ce langage. Cependant, il faut bien dire que cette version permet un réel gain de temps dans la saisie du code. Avec sa syntaxe similaire aux langages de haut niveau il est presque aussi rapide de taper du code en assembleur que dans un langage comme le C.
Bref, si vous êtes amateur de performance et de prise de tête alors ce langage est fait pour vous.


American Standard Code for Information Interchange

Un article de Wikipédia, l'encyclopédie libre.

La table des caractères ASCII sous une forme condensée qui met en évidence une organisation fondée sur la base 16.

PDF : fr en
 v · d · m
0
1
2
3
4
5
6
7
8
9
A
B
C
D
E
F
000
NUL
SOH
STX
ETX
EOT
ENQ
ACK
BEL
BS
HT
LF
VT
FF
CR
SO
SI
001
DLE
DC1
DC2
DC3
DC4
NAK
SYN
ETB
CAN
EM
SUB
ESC
FS
GS
RS
US
002
SP
!
"
#
$
%
&
'
(
)
*
+
,
-
.
/
003
0
1
2
3
4
5
6
7
8
9
:
;
<
=
>
?
004
@
A
B
C
D
E
F
G
H
I
J
K
L
M
N
O
005
P
Q
R
S
T
U
V
W
X
Y
Z
[
\
]
^
_
006
`
a
b
c
d
e
f
g
h
i
j
k
l
m
n
o
007
p
q
r
s
t
u
v
w
x
y
z
{
|
}
~
DEL

Les 95 caractères ASCII affichables :
 !"#$%&'()*+,-./
0123456789:;<=>?
@ABCDEFGHIJKLMNO
PQRSTUVWXYZ[\]^_
`abcdefghijklmno
pqrstuvwxyz{|}~
Cette section doit être recyclée. Une réorganisation et une clarification du contenu sont nécessaires. Discutez des points à améliorer en page de discussion.

L'American Standard Code for Information Interchange (Code américain normalisé pour l'échange d'information), plus connu sous l'acronyme ASCII ([askiː]) est une norme de codage de caractères en informatique ancienne et connue pour son influence incontournable sur les codages de caractères qui lui ont succédé. Elle était la plus largement compatible pour ce qui est des caractères latins non accentués.

ASCII contient les caractères nécessaires pour écrire en anglais. Les caractères accentués sont fournis par d'autres normes, comme aujourd'hui, l'Unicode. Le jeu de caractères codés ASCII est le principal système qui a permis l'échange de textes en anglais à un niveau mondial, limitant ainsi l'usage des langues locales au travers d'extensions régionales.

L'ASCII est une des variantes de l'ISO/CEI 646. Il est inclus dans plusieurs dizaines de normes et standards augmentant les caractères disponibles ou extensions (ASCII étendu) Celles-ci peuvent être régionales (ISO/CEI 8859), nationales (GB 18030) ou internationales (ISO 2022, ISO/CEI 10646 ou Unicode). Avec l'avènement de la mondialisation et de l'internationalisation des systèmes d'information, les limitations de l'ASCII ne sont plus acceptées que dans des domaines très techniques qui requirent la compatibilité avec des protocoles ou systèmes anciens. Malheureusement, l'ASCII n'a donné naissance qu'à des normes de codage incompatibles entre elles.

Dans la norme Unicode, le standard ASCII est défini sous le nom de « C0 Controls and Basic Latin ».

Histoire

Avant la standardisation, de nombreux codages de caractères incompatibles entre eux existaient[1].

En 1960, l'ISO a créé le technical committee on computers and information processing[2]. Il a été divisé en six groupes de travail.

  • Working Group A: Glossary
  • Working Group B: Character Sets and Coding
  • Working Group C: Character Recognition
  • Working Group D: Input and Output Media
  • Working Group E: Programming Languages
  • Working Group F: Digital Data Transmission

L'American Standards Association était chargé du standard des États-Unis.

L'ANSI a reconnu le consortium Business Equipment Manufacturers Association (BEMA, puis, CBEMA) comme le parrain du travail de standardisation du traitement des données. En 1960 BEMA a formé un groupe de traitement des données des partenaires, dont Minneapolis-Honeywell. Ce groupe a formé un Plans and Policies Committee, qui à son tour a formé l'Engineering Committee. L'Engineering Committee a formé le comité X3, qui a été reconnu par l'ASA comme sectional committee.

La liste des caractères à considérer et leur position ont été débattues[3].

Elle a été inventée par l'américain Bob Bemer en 1961.[réf. nécessaire]

En 1961, le DoD met au point un code standard de transmission de donnée sur 8 bits[4]. Ce standard 8 bits est une variante des standards FIELDATA sixbits utilisés dans la décennie précédente par la défense. Il a eu une influence notable sur la première version de l'ASCII.

En 1963, la première version publiée de l'ASCII apparaît.

Auparavant, d'autres standards étaient utilisés notamment sur les cartes perforées[5].

Sa dernière version stabilisée a été normalisée par l’ANSI en 1986 sous la désignation ANSI X3.4:1986 (après deux autres versions en 1967 et 1968, historiquement normalisées par l’ASI, devenu ANSI mais qui ne normalisait pas encore toutes les positions). C’est également la variante américaine des jeux de caractères codés selon la norme ISO/CEI 646 avec laquelle on la confond souvent (d’où sa désignation également comme US-ASCII pour lever l’ambigüité, désignation préférée dans le registre IANA des jeux de caractères codés).

À l'époque elle a été en concurrence avec des standards incompatibles. Par la suite, l'existence de nombreux codages reprenant les conventions de l'ASCII l'a rendu très populaire.

Principes

L'ASCII définit seulement 128 caractères numérotés de 0 à 127 et codés en binaire de 0000000 à 1111111. Sept bits suffisent donc pour représenter un caractère codé en ASCII. Toutefois, les ordinateurs travaillant presque tous sur un multiple de huit bits (multiple d'un octet) depuis les années 1970, chaque caractère d'un texte en ASCII est souvent stocké dans un octet dont le 8e bit est 0. Aujourd'hui encore, certains systèmes de messagerie électronique et de SMS fonctionnent avec des bytes ou multiplet composés de seulement sept bits (contrairement à un octet qui est un byte ou multiplet standardisé à huit bits).

Les caractères de numéro 0 à 31 et le 127 ne sont pas affichables ; ils correspondent à des commandes de contrôle de terminal informatique. Le caractère numéro 127 est la commande pour effacer. Le caractère numéro 32 est l'espace. Les autres caractères sont les chiffres arabes, les lettres latines majuscules et minuscules sans accent et quelques symboles de ponctuation.

L'absence des caractères des langues étrangères à l'anglais rend ce standard insuffisant à lui seul pour des textes étrangers (par exemple en langue française), ce qui rend nécessaire l'utilisation d'autres encodages.

Lorsqu'il est employé seul pour la langue anglaise, il interdit l'usage des accents dans la langue anglaise (cf wikt:en:Appendix:English words with diacritics).

Limitations

Quelques-uns des caractères graphiques ASCII ont provoqué une polysémie. Ceci est en tout ou partie lié au nombre limité de codets dans un jeu à sept bits. Ceci se retrouve notamment dans les symboles de ponctuation et l'utilisation des guillemets. L'ASCII a été conservé parce qu'il est omniprésent dans de nombreux logiciels. Cet héritage se retrouve dans Unicode ou ces signes sont dans un bloc disjoint des autres symboles similaires, se trouvant pour la plupart codés à partir de U+2000[6].

Internationalisation

Les limites du standard américain ASCII ont conduit, sur trois périodes différentes, à trois approches de l'internationalisation :

  • L'utilisation de standards régionaux à caractères-monooctets, techniquement les plus faciles à mettre en place ;
  • L'utilisation de standards extensibles, où un même octet peut représenter un caractère différent suivant le contexte (famille ISO 2022) ainsi que des extensions où un caractère est codé sur plusieurs octets ;
  • L'utilisation du Standard Unicode (famille UTF), qui est celui qui comprend le plus grand nombre de caractères.

Les standards régionaux ont l'inconvénient de ne permettre la représentation que d'un ensemble réduit de caractères, comme les caractères d'Europe occidentale. Avec cette approche, il est nécessaire d'indiquer l'encodage à l'extérieur du flot.

Les standards ISO 2022 ont l'inconvénient d'être contextuels. Il se peut que des logiciels utilisant certains algorithmes de recherche manquent d'interopérabilité à cet égard.

Les formes de codage définies par le standard Unicode ont l'inconvénient de la présence éventuelle de la fonctionnalité d'indicateur d'encodage en début de flot, qui le cas échéant est introduit par le caractère Byte Order Mark. Certains logiciels anciens ne sont pas compatibles avec la présence de ces trois octets, et ne pourront pas l'être en raison de la complexité conceptuelle que représente le fait de traiter ces trois octets. En particulier, certaines opérations deviennent plus complexes comme la concaténation de chaînes.

Standardisation

Le jeu de codage ASCII est défini quasiment identiquement par plusieurs standards différents, a de nombreuses variantes et a donné naissance à une foison (des dizaines ou des centaines) d'extensions plus ou moins incompatibles entre elles.

Les principales extensions sont justifiées par le fait que l'ASCII ne répond pas aux divers besoins régionaux. Elles sont proposées par des organismes de normalisation, ou par des fournisseurs de produits et de services.

Les standards ASCII

Note: ne pas confondre USASI X3.4-1968 ou ANSI X3.4-1968 et ANSI X3.4:1986

Normes définissant ou ayant défini ce système de codage des caractères:

  • Les standards ASCII des États-Unis (les standards hérités, et le standard en vigueur)
    • ASA X3.4-1963, (incomplet avec 28 positions libres, et un code de commande non assigné)
    • USASI X3.4-1967, (renommé rétroactivement ANSI X3.4-1967); ne normalisait pas encore toutes les positions.
    • USASI X3.4-1968, (renommé rétroactivement ANSI X3.4-1968); ne normalisait pas encore toutes les positions.
    • ANSI X3.4-1977,
    • ANSI X3.4:1986 (en 1986, et en vigueur aujourd'hui)

Les standards internationaux suivants sont généralement considérés compatibles (quasi-identiques) avec le standard ASCII en vigueur de 1986 à 2011, tout en constituant une normalisation internationale officielle:

  • Norme ISO/CEI 646
    • ISO/CEI 646-US Variante des États-Unis
    • Variante IRV internationale
  • Code page IBM 367.
  • Alphabet International de Référence
    • Alphabet International de Référence no 5 (de 1988)[7].
    • Alphabet International de référence no 5 (dans le jeu G0 de l'IRV)[8].

La désignation US-ASCII ou ASCII é-u, ASCII des États-Unis est un mix des désignations précédentes. Le registre IANA lui attribue la dénomination US-ASCII, sans en définir le codage.

Approximation, variantes et extensions

  • Norme ISO/CEI 646
    • Variante INV invariable (incomplète par rapport aux deux précédentes)

Trois types de codages de caractères se rapprochent de l'ASCII :

  • ceux qui ne changent que par la dénomination ; ils sont essentiellement identiques à l'ASCII
  • ceux qui sont des variantes, l'ASCII étant à l'origine la variante locale aux États-Unis de l'ISO 646
  • ceux qui l'augmentent, dits extensions

Alias

En juin 1992, le RFC[9] et la chambre d'enregistrement de jeux de caractères Internet Assigned Numbers Authority [10] ont reconnu les alias insensibles à la casse suivants convenables pour l'utilisation dans des protocoles internet :
  • ANSI_X3.4-1968 (canonical name)
  • iso-ir-6
  • ANSI_X3.4-1986
  • ISO_646.irv:1991
  • ASCII (with ASCII-7 and ASCII-8 variants)
  • ISO646-US
  • US-ASCII (preferred MIME name)[10]
  • us
  • IBM367
  • cp367
  • csASCII

L'IANA promeut plus particulièrement la dénomination « US-ASCII » pour Internet.

Variantes

Article détaillé : ISO/CEI 646.

ASCII a donné naissance à certaines variantes de l’ASCII qui conservent la plupart des caractères mais en remplacent certains. Dès lors, il ne s’agit plus d’ASCII à strictement parler.

Huitième bit et augmentations

Article détaillé : ASCII étendu.

De nombreuses normes de codage de caractères ont repris les codes ASCII et ajouté d’autres caractères pour les codes supérieurs à 127.

Extensions mono-octets

En particulier, beaucoup de pages de codes étendent l'ASCII en utilisant le 8e bit pour définir des caractères numérotés de 128 à 255. La norme ISO/CEI 8859 fournit des extensions pour diverses langues. Par exemple, l’ISO 8859-1, aussi appelée Latin-1, étend l’ASCII avec les caractères accentués utiles aux langues originaires d’Europe occidentale comme le français ou l’allemand.

Par abus de langage, on appelle souvent « ASCII » des normes qui étendent ASCII, mais qui ne sont pas compatibles entre elles (et parfois même ne sont pas compatibles sur leurs 128 premiers caractères codés). En particulier, les standards Windows-1252 (couramment utilisé sur Microsoft Windows dans les pays occidentaux), ISO 8859-1 (couramment utilisé sur Internet et UNIX) et les pages de code pour PC numéro 437 et 850 (couramment utilisées sur DOS) ne sont pas la norme ASCII. Cet abus de langage ne va pas sans causer des confusions causant des incompatibilités, souvent rendues visibles par le fait que les caractères non ASCII comme les « lettres accentuées » (éÈç) s'affichent mal. On écrit parfois ASCII de base pour bien identifier ASCII, et pas un standard plus étendu.

Extensions asiatiques, à base de séquences d'échappement

Afin d’unifier les différents codages de caractères complétant l'ASCII et y intégrer les codages complètement différents (le JIS pour le japonais par exemple, qui bien que développé aussi sur la base de l’US-ASCII, en diffère dans l’assignation d’un des 128 premiers codets), la norme ISO/CEI 10646 a été inventée (et aussi développée au départ séparément par le Consortium Unicode dans une version de sa norme Unicode 1.0 initialement incompatible avec ISO/CEI 10646.

Voir notamment ISO 2022.

Extensions Unicode

La version 1.0 a été abandonnée depuis la version 1.1 afin d’unifier et fusionner les deux répertoires dans un jeu universel de caractères codés). ISO/CEI 10646 codifie des dizaines de milliers de caractères, mais les 128 premiers restent compatibles avec ASCII (dans sa dernière version X3.4-1986) ; la norme Unicode y ajoute des sémantiques supplémentaires.

Toutefois, certains pays d’Asie orientale (la République populaire de Chine, les anciens dominions britannique et portugais en Chine, de Hong Kong et Macao, qui sont devenus depuis des régions administratives spéciales de Chine, la République de Chine à Taïwan, et le Japon) ont choisi de continuer à développer leur propre norme pour coder le jeu de caractères universel, tout en choisissant de les maintenir entièrement convertibles avec l’ISO/CEI 10646 ; parmi ces normes asiatiques, seule la norme nationale japonaise continue à maintenir une différence dans ses 128 premières positions avec le jeu ASCII, en codant le symbole monétaire du yen à la place de la barre oblique inversée (comme c’est aussi le cas dans la variante japonaise de la norme ISO/CEI 646).

Parmi les nombreuses extensions 8 bits de l'ASCII, le Multinational Character Set créé par Digital Equipment Corporation pour le terminal informatique VT220 est considéré comme à la fois l'ancêtre de l'ISO 8859-1 et de l'Unicode[11].

Influence

L'ASCII a eu une influence importante dans le monde informatique. En particulier il a pendant longtemps limité les caractères disponibles aux caractères latins non accentués, notamment dans le monde de l'internet, que ce soit pour les noms de domaine, les adresses de courrier électronique, les caractères disponibles dans le Bios, ou les caractères dans lesquels peuvent être écrits des programmes informatiques.

Description

Table des 128 caractères ASCII

Table de correspondance ASCII

Dans la table suivante, les 33 caractères de contrôle (codes 0 à 31 et 127) sont présentés avec leur nom en anglais suivi d'une traduction entre parenthèses.

Code en base |  |  |  | Caractère | Signification
10 | 8 | 16 | 2
0 | 0 | 00 | 0000000 | NUL | Null (nul)
1 | 01 | 01 | 0000001 | SOH | Start of Header (début d'en-tête)
2 | 02 | 02 | 0000010 | STX | Start of Text (début du texte)
3 | 03 | 03 | 0000011 | ETX | End of Text (fin du texte)
4 | 04 | 04 | 0000100 | EOT | End of Transmission (fin de transmission)
5 | 05 | 05 | 0000101 | ENQ | Enquiry (End of Line) (demande, fin de ligne)
6 | 06 | 06 | 0000110 | ACK | Acknowledge (accusé de réception)
7 | 07 | 07 | 0000111 | BEL | Bell (caractère d'appel)
8 | 010 | 08 | 0001000 | BS | Backspace (espacement arrière)
9 | 011 | 09 | 0001001 | HT | Horizontal Tab (tabulation horizontale)
10 | 012 | 0A | 0001010 | LF | Line Feed (saut de ligne)
11 | 013 | 0B | 0001011 | VT | Vertical Tab (tabulation verticale)
12 | 014 | 0C | 0001100 | FF | Form Feed (saut de page)
13 | 015 | 0D | 0001101 | CR | Carriage Return (retour chariot)
14 | 016 | 0E | 0001110 | SO | Shift Out (fin d'extension)
15 | 017 | 0F | 0001111 | SI | Shift In (démarrage d'extension)
16 | 020 | 10 | 0010000 | DLE | Data Link Escape
17 | 021 | 11 | 0010001 | DC1 | Device Control 1 à 4 (DC1 et DC3 sont généralementutilisés pour coder XON et XOFF dans un canal de communication duplex)
18 | 022 | 12 | 0010010 | DC2
19 | 023 | 13 | 0010011 | DC3
20 | 024 | 14 | 0010100 | DC4
21 | 025 | 15 | 0010101 | NAK | Negative Acknowledge (accusé de réception négatif)
22 | 026 | 16 | 0010110 | SYN | Synchronous Idle
23 | 027 | 17 | 0010111 | ETB | End of Transmission Block (fin du bloc de transmission)
24 | 030 | 18 | 0011000 | CAN | Cancel (annulation)
25 | 031 | 19 | 0011001 | EM | End of Medium (fin de support)
26 | 032 | 1A | 0011010 | SUB | Substitute (substitution)
27 | 033 | 1B | 0011011 | ESC | Escape (échappement)
28 | 034 | 1C | 0011100 | FS | File Separator (séparateur de fichier)
29 | 035 | 1D | 0011101 | GS | Group Separator (séparateur de groupe)
30 | 036 | 1E | 0011110 | RS | Record Separator (séparateur d'enregistrement)
31 | 037 | 1F | 0011111 | US | Unit Separator (séparateur d'unité)
32 | 040 | 20 | 0100000 | SP | Espace (Space en anglais)
33 | 041 | 21 | 0100001 | ! | Point d'exclamation
34 | 042 | 22 | 0100010 | " | Guillemet droit
35 | 043 | 23 | 0100011 | # | Croisillon ou dièse ou signe numéro[8]
36 | 044 | 24 | 0100100 | $ | Dollar
37 | 045 | 25 | 0100101 | % | Pourcent
38 | 046 | 26 | 0100110 | & | Esperluette ou perluète[8]
39 | 047 | 27 | 0100111 | ' | Apostrophe ou guillemet fermant simple ou accent aigu[12]
40 | 050 | 28 | 0101000 | ( | Parenthèse ouvrante
41 | 051 | 29 | 0101001 | ) | Parenthèse fermante
42 | 052 | 2A | 0101010 | * | Astérisque
43 | 053 | 2B | 0101011 | + | Plus
44 | 054 | 2C | 0101100 | , | Virgule
45 | 055 | 2D | 0101101 | - | Moins ou tiret[8] ou trait d'union
46 | 056 | 2E | 0101110 | . | Point
47 | 057 | 2F | 0101111 | / | Barre oblique (Slash en anglais)
48 | 060 | 30 | 0110000 | 0 | Le chiffre zéro
49 | 061 | 31 | 0110001 | 1 | Le chiffre un
50 | 062 | 32 | 0110010 | 2 | Le chiffre deux
51 | 063 | 33 | 0110011 | 3 | Le chiffre trois
52 | 064 | 34 | 0110100 | 4 | Le chiffre quatre
53 | 065 | 35 | 0110101 | 5 | Le chiffre cinq
54 | 066 | 36 | 0110110 | 6 | Le chiffre six
55 | 067 | 37 | 0110111 | 7 | Le chiffre sept
56 | 070 | 38 | 0111000 | 8 | Le chiffre huit
57 | 071 | 39 | 0111001 | 9 | Le chiffre neuf
58 | 072 | 3A | 0111010 | : | Deux-points
59 | 073 | 3B | 0111011 | ; | Point-virgule
60 | 074 | 3C | 0111100 | < | Inférieur
61 | 075 | 3D | 0111101 | = | Égal
62 | 076 | 3E | 0111110 | > | Supérieur
63 | 077 | 3F | 0111111 | ? | Point d'interrogation
64 | 0100 | 40 | 1000000 | @ | Arobace ou arobase ou A commercial[8]
65 | 0101 | 41 | 1000001 | A |
66 | 0102 | 42 | 1000010 | B |
67 | 0103 | 43 | 1000011 | C |
68 | 0104 | 44 | 1000100 | D |
69 | 0105 | 45 | 1000101 | E |
70 | 0106 | 46 | 1000110 | F |
71 | 0107 | 47 | 1000111 | G |
72 | 0110 | 48 | 1001000 | H |
73 | 0111 | 49 | 1001001 | I |
74 | 0112 | 4A | 1001010 | J |
75 | 0113 | 4B | 1001011 | K |
76 | 0114 | 4C | 1001100 | L |
77 | 0115 | 4D | 1001101 | M |
78 | 0116 | 4E | 1001110 | N |
79 | 0117 | 4F | 1001111 | O |
80 | 0120 | 50 | 1010000 | P |
81 | 0121 | 51 | 1010001 | Q |
82 | 0122 | 52 | 1010010 | R |
83 | 0123 | 53 | 1010011 | S |
84 | 0124 | 54 | 1010100 | T |
85 | 0125 | 55 | 1010101 | U |
86 | 0126 | 56 | 1010110 | V |
87 | 0127 | 57 | 1010111 | W |
88 | 0130 | 58 | 1011000 | X |
89 | 0131 | 59 | 1011001 | Y |
90 | 0132 | 5A | 1011010 | Z |
91 | 0133 | 5B | 1011011 | [ | Crochet ouvrant
92 | 0134 | 5C | 1011100 | \ | Barre oblique inversée (backslash ou antislash en anglais)
93 | 0135 | 5D | 1011101 | ] | Crochet fermant
94 | 0136 | 5E | 1011110 | ^ | Accent circonflexe (avec chasse)
95 | 0137 | 5F | 1011111 | _ | Tiret bas ou trait bas[8] ou souligné (underscore en anglais)
96 | 0140 | 60 | 1100000 | ` | Accent grave (avec chasse)[13]
97 | 0141 | 61 | 1100001 | a |
98 | 0142 | 62 | 1100010 | b |
99 | 0143 | 63 | 1100011 | c |
100 | 0144 | 64 | 1100100 | d |
101 | 0145 | 65 | 1100101 | e |
102 | 0146 | 66 | 1100110 | f |
103 | 0147 | 67 | 1100111 | g |
104 | 0150 | 68 | 1101000 | h |
105 | 0151 | 69 | 1101001 | i |
106 | 0152 | 6A | 1101010 | j |
107 | 0153 | 6B | 1101011 | k |
108 | 0154 | 6C | 1101100 | l |
109 | 0155 | 6D | 1101101 | m |
110 | 0156 | 6E | 1101110 | n |
111 | 0157 | 6F | 1101111 | o |
112 | 0160 | 70 | 1110000 | p |
113 | 0161 | 71 | 1110001 | q |
114 | 0162 | 72 | 1110010 | r |
115 | 0163 | 73 | 1110011 | s |
116 | 0164 | 74 | 1110100 | t |
117 | 0165 | 75 | 1110101 | u |
118 | 0166 | 76 | 1110110 | v |
119 | 0167 | 77 | 1110111 | w |
120 | 0170 | 78 | 1111000 | x |
121 | 0171 | 79 | 1111001 | y |
122 | 0172 | 7A | 1111010 | z |
123 | 0173 | 7B | 1111011 | { | Accolade ouvrante
124 | 0174 | 7C | 1111100 | | | Barre verticale
125 | 0175 | 7D | 1111101 | } | Accolade fermante
126 | 0176 | 7E | 1111110 | ~ | Tilde
127 | 0177 | 7F | 1111111 | DEL | Delete (effacement)

On peut aussi présenter la table des caractères ASCII sous cette forme plus condensée qui met en évidence une organisation fondée sur la base 16.

PDF : fr en
 v · d · m
0
1
2
3
4
5
6
7
8
9
A
B
C
D
E
F
000
NUL
SOH
STX
ETX
EOT
ENQ
ACK
BEL
BS
HT
LF
VT
FF
CR
SO
SI
001
DLE
DC1
DC2
DC3
DC4
NAK
SYN
ETB
CAN
EM
SUB
ESC
FS
GS
RS
US
002
SP
!
"
#
$
%
&
'
(
)
*
+
,
-
.
/
003
0
1
2
3
4
5
6
7
8
9
:
;
<
=
>
?
004
@
A
B
C
D
E
F
G
H
I
J
K
L
M
N
O
005
P
Q
R
S
T
U
V
W
X
Y
Z
[
\
]
^
_
006
`
a
b
c
d
e
f
g
h
i
j
k
l
m
n
o
007
p
q
r
s
t
u
v
w
x
y
z
{
|
}
~
DEL

Caractères de contrôle

NUL

Originellement une NOP, un caractère à ignorer. Lui donner le code 0 permettait de prévoir des réserves sur les bandes perforées en laissant des zones sans perforation pour insérer de nouveaux caractères a posteriori. Avec le développement du langage C il a pris une importance particulière quand il a été utilisé comme indicateur de fin de chaîne de caractères.

SOH

Start of heading : début d'en-tête. Il est aujourd'hui souvent utilisé dans les communications séries pour permettre la synchronisation après erreur[14].

DEL

Delete : effacement. Lui donner le code 127 (1111111 en binaire) permettait de supprimer a posteriori un caractère sur les bandes perforées qui codaient les informations sur 7 bits. N'importe quel caractère pouvait être transformé en DEL en complétant la perforation des 7 bits qui le composaient.

LF, CR, fin de ligne

Dans un fichier texte, la fin d'une ligne est représentée par un ou deux caractères de contrôle. Plusieurs conventions existent :

  • sur les systèmes Multics, Unix, Type Unix (Linux, AIX, Xenix, Mac OS X, etc.), BeOS, AmigaOS, RISC OS entre autres, la fin de ligne est indiquée par un saut de ligne (LF) ;
  • sur les machines Apple II et Mac OS jusqu'à la version 9, la fin de ligne est indiquée par un retour chariot (CR) ;
  • sur les systèmes DEC, RT-11 et généralement tous les premiers systèmes non-Unix et non-IBM, CP/M, MP/M, MS-DOS, OS/2 ou Microsoft Windows, la fin de ligne est indiquée par un retour chariot suivi d'un saut de ligne (CR suivi de LF).

Ainsi, lorsqu'on transfère un fichier ASCII entre des systèmes ayant des conventions de fin de ligne différentes, il faut convertir les fins de ligne pour pouvoir le manipuler confortablement sur le système cible. Autrement, il faut utiliser un éditeur de texte capable de gérer les diverses conventions de fin de ligne, ce qui n'est par exemple pas le cas du classique Bloc-notes de Microsoft Windows. Les programmes utilisant les fichiers ASCII ne sont en général pas perturbés par un changement de type de fin de ligne.

SUB

Il est souvent associé à la combinaison de touche Contrôle + z, et est utilisé dans les communications séries pour permettre l'envoi des données en lieu et place de la touche entrée.

Voir aussi

Notes et références

  1. ↑ http://www.trailing-edge.com/~bobbemer/SURVEY.HTM [archive]
  2. ↑ http://discover.lib.umn.edu/cgi/f/findaid/findaid-idx?c=umfa;cc=umfa;rgn=main;view=text;didno=cbi00067 [archive]
  3. ↑ http://www.cs.tut.fi/~jkorpela/latin1/ascii-hist.html [archive]
  4. ↑ Appendix §A.6.8 de la norme de A963
  5. ↑ Becker Pascal, Histoire des supports informatiques (lire en ligne [archive])
  6. ↑ (fr) Unicode 5.0 en pratique, chapitre 7 « Ponctuation » [archive], Patrick Andries.
  7. ↑ Alphabet International de référence no 5, Union international des télécommunications,‎ 1988 (lire en ligne [archive])
  8. ↑ a, b, c, d, e et f Alphabet International de référence : ANCIEN ALPHABET INTERNATIONAL no 5 ou AI5, Union international des télécommunications,‎ 1992 (lire en ligne [archive])
  9. ↑ (en) Rationel Almen Planlaegning, Request for Comments: 1345 : Character Mnemonics & Character Sets, Network Working Group,‎ juin 1992 (RFC 1345 [archive]).
  10. ↑ a et b Internet Assigned Numbers Authority (May 14, 2007). "Character Sets [archive]". Accessed 2008-04-14.
  11. ↑ Roman Czyborra, « ISO 8859-1 and MCS, from ISO 8859 Alphabet Soup » [archive]
  12. ↑ La norme ANSI X3.4 définit le caractère 39 par apostrophe (closing single quotation mark, acute accent) et les anciennes tables de caractères le représentaient souvent incliné. Les encodages plus récents restreignent ce code à la représentation de l'apostrophe verticale (ni penchée à droite, ni à gauche, mais neutre). Voir (en) Latin-1's apostrophe, grave accent, acute accent [archive].
  13. ↑ Le code 96 est également employé comme guillemet ouvrant simple en ASCII. En Unicode, il existe un code plus approprié.
  14. ↑ (en) ASCII character set [archive]


IBM Scan Codes

The following table is nothing to do with ASCII, but has been requested by a number of you out there. When a key on your keyboard is pressed, a code is sent which can be recognised by software. Programmers will find the most use for this table to map keys to actions for the function keys etc.

EBCDIC

ASCII is not the only format in use out there. IBM adopted EBCDIC (Extended Binary Coded Decimal Interchange Code) developed for punched cards in the early 1960s and still uses it on mainframes today. It is probably the next most well known character set due to the proliferation of IBM mainframes. It comes in at least six slightly differing forms, so again here is the most common.


MASM WIKI

Microsoft Macro Assembler

Le logiciel Microsoft Macro Assembler (Macro Assembleur de Microsoft, plus connu sous l'acronyme MASM) est un assembleur pour la famille de processeurs x86. Il fut à l'origine développé par Microsoft pour le développement de leur système d'exploitation MS-DOS.

MASM supporte une grande variété de macros aidant à la programmation en langage assembleur ainsi que des idiomes de programmation structurée, incluant des constructions de haut niveau pour les boucles, les appels de procédures, les branchements, etc. ce qui fait de MASM un assembleur à programmation de haut niveau. Les dernières versions de MASM ont la possibilité de produire des programmes pour le système d'exploitation Windows. MASM fut un des rares outils de développement de Microsoft pour lequel il n'y eut pas de versions 16 et 32 bits séparées.

  • 1 Compétition entre assembleurs
  • 2 Versions de MASM
  • 3 Projets reconnaissant MASM
  • 4 Articles connexes
  • 5 Liens externes

Compétition entre assembleurs

Dans les premières années de la décennie 1990 d'autres assembleurs alternatifs prirent une certaine part de marché à MASM, parmi lesquels TASM de Borland, le partagiciel A86 et NASM vers la fin de la décennie. Toutefois, deux évènements à la fin des années 1990 permirent à MASM de garder un solide support de la communauté des programmeurs en assembleur : en premier lieu, MASM, qui était jusqu'alors un logiciel commercial, fut distribué gratuitement comme partie du Driver Development Kit ou DDK. Dans un deuxième temps, le pack MASM32 maintenu par Steve Hutchesson ainsi que les tutoriaux d'Iczelion apparurent permettant de programmer directement et relativement aisément des applications 32 bits fonctionnant sous Windows. Ces deux événements combinés assurèrent à MASM sa continuité dans le temps.

MASM reste encore aujourd'hui un assembleur phare de la communauté des programmeurs en assembleur pour la plateforme Win32, mais d'autres assembleurs comme GAS, NASM, TASM, FASM, GoAsm, RosAsm ou HLA rassemblent chacun une communauté importante.

Versions de MASM

Bien que MASM ne soit plus un produit commercial, Microsoft continue à assurer son support du fait d'une utilisation assez importante du langage assembleur en développement interne chez Microsoft. Depuis que Microsoft a arrêté la vente de MASM, de nombreuses mises à jour ont été produites pour la lignée de MASM 6.x (la dernière mise à jour de cette lignée est la version 6.15 qui était incluse dans le Visual C++ 6.0 Processor Pack). MASM 7.0 fut inclus avec Visual C++ .NET 2002, MASM 7.1 avec Visual C++ .NET 2003 et MASM 8.0 avec Visual C++ .NET 2005 (cette dernière version est la première à pouvoir assembler du code 64 bits). Pour les versions de MASM incluses avec Visual C++, l'exécutable de MASM s'appelle ml.exe et se situe dans le répertoire bin. La version 64 bits de MASM incluse avec Visual C++ 2005 se nomme ml64.exe et se situe dans le même répertoire. La documentation de MASM pour ces versions est incluse avec la documentation de Visual C++.

Projets reconnaissant MASM

De nombreux projets reconnaissant MASM ont vu le jour. Ainsi, des environnements de développement intégrés permettent un développement plus aisé avec MASM (qui s'utilise habituellement en ligne de commande) parmi lesquels Qedit, Radasm ou WinAsm Studio. On notera aussi des débogueurs comme OllyDbg qui reconnaît la syntaxe MASM, ou des désassembleurs comme IDA.

De nombreux forums ou sites internet proposent des codes sources, de la documentation ou de l'aide concernant cet assembleur, qui reste un assembleur de référence.

La prise en charge officielle de MASM par Microsoft se résume aujourd'hui à ajouter des instructions lorsque de nouveaux processeurs voient le jour et à améliorer la prise en charge du 64 bits.

Articles connexes[modifier | modifier le code]

  • Assembleur
  • Programme assembleur
  • GNU Assembler
  • FASM
  • Turbo Assembler
  • NASM
  • RosASM

Liens externes[modifier | modifier le code]

  • (en) Téléchargement de MASM pour Visual C++ 2005 Express Edition - Sur le site de Microsoft
  • (fr) Tutoriel MASM : Pas à Pas vers l'Assembleur


MASM - OSDev Wiki

MASM

From OSDev Wiki
Jump to: navigation, search

The Microsoft Macro Assembler is an X86 architecture assembler for MS-DOS and Microsoft Windows. While the name MASM has earlier usage as the Unisys OS 1100 Meta-Assembler, it is commonly understood in more recent years to refer to the Microsoft Macro Assembler. It is an archetypal MACRO assembler for the x86 PC market that is owned and maintained by a major operating system vendor and since the introduction of MASM version 6.0 in 1991 has had a powerful preprocessor that supports pseudo high level emulation of variety of high level constructions including loop code, conditional testing and has a semi-automated system of procedure creation and management available if required. Version 6.11d was 32 bit object module capable using a specialised linker available in the WinNT 3.5 SDK but with the introduction of binary patches that upgraded version 6.11d, all later versions were 32 bit Portable Executable console mode application that produced both OMF and COFF object modules for 32 bit code.

NOTE: Using MASM for operating system development is not prohibited in the license agreement although you may sometimes hear that. This is because people often confuse the MASM and MASM32 licenses; they are 2 unrelated projects.

While recent versions of MASM only come with Visual Studio, its syntax is in widespread use in existing code and is also used as a guideline in the development of other assemblers, such as JWASM and Pelle's PoAsm assembler.

Contents

[hide]
  • 1 History
  • 2 Usage
    • 2.1 Addressing Notation
    • 2.2 Square Brackets
    • 2.3 Notation Abreviation
    • 2.4 Limited Type Checking
    • 2.5 Calling Conventions
    • 2.6 Pseudo High Level Emulation
    • 2.7 Pre-Processor
  • 3 Object Module Compatibility
    • 3.1 COFF Object Modules Reference
  • 4 Compatible Linkers
  • 5 Microsoft Reference For ML.EXE
    • 5.1 Publication
    • 5.2 Online
  • 6 Microsoft Licence
  • 7 MASM Compatible Assemblers

History

The Microsoft Assembler has been in production since 1981 and is upgraded by Microsoft on a needs basis to reflect technology changes in both operating systems and processor hardware capacity. The copyright string from the 1991 version of ML.EXE is as follows.

   Microsoft (R) Macro Assembler Version 6.00
   Copyright (C) Microsoft Corp 1981-1991. All rights reserved.

The last freestanding commercial version of the Mirosoft assembler was version 6.11d released in 1993 and retailed through the middle to late 1990s. With the release of 32 bit versions of Windows with both the OEM win95 and WinNT version 4.0, Microsoft developed ML.EXE mainly for internal use as an operating system vendor and it was mainly available only through MSDN subscription for the development of device drivers but Microsoft developed patches for the last commercial version of ML.EXE that upgraded it from a 16 bit MZ executable to a proper 32 bit portable executable file that ran natively on the 32 bit Windows platforms. With the release of the 6.14 patch, ML.EXE became a very reliable tool that supported Intel opcodes up to the early SSE instruction set.

In middle 2000 Microsoft re-integrated ML.EXE back into their VC98 commercial software development package with the processor pack as the downloadable file VCPP5.EXE which was licenced so that licenced end users of VC98 could redistribute the processor pack to other licenced end users of VC98 (VCPP5.EXE EULA) and all versions of Microsoft Visual C and Visual Studios have contained ML.EXE as a component since that time. The ML.EXE version supplied in the VCPP5 pack was ML.EXE version 6.15 which added support for the SSE2 Intel instruction set. Successive versions of ML.EXE have been developed on a needs basis to include later Intel opcodes. Later in Visual C++ 2005, a seperate 64-bit version of MASM appeared under the file name ml64.exe.

Although MASM is no longer a freestanding commercial product, it has since 2000 been a component of the Microsoft commercial development environment Visual Studio but Microsoft have also made it availabe in many different packages for device development and more recently in the free downloadable versions of Visual Studio.

Version 7.0 was included with Visual C++ .NET 2002. Version 7.1 was included with Visual C++ .NET 2003. Version 8.0 was included with Visual C++ 2005 which also includes a version that can assemble x64 code. Version 9.0 is included with Visual C++ 2008. Some of the newer versions of MASM are also included in various Microsoft SDKs and DDKs.

ML.EXE is typically an internal usage industrial tool maintained by a major operating system vendor to serve their own purpose without the need to make it a particularly "user friendly" application as the vast majority of its users are experienced programmers who have used it for many years. Microsoft have tended to use assembler code in the very low levels of their operating systems where even the best C compilers do not deliver sufficiently optimised code for the intended purpose. This is evident for programmers with enough technical experience who have some need to disassemble occasional OS components for research and compatibility purposes like NTOSKRNL.EXE and HAL.DLL and the tell tale indication of code written by hand in ML.EXE is the use of the trailing LEAVE mnemonic at the end of a procedure with a stack frame.

The two current ML versions as of January 2010 are as follows,

2009 ML version copyright string

   Microsoft (R) Macro Assembler Version 9.00.30729.01
   Copyright (C) Microsoft Corporation.  All rights reserved.

2009 ML64 version copyright string

   Microsoft (R) Macro Assembler (x64) Version 9.00.30729.207
   Copyright (C) Microsoft Corporation.  All rights reserved.

Usage

The Microsoft assembler has been the main vehicle for preserving the earlier Intel assembler notation and it can still be written as a fully specified language, a format that many dis-assemblers produce. The most common notation of this type are the data size specifiers,

   BYTE PTR  The data size specifier for the target being 8 bit.
   WORD PTR  The data size specifier for the target being 16 bit.
   DWORD PTR The data size specifier for the target being 32 bit.

Addressing Notation

ML.EXE maintains the historical distinction between transient stack addressing and fixed data addressing by using the notation OFFSET to denote data in either the initialised or uninitialised data sections. Transient stack addressing is handled by a number of methods. With a procedure that uses a stack frame, named LOCAL variables are used for readability purposes and where the address of the variable is required it can be accessed eith by the LEA mnemonic or in an INVOKE call by the ADDR operator. The LOCAL variables are [EBP] stack addresses when used within a procedure. Procedures written without a stack frame are generally written purely in mnemonics using direct [ESP] based argument addressing. To maintain compatibility with the historical MASM method of pseudo high level notation, there is a notation to turn off the stack frame generation for the procedure on a needs basis.

Square Brackets

ML.EXE does not require the addition of square brackets around a named variable but will tolerate such notation deviation by ignoring the notation. This notation difference has at time been a source of confusion for programmers familiar with other assemblers that use the square brackets to denote an address.

   mov eax, local_var     ; Standard ML.EXE notation
   mov eax, [local_var]   ; Square brackets are ignored by ML.EXE in this context.

There is no Intel mnemonic that will produce the extra level of indirection implied by placing un-necessary square brackets around a named variable and the practice leads to confusion of programmers who are experienced in using other x86 assemblers that use the square bracket notation differently. ML.EXE uses square brackets around direct mnemonic code to perform the dereferencing operation as in the following example.

   lea eax, variable_name   ; load the address of a stack variable into the EAX register
   mov eax, [eax]           ; dereference the CONTENT of the variable and copy it into the EAX register

ML.EXE will allow the following.

   mov eax, [eax+ebx]
   mov eax, [eax][ebx]

In this context the second pair of square brackets perform the ADDITION function within the complex addressing notation. It is a useful technique to use when writing procedures that do not have a stack frame as the second pair of brackets can be used to contain the stack displacement that changes with PUSH and POP mnemonics.

Notation Abreviation

Over a long period a form of shorthand notation developed as the parsers in early versions improved and generally if the assembler can determine the size of the data the data size specifier is not necessary although it still can be used. This shorthand has confused some users who have used other assemblers which are not by default data size specified tools. It can lead to problems when the user is not familiar with the default data size specifiers while using the shorthand notation.

   movzx eax, [esi]            ; generates an error - data SIZE cannot be determined by the assembler
   movzx eax, BYTE PTR [esi]   ; zero extend a BYTE into the 32 bit EAX register

Limited Type Checking

From at least version 6.0, ML.EXE has supported a pseudo high level notation for creating procedures that perform argument size and count checking. It is part of a system using the PROC ENDP PROTO and INVOKE operators. The PROTO operator is used to define a function prototype that has a matching PROC that is terminated with the ENDP operator. The prototyped procedure can then be called with the INVOKE operator which is protected by the limited size and argument count checking. There is additional notation at a more advanced level for turning off the automatically generated stack frame for the procedure where stack overhead in the procedure call may have an effect with very small procedures. ML.EXE is also capable of being written completely free of the pseudo high level notation using only bare Intel mnemonics.

Using an example prototype from the 32 bit Windows API function set,

   SendMessage PROTO STDCALL :DWORD,:DWORD,:DWORD,:DWORD
   SendMessage equ <SendMessageA>

The code to call this function using the INVOKE notation is as follows.

   invoke SendMessage,hWin,WM_COMMAND,wParam,lParam

Which is translated exactly to,

   push lParam
   push wParam
   push WM_COMMAND
   push hWin
   call SendMessage

The advantage of the INVOKE method is that it tests the size of the data types and the argument count and generates an assembly time error if the arguments do not match the prototype.

Note that ML64.EXE does not currently support the INVOKE notation and may not in the future. Based off Microsoft's history of updating earlier versions of ML.EXE on a needs basis for their own internal usage, this feature set may not be developed unless they have a need to add it for their own usage.

Calling Conventions

ML.EXE supports a number of different calling conventions on both the 16 bit real mode DOS operating system, the 16 bit Windows versions and the later 32 bit versions. ML.EXE supports the C, SYSCALL, STDCALL, BASIC, FORTRAN and PASCAL calling conventions.

Pseudo High Level Emulation

ML.EXE provides a notation to emulate a variety of high level control and loop structures.
It supports the .IF block structure,

 .if
   -
 .elseif
   -
 .else
   -
 .endif

It also supports the .WHILE loop structure,

 .while eax > 0
   sub eax, 1
 .endw

And the .REPEAT loop structure.

 .repeat
   sub eax, 1
 .until eax < 1

The high level emulation also supports C runtime comparison operators that work according to the same rules as Intel mnemonic comparisons. For the .IF block notation the distinction between SIGNED and UNSIGNED data is handles with a minor data type notation variation where the storage size DWORD which is by default UNSIGNED can also be specified as SDWORD for SIGNED comparison. This data type distinction is only appropriate for the pseudo high level notation as it is unused at the mnemonic level of code where the distinction is determined by the range of conditional evaluation techniques available in the Intel mnemonics.

The combined pseudo high level emulation allows MASM to more easily interface with the later current operating systems that use a C style application programming interface. Generally the pseudo high level interface is used for non-speed critical code where clarity and readability are the most important factors, speed critical code is usually written directly in mnemonics.

Note that ML64.EXE does not support all of the earlier pseudo high level notation and may not in the future. Based off Microsoft's history of updating earlier versions of ML.EXE on a needs basis for their own internal usage, this feature set may not be developed unless they have a need to add it for their own usage.

Pre-Processor

The Microsoft assembler has a very powerful pre-processor that has considerable more functionality than modern C compilers which is consistent with its designation as a macro assembler and it has been designed from the introduction of ML.EXE version 6.0 with C style pseudo high level functionality for programmers who prefer to use this style of notation for not speed critical code. On the down side the pre-processor is an old design that is known to be quirky in its operation and reasonably difficult to use without a lot of experience when writing macros that are of a more complex nature.

At their simplest macros written for the ML.EXE pre-processor are useful for automating many different simple tasks.

   ; ----------------------------
   ; memory to memory assignment
   ; ----------------------------
     m2m MACRO M1, M2
       push M2
       pop  M1
     ENDM

   ; --------------------------------------------------
   ; memory to memory assignment using the EAX register
   ; --------------------------------------------------
     mrm MACRO m1, m2
       mov eax, m2
       mov m1, eax
     ENDM

Using the EXITM <return item> notation a macro can return a value or register in a way that can used similar to a high level function call. Using a very simple example,

   addregs32 MACRO reg1, reg2
     add reg1, reg2
     EXITM <reg1>
   ENDM

In the .CODE section.

   mov ecx, 16
   mov edx, 8

   mov eax, addregs32(ecx, edx)

Which disassembles exactly to the following mnemonics.

   0040102B B910000000             mov     ecx,10h
   00401030 BA08000000             mov     edx,8
   00401035 03CA                   add     ecx,edx
   00401037 8BC1                   mov     eax,ecx

At a slightly more complex level the pre-processor can be used to emulate higher level languages which allows non-critical code to be simplified for higher programming throughput.

   fn MessageBox,0,str$(eax),"Title",MB_OK

In this working example fn is a macro that encapsulates the INVOKE notation and adds functionality so that quoted text can be inserted directly into the API function call in much the same way as a high level language. The str$() macro is an emulation of traditional basic for converting numeric data as either a memory operand or a register into string data for display. The example is taken from the MASM32 Project main macro file.

Object Module Compatibility

The 32 bit versions of ML.EXE introduced with the patches for the last commercial version onwards produce object modules in both the older OMF format and the Microsoft version of the Portable Executable specification COFF format. The object module format is compatible with modern Microsoft C compilers and object modules produced by either ML.EXE or CL.EXE can be routinely intermixed and linked into applications written either with ML.EXE or CL.EXE.

COFF Object Modules Reference

  • http://download.microsoft.com/download/e/b/a/eba1050f-a31d-436b-9281-92cdfeae4b45/pecoff.doc
  • http://www.microsoft.com/whdc/system/platform/firmware/PECOFF.mspx

Compatible Linkers

For building 16 bit MS-DOS applications a Microsoft OMF linker is required as the 32 bit linkers build 32 bit PE code. The original linkers provided with commercial versions of MASM work correctly and for later versions, Microsoft have had various links over time for their last OMF 16 bit linker that have been available on their website.

Microsoft Reference For ML.EXE

Publication

  • Mirosoft Macro Assembler Programmerss Guide (c) 1991 The Microsoft Corporation. (Supplied with MASM version 6.0)
  • Programmer's Guide (c) 1992 The Microsoft Corporation. (Supplied with MASM version 6.1)

Online

  • http://msdn.microsoft.com/en-us/library/afzk3475(VS.71).aspx

Microsoft Licence

MASM has been available over a very long period and has been subject to a number of licencing methods over that time. The different licences break down into two different types, the commercial versions of MASM as either a seperate product or a later component of the Visual C development environment may be used for any purpose including developing non-Microsoft operating system components but almost exclusively the version made available from Microsoft at no cost are restricted to use on Microsoft operating systems and specifically exclude the production of Open Source code. With the wide range of different licences over the products lifetime the individual licence should be read in detail to determine what it can be used for and what if any restrictions apply in its usage.

MASM Compatible Assemblers

For assembler programmers who are unable to use the Microsoft assembler for licencing reasons there are two directly MASM compatible assemblers that can build almost all MASM code apart from the more complex macros developed under MASM.

  • Pelle's Macro Assembler is a component of the Pelles C development environment and comes complete with detailed documentation supplied with Pelles C. For the assembler language programmer, Pelles C comes with a compatible linker and resource compiler as well as a mature C compiler and an IDE that also contains its own resource editor. It is both mnemonic and operator compatible with MASM but diverges in its macro capacity. It is both 32 bit and 64 bit capable.
  • http://www.smorgasbordet.com/pellesc/download.htm
  • JWASM Macro Assembler is a MASM clone that has a very high level of compatibility with the original Microsoft Macro Assembler. It is currently supplied as both source code and a working binary and it comes close to assembling almost all MASM code including the vast majority of MASM macros. It will build MASM code for 16, 32 and 64 bit platforms. It is burdened by having no supporting documentation and relies wholly on the availability of documentation from Microsoft for MASM. It is available under the Sybase Open Watcom EULA.
  • http://www.japheth.de/JWasm.html
Retrieved from "http://wiki.osdev.org/index.php?title=MASM&oldid=10011"
Category:
  • Assemblers
Personal tools
  • Log in
Namespaces
  • Page
  • Discussion
Variants
Views
  • Read
  • View source
  • View history
Actions
Navigation
  • Main Page
  • Forums
  • FAQ
  • OS Projects
  • Random page
About
  • This site
  • Joining
  • Editing help
  • Recent changes
Toolbox
  • What links here
  • Related changes
  • Special pages
  • Printable version
  • Permanent link
  • This page was last modified on 5 April 2010, at 13:34.
  • This page has been accessed 22,254 times.
  • Privacy policy
  • About OSDev Wiki
  • Disclaimers
  • Powered by MediaWiki


Débuter l'assembleur avec MASM32

Eh oui, ça y est, je me décide *enfin* à écrire un tutoriel sur le langage assembleur avec MASM32. Je me suis souvent dis que ça ne tiendrait pas la route, en raison de mes vagues connaissances à ce sujet. Mais c'est le fait d'écrire ce tutoriel (je ne sais pas s'il sera grand, ça, on verra plus tard) qui consolidera peut-être ce savoir. Et, bien évidemment, j'espère que ce "savoir" se diffusera aussi aux lecteurs, c'est-à-dire vous !

Pour ceux qui ne connaissent pas le codage de l'information et d'autres pré-requis, absolument pas de panique. Ayant envie d'entrer dans le vif du sujet dès le début, je mettrai les pré-requis en annexes. Car normalement, pour commencer l'assembleur, il faut être patient. Les tutoriels vous demandent de maîtriser le codage de l'information en bases 2, 10 et 16 ; c'est pas bien dur, hein, on s'y fait. Ils vous listent également l'histoire de l'architecture des processeurs INTEL, qui sont le cerveau de l'ordinateur. Ce qu'il faut savoir - je pense - c'est que le langage assembleur est en fait un intermédiaire entre le langage machine compris par le processeur, et l'humain. Le langage assembleur est donc, après le langage machine, le langage le plus bas niveau dans la programmation. Un schéma, pour résumer :

Schéma hiérarchique des langages

Je vous préviens, j'ai écrit n'importe quoi dans "assembleur" et "binaire" ; c'est juste pour vous schématiser la tronche des langages, quoi.

En résumé, ce tutoriel va vous apprendre à "parler" le langage du processeur. Ca serait bête de vous apprendre à écrire une suite d'octets en hexadécimal (même si ça se fait, pour concevoir des shellcodes ou taper dans les fichiers binaires via un éditeur hexadécimal) alors qu'on a le langage assembleur pour faire ça.

Rhaaa, je vous mets en appétit, mais je dois tout de même vous mettre en garde sur certains pré-requis à avoir.
  • Faire de l'assembleur, je ne vous le cache pas, c'est très compliqué. En plus, on va en faire sous Windows, et je vous demande d'avoir des bases en C. C'est impératif, et vous comprendrez plus tard pourquoi.
  • Tourner sur un windows 32 bits. Si vous êtes sur une architecture 64 bits, j'ai le regret de vous annoncer que vous ne pourrez vous servir de ce tutoriel qu'à des fins théoriques.
  • J'allais oublier the most important : avoir windows.

Enfin, je tiens à préciser que ce tutoriel s'adresse aux curieux comme moi, et à ceux qui veulent un peu comprendre comment ça fonctionne. Je ne ferai jamais de vous des programmeurs en assembleur. Ce langage est dépassé et ne vous servira pas à écrire une application complète (quel intérêt, quand on a des langages évolués ?). C'est juste pour l'amusement.

Petits trucs "de base" à savoir

Dans notre ordinateur, on a plusieurs types de mémoire :
  • RAM (Random Access Memory) : la mémoire vive, donc tous les logiciels se servent pour stocker des informations dedans. Cette mémoire est grande, rapide, et se vide lorsqu'il n'y a plus de courant qui l'alimente. Néanmoins, on peut en trouver certaines qui sont constamment alimentées avec une pile de lithium ;
  • ROM (Read-Only Mémory) : la mémoire morte, ou "en lecture seule" comme on le traduit de l'anglais. Cette mémoire sert à stocker des informations permanentes, notamment sur le système d'exploitation de votre ordinateur, de votre BIOS, bref, des informations qui restent écrites et effaçable par réécriture. Pour réécrire la mémoire, il y a différents moyens - à titre informatif - comme exposer la mémoire aux rayons UV, par exemple (ouais, j'ai étudié ça en électronique, c'était marrant). Vous comprenez, par ailleurs, pourquoi on parle de CD-ROM. Parce qu'une fois gravés, on ne peut pas modifier les données, à condition que le CD soit "RW", mais là, il faut réécrire par dessus. ;
  • Disque dur : Grosse capacité de mémoire. Permet de stocker des fichiers à long terme. La mémoire des disques durs actuels va jusqu'à se mesurer en Terra-Octets, soit 1000 Go. Cette mémoire est lente, si on compare la rapidité d'accès de la RAM ;
  • Les registres : Certes, pour les non-connaisseurs, je vous prends en traitre. Voyons plus bas ce que sont les registres !

Les registres

Les registres sont de petites mémoires dont la taille dépend de notre architecture logicielle. Je m'explique : vous avez un système d'exploitation 32 bits, cela signifie donc que la taille de vos registres fait... 32 bits ! C'est très petit, me direz-vous, et "quel intérêt ?", vous me demandez donc. Patience, j'y viens.

Les registres sont de mémoires minuscules et très rapides. Elles sont, pour certaines, internes au processeur, et ce dernier s'en sert constamment pour faire les opérations de bases, que ça soit logiques - AND, OR, XOR... - et arithmétiques - addition, soustraction, multiplication, division, ... et donc pour traiter l'info. Il faut le rappeler : un ordinateur, c'est con ; on va pas lui demander en langage machine "Affiche-moi coucou à l'écran" en une seule instruction. Il y a plusieurs milliers d'instructions assembleur derrière. Enfin, je vous rassure, on n'ira pas écrire ces milliers d'instructions pour faire un bête "Hello world". C'est juste que c'est pas comme le C, où vous n'avez qu'à faire ça :
Code : c
#include <stdio.h>
int main() {
        printf("Hello, world!\n");
        return 0;
}

Mais enfin, je m'écarte du sujet, là. Voyons les quatre registres de base (eh oui, ils ont un nom !) :
  • Registre accumulateur : on s'en sert conventionnellement pour stocker des valeurs de retour de fonctions. On le note "eax" lorsqu'il s'agit de manipuler toute sa taille
  • Registre de base : conventionnellement... je sais pas à quoi ça peut servir. Un registre de base, quoi. Ca va pas vous empêcher de l'utiliser. On le note "ebx"
  • Registre de compteur : conventionnellement, ça sert pour faire des boucles. Noté "ecx"
  • Registre de données : "edx". On s'en sert - probablement - pour manipuler des... données !

Chaque registre a une taille de 32 bits, mais il est possible de les manipuler par plus petite taille. Prenons par exemple eax. On peut manipuler sa partie basse sur 16 bits, à savoir "ax". Cette même partie, ax, contient deux sous-parties. La partie haute est notée ah, la partie basse est notée al.

Un schéma pour résumer le tout :

Schéma de la structure des registres de base

Rassurez-vous, ça n'est pas bien grave si vous ne retenez pas tout ce remue-ménage. Tout ce qu'il faut savoir, c'est que les registres peuvent êtres manipulés par tranche de 32, 16 et 8 bits.

Notez qu'il existe d'autres registres que nous verrons dans la suite du tutoriel ; ça serait dommage de vous barber dès le début avec ça. Voyons maintenant la notion d'adresses :

Les adresses

Il faut impérativement comprendre cette notion pour continuer. En assembleur, quand on programme, on adressera nos données et nos sections de code par des labels, ou étiquettes. Sauf qu'une fois le code compilé, le tout est accessible par des adresses mémoires. Ces adresses sont codées sur....... 32 bits ! (ce qui explique pourquoi on parle d'OS 32 bits).

On représente souvent ses adresses en hexadécimal. Exemple : 0x7f3d215a, le 0x devant pour préciser que ce qui suit est de l'hexadécimal. La RAM contient des adresses mémoires, qui contiennent elle-même des données. Si vous avez fait du C et que vous êtes familiarisé avec la notion de "pointeur", vous devriez savoir de quoi je parle.

Et bien, sachez qu'en plus des valeurs de variables, les intructions assembleur sont aussi adressées. Une fois notre programme chargé en mémoire, les octets qui disent au processeur de mettre à zéro un registre - par exemple, hein - se trouvent à une adresse mémoire. Mais enfin, nous utiliserons OllyDbg - outil de debuging puissant - pour mieux comprendre comment ça fonctionne.

Ce qu'il nous faudra étudier, maintenant, c'est le concept de pile !

La pile

Les gens l'appellent souvent "stack". La pile est une zone de mémoire située dans la mémoire accessible en écriture allouée par le programme. Le principe de fonctionnement se résume par ce sigle : LIFO => Last In, First Out, ou "Dernier entré, premier sorti".

Prenez par exemple une pile d'assiettes :
|__________________|
|__________________|
|__________________|
|__________________|

On a quatre assiettes empilées. Si on veut retirer la deuxième assiette :
|__________________|
|__________________|
|__________________|
|__________________|

En partant du haut, il va falloir dépiler la première assiette. On se retrouve donc avec l'assiette rouge au sommet :
|__________________|
|__________________|
|__________________|

Pour enfin la dépiler. Elle a disparu :

|__________________|
|__________________|

Je vais prendre un exemple qui se rapproche plus de la situation réelle. La pile est une zone de mémoire, comme je vous l'ai dit. Elle a donc ses adresses mémoires. Elle est délimitée par deux registres qui font office de pointeurs :
  • esp : "Extended Stack Pointer", ou "pointeur étendu de pile". Ce registre contient et contiendra toujours, en tant que valeur, l'adresse mémoire qui pointe sur le sommet de la pile. Par exemple, si esp contient 0x00405632, alors le sommet de la pile pointera sur l'adresse mémoire 0x00405632, qui contiendra une valeur spécifique ;
  • ebp : "Extended Base Pointer", ou "Pointeur étendu de base". A ne pas confondre avec ebx. Le registre ebp pointe sur le bas de la pile.

Enfin, quelque chose à savoir : esp sera toujours plus petit qu'ebp. Plus l'on va vers le haut de la pile, plus les adresses seront basses. A l'inverse, plus l'on ira bas dans la pile, plus les adresses seront hautes.

Allez, encore un schéma qui vaudra mieux qu'un long discours :

La pile au beau milieu de la mémoire

Notez que j'ai volontairement mis des valeurs aléatoire dans la pile. C'est pour les représenter au beau milieu de notre zone de mémoire. On voit que le registre esp pointe sur le sommet de la pile, qui est adressée à 0xbfffffcb et la valeur à ce sommet est 1561561 (adresse que j'ai mise au pif). Cette adresse est basse, comparée à 0xbfffffff qui est pointée par ebp.

On remarque que la valeur 1561561 est au sommet de la pile. Si on la dépile, au final, on aura :

La pile au beau milieu de la mémoire, après dépilage de 1561561

Vous l'aurez compris, le registre esp s'est mis à pointer sur la valeur du dessous : 27527272. Notez qu'on peut aussi modifier une valeur au milieu de la pile - qui n'est donc pas nécessairement au sommet - mais on ne pourra pas la dépiler comme ça.

Quel est l'intérêt d'utiliser la pile ?

La pile est utilisée pour beaucoup de choses. Notamment pour sauvegarder la valeur des registres lorsqu'on appelle une routine (ou fonction) en assembleur. On se sert également de la pile pour empiler nos arguments avant d'appeler une fonction qui va elle-même les dépiler.

Je pense avoir dit le nécessaire pour vous faire *enfin* programmer !

All you need is...

Nous allons enfin passer à la pratique. Téléchargez Masm32 à cette adresse : http://www.masm32.com/masmdl.htm. Installez-le ensuite. Il se trouvera normalement dans C:\masm32. Je vous demanderai de créer un dossier nommé "asm_sources" également à la racine du site. Ça facilitera votre organisation. C'est dans ce dossier que nous ferons des sous-dossiers pour chaque programme compilé. Une fois le dossier asm_sources créé, allez dedans, et créez un nouveau dossier nommé hello. Dedans, créez le fichier hello.asm, et inserez-y le code suivant :
Code : asm
.386
.model flat, stdcall
option casemap :none

include \masm32\include\msvcrt.inc
include \masm32\include\kernel32.inc

includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\msvcrt.lib

.data
    Phrase db "Hello !",10
    Taille dd 8

.code
start:
    mov eax, Taille
    push eax
    push offset Phrase
    push 1
    call crt__write

    push 0
    call ExitProcess
end start

Tout ce code permet de faire :
Hello !

Pour le compiler, faites un fichier "make.bat" dans le répertoire du fichier, et mettez-y les instructions suivantes :
Code : dos
@echo off
\masm32\bin\ml /c /Zd /coff hello.asm
\masm32\bin\Link /SUBSYSTEM:CONSOLE hello.obj
pause

Il vous suffira simplement de double-cliquer sur "make.bat" pour voir, normalement, apparaître :
Microsoft (R) Macro Assembler Version 6.14.8444
Copyright (C) Microsoft Corp 1981-1997. All rights reserved.

Assembling: hello.asm
Microsoft (R) Incremental Linker Version 5.12.8078
Copyright (C) Microsoft Corp 1992-1998. All rights reserved.

Appuyez sur une touche pour continuer...

La ligne 2 du fichier bat réalise la transformation du code source en code objet ; du code machine directement compréhensible par le processeur. Enfin, la troisième ligne réalise l'édition de liens grâce au fichier objet hello.obj qui a été généré lors de l'instruction en ligne 2. Au final, vous avez un fichier exécutable pondu dans le même répertoire que vos autres fichiers. Pour le lancer :

Microsoft Windows XP [version 5.1.2600]
(C) Copyright 1985-2001 Microsoft Corp.

C:\Documents and Settings\Geoffrey>cd ../../asm_sources/hello

C:\asm_sources\hello>hello
Hello !

C:\asm_sources\hello>

Sans trop de difficulté, on a fait notre premier programme en assembleur. Voyons maintenant pas à pas la signification des lignes du code source (quand même !)

Les directives

En assembleur masm32, on utilise des directives pour indiquer certaines options au compilateur. Ici, nous avons :
Code : asm
.386
.model flat, stdcall
option casemap :none

include \masm32\include\msvcrt.inc
include \masm32\include\kernel32.inc

includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\msvcrt.lib

Première ligne : .386. Cette directive indique que l'on va utiliser le jeu d'instructions d'un processeur x86 32 bits. Ne m'en demandez pas plus à ce sujet, je sais juste qu'il est important de mettre cette ligne.
Seconde ligne : .model. Cette directive spécifie le modèle de mémoire du programme. "flat" signifie qu'on va travailler avec des adresses mémoires "lointaines" ou "prêtes". "stdcall" indique que, lors d'appels aux fonctions, les arguments devront être empilés de droite à gauche.

Qu'est-ce que ça signifie ?

Et bien, reprenons le code assembleur, où je fais appel à la fonction write. Sa signature en C est la suivante :
Code : C
#include <unistd.h>
ssize_t write(int fildes, const void *buf, size_t nbyte);

La fonction write prend trois arguments :
  • fildes : "FILe DEScriptor", ou descripteur de fichier. La fonction write peut, en effet, écrire dans des fichiers, ou dans les flux standards tel que stdout (la sortie, l'écran) ;
  • buf : "BUFfer", ou "tampon". Il s'agit d'un pointeur vers les données à écrire ; il s'agit généralement d'une chaîne de caractères.
  • nbyte : "Number of BYTE", ou "nombre d'octets". Indique le nombre d'octets à écrire.

Il y aura trois arguments à empiler, et comme on fonctionne de "droite à gauche", on empilera d'abord nbyte, puis *buf, et enfin fdes. Enfin, continuons après cette brève parenthèse.

option casemap :none indique au compilateur que les noms d'étiquettes seront sensibles à la casse. C'est-à-dire que l'étiquette hello - qui pointera sur un bloc de données - et Hello - qui pointera sur un autre bloc de données - seront différentes. C'est comme les noms de fonction en C : on vous a normalement appris que Main() et main(), c'est pas pareil !

Passons aux include et includelib (je récapitule) :
Code : asm
include \masm32\include\msvcrt.inc
include \masm32\include\kernel32.inc

includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\msvcrt.lib

la directive "include" en masm32 correspond à un "#include" en C. Les fichiers .inc contiennent les signatures des fonctions à utiliser. Eh oui, sous Windows, on doit se servir des fonctions "mappées" dans les fichiers DLL. Les fichiers inc contiennent les définitions des fonctions.

Enfin, la directive includelib indique au compilateur qu'on veut se servir des fichiers lib qui, eux, contiennent carrément le code des fonctions.

Vous avez vu que je me sers de kernel32.lib/inc et msvcrt.lib/inc. Kernel32 contient la fonction ExitProcess(), qui consiste à quitter proprement le programme pour rendre la main au système d'exploitation (il y a du code qui s'en charge, et dont on ne doit pas se soucier) et msvcrt contient le code de la fonction write(), que je vous ai décrite plus haut.

Les sections

Dans notre code, nous avons déclaré deux sections. Voyons la première :
Code : asm
.data
    Phrase db "Hello !",10
    Taille dd 8

La directive ".data" indique le début de notre section data, qui contient des données initialisées. C'est là ça devient intéressant. En fait, cette section sert à déclarer des données dont nous nous servirons dans le code.

Code : asm
Phrase db "Hello !",10

Cette instruction signifie que je déclare une chaîne de caractères qui contient le mot "Hello !", suivi de l'octet 10, qui correspond à un retour à la ligne. Phrase désigne un label afin de pointer aisément sur notre chaîne de caractères. enfin, l'inscruction db signifie "declare byte", afin de préciser que les unités ont pour taille 1 octet (8 bits).

Code : asm
Taille dd 8

Même principe, sauf que dd signifie "declare double". Un "double", ici, correspond à quatre octets (32 bits). Le label se nomme Taille, et la donnée est de '8' ; étant codée sur quatre octets, on aura donc, en hexadécimal, 0x00000008. Cette donnée correspond en fait à la taille de la chaîne de caractère "Hello !",10. Voici, après compilation, l'organisation de la section data :
Code :
+---+---+---+---+---+---+---+----+----+----+----+----+-------------
|'H'|'e'|'l'|'l'|'o'|' '|'!'|0x0A|0x08|0x00|0x00|0x00| ..........
+---+---+---+---+---+---+---+----+----+----+----+----+-------------
  ^                                ^
  |                                |
  |                                |
Phrase                            Taille

Vous verrez que j'ai volontairement représenté certains octets sous leur forme hexadécimale. 0x0A correspond, en décimal, à la valeur 10, donc à notre retour à la ligne. Enfin, vous verrez que Taille pointe sur 0x00000008, qui est une valeur écrite à l'envers en mémoire. Elle est écrite à l'envers car on ne veut pas lire "quatre octets à la suite", "mais un entier à la fois". Dès lors, pour représenter, par exemple, le nombre 0x65231489 en mémoire, ça sera :
Code :
+----+----+----+----+----------
|0x89|0x14|0x23|0x65|..........
+----+----+----+----+----------

Mais revenons-en à notre schéma plus au-dessus, où j'ai représenté les données du programme. J'ai montré que Phrase et Taille pointaient sur ces données. Ces labels correspondront en fait, après la compilations, à des adresses mémoires.

Si Phrase correspond à l'adresse mémoire 0x00401000, alors Taille correspondra à l'adresse mémoire 0x40100008, car Phrase pointe sur huit octets. Enfin, vous verrez que si vous vous mettez à pointer sur Phrase+8, vous retomberez sur Taille.

Ce qu'il faut savoir, en résumé, c'est que le fait de déclarer des données de façon séquentielle reviens à les écrire de la même façon dans la section data de notre exécutable.

Étudions à présent la section .code, qui correspond à la section exécutable de notre programme. Cela signifie que les octets - qui seront en fait représentés par des instructions en assembleur - écrits dans cette section seront lus par le processeur et exécutés.
Code : asm
.code
start:

La directive "start:", elle, indique le point d'entrée du programme. C'est comme la fonction main() en C. C'est après cette directive que les choses deviennent intéressantes, mais intéressons-nous à l'algorithme logique du programme.

Comme nous l'avons vu, le programme s'est contenté d'afficher bêtement "Hello !", et de rendre la main au système d'exploitation. Il a donc fallu appeler write(), et ExitProcess(). En premier lieu, il faut donc empiler les arguments de write(), appeler la fonction, puis empiler les arguments de ExitProcess() et enfin appeler cette fonction.

Code : asm
    mov eax, Taille
    push eax
    push offset Phrase
    push 1
    call crt__write

    push 0
    call ExitProcess

La première ligne indique au processeur de mettre dans le registre eax la valeur pointée par le label Taille, à savoir 0x00000008. Le registre eax, après cette instruction, contiendra - sur 32 bits, soit 4 octets - 0x00000008. En assembleur intel, on a la synthaxe suivante :

mov destination, source

Et "destination", par l'intruction "mov", recevra en nouvelle valeur "source" et aura son ancienne valeur écrasée.

Code : asm
push eax

L'instruction push, en assembleur, consiste à mettre une donnée au sommet de la pile (à l'empiler, quoi... Je me complique la vie !). Ici, on a empiler la valeur d'eax, à savoir, 8. On a empilé notre troisième argument de write() ; vous vous souvenez quand je vous ai dit qu'il fallait empiler les arguments de droite à gauche, donc dans l'ordre inverse ?

Code : asm
push offset Phrase

On va encore empiler quelque chose, sauf qu'ici, il ne s'agit pas d'empiler une chaîne entière, mais un pointeur vers celle-ci. L'instruction offset indique que l'on va empiler l'adresse mémoire de notre chaîne. En C, on passe des pointeurs en paramètres. Et que contiennent les pointeurs ? Des adresses mémoires. C'est la même, vous dis-je !

Code : asm
push 1

Enfin, on empile la valeur 1. Cette valeur est représentée par défaut sur 32 bits (4 octets) puisque nous sommes sur un système d'exploitation 32 bits. Le nombre 1 correspond à la sortie standard, soit l'écran. Cela indique que l'on va écrire nos octets à l'écran. Et enfin, on appelle la fonction :

Code : asm
call crt__write

Pourquoi "crt__write" et pas "write" ?

Je ne sais pas ce que signifie crt (à vrai dire, j'ai pas vraiment cherché ; c'est pas bien, je sais) mais j'ai mené une petite recherche dans les fichiers .inc, et j'ai vu que la fonction write() était déclarée en "crt__write".

L'instruction call correspond à un saut très très lointain sur une autre adresse mémoire. Lors de la compilation, le compilateur se débrouillera pour remplacer crt__write par une adresse mémoire sur laquelle sauter. Oui, les fonctions qui se situent dans les DLL se situent à des adresses, toute donnée est adressée. Le call se charge aussi d'empiler l'adresse de l'instruction qui se situe juste derrière ; cela permettra au processeur de revenir où il en était après l'exécution de la fonction.

On vient donc d'exécuter cet équivalent en C :
Code : C
write(1,"Hello !\n",8);

Il nous faut enfin quitter le programme proprement. En C, cela reviendra à utiliser :
Code : C
ExitProcess(0);

la fonction prend un unique argument ; sa valeur, 0, indique que le déroulement du programme a été normal, et qu'on le quitte proprement. On peut utiliser d'autres codes en fonction d'éventuelles erreurs produites pendant le déroulement du programme, que ça soit 1, -1... 1 reste la valeur conventionnelle aussi bien sous Windows que Linux (je connais pas Mac, par contre. J'aime pas les pommes).

De ce fait :
Code : asm
    push 0
    call ExitProcess

Consiste à mettre la valeur 0x00000000 sur la pile et d'appeler la fonction ExitProcess(), qui va terminer proprement le processus en rendant la main au système d'exploitation (qui, lui, aura récupéré le 0 passé à la fonction. On peut traiter ça avec des algos, mais nous n'expliciterons pas la chose).

Et enfin, on indique la fin de la routine principale :
Code : asm
end start

Dites-moi, sérieusement... Il y avait quoi de dur ?

Désassembler le programme

Je vous avais promis une session de debug avec OllyDbg. Commencez par le télécharger à cette adresse : http://www.ollydbg.de/odbg110.zip. Décompressez-le dans un dossier quelconque, que ça soit sur le Bureau ou dans "Mes Documents", ça n'a pas d'importances. Ouvrez la bête, et faites File > Open, enfin, cherchez votre fameux hello.exe que l'on a compilé ensemble. Voici une sous-fenêtre que vous devriez normalement obtenir :

Sous-fenêtre d'Olly Dbg

Pour ceux qui n'ont jamais utilisé cet outil, ne vous en faites pas, j'ai numéroté les parties pour vous expliquer en détail.
  1. La section code de notre programme. Il y a, tout en haut, la première instruction qui sera exécutée. La "scrollbar" s'est, en effet, positionnée au point d'entrée. Dans cette fenêtre, on a quatre colonnes qui représente respectivement : l'adresse mémoire de l'instruction, l'équivalent hexadécimal de l'instruction (son équivalent en langage machine pur et dur, quoi), l'instruction assembleur, et, enfin, des informations supplémentaires sur l'instruction.
  2. Cette frame donne l'état des registres. Vous remarquez qu'il y a EAX, EBX, ECX, EDX, EBP, ESP et d'autres que je n'ai pas explicités. C'est le moment, si on veut. ESI (Extended Source Index) et EDI (Extended Data Index) sont des registres qui sont manipulables dans le code. A quoi ils servent... Je ne saurais pas vous dire. EIP, lui, signifie Extended Instruction Pointer. Ce registre contient l'adresse de l'instruction suivante. Ici, EIP contient 00401000, ce qui signifie que l'instruction qui va être exécutée sera celle à l'adresse 00401000, soit MOV EAX,DWORD PTR DS:[403008], qui correspond, dans notre code, à "mov eax, Taille".
  3. Cette fenêtre montre la pile. En haut de la frame, on a le sommet de la pile. Pour être fixé, regardez la valeur d'ESP - 0012ffc4 - et l'adresse en haut de la frame : ce sont les mêmes.
  4. La section data. On remarque, par ailleurs, que nos données sont bien écrites les unes à la suite des autres, comme je vous l'avais schématisé.

Pour exécuter une instruction à la fois, appuyez sur F7. Hop, vous venez d'exécuter MOV EAX,DWORD PTR DS:[403008]. regardez à présent la valeur d'EAX : le registre contient 0x00000008. Ensuite, tracez jusqu'à CALL DWORD PTR DS:[402008]. Là, vous avez deux options :
  • Soit vous appuyez sur F7, et vous tracez pas à pas le code assembleur de la fonction write(), qui correspond à un gros bordel que moi-même je ne connais pas.
  • Sois vous appuyez sur F8, et vous tracez le CALL sans entrer dedans. C'est comme si vous traciez une instruction normale.

Que dire d'autre à propos d'Ollydbg ? Il est pratique si vous avez fait un programme et qu'il y a un bug que vous avez du mal à résoudre. Ca vous permet de debugger facilement vos futurs programmes écrits en MASM32, en tout cas.

Conclusion

J'ai explicité pas mal de trucs dans cette introduction, tout comme j'en ai oubliés certains. Il existe pas mal de tutoriels qui vous explique bien plus de fondamental que ça, à savoir, les instructions de saut conditionnels/inconditionnels (pour implémenter les boucles ou les conditions, par exemple), le pop qui permet de dépiler une valeur (on l'a pas vu, mais c'est pas bien grave), les registres d'état, etc. Des liens pour vous guider :

http://win32assembly.online.fr/. Bien que le site soit en anglais, c'est pour moi une mine d'or pour les curieux.
http://jeanfrancoisdelnero.free.fr/prog.htm Contient quelques progs en assembleur, et une petite section lien en bas de page.

Ce que j'ai à dire pour ma part : l'assembleur, c'est pas méchant. C'est sympa si on veut comprendre comment fonctionne la programmation au plus bas niveau. Sous windows, on fait des appels de fonction. Sous linux, le noyau fournit directement des appels noyau grâce à des interruptions, ce qui rend la programmation encore plus simple puisqu'il ne faut pas nécessairement faire de CALL. Enfin, ça, c'est une autre affaire.

Enfin, je tiens à dire que je suis assez amateur, et que ce tutoriel n'est pas exhaustif et contient de très nombreux défauts. J'espère juste que ceux qui l'ont lu ne s'en sortiront pas sans n'avoir rien appris ! Pour toute question : geo [point] 669 [at] gmail [point] com.
J'oubliais : énorme merci à Overcl0k, sans qui la rédaction de ce tutoriel n'aurait probablement pas eu lieu.

Geo


Assembleur/4602 - MASM - MASM32

Vu dans ... https://pierre.maurette.fr/assembleur/bouquins/4602/chap05_masm

MASM - MASM32

Pour programmer en pur assembleur, nous avons décidé de nous appuyer sur MASM, officiellement Microsoft Macro-Assembleur , dans ses versions ml.exe 6.15.8803 et 7.00.9254. Pour les tests, la première a parfois été renommée ml615.exe , la seconde ml7.exe . c'est sous ce nom qu'ils peuvent apparaître de temps en temps dans divers fichiers du CD-Rom.

Pourquoi MASM, plutôt que TASM, NASM, Paradigm ? Parce que ses règles de langage et de syntaxe sont une référence de fait, et les syntaxes des autres produits s'en inspirent parfois. Nous avons déjà abordé ce point.

MASM32 est un kit bâti autour de MASM, en version 6.14 au moment de la rédaction de ces lignes.

Les défauts de MASM, sur lesquels nous ne revenons pas, n'empêchent en rien une programmation efficace. Il s'agit essentiellement d'un certain laxisme de l'assembleur quand il doit interpréter les constructions d'un code source. C'est la raison pour laquelle nous insisterons sur l'utilisation qui devrait au début être systématique des fichiers listing .lst .

Dans le cadre de cet ouvrage, nous nous contenterons d'installer et de prendre en main MASM (ou MASM32). L'objectif est de placer le lecteur en situation d'expérimenter confortablement. Pour une description complète de la syntaxe et des nombreuses notions souvent complexes de ce macro-assembleur, le lecteur se reportera à l'édition de la collection "Référence".

5.1 Installer une distribution MASM

MASM désigne non pas un programme, mais un ensemble d'outils, bâti autour essentiellement du ou des assembleurs ml.exe et du ou des lieurs link.exe . Depuis, semble-t-il, une version 6.1x, MASM n'est plus disponible à la vente en tant que produit complet, accompagné de sa documentation. Cet assembleur n'est plus considéré comme un produit de développement commercial, mais plus comme un outil nécessaire, entretenu de façon minimale mais suffisante.

Cet état de fait présente l'avantage de rendre le produit librement accessible, mais complique notre tâche, puisqu'il faut partir à la chasse aux éléments et ensuite les installer, c’est-à-dire le plus souvent les recopier dans des dossiers correctement choisis.

Bien que non distribué, il n'est pas impossible, le produit ayant été relativement répandu à une certaine époque, que vous ayez la chance d'en posséder encore une copie complète. Les bennes à ordures de certains organismes de formation sont un bon territoire de chasse, histoire vécue ! Seul problème dans ce cas, trouver une des dernières versions 6.1x, contenant 5 disquettes 3"1/2 1.44MB encore lisibles. Si vous avez la chance d'être dans cette situation, faites immédiatement une copie des cinq disquettes de distribution sur disque dur.

La principale source d'approvisionnement était jusqu'à récemment les divers DDK (Drivers Development Kit), en accès libre sur le site de Microsoft. La politique de l'éditeur concernant ces kits a changé et nombre de liens fournis sur Internet sont devenus obsolètes. Signalons à ce sujet que les auteurs de ces pages de liens préfèrent souvent conserver ces liens morts en toute connaissance de cause. Les divers SDK/DDK existent toujours, mais les modalités pour se les procurer ont changé.

Des liens précis ou des liens vers des pages de liens sont disponibles sur le CD-Rom. De plus, un moteur de recherche comme Google fournit également de bons renseignements.

Si vous hésitez sur une version à installer, il est vivement conseillé d'installer l'ensemble MASM32. Vous aurez ainsi tout ce qu'il faut pour travailler immédiatement, y compris de la documentation et les fichiers .lib et .inc nécessaires.

Dans MASM32 version 8, la version de l'assembleur ml.exe est la 6.14.8444, celle du lieur link.exe la 5.12.8078. Il existe deux versions plus récentes de l'assembleur, très proches de cette 6.14 : une 6.15.8803, incluse dans le Visual Studio Processor Pack, toujours intéressant à télécharger, ne serait-ce que pour la documentation et la 7.0 de Visual Studio .NET. Mais, répétons-le, MASM32 v. 8 est tout à fait suffisant. Ces deux versions sont également plus récentes que celles fournies avec MASM d'origine Microsoft.

Il existe deux situations pour lesquelles vous pouvez avoir besoin d'autres programmes que ceux fournis avec le kit MASM32, situations qu'il ne faut pas confondre :

Pour générer un exécutable DOS 16 bits, il faut utiliser le lieur segmenté link.exe (dernière version 5.60.339) ou éventuellement tout autre lieur DOS compatible.

Le problème est différent pour l'assembleur ml.exe : à partir de la version 6.12, il s'agit d'une application console 32 bits. Attention, ceci n'a rien à voir avec le code objet généré. La dernière version tournant en environnement DOS 16 bits est la 6.11d. Les situations débouchant aujourd'hui sur ce besoin sont certainement rares.

Nous verrons comment intégrer les outils nécessaires pour assembler du code 16 bits à partir d'une installation MASM32.

Dans les versions antérieures à 6.x de MASM, l’assembleur portait le nom de masm.exe . Dans le seul but de pouvoir réutiliser les makefiles des anciens projets, les versions 6.x de MASM sont fournies avec un exécutable masm.exe , qui n’est qu’un simple traducteur (MASM Compatibility Driver Version 6.11), qui appelle ml.exe en adaptant les paramètres de la ligne de commandes.

Reste le problème de la documentation exhaustive. Les dernières versions vendues officiellement étaient accompagnées d'un ensemble de quatre ouvrages, dont il circule des versions .doc ou .pdf . Depuis, peu de choses ont évolué, au plan de la syntaxe et de la philosophie du produit. Il suffit de vérifier les points de détail qui peuvent avoir changé.

La première chose à faire est de consulter l’aide en ligne de commandes, en saisissant par exemple ml /? ou ml /? >h.txt pour récupérer la sortie dans un fichier texte. Nous obtenons ainsi un résultat strictement identique pour les versions 6.15 et 7.0.

Ensuite, tout dépend de la façon dont la nouvelle version a été approvisionnée. Pour la 7.0 de Visual Studio .NET, l’aide en ligne contient une rubrique Microsoft Macro Assembler Reference . Pour la 6.15, le Visual Studio Processor Pack inclut un ficher MasmRef.doc . Les deux décrivent, de la même façon brute mais exhaustive, options en ligne de commandes, messages d’erreur, directives, opérateurs et symboles, pour ml.exe et éventuellement pour tel ou tel utilitaire. Les principales différences visibles sur la version 7.0 concernent les directives de type de processeur, ce qui n’a rien d’étonnant.

Si vous ne passez pas par une procédure d'installation, vous pourrez vous inspirer de ce qui suit, ainsi que de ce qui a été écrit sur le sujet au chapitre précédent, pour procéder manuellement. Il n'est pas nécessaire de chercher à tout prix à innover et la structure de dossiers habituelle conviendra : créez un dossier nommé MASM par exemple, ou DEV si vous centralisez les outils de plusieurs langages pour partager ceux, nombreux, qui sont communs. Ensuite, créez une série de sous-dossiers, qui peuvent être BIN (les exécutables de base), INCLUDE (pour les .inc , mais aussi les .h s'il y a lieu), LIB , et tous ceux qui vous semblent utiles pour structurer la chose, DOC , TOOLS ou OUTILS , SOURCES (pour les sources des .lib ), etc.

Il est tout à fait pertinent de partir d'une installation existante (Visual Studio, C++Builder, C++ 5.50) et d’ajouter simplement les fichiers nécessaires dans les dossiers adéquats. Le dernier nommé, C++ 5.50, un compilateur C++ en lignes de commande gratuit et présent sur le CD-Rom, serait une bonne solution, plutôt dans le cas d'assembleurs de la famille TASM.

Commençons par le commencement, nous allons donc décrire deux installations, celle de MASM 6.11 et celle de MASM32.

5.1.1 Installation de MASM 6.11

Nous allons installer ensemble MASM à partir d'une copie sur disque dur d'une distribution version 6.11, puis appliquer un patch de mise à jour vers la version 6.13. Celui-ci a été chargé sur Internet, il s’appelle ml613 . Quoi qu’il en soit, c’est dans cette arborescence d’installation que nous copierons les divers composants de MASM, au fur et à mesure de l’apparition de nouvelles versions. Pour cette raison, nous allons nommer notre dossier d’installation tout simplement MASM .

Si vous ne possédez pas cette distribution telle quelle, vous pouvez vous inspirer de ce qui suit pour créer une arborescence analogue et y copier les fichiers utiles.

L’installation sera décrite sous XP, qui est aujourd'hui l’environnement le plus éloigné de l’environnement cible de ce package. Qui peut le plus peut le moins, tout devrait fonctionner de la même façon sous d’autres versions de Windows. L'installation a d'ailleurs été faite dans une partition partagée entre plusieurs OS sélectionnables au boot, MASM sera utilisé à partir de Windows 2000 et Windows 98 sans problème.

Ce fait est logique, puisqu'en fait d’installation, il s’agit pour l'essentiel d’une copie après décompression, et c’est bien ce que nous recherchons.

Le dossier MASM occupera aux alentours de 8 Mo. Il est bien clair que, au moment de faire des choix, la place occupée sur le disque ne sera pas un critère déterminant, alors que la volonté de ne pas perturber son système d’exploitation en sera un.

Considérons le contenu de la première disquette d’installation dans …\\masm6\disque1 et lançons par un double-clic setup.exe .

Astuce

Simuler des disquettes

Il est très conseillé, comme signalé plus haut, de sauvegarder ses logiciels sur disquettes sur une série de répertoires, par exemple ..\D1 , .., ..\Dn , sur disque dur ou CDRW. La première idée qui vient est d'en faire ensuite autant de copies sur disquettes neuves pour procéder à l'installation.

Il est généralement possible de procéder autrement : copier le contenu de la première disquette dans un répertoire (parfois, la racine d'une partition), et lancer l'install. Ensuite, il suffit de profiter de l'invitation à changer de disquette et du multitâche de Windows pour modifier le contenu du répertoire, en y copiant successivement le contenu des sauvegardes de chaque disquette.

Parfois, si les disquettes ne contiennent pas de nom de fichier en commun, il est possible de tout copier dans un seul répertoire d'installation.

Laissons passer l’écran de bienvenue et nous arrivons sur l’écran figurant sur l’illustration.

figure 5.01 Début d’installation

Nous allons bien entendu appuyer sur Entrée pour continuer l’installation avec choix, non sans avoir remarqué, à l’avant-dernière ligne et à la précédente, la possibilité de consulter la liste des fichiers du package et celle d’extraire chacun d’eux individuellement, ce qui pourra être utile ultérieurement.

Nous passons par une série de choix ; nous avons opté pour les suivants.

figure 5.02 Étapes de l’installation

Ce qui est ici appelé Windows est la version 3. Les choix que nous avons faits installent un maximum de fichiers.

PWB est l’atelier intégré, qui permet d’accéder à l’aide tout en éditant, compilant et testant les programmes. L'espace disque n'est pas cher, il est préférable de l’installer même sans envisager de l’utiliser.

N’installez pas de driver de souris, car XP ou 98 s’occupe de ce point. masm.exe étant proposé pour des raisons de compatibilité, le copier ne peut pas nuire. Enfin, nous installons les fichiers d’aide et les exemples.

Nous choisissons d’installer sur C: , ensuite nous éditons le dossier de masm611 en masm , pour le premier dossier proposé, bin . Cette modification n’est à faire que pour ce dossier, les autres suivront. L’installation se poursuit ; il suffit de confirmer tous les choix puis de quitter.

Il reste à installer éventuellement le patch vers 6.11d ou 6.13. Un patch contient généralement une nouvelle version de ml.exe , plus éventuellement de nouveaux fichiers textes et utilitaires. Si vous récupérez ml.exe d’une autre façon, il faut copier au minimum ce fichier, ainsi que celui de messages d’erreurs ml.err . MasmRef.doc est également utile.

Pour des raisons de gestion de la mémoire étendue, la version 6.13 nécessite au minimum Windows NT ou 95 pour fonctionner, ce qui ne devrait pas poser de problème, sauf si vous tenez à booter en DOS vrai pour développer. Mais, dans ce cas, il aurait été préférable de faire l’installation sous DOS. Précisons que cette limitation n’empêche pas 6.13 de générer des applications DOS. Pour être exact, la 6.13 va s’exécuter dans une fenêtre DOS de Windows à partir de 95.

Le fichier ml613.exe n’est qu’un fichier compressé auto-décompactable. Décompactons-le donc dans un dossier ml613 par exemple et commençons la mise à jour. Nous menons cette opération sous Windows, et non en ligne de commandes.

Il est conseillé dans le readme.txt de sauvegarder quelques fichiers ( ml.exe , ml.err , h2inc.exe , h2inc.err et win.inc ). Cela est facultatif, puisque nous savons les récupérer à partir de la 6.11.

Copions patch.exe , patch.rtd et patch.rtp dans c:\masm\ , puis lançons patch.exe , en fenêtre DOS si nous souhaitons pouvoir lire les résultats. Nous pouvons effacer les trois fichiers patch copiés. Il reste à copier h2inc.exe et h2inc.err dans le dossier bin et win.inc dans le dossier include .

Vous pouvez renommer readme.txt en readme613.txt , puis le copier dans la racine du dossier d’installation ( c:\masm\ dans notre cas). Copiez également les autres fichiers textes, en remplacement de ceux existant.

Avant de faire le ménage, pensez à recopier la documentation dont vous disposez dans le dossier d’installation ou à tout autre endroit où vous avez pour excellente habitude de la centraliser. Dans ce dernier cas, renommez-le de façon explicite, Docs_masm_6 par exemple.

Vous pouvez maintenant effacer les dossiers \\masm6 et ml613 . Cette installation n’a modifié aucun fichier système, ni la base de registre bien entendu. Vous pouvez éventuellement zipper et archiver le dossier c:\masm complet, à une étape où tout fonctionne correctement. Un peu plus tard serait le mieux.

Si le programme d’installation n’a pas modifié le système, c’est parce qu’il utilise une autre très bonne méthode pour arriver au même résultat. Il a fabriqué un certain nombre de fichiers ; libre à nous de les utiliser. Ces fichiers se trouvent dans le dossier binr , à l’exception de tools.pre , qui est dans init .

Le fichier new-vars.bat , prévu pour modifier autoexec.bat , contient :

SET PATH=C:\MASM\BIN;C:\MASM\BINR;%PATH%
SET LIB=C:\MASM\LIB
SET INCLUDE=C:\MASM\INCLUDE
SET INIT=C:\MASM\INIT
SET HELPFILES=C:\MASM\HELP\*.HLP
SET ASMEX=C:\MASM\SAMPLES
SET TMP=D:\WINDOWS\TEMP

Nous allons l’utiliser pour modifier non pas notre autoexec.bat (nous sommes sous XP, et de plus nous n’aimons pas ça), mais un fichier masmxp.bat , comme suit :

PATH = %SystemRoot%\system32

SET PATH=C:\MASM\BIN;C:\MASM\BINR;%PATH%
SET LIB=C:\MASM\LIB
SET INCLUDE=C:\MASM\INCLUDE
SET INIT=C:\MASM\INIT
SET HELPFILES=C:\MASM\HELP\*.HLP
SET ASMEX=C:\MASM\SAMPLES
SET TMP=D:\WINDOWS\TEMP

%SystemRoot%\system32\cmd.exe

Élaborez dès maintenant le fichier masm.bat , adapté à vos dossiers et à votre version de Windows.

Il sera ensuite possible de créer des raccourcis vers ce fichier, pour par exemple lancer la session en mode Plein écran et de le modifier légèrement pour lancer directement l’atelier : il suffit de remplacer la dernière ligne par pwb ou par qh , pour lancer l’aide, une fois celle-ci configurée.

new-conf.sys comporte des lignes à ajouter éventuellement à un fichier config.sys . Il ne nous intéresse pas dans notre configuration.

new-sys.ini sert éventuellement à modifier le fichier system.ini . Gardons-le au frais pour l’instant. Il est utile si nous souhaitons exploiter cvw , une version Windows de CodeView, mais qui semble ne pas vouloir fonctionner sur les versions actuelles.

Le fichier tools.pre , dans le dossier init , sera simplement renommé tools.ini . Cela va permettre aux utilitaires d’environnement de retrouver les fichiers nécessaires à leur fonctionnement. Après avoir ouvert une fenêtre par le batch fabriqué au paragraphe précédent, testez qh , avant et après le renommage de tools.pre .

Vous pouvez maintenant découvrir qh et pwb . avant d’aborder la première application, essayez par exemple la séquence suivante :

Lancez masm.bat , puis qh . Cliquez sur <Contents> , puis sur <Assembly> dans le rectangle Languages . Repérez le rectangle System Resources pour un usage ultérieur, puis cliquez sur <BIOS Calls> , <13h-Direct Disk Services> et enfin 02h Read Sectors .

figure 5.03 La fonction Read Sector dans Quick Help

Une fois les fonctions BIOS repérées, vous pouvez revenir quelques étapes en arrière, pour explorer les fonctions <MS‑DOS Calls> , à la recherche des fonctions de gestions de fichiers.

Si vous disposez de cette aide, elle sera utile. En revanche, il est certain que l’utilisation de pwb risque de nous apporter des déboires, à cause de sa vétusté, si nous utilisons une version de Windows à partir de la 95. Il est préférable d'utiliser, pour un plus grand confort, un éditeur indépendant et surtout exploiter les possibilités de multitâche de Windows.

5.1.2 Présentation et installation de MASM32

Rappelons que l'ensemble MASM32 ne permet pas tel quelle la programmation DOS 16 bits. C'est d'ailleurs pratiquement son seul inconvénient majeur. Nous proposerons un bricolage fonctionnel à la fin de cette rapide prise en main.

C'est par contre une solution extrêmement confortable, parce que complète en une seule installation, pour aborder la programmation Windows. Sans être exhaustif et sans affirmer non plus qu'il n'existe pas de solution concurrente, voyons quelques goodies de MASM32 :

Ensemble complet et cohérent pour faire du développement 32 bits, jusqu'à l'éditeur de code.

Intégration des bibliothèques et fichiers d'en-tête nécessaires pour du développement Windows immédiat.

L'environnement permet de fonctionner en syntaxe MASM pure.

Installation efficace, peu contraignante et évolutive, nous allons y revenir.

Bibliothèques propres à la distribution fort utiles, fournies avec code source.

Une grande quantité de documentation et tutoriaux inclus en un seul téléchargement.

Produit suffisamment populaire pour générer une bonne activité sur internet.

Embryon d'activité et de documentation en langue française.

L'auteur a découvert le projet MASM32 sur Internet, n'y est absolument pas impliqué et donc n'a aucune possibilité d'en garantir la pérennité.

Les liens pour télécharger MASM32 sont fournis sur le CD-Rom. Une recherche Google sur ce mot clé tout simplement les fournit parmi les quelques premières réponses. Au moment de la rédaction de ces lignes, il est possible de télécharger les packages compressés : masm32v7.zip (environ 5,2 Mo) et masm32v8.exe (environ 3,1 Mo).

L'installation ne pose pas de problème particulier. Pour la version 7, install.exe peut très bien être lancé directement à partir du désarchiveur (WinRar ou WinZip). Pour la version 8, il suffit de lancer masm32v8.exe . En revanche, bien qu'il soit possible d'accéder au contenu masm32v8.exe à l'aide d'un désarchiveur, il ne faut pas tenter une installation personnalisée par ce moyen, un grand nombre d'éléments comme les librairies étant construits lors de l'installation.

Le seul choix proposé est la partition d'installation.

figure 5.04 Installation de MASM32

Bien que le processus semble bloqué aux premiers instants, l'installation est assez rapide sur une machine récente. Le facteur global de décompression est assez impressionnant.

Donc, tout s'installe dans un dossier masm32 , à la racine de la partition choisie. Le nom du répertoire est imposé. Nous allons comprendre pourquoi. En cas d'installation simultanée de deux versions, 7 et 8 par exemple, il faudra donc choisir de le faire sur deux partitions différentes.

Rien ne s'installe en dehors de ce dossier, pas de raccourcis, la base de registre n'est pas modifiée, ni les variables d'environnement. Donc, MASM32 qui vient d'être installé ne doit pas interférer avec des installations antérieures d'autres environnements de développement dont certains programmes peuvent porter le même nom.

Il en découle qu'il n'existe pas de processus spécifique de désinstallation, il suffit d'effacer le dossier masm32 , après bien entendu avoir sauvegardé son travail personnel.

Autre conséquence, dans le cas où vous auriez plusieurs systèmes d'exploitation installés sur votre machine et le désir légitime de tester vos programmes sous ces divers OS, une seule installation suffira. Vous devriez même pouvoir le faire sur une partition qui ne porterait pas la même lettre dans tous les systèmes. Mais ce dernier point n'a pas été testé, les partitions aux noms incertains apportant souvent d'autres ennuis. Il reste une possibilité (improbable) que le processus d'installation code en dur le nom de la partition d'installation dans certains fichiers.

Enfin, sous réserve de ce dernier point, il serait possible de faire une archive du dossier masm32 juste après l'installation. Mais pour quel gain ?

Nous voilà face à une foule d'outils, d'exemples et de documentations diverses. Nous n'utilisons pas de façon habituelle l'éditeur fourni avec cet environnement, et il vous appartiendra de le découvrir par vous-même si vous souhaitez l'adopter. Néanmoins, pour ceux qui sont fâchés avec la langue anglaise, nous allons ensemble effectuer une prise en main de niveau zéro. Ceci va également nous permettre de découvrir quelques fichiers qui nous seront utiles et qui semblent en première approche sous-documentés.

Nous considérons que MASM32 a été installé dans la partition C: . Avec l'Explorateur, allez dans C:\MASM32\EXAMPLE1\LISTBOX . Vous pouvez par curiosité double-cliquer sur listbox.exe . Ensuite, effacez les fichiers listbox.exe et listbox.obj .

Maintenant, dans C:\MASM32\ , vous pouvez lancer qeditor.exe . Vous aurez avantage, si vous pensez utiliser ce programme de façon habituelle, à créer un raccourci vers lui et le déposer par exemple sur le Bureau.

Par le menu File / Open , ouvrez le fichier C:\MASM32\EXAMPLE1\LISTBOX\listbox.asm .

figure 5.05 QEditor

Vous pouvez constater que cet éditeur est de type SDI (Single Document Interface), c’est-à-dire qu'il ne peut ouvrir qu'un seul document. Pour travailler sur plusieurs documents simultanément, il faut ouvrir plusieurs instances de QEditor, ce qui peut être obtenu par File / New Instance ou tout simplement en le lançant plusieurs fois.

Étudiez le menu Project .

figure 5.06 Le menu Project

Run Program ne fait rien, pas même de message d'erreur ou d'avertissement. Essayez Assemble & Link . Une fenêtre de type DOS apparaît.

figure 5.07 Construction de LISTBOX.exe

Les fichiers listbox.obj et listbox.exe ont été créés dans le dossier C:\MASM32\EXAMPLE1\LISTBOX . Nous pouvons maintenant relancer la commande Project / Run Program . Et le programme tourne effectivement.

figure 5.08 Le programme LISTBOX

Voilà, vous pouvez maintenant vous lancer, si vous le souhaitez, à la découverte des menus Tools , Templates , Script et Help , ce dernier étant dans un premier temps le plus enrichissant. Réservé aux anglophones, rappelons-le encore.

Ce qui nous intéresse d'urgence, c'est la façon dont fonctionne le menu Project . Bizarrement, dans Help / Quick Editor Help , même en utilisant la fonction Rechercher , l'aide semble muette sur le sujet. Aide-toi, le ciel t'aidera. Une étude des fichiers .ini ou une recherche des fichiers contenant par exemple Assemble ASM file , nous amène rapidement, dans le même dossier que qeditor.exe , à menus.ini , dont voici un extrait :

[&Project]
Compile &Resource File,\MASM32\BIN\Bres.bat {b}
&Assemble ASM file,\MASM32\BIN\Assmbl.bat {b}
-
&Link OBJ File,\MASM32\BIN\Lnk.bat {b}
Assemble && Link,\MASM32\BIN\Build.bat {b}
&Build All,\MASM32\BIN\Bldall.bat {b}
Run &Makeit.bat,makeit.bat
-
Console Link &OBJ File,\MASM32\BIN\Lnkc.bat {b}
&Console Assemble && Link,\MASM32\BIN\Buildc.bat {b}
Console Build &All,\MASM32\BIN\Bldallc.bat {b}
-
&Run Program,{b}.exe

L'interprétation en est immédiate. Le caractère & précède la lettre de raccourci de l'élément de menu, exactement comme dans les fichiers de scripts de ressources. Le caractère - seul sur une ligne de menu devient un séparateur. Enfin, {b} est remplacé par le nom du fichier en cours d'édition, sans extension.

Il est ainsi facile d’ajouter ou de modifier un élément du menu Project , ainsi que Tools , Templates , Script et Help .

À l’inverse, et notre but était bien là, nous savons maintenant où trouver une série de fichiers batch, que nous allons modifier pour réutilisation dans l'environnement de notre choix. C’est une dizaine de fichiers .bat du dossier C:\MASM32\BIN .

Ces fichiers sont très simples à interpréter. Le principe de la modification sera de changer les références du type \masm32\bin\ml /c /coff "%1.asm" en ?:\masm32\bin\ml /c /coff "%1.asm" , où ? est la lettre de votre partition d'installation. Il en est de même pour les fichiers batch particuliers de certains exemples. De la même façon, selon l'utilisation que vous ferez de MASM32 et de ces nombreux et excellents exemples, vous pourrez être amenés à modifier certaines lignes dans le code source :

include \masm32\include\windows.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc

includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib

en (par exemple) :

include c:\masm32\include\windows.inc
include c:\masm32\include\user32.inc
include c:\masm32\include\kernel32.inc

includelib c:\masm32\lib\user32.lib
includelib c:\masm32\lib\kernel32.lib

Vous trouverez un grand nombre d'utilitaires, parfois avec code source en assembleur. Sans code source, mais tout à fait utile : dumppe.exe , utilisé par les fonctions Tools / Dis‑assemble EXE file et Tools / Dis‑assemble DLL de QEditor.

Les lignes qui suivent et terminent cette rapide découverte de MASM32 s'adressent à ceux parmi les lecteurs qui, séduits par MASM32, chercheraient toutefois à tester quelques programmes DOS, pour un effort minimal, en termes de téléchargement et d'installation.

Nous avons vu, en introduisant MASM, que l'outil nécessaire et souvent manquant pour obtenir des exécutables DOS 16 bits est le lieur segmenté. Chez Microsoft, nous avons cité la version 5.60.339 de link.exe , téléchargeable sous forme d'une archive lnk563.exe (voir CD-Rom). Nous avons extrait link.exe de cette archive et l'avons copié sous le nom link560.exe , dans le dossier C:\MASM32\BIN .

Ensuite, nous avons ajouté trois lignes au fichier menus.ini :

...
Console Build &All,\MASM32\BIN\Bldallc.bat {b}
-
&DOS Construit,\MASM32\BIN\builallD.bat {b}
DOS Assemble,\MASM32\BIN\assmblD.bat {b}
DOS Lien,\MASM32\BIN\lnkD.bat {b}
-
&Run Program,{b}.exe
...

Ceci modifie le menu Project .

figure 5.09 Menus supplémentaires

Il nous reste à fabriquer et à sauver les fichiers batch dans le dossier C:\MASM32\BIN . Ceci nous donne :

@echo off

if exist "%1.obj" del "%1.obj"
if exist "%1.exe" del "%1.exe"
if exist "%1.lst" del "%1.lst"
if exist "%1.map" del "%1.map"

\masm32\bin\ml /Fl /Sa /Fm /Bl"\masm32\bin\link560.exe" %1.asm > \masm32\bin\asmbl.txt

\masm32\thegun.exe \masm32\bin\asmbl.txt
LEGENDE=Le fichier builallD.bat

Remarquez ici l'option /Bl NomFichier , qui permet de modifier le nom du lieur.

@echo off

if exist "%1.obj" del "%1.obj"
if exist "%1.exe" del "%1.exe"
if exist "%1.lst" del "%1.lst"
if exist "%1.map" del "%1.map"

\masm32\bin\ml /Fl /Sa /Fm /c %1.asm > \masm32\bin\asmbl.txt

\masm32\thegun.exe \masm32\bin\asmbl.txt
LEGENDE=Le fichier ASSMBLD.bat

@echo off

if exist "%1.exe" del "%1.exe"

\masm32\bin\link560.exe %1.obj;> \masm32\bin\lnk.txt

\masm32\thegun.exe \masm32\bin\lnk.txt
LEGENDE=Le fichier LNKD.bat

Pour un usage plus soutenu, ces trois fichiers demandent certainement à être améliorés ou personnalisés. Sous cette forme, ils fonctionnent et permettent de construire un petit programme d'essai, dans le dossier Test_DOS .

L'étude complète de MASM n'est pas dans les objectifs de ce livre. Elle pourrait d'ailleurs faire l'objet d'un ouvrage à elle seule. Nous allons simplement présenter un aperçu général de la syntaxe au travers de l'étude d'un code source.

Il est tout à fait possible, à partir de là, de progresser à l'aide de documentation (voir CD-Rom, puis Internet) et d'expérimentations. Dans cette optique, nous traiterons en fin de chapitre la génération et l'interprétation de fichiers listings, indispensables à la compréhension du fonctionnement de certaines directives.

5.2 Le code source, généralités

À l'exception des symboles prédéfinis et de ceux définis par l'utilisateur, MASM n'est pas sensible à la casse, c’est-à-dire qu'il ne fait pas la différence entre majuscules et minuscules. Il n'est pas bon de trop profiter de ce faux avantage et bien préférable de se fixer des contraintes. Nommez les mnémoniques et registres toujours de la même façon dans un projet donné ou sur l'ensemble de votre œuvre, donnez un nom à chaque variable ou étiquette selon une règle de nommage qui peut être personnelle mais qui inclut la casse et référencez ces éléments toujours de la même façon. Pas de code de ce genre :

label1: mov eax, 4
        MOV EBX, EAX
        anD ebx, 4
        JZ LABEL1
        jmp Label1

Ceci est particulièrement important si vous programmez plusieurs langages.

À l’inverse, mais pour les mêmes raisons, lors de l'utilisation d'un compilateur sensible à la casse, évitez d'utiliser cette caractéristique pour faire la différence entre deux identificateurs.

Regardons le listing simpliste suivant :

 1 ;--------------------------------------------------;
 2 ;Programme hello "squelet"
 3 ;Pierre Maurette pour Assembleur / Micro Application
 4 ;Sète, le 3/03/2003
 5 ;--------------------------------------------------;
 6 lowbyte EQU     low
 7 ;--------------------------------------------------;
 8         .286
 9         .MODEL SMALL
10 ;--------------------------------------------------;
11         .STACK 500
12 ;--------------------------------------------------;
13 const1  EQU     513+6
14 ;--------------------------------------------------;
15         .DATA
16 bijor   DB      "Bonjour, e-monde !",0Dh, 0Ah, "$"
17 IFDEF DEBUG
18 testdb  DB      "Mode DEBUG",0Dh, 0Ah, "$"
19 ENDIF
20 str1    DB      " ",0Dh,0Ah, "$"
21 var1    SBYTE   7
22 var2    WORD    2
23 ;--------------------------------------------------;
24         .CODE
25 debut:   mov ax, @data  ;initialisation data segment
26          mov ds, ax
27 ;--------------------------------------------------;
28          ; Message de bienvenue
29          mov ah, 09h
30          mov dx, offset bijor
31          int 21h
32 ;--------------------------------------------------;
33          ;Code d'essai
34          IFDEF DEBUG
35            ;.ERRDEF DEBUG
36            mov ah, 09h
37            mov dx, offset testdb
38            int 21h
39          ENDIF
40          mov al, var1
41          mov al, byte ptr var2
42          mov al, lowbyte const1
43          .IF SBYTE PTR al > 9
44          mov al, 3 * 3
45          .ENDIF
46          cmp al, 0
47          jnl suite
48          mov al, 0
49 suite:   add al, '0'
50          mov str1, al
51          mov ah, 09h
52          mov dx, offset str1
53          int 21h
54 ;--------------------------------------------------;
55          ; attente touche
56          mov ah, 00h
57          int 16h
58
59          ;et fin du programme
60          mov AH, 4Ch             ;fin du programme
61          int 21h                 ;et retour au DOS
62
63          END debut
64 ;--------------------------------------------------;

Ce petit programme exécutable sous DOS sera assemblé et lié par une suite de commandes regroupées dans un ficher batch :

echo off
PATH = %SystemRoot%\system32
SET PATH=C:\MASM\BIN;C:\MASM\BINR;%PATH%
SET LIB=C:\MASM\LIB
SET INCLUDE=C:\MASM\INCLUDE

del *.obj
del *.exe
del *.lst
del *.map
del listing.txt

REM ml7 /? >ml7.txt
REM ml615 /? >ml615.txt

REM ml7 /Zi /Fl"listing.txt" /Sf /Sg /Fm /omf %1.asm
ml615 /Zi /Fl"%1.txt" /Fm /Sg /Sf /omf %2 %1.asm
REM ml615 /Zi /Fl /Sa /Fm /omf %1.asm
REM ml615 /Zi /Fl /Sa /Fm %1.asm
REM dir
pause

Les lignes débutant par SET servent à positionner temporairement, c’est-à-dire pour la session ouverte par le fichier batch, des variables d'environnement. Pour le reste, nous pouvons retrouver les commutateurs de la ligne de commandes utilisés en faisant ml /? ou ml /? >h.txt .

À partir de ces listings, nous allons prendre un premier contact avec le vocabulaire MASM. Il est difficile d'être totalement précis dans la catégorisation des éléments du langage, la notion de directive par exemple s'applique à des éléments fonctionnellement très variés. Il faut faire avec, et ce n'est pas un vrai problème. Sauf éventuellement pour rédiger un texte à visée pédagogique. Cette syntaxe est basée sur cinq grandes catégories d'éléments :

1 Les instructions , que nous reconnaissons facilement à partir de la ligne 25. Elles nous intéresseront dans cette partie de l'ouvrage quand, comme à la ligne 30, elles mettent en œuvre pour l'écriture de l'opérande des spécificités de MASM. Pour le reste, elles sont explorées particulièrement dans le chapitre Le jeu d'instructions .

2 Des directives , éléments propres à MASM, qui permettent de passer des ordres à l'assembleur. En réalité, les directives peuvent être définies comme ce qui n'est pas classé dans les autres catégories. Certaines produisent du code, comme à la ligne 43 le .IF . D'autres se contentent de transmettre une information à l'assembleur, comme le .286 de la ligne 8 ou le IFDEF de la ligne 34.

3 Les attributs sont également de types relativement variés. Globalement, ce sont les paramètres des directives. Nous trouvons des directives avec attribut aux lignes 9, 11, 13 et bien d'autres.

4 Les opérateurs , qui sont utilisés dans les expressions, qui peuvent par exemple calculer un attribut. Nous en voyons aux lignes 13 (+) et 43 (>) par exemple.

5 Des symboles prédéfinis , par lesquels MASM permet au programme d'accéder à certaines valeurs : à la ligne 25, @data est un symbole qui remplace la valeur du sélecteur de segment des données.

Il est habituel, depuis l'origine de la littérature sur l'assembleur, de présenter la ligne d'instructions standard de la façon suivante :

[[Label:]] [[Mnémonique]] [[Opérandes]] [[;Commentaires]]

C'est bien joli, mais dans le listing proposé, seule la ligne 25 correspond à ce schéma. Il est préférable d'aborder les éléments syntaxiques par familles et ensuite par thèmes.

Quelques remarques fondamentales pour mieux situer les éléments de ce code source dans le processus de fabrication de l'exécutable. Nous avons dit qu'il est difficile d'avoir une attaque rigoureuse de la syntaxe de MASM. Il est vrai qu'un label, ou étiquette, et un nom de variable, c'est pareil et ce n'est pas non plus la même chose. Il y a par contre deux points sur lesquels il est possible de catégoriser :

Différencier ce qui est connu dès l'assemblage et ce qui ne le sera qu'à l'exécution. Ce point est fondamental.

Dans le code source, différencier les lignes qui génèrent de l'octet en mémoire de celles qui n'en produisent pas. L'étude du fichier listing est très utile pour la compréhension de ce point.

Quelles lignes produisent de l'occupation mémoire ? 16, 18, 20 à 22, 25, 26, 29 à 31, 36 à 38, 41 à 53 (y compris 43 et 45), 56, 57,60 et 61.

Les lignes 18, et 36 à 38 produisent bien des données et du code, si l'assembleur les traite. Nous y reviendrons un peu plus loin. Quand à la ligne 11, elle crée une pile, donc de la mémoire, c'est un cas un peu particulier.

Aux lignes 15 et 24, nous trouvons les directives .DATA et .CODE . Elles correspondent au début de deux zones de mémoire, des segments logiques. Attention, ces segments ne sont pas ceux du 8086, même s'il peut y avoir correspondance parfois. Un compteur démarre à cet endroit, un compteur de position, un pour chaque segment. Il est incrémenté d'un nombre variable d'unités à chaque ligne qui génère de la mémoire. La valeur dans ce compteur est très proche d'un offset.

Qu'est-ce qu'un label ou étiquette en bon français ? Un objet, une constante nommée, qui prend la valeur du compteur de position de l'endroit où il est placé dans le code source. C'est en première approche très peu différent d'un nom de variable. Ces constantes, noms de variables, de labels, mais également de segments sont utilisables par les instructions du programme pour accéder à la mémoire. C'est ainsi qu'il est possible d'écrire à la ligne 40 mov al, var1 , ou à la ligne 47 jnl suite . Que fait l'assembleur à l'arrivée sur la ligne 40 ? quand il était passé par la ligne 21, il avait noté dans une table qu'il existait dorénavant un symbole var1 , qui correspondait à un offset donné dans le segment débuté par .DATA , disons le segment pointé par DS pour simplifier. Il va donc utiliser sa documentation Intel pour fabriquer les trois octets de l'instruction, A0 pour l'opcode, plus les deux octets de l'offset. C'est en réalité un peu plus sioux que ça, mais nous pouvons en rester à cette image. Il génère vraiment trois octets. En fait, il connaît ces adresses à un décalage près.

Puisque nous en sommes au travail de l'assembleur, détaillons une séance complète d'assemblage, en sachant que beaucoup de notions nous sont peut-être encore inconnues :

1 Dans un premier tour de piste, il évalue les conditions d'assemblage conditionnel et nettoie le source de l'inutile.

2 Il développe ce qui doit l'être (macros, equates). Ici, il remplace par exemple à la ligne 42 lowbyte par low , comme il lui a été demandé à la ligne 6. Fin de la passe 1.

3 Dans le même ordre d'idée, il calcule ce qu'il doit, par exemple à la ligne 44 : 3 x 3 = 9 (bravo).

4 Il code les instructions qu'il sait coder : la ligne 46, par exemple.

5 Il remplace les offsets qu'il ne connaît pas entièrement par l'offset interne, celui correspondant plus ou moins au compteur de position.

6 Il copie dans le fichier objet les segments et leurs attributs.

7 Il copie dans le fichier objet des marqueurs pour repérer ce qui est à corriger en fonction des adresses réelles des segments (c'est bien cela qui manquait).

8 Il fabrique le fichier listing si demandé.

9 Il fabrique une ligne de commandes pour le lieur, en particulier il lui indique les librairies à lier et l'appelle.

10 Il se recouche, parce qu'il a bien travaillé et qu'il est très fatigué.

Les deux ou trois premières phases sont le fait d'une couche particulière, correspondant parfois dans d'autres langages à un programme indépendant : le préprocesseur. Nous n'avons pas parlé ici des possibles inclusions de fichiers, .inc en général : ces inclusions ne changent rien, les inclusions créent un fichier source développé, c'est tout.

Ensuite le lieur :

1 Arrange les segments au mieux, en fonction des instructions de l'assembleur, il résout donc toutes les adresses à une seule inconnue près : l'adresse réelle du début de ce bloc.

2 Il corrige les offsets marqués.

3 Il copie les informations sur les adresses à modifier (remplir par une valeur correcte) dans l'en-tête du fichier .exe sous forme d'une table de relogement (ou relocation).

4 Il fabrique et sauve ce fichier exécutable.

Et enfin le chargeur (loader) du système d'exploitation :

1 Il fabrique dans la mémoire un en-tête (PSP), qui par exemple contient les paramètres de la ligne de commandes, des informations pour le retour en fin d'exécution, etc.

2 Il alloue de la mémoire au programme, et là, il connaît enfin toutes les adresses.

3 Il charge le programme en mémoire.

4 Il corrige les adresses qui doivent l'être (celles figurant dans la table créée par le lieur).

5 Il initialise les registres de segment et lance le programme.

5.3 Génération et lecture des listings

Placer physiquement un article sur les listings au tout début d’un parcours d’apprentissage peut sembler anachronique. Il est pourtant clair que, lors de la découverte de notions nouvelles comme les données ou les macros, la consultation d’un listing est souvent plus enrichissante que le test du programme, même au sein d’un débogueur.

En réalité, la compilation d’un source avec génération de listing, sans édition de lien, est tout à fait suffisante dans beaucoup de cas pour accompagner la lecture de la documentation. Nous aurons donc besoin de produire et de lire un fichier listing dès le début de l'apprentissage.

À l’inverse, l’interprétation des listings aborde des notions qui devront être admises en première lecture.

Pour désigner un listing, nous utiliserons le mot listing, issu de l’anglais ... listing. Plus sérieusement, dans un dictionnaire déjà un peu ancien, nous avons relevé la définition du mot listing (ou listage) : document produit par l’imprimante d’un ordinateur. Effectivement, le listing est historiquement orienté imprimante. Il s’agissait d’un document important dans la gestion de projet, voire contractuellement d’un élément de la livraison finale. MASM est bien plus efficace que bien des compilateurs C ou C++ sur le plan de la génération des listings.

Pour cette présentation, nous nous baserons sur ml.exe version 7.0 avec tests sur 6.15 en cas de doute.

Vous trouverez quelques fichiers évoqués dans les lignes qui suivent dans un répertoire du CD-Rom.

5.3.1 Génération d’un listing

Deux familles d’actions influent sur la génération d’un fichier listing :

Les paramètres de la ligne de commandes à l’appel de ml.exe .

Une série de directives au sein du code source.

Les paramètres de la ligne de commandes qui intéressent la génération d’un fichier de listing sont /Fl ainsi que tous les /S? . Ajoutons /EP qui envoie un listing passe 1 à l’écran. Tous sont décrits dans le tableau récapitulatif des commutateurs de la ligne de commandes. Par défaut, c’est-à-dire quelles que soient les directives dans le source et si le commutateur /Fl n’est pas envoyé à ml.exe , aucun fichier listing ne sera généré.

Pour lire le tableau, il faut bien voir que certaines de ces directives vont par couples, comme par exemple .LIST/.NOLIST . Ces couples fonctionnent en flip-flop, pour déterminer des zones de listing dans laquelle le comportement sera déterminé.

Directives de gestion des listings
Directive | Effet
.LISTALL | Équivalent à .LIST + .LISTIF + .LISTMACROALL .
.LIST | Positionnée par défaut. Démarre le listing des instructions.
.NOLIST | Interdit le listing des instructions.
.XLIST | Autre forme de .NOLIST
.LISTIF | Force le listing des instructions non assemblées en cas d’assemblage conditionnel.
.TFCOND | Autre forme de .LISTIF
.NOLISTIF | Stoppe l’effet de .LISTIF . Les instructions non assemblées ne sont plus listées.
.SFCOND | Autre forme de .NOLISTIF
.NOCREF [nom[,nom..]] | Interdit le listing des noms de symboles dans la table. Possibilité de limiter cette interdiction à certains symboles dont les noms sont donnés.
.XCREF | Autre forme de .NOCREF
.CREF | Stoppe l’effet de .NOCREF (ou .XCREF ).
.LISTMACROALL | Force le listing complet de macros développées.
.LALL | Autre forme de .LISTMACROALL .
.LISTMACRO | Positionnée par défaut. Liste les instructions des macros développées qui génèrent code ou données.
.XALL | Autre forme de .LISTMACRO
.NOLISTMACRO | Interdit le listing des macros développées.
.SALL | Autre forme de .NOLISTMACRO
PAGE | Génère un saut de page.
PAGE [[nl][nc]] | Positionne les dimensions de la page à nl lignes de nc caractères.
PAGE + | Changement de section. Le N° de page repasse à 1.
TITLE texte | Fixe le titre du listing.
SUBTITLE texte | Fixe le sous-titre du listing.
SUBTTL texte | Autre forme de .SUBTITLE texte.

Il est visible que certains comportements sont commandés à la fois par un commutateur de la ligne de commandes et par une directive. Il est donc possible que surviennent des ordres contradictoires. Voici quelques règles de priorité applicables :

Sans commutateur /Fl , aucun listing ne sera généré.

Le commutateur /Sa (avec /Fl , répétons-le) rend inopérantes les directives du code source visant à interdire ou limiter le listing.

Dans le code source, .NOLIST masque les autres directives, comme .LISTMACROALL .

Les commutateurs /Sx , /Ss , /Sp , /Sl positionnent les comportements à une valeur différente de celle par défaut. Ensuite, les directives correspondantes reprennent au besoin la main.

Bien qu’il ne s’agisse pas à proprement parler de listing, citons ici la directive ECHO (ou %OUT , c’est équivalent). Elle permet d’envoyer du texte sur STDOUT , donc à priori l’écran. Ce peut être utilisé par exemple pour signaler qu’un processus d’assemblage risque d’être long, et à signaler au fur et à mesure différentes étapes de l’assemblage. Un exemple, avec une macro texte prédéfinie :

%ECHO Programme &@FileName
 ECHO par l'excellent Julius Caius Caesar
 ECHO Début de l'assemblage ...

Manipulons maintenant pour mettre un peu en pratique. Avec un fichier test.asm ne contenant pour l’instant aucune directive listing, ajoutez /Fl dans la ligne de commandes, par exemple en modifiant un fichier build.bat . Vérifiez que le commutateur de ligne de commandes /Sa n’est pas actif, ni aucun commutateur de type /S? . Un fichier listing portant le nom test.lst est créé. Remplaçons le commutateur par /Fllisting.txt ou /Fl"listing.txt" (attention, pas d’espace devant le nom du fichier). Le fichier listing créé porte maintenant le nom listing.txt .

Nous analyserons les fichiers listing un peu plus loin. Si vous y jetez un coup d’œil et si vous avez un include test.inc dans votre source, vous constatez que ce fichier est logiquement listé au moment de son inclusion.

Dans le fichier source, rajoutez la ligne include win.inc , où un autre gros fichier d’en-tête selon votre installation. Le fichier listing prend de l’embonpoint et perd par la même occasion de la lisibilité. La raison est claire, mais le phénomène deviendra gênant dans les applications Windows. Modifions :

.NOLIST
include win.inc
.LIST

Le début du listing devient plus lisible, mais la taille demeure importante, à cause de la taille des symboles. Les symboles issus de notre code sont de plus noyés dans ceux issus de win.inc . Modifions à nouveau :

.NOCREF
.NOLIST
include win.inc
.LIST
.CREF

Maintenant, tous nos symboles sont listés, mais plus ceux en provenance de win.inc .

Une dernière manipulation, avant de passer aux listes de commutateurs et de directives. Nous avons dans notre code d’essai une zone assemblée sous condition :

;UTILE EQU UTILE
…
IFDEF UTILE
         ; Partie "utile" (!!)
;        mov ax, 69
         mov ax, 60 + (3 * 3)
         cmp ax, bx
         jne @F

         mov ah, 09h
         mov dx, offset egal
         int 21h
ENDIF

En jouant sur la mise ou non en commentaire de la première ligne, nous constatons que n’est listé dans listing.txt que ce qui est effectivement assemblé. Or, dans le cadre d’un projet ou deux parties du code ne sont jamais assemblées ensemble, il sera parfois gênant de ne pouvoir produire un listing plus complet. Nous pouvons utiliser les directives .LISTIF (ou . LISTALL ) et .NOLISTIF pour modifier cet état de fait dans tout le source ou sur certaines zones. Nous verrons alors le code source des parties non assemblées, mais évidemment pas le code objet généré. Le commutateur /Sx (et /Sa ) produit un effet similaire sur l ‘ensemble du source.

5.3.2 Contenu du fichier listing

Vous pouvez utiliser pour cette découverte du fichier listing à la fois celui généré par nos manipulations précédentes ( test.lst ou listing.txt ) et le fichier sk_win.lst issu d’une application Windows et présent sur le CD-Rom. Vous aurez ainsi à disposition une application DOS 16 bits et une autre en 32 bits, sous Windows.

En cas d’erreur à l’assemblage, le fichier listing est généré autant que faire se peut. Vous trouverez un message d’erreur au-dessous de l’instruction fautive :

                     mov var1, var2
test.asm(59) : error A2070: invalid instruction operands

Supposons que tout s’est bien passé. Si nous avons positionné les options adéquates, nous avons trois grandes zones dans le fichier listing généré :

1 La sortie du préprocesseur, ou passe 1. C’est le travail de première lecture de l’assembleur, sans génération de code. Les fichiers inclus sont parcourus, les macros développées. Cette partie alourdit inutilement le listing. Il est généralement inutile de la demander par le commutateur /Sf .

2 La passe 2 (et finale) du travail du compilateur. C’est la génération du code proprement dite, listée encore de façon chronologique.

3 Une partie synthétique : les diverses tables regroupant les macros, les diverses structures définies, segments, groupes et symboles.

La section génération du code

Attention, le fichier listing est généré avec des tabulations. Il est préférable de configurer la taille de la tabulation à 8 voire plus dans votre éditeur. Nous n’avons pas ici respecté cette valeur pour des raisons de mise en page. Cette valeur de 8 est par contre trop importante pour la saisie de code profondément indenté, une valeur de 2 à 4 étant préférable.

Dans le listing vous retrouvez bien entendu tout votre code source, commentaires compris, au fur et à mesure qu’il est parcouru par l’assembleur, et en fonction des options et directives de listing. Ce source occupe la droite de la ligne d’écran. Les quatre premières colonnes, à gauche, sont réservées au code généré. Entre les deux groupes de colonnes peuvent se trouver certains symboles. Par exemple C indique des lignes, quel que soit leur contenu, hors du fichier principal, donc dans un fichier inclus :

            include resrc1.inc
               C
               C option expr32
               C option casemap:none
               C
               C ; Begin of file resrc1.h
 = 00000001          C IDI_ICON     EQU      1t
 = 00000001          C IDOK         EQU      1t
 = 00000002          C IDM_MENU     EQU      2t

Voyons le contenu des colonnes de gauche, code généré. Tout d’abord, le cas particulier : pour les equates, ou plus généralement les constantes symboliques manifestes, nous trouvons à gauche la valeur affectée, pour laquelle il n’y a bien entendu pas d’affectation mémoire, précédée du signe = :

= blibli            VALT1     TEXTEQU <blibli>
= 45                VALT2     TEXTEQU %(3*15)
= @FileName         VALT3     EQU     @FileName
= 0000              NULL      EQU     0
= 004E              VALEUR    =       78
= TEST              VALT31    TEXTEQU @FileName
= blibli            VALT4     CATSTR  VALT1 VALT2 VALT3
= MaClasse->Taille  VALT5     TEXTEQU <MaClasse-!>Taille>
= "Bonjour"         VALT6     EQU     "Bonjour"
= "Aurevoir"        VALT6     EQU     "Aurevoir"

Dans le cas général d’une ligne générant de la mémoire, code ou données, la première colonne est toujours une adresse, plus précisément un offset. Il est noté en hexadécimal, donc sur 4 signes dans un modèle 16 bits et 8 dans un modèle 32 bits. Par exemple, la première occurrence d’une directive de segment indique toujours 0000. Ensuite, l’assembleur gère cet offset :

0000                    .DATA
                        ORG 10h
0010 00000000           VARX    dword ?
...
; Code
…
0014                    .DATA
0014 000C               var1    dw   12

Nous voyons dans cet exemple que, dans le cas d’une déclaration, la mémoire réservée et initialisée est indiquée à la suite de l’offset. Il en est de même pour les chaînes de caractères. Les réservations mémoire par la directive DUP font appel à une présentation particulière :

0040   0020 [     Table1 byte  32 dup (0FFh)
        FF
       ]
0060   0040 [     Table2 dword 64 dup (?)
        00000000
       ]

Il faut bien lire dans les colonnes, par exemple 0040 0020[FF] , pour 32 octets initialisés à 255 à l’offset 64.

Pour une ligne de code ordinaire, contenant une instruction, après l’offset, nous trouvons optionnellement (commutateur /Sc ) une indication du nombre de cycles nécessaires à l’instruction. Bien entendu cette donnée n’est pas mesurée, mais prise dans une table et dépend du processeur déclaré. Donc, cette indication est sur un processeur moderne peu utile. Ensuite, c’est le code généré pour l’instruction, s’il est connu à l’assemblage :

0023   4   B8 0045      mov ax, 60 + (3 * 3)

Cette instruction est complètement définie : offset 0023h , 4 cycles sur un 8086, B8h opcode du MOV immédiat, 0045h soit 69, l’assembleur ayant calculé 60 + (3* 3) . Il n’y a pas d’espace entre 00 et 45, ce n’est pas innocent. C’est un WORD, si c’est une image de la mémoire que nous voulons représenter, c’est B8 45 00 qu’il faut écrire (little endian).

Si le code n’est entièrement déterminé à l’assemblage, mais sera résolu par le lieur, la lettre R indique ce caractère relogeable :

002C   4   BA 002A R    mov dx, offset egal

Dans ce cas, BA est l’opcode correct. 002A n’est pas l’offset de la variable egal . C’est l’offset de la variable dans la zone de données à laquelle elle appartient. Cette valeur sera calculée, avec l’ensemble des valeurs relogeables, par le lieur. Le mot segment est normalement utilisé ici pour désigner les zones de données, il entraîne de graves ambiguïtés.

De la même façon, la lettre E indique une donnée externe, ici une adresse, qui sera également résolue par le lieur :

000001F7   7m  E8 00000000 E  *  call InitCommonControls

L’astérisque * qui apparaît dans cette ligne indique du code généré par MASM. Comme ici par la directive conditionnelle .IF :

                     .IF(ax == bx)
 0026  3B C3         *      cmp    ax, bx
 0028  75 07         *      jne    @C0001
 002A  B4 09                  mov ah, 09h
 002C  BA 0016 R              mov dx, offset egal
 002 F  CD 21                  int 21h
                     .ENDIF
 0031          *@C0001:

La directive INVOKE génère beaucoup de code de ce type.

Enfin, un entier de 1 à 9 ou un signe + dans la colonne centrale indique un niveau d’imbrication dans les développements de macros. Voici un exemple, extrait de la partie passe 1 du listing (le rôle de la macro MINMAXLIST est décrit par ailleurs) :

                 C MINMAXLIST    MACRO param1, param2, args
                 C    p1 = 0
                 C    FOR p2, <args>
                 C           IF p2 GT p1
                 C               p1 = p2
                 C           ENDIF
                 C    ENDM
                 C    param1 EQU p1
                 C
                 C    p1 = 7FFFFFFFh
                 C    FOR p2, <args>
                 C           IF p2 LT p1
                 C               p1 = p2
                 C           ENDIF
                 C    ENDM
                 C    param2 EQU p1
                 C
                 C    ENDM
                 C
                 C MINMAXLIST   WM_MAXI, WM_MINI, <1,2,3>
                1C      ??0000 = 0
                2C                      ??0000 = 1
                2C                      ??0000 = 2
                2C                      ??0000 = 3
                1C      ??0000 = 7FFFFFFFh
                2C                      ??0000 = 1

La section des tables

Cette section comporte au maximum sept tables :

1 Macros ;

2 Structures et unions ;

3 Structures de champs de bits (records) ;

4 Types ;

5 Segments et groupes ;

6 Procédures et fonctions ;

7 Symboles.

Seules les 5 et 7 sont de tous les projets, les trois dernières si nous considérons qu’un main() ne fait pas de mal. Les éléments de ces tables, à l’exception de la table des segments et groupes, sont listés par ordre alphabétique.

La table des macros se contente de les lister, en précisant toutefois s’il s’agit d’une procédure, qui ne renvoie rien, ou d’une fonction, qui donc renvoie quelque chose :

Macros:

                N a m e                 Type

ArgCount . . . . . . . . . . . . . . .  Func
MINMAXLIST . . . . . . . . . . . . . .  Proc
MMOV . . . . . . . . . . . . . . . . .  Proc

La table des structures et unions indique pour chacune d’entre elles son nom et sa taille en octets, suivi de la liste des éléments avec indication pour chacun de leur offset par rapport au début de la structure et du type. Cette table peut être très utile à imprimer, pour du travail à partir de fichiers .inc mal connus :

Structures and Unions:

                N a m e                  Size
                                         Offset      Type

ABCFLOAT . . . . . . . . . . . . . . .   0000000C
  abcfA  . . . . . . . . . . . . . . .   00000000    DWord
  abcfB  . . . . . . . . . . . . . . .   00000004    DWord
  abcfC  . . . . . . . . . . . . . . .   00000008    DWord
CPINFOEXA  . . . . . . . . . . . . . .   0000011C
  MaxCharSize  . . . . . . . . . . . .   00000000    DWord
  DefaultChar  . . . . . . . . . . . .   00000004    Byte
  LeadByte . . . . . . . . . . . . . .   00000006    Byte
  UnicodeDefaultChar . . . . . . . . .   00000012    Word
  CodePage . . . . . . . . . . . . . .   00000014    DWord
  CodePageName . . . . . . . . . . . .   00000018    Byte

Pour chaque structure de champs de bits ou record, Width donne la taille en bits de la structure complète, # fields le nombre de champs dans le record.

Pour chaque champ, Shift donne l’offset en bits du LSB (bit de poids faible) du champ par rapport au LSB du record. Width est le nombre de bits du champ, Mask donne la valeur maximale du champ, Initial est la valeur initiale du champ s’il est initialisé :

Records:

        N a m e           Width         # fields
                          Shift         Width         Mask   Initial

FPOProlog  . . . . . . .  00000010      00000006
  cbFrame  . . . . . .    0000000E      00000002      C000     ?
  reserved . . . . . .    0000000D      00000001      2000     ?
  fUseBP . . . . . . .    0000000C      00000001      1000     ?
  fHasSEH  . . . . . .    0000000B      00000001      0800     ?
  cbRegs . . . . . . .    00000008      00000003      0700     ?
  cbProlog . . . . . .    00000000      00000008      00FF     ?
ImportRec  . . . . . .    00000010      00000003
  Reserved . . . . . .    00000005      0000000B      FFE0     ?
  NameType . . . . . .    00000002      00000003      001C     ?
  Type2  . . . . . . .    00000000      00000002      0003     ?

La table des types liste les types définis par TYPEDEF . Size est la taille en octets du type, Attr le type de base de la définition :

Types:

       N a m e             Size         Attr

HWINSTA  . . . . . . .     00000004     DWord
HWND . . . . . . . . .     00000004     DWord
INT64  . . . . . . . .     00000008     QWord

La liste des groupes et segments n’appelle pas de commentaire particulier. Voici un exemple pour un programme Windows :

Segments and Groups:

          N a m e         Size    Length   Align  Combine Class

CONST  . . . . . . . . . .32 Bit  0000008B DWord  Public  'CONST'  ReadOnly
FLAT . . . . . . . . . . .GROUP
_BSS . . . . . . . . . . .32 Bit  000001C0 DWord  Public  'BSS'
_DATA  . . . . . . . . . .32 Bit  00000289 DWord  Public  'DATA'
_TEXT  . . . . . . . . . .32 Bit  0000078A DWord  Public  'CODE'

Et pour un programme DOS :

Segments and Groups:

          N a m e         Size   Length  Align   Combine  Class

DGROUP . . . . . . . . . .GROUP
_DATA  . . . . . . . . . .16 Bit  0177   Word     Public  'DATA'
STACK  . . . . . . . . . .16 Bit  0100   Para     Stack   'STACK'
_TEXT  . . . . . . . . . .16 Bit  0035   Word     Public  'CODE'

La table des procédures et fonctions liste toutes les fonctions et procédures référencées par le programme, donc y compris les externes.

Procedures,  parameters and locals:

                N a m e                 Type     Value    Attr

Main . . . . . . . . . . . . . . . . .    P Near     0000      _TEXT    Length= 0035 Public

Procedures,  parameters and locals:

                N a m e                 Type     Value    Attr

AProposProc  . . . . . . . . . . . . .    P Near     00000528 _TEXT    Length= 0000004E Public STDCALL
  hDlg . . . . . . . . . . . . . . . .    DWord     bp + 00000008
  uMsg . . . . . . . . . . . . . . . .    DWord     bp + 0000000C
  wParam . . . . . . . . . . . . . . .    DWord     bp + 00000010
  lParam . . . . . . . . . . . . . . .    DWord     bp + 00000014
AbortDoc . . . . . . . . . . . . . . .    P Near     00000000 FLAT    Length= 00000000 External STDCALL
AbortPath  . . . . . . . . . . . . . .    P Near     00000000 FLAT    Length= 00000000 External STDCALL
ActivateKeyboardLayout . . . . . . . .    P Near     00000000 FLAT    Length= 00000000 External STDCALL
AddAtomA . . . . . . . . . . . . . . .    P Near     00000000 FLAT    Length= 00000000 External STDCALL
AddAtomW . . . . . . . . . . . . . . .    P Near     00000000 FLAT    Length= 00000000 External STDCALL

La table des symboles regroupe ce qui reste. Donc en particulier mélange les variables, les labels (étiquettes) et les constantes symboliques, définies généralement par les equates ou par l’assembleur lui-même. Ces dernières sont de type Number ou Text , qui justement ne sont pas réellement des types. Pour les variables, c’est un vrai nom de type qui apparaît dans cette colonne Type .

La colonne Value représente pour les constantes symboliques vraiment la valeur du symbole. Pour les variables et les labels, cette valeur est en réalité l’offset du symbole par rapport au début du segment qui le contient.

Symbols:

          N a m e          Type      Value    Attr

??0000 . . . . . . . . . . Number    0001h
@CodeSize  . . . . . . . . Number    0000h
@DataSize  . . . . . . . . Number    0000h
@Interface . . . . . . . . Number    0000h
@Model . . . . . . . . . . Number    0002h
@code  . . . . . . . . . . Text      _TEXT
@data  . . . . . . .  . .  Text      DGROUP
@fardata?  . . . . . . . . Text      FAR_BSS
@fardata . . . . . .  . .  Text      FAR_DATA
@stack . . . . . . .  . .  Text      DGROUP
NULL . . . . . . . . . . . Number    0000h
SC . . . . . . . . . . . . Byte      0160     _DATA
Table1 . . . . . . .  . .  Byte      0040     _DATA
Table2 . . . . . . . . . . DWord     0060     _DATA
UTILE  . . . . . . .  . .  Text      UTILE
VARX . . . . . . . . . .   DWord     0010     _DATA
WM_MAXI  . . . . . . . . . Number    0003h
WM_MINI  . . . . . .  . .  Number    0001h
bijor2 . . . . . . . . . . Byte      0161     _DATA
bijor  . . . . . . .  . .  Byte      0014     _DATA
debut  . . . . . . .  . .  L Near    0000     _TEXT
egal . . . . . . . .  . .  Byte      002A     _DATA
nomfichier . . . . .  . .  Byte      0031     _DATA
var1 . . . . . . . .  . .  Word      003C     _DATA
var2 . . . . . . . . . . . Word      003E     _DATA

Ce site est créé et maintenu (laborieusement) par Pierre Maurette et hébergé par 1 & 1


Logiciel - MASM - Présentation du logiciel

Vu dans ... https://www.gladir.com/SOFTWARE/MASM/presentation.htm
Fiche technique
Système d'exploitation : | DOS/Windows/OS/2
Auteur : | Microsoft
Date de publication : | 1981 à actuellement
Catégorie : | Compilateur assembleur

Sommaire

Le logiciel Macro Assembler de Microsoft est un compilateur pour le langage de programmation Assembleur 80x86 et 64 bits. Il s'agit de l'un des compilateurs assembleurs 8086 les plus ancien à avoir survécu à tous les changements d'environnement matériel et logiciels s'étant produit depuis les 40 ans dernières années. Jusqu'à la version 5.0, le compilateur était uniquement disponible pour le système d'exploitation MS-DOS. Ensuite, à partir de la version 5.1 jusqu'à la version 6.11, il était disponible pour les systèmes d'exploitation MS-DOS et OS/2. Ensuite, il fut uniquement proposé pour le système d'exploitation Windows avec l'exécutable «ML.EXE» ou «ML64».

Vu dans ... https://www.gladir.com/SOFTWARE/MASM/presentation.htm

Version

Voici les différentes versions du MASM :

Version | Année | Description
MACRO-86 | 1981 | Produit originale, inclus le M86 (prédécesseur de MASM), LINK, LIB and CREF
1.00 | 1981 | Première version officielle de MASM
1.00 | 1981 | Version proposé par IBM
1.10 | 1982 | Support des instructions du coprocesseur mathématique 8087 et du DOS 2.0 (fichier gérer par des Handle)
1.25 | 1983 | Support de l'émulation du 8087
1.27 | 1984 | Corrections de bogues mineurs
2.00 | 1984 | Version proposé par IBM, support d'instructions 80186, 80286 et 80287, ajout de directives .186, .286c, .287, .8086, .8087
3.00 | 1984 | Support des instructions du mode protégé du 80286, ajout des utilitaires MAKE, SYMDEB et MAPSYM, ajout de directive .286p.
3.01 | 1985 | Mise à jour mineurs sur les utilitaires SYMDEB et MAPSYM.
4.00 | 1985 | Ajout des utilitaires EXEMOD et EXEPACK, ajout de directives .err, .err1, .err2, .errb, .errdef, .errdif, .erre, .erridn, .errnb, .errndef et .errnz.
5.00 | 1987 | Support des instructions 386 et 387, simplification des directives de segment, support de multiples modèle de mémoire, variables communes, utilisation des mémoires d'environnement MASM, INCLUDE et TMP, aide de la ligne de commande, ajout de CodeView (CV) (remplaçant les utilitaires SYMDEB et MAPSYM) et CVPACK, ajout des directives .286, .386, .386c, .386p, .387, align, .alpha, byte, .code, comm, .const, .data, .data?, df, dosseg, dword, .errdifi, .erridni, .fardata, .fardata?, fword, ifdifi, ifidni, .model, .msfloat, qword, .seq, .stack, tbyte et word
MASM/2 | 1987 | Version proposé par IBM, version spécifique au système d'exploitation OS/2 basée sur MASM 4.00, inclut les versions liées de MASM, LINK, LIB, CREF, MAKE et EXEMOD, comprend la version DOS (CV) et la version OS/2 (CVP) de CodeView.
5.10 | 1988 | Ajout des étiquettes locales (@@, @B, @F), macro de fonctions de chaînes de caractères (CATSTR, INSTR, SIZESTR, SUBSTR), un support OS/2, ajout des utilitaires BIND, EXEHDR et IMPLIB, ajout des directives catstr, elseif, elseif1, elseif2, elseifb, elseife, elseifdef, elseifdif, elseifdifi, elseifidn, elseifidni, instr, sizestr et substr.
5.10A | 1989 | Corrections de bogues mineurs.
5.10B | 1989 | Inclus avec le Windows 3.1 DDK
6.00 | 1991 | ML au lieu de MASM, ajout du pilote de compatibilité MASM, support d'instructions 486, assemblage multi-passes, prise en charge du modèle de mémoire FLAT, prise en charge du modèle TINY (pour les fichiers .COM), meilleur traitement des macros, allongement automatique du saut conditionnel, prototypes de fonctions de langage de haut niveau et appels (INVOKE et PROTO), ajout de NMAKE (remplaçant MAKE) et de H2INC, ajout de QuickHelp (QH), ajout de PWB (Programmer's Workbench), enlève les utilitaires CREF, EXEMOD et EXEPACK, ajout de directives .486, .486p, .dosseg, echo, .exit, extern, externdef, for, forc, goto, includelib, invoke, .listall, .listif, .listmacro, .listmacroall, .no87, .nocref, .nolist, .nolistif, .nolistmacro, option, popcontext, proto, pushcontext, real4, real8, real10, repeat, sbyte, sdword, .startup, struct, subtitle, sword, textequ, typedef, union et while.
6.00B | 1992 | Correction de bogues mineurs, c'est la dernière version à avoir un pure exécutable DOS.
6.10 | 1992 | Support de COFF, Windows, utilise le DOSXNT DOS extender (exécutable DOS/Windows), enlève le support OS/2, BIND et CVP.
6.10a | 1992 | Distribution de patch, correction de bogues mineurs.
6.11 | 1993 | Support d'instructions Pentium, dernière version commerciale, ajout de directive .586, .586p et alias.
6.11a | 1994 | Distribution de patch, correction de bogues mineurs.
6.11c | 1994 | Inclus avec le Windows 95 DDK et le Windows NT 3.5 DDK.
6.11d | 1995 | Distribution de patch, correction de bogues mineurs, dernière version DOS.
6.12 | 1997 | Distribution de patch, support du Pentium Pro et des instructions MMX, ajout des directives .686, .686p et .mmx.
6.13 | 1997 | Distribution de patch, support d'instructions K3D d'AMD, ajout de la directive .k3d.
6.14 | 1999 | Distribution de patch, support d'instructions SSE, ajout des directives oword et .xmm.
6.15 | 2000 | Inclus avec le Visual Studio 6.0 Processor Pack, support d'instructions SSE2.
7.00 | 2002 | Inclus avec le Visual Studio .NET 2002, le COFF est le format d'objet par défaut, le fichier «ML.ERR» est enlevé, les messages textes sont intégrés dans le ML.EXE.
7.10 | 2003 | Inclus avec le Visual Studio .NET 2003.
8.00 | 2005 | Inclus avec le Visual Studio 2005, support des instructions SSE3, ajout de l'exécutable ML64.
9.00 | 2008 | Inclus avec le Visual Studio 2008, support des instructions SSSE3, SSE4.1 et SSE4.2.
10.00 | 2010 | Inclus avec le Visual Studio 2010, support des instructions AVX et x64, enlève le support d'assemblage 16 bits.

Concurrent

Les concurrents du MASM sont FASM (Flat Assembler) de Tomasz Grysztar, gas (GNU Assembler), NASM (Netwide Assembler), TASM de Borland et le Yasm.

Dernière mise à jour : Dimanche, le 3 juillet 2016


Full Listing.htm

Full Listing

ALIGN ASSUME
.BREAK
.CODE
COMMENT
.CONST
.CONTINUE
.CREF
.NOCREF
.DATA
.DATA?
Data Types
ECHO
END
ENDM
EQU
TEXTEQU
.ERR
.ERRB
.ERRNB
.ERRDEF
.ERRNDEF
.ERRDIF
.ERRIDN
.ERRE
.ERRNZ
EXITM
EXTERNDEF
EXTERN
FOR
FORC
GOTO
IF
.IF
[ELSE]IF
[ELSE]IFE
[ELSE]IFB
[ELSE]IFNB
[ELSE]IFDEF
[ELSE]IFNDEF
[ELSE]IFDIF[I]
[ELSE]IFIDN[I]
INCLUDE
INCLUDELIB
INVOKE
LABEL
.LIST
.LISTALL
.LISTIF
.LISTMACRO
.LISTMACROALL
LOCAL
MACRO LOCAL
MACRO
.MODEL
.NOLIST
.NOLISTIF
.NOLISTMACRO
OPTION LJMP
OPTION NOLJMP
OPTION DOTNAME
OPTION NODOTNAME
OPTION READONLY
OPTION NOREADONLY
OPTION SCOPED
OPTION NOSCOPED
OPTION LANGUAGE
OPTION CASEMAP
OPTION EMULATOR
OPTION NOEMULATOR
OPTION OFFSET
OPTION PROLOGUE
OPTION EPILOGUE
OPTION NOKEYWORD
OPTION EXPR16
OPTION EXPR32

OPTION SEGMENT OPTION NOSIGNEXTEND
OPTION PROC
ORG
PROC
PROTO
PUBLIC
PURGE
PUSHCONTEXT
POPCONTEXT
.RADIX
RECORD
REPEAT
.REPEAT
STRUCT
.TFCOND
TYPEDEF
TYPEDEF Directive
UNION
USES
WHILE
.WHILE
label:
Alternate Quotes
Literal Text
Character Negation
text comment
Macro text comment
Macro Expression
&parameter&
DUP
HIGH
LOW
HIGHWORD
LOWWORD
LENGTHOF
SIZEOF
LENGTH
SIZE
MASK
OFFSET
LROFFSET
PTR
SHORT
THIS
TYPE
OPATTR
WIDTH
CATSTR
INSTR
SIZESTR
SUBSTR
Local Code Labels
Line Continuation
Name Assignment
Location Counter $
Data Initialisation ?
Radix Specifiers
Logical Operators
Relational Operators
Macro Function ArgI
Macro Function Reverse Ordering
Register Summary
Processor Flags
Stack of 80-bit Data Registers
Comparison run-time operators
VARARG (Macro)
VARARG (Proc)
Calling Conventions
Memory model
.MODEL directive
Flat memory model
Nested Macros


MACRO LOCAL.htm

@macros internes Writed by J2M

@@ | Définit un label de code avec @B et @F
@B | Position du précédent label @@
@F | Position du prochain label @@
@Time | Heure systéme au format 24 heures hh:mm:ss Ex.. % ECHO Assembled the @Date at @Time by J2M
@Date | Date systéme au format mm/jj/an Ex.. ci-dessus
@Version | Exemple: 610 sous MASM 6.1 Ex.. % ECHO @Version
Echo | Shown d'un message lors de la compilation Ex.. Echo "compile des includes"
% Echo | Shown d'un message et execution des macros du type interne comme @Time , @date Ex.. % ECHO Assembled the @Date
Title | Définit le titre du listing
SubTiltle | Définit le sous-titre du listing (Idem à SUBTTL)


BREAK.htm

.BREAK

Syntax:

.BREAK [.IF condition]

Description

Terminates the nearest enclosing .WHILE or .REPEAT directive. If
the .IF condition is present, the loop is terminated only if the
value of <condition> is true.


CODE.htm

.CODE

Syntax: .CODE [name]

Description

Starts a code segment (with segment name <name>, if given) and ends the previous segment, if any. Aligns the segment on a 2-byte boundary (.8086, .186, .286) or a 4-byte boundary (.386, .486). The .MODEL directive must precede this directive.

Segment name <name> is an optional parameter that overrides the default segment name. If <name> is not specified, the assembler generates a segment called _TEXT (tiny, small, compact, and flat models) or <modulename>_TEXT (medium, large, and huge models).


CONST.htm

.CONST

Syntax:

.CONST

Description

Starts a constant data segment (called CONST in DGROUP) and ends the previous segment, if any. For consistency with other languages, this segment should contain all strings, real numbers, and other constant data accessed by a high-level language. The CONST segment has the READONLY attribute.

The .MODEL directive must precede this directive.


CONTINUE.htm

.CONTINUE

Syntax:

.CONTINUE [.IF condition]

Description

Skips to the code that evaluates the loop condition of the nearest enclosing loop. If the .IF condition clause is present, the skip will occur only if the value of <condition> is true.

This directive is valid only within a .REPEAT or .WHILE block.


CREF.htm

.CREF

Syntax:

.CREF

.NOCREF [name[, name]...]

Description

The .CREF directive enables collection of information for all symbols. These symbols will appear in the symbol table at the end of a listing file. If you generate a source-browser file with the /FR or /Fr command-line option, the browser will be able to access cross-reference information for these symbols. This directive is in effect by default.

The .NOCREF directive turns off cross-referencing for all symbols. Any references to symbols while .NOCREF is in effect are omitted from the cross-reference listing. If the <name> parameter is given with this directive, only the cross-reference information for the symbols specified by <name> is omitted.

.XCREF is a synonym for .NOCREF and is provided for compatibility with previous versions of the assembler.


DATA.htm

.DATA

Syntax:

 .DATA

.DATA?

Description

The .DATA directive starts the initialized data segment (with segment name _DATA) and ends the previous segment, if any. The .DATA segment should contain all global data that have initial values.

The .DATA? directive starts the uninitialized data segment (with segment name _BSS) and ends the previous segment, if any. Place all uninitialized data in the .DATA? segment.

Although uninitialized data can be placed in the .DATA segment by declaring data with the ? operator, use the .DATA? directive to minimize the size of the .EXE file and to maximize compatibility with other languages.

The .MODEL directive must precede these directives. It generates a GROUP statement that places _DATA and _BSS in DGROUP.


ERR.htm

.ERR

Syntax:

.ERR [message]

Description

Generates an A2052 error message when assembled. Generally, this directive occurs in a conditional-assembly block and is used to indicate some error condition discovered at assembly time. This directive can be useful for verifying that the program assembled correctly and that user-defined bounds were not exceeded.

If <message> is given, it will be displayed with the standard assembler error messages. The <message> parameter is any text item


ERRB.htm

.ERRB

Syntax:

 .ERRB <textitem> [,message]

.ERRNB <textitem> [,message]

Description

The .ERRB directive generates an A2057 error if <textitem> is blank. The .ERRNB directive generates an A2058 error if <textitem> is not blank.

These directives are usually used within macro definitions; a macro parameter is replaced by an empty string if you call the macro and do not give a corresponding argument. These directives let you write macros that generate an assembly-time error if the wrong number of arguments is used in the macro call. However, the :REQ parameter attribute or the variable argument feature often provides the same functionality in a more straightforward way.

Parameter Description

textitem Item to be tested, any text item.

message Programmer-supplied error message, any text item.


ERRDEF.htm

.ERRDEF

Syntax:

.ERRDEF name [,message]

.ERRNDEF name [,message]

Description

The .ERRDEF directive generates an A2056 error message if <name> is a previously defined symbol. The .ERRNDEF directive generates an A2055 error message if <name> has not been previously defined.

One of the most common uses of the .ERRNDEF directive is to ensure that a symbol has been defined before you attempt to use it. This situation can occur if the source code depends on the command-line /D option or the Macro Assembler Global Options dialog box to define a symbol.

If <message> is given, it will be displayed with the standard assembler error messages. The <message> parameter is any text item.


ERRDIF.htm

.ERRDIF

Syntax:

 .ERRDIF[I] <textitem1>, <textitem2> [,message]

.ERRIDN[I] <textitem1>, <textitem2> [,message]

Description

The .ERRDIF directive generates an A2060 error if <textitem1> and <textitem2> are different. .ERRIDN generates an A2059 error if the arguments are identical. These directives are commonly used inside macros to test for bad values passed as parameters. The .ERRDIFI and .ERRIDNI directives act the same as the .ERRDIF and .ERRIDN directives but perform case-insensitive comparisons.

The <textitem1> and <textitem2> parameters are text items.

If <message> is given, it will be displayed with the standard assembler error messages. The <message> parameter is any text item.


ERRE.htm

.ERRE

Syntax:

.ERRE expression [,message]

.ERRNZ expression [,message]

Description

Tests value of <expression> and generates an error depending on the resulting value. The .ERRE directive generates an A2053 error if <expression> evaluates to false (zero). .ERRNZ generates an A2054 error if <expression> evaluates to true (nonzero). If <message> is given, it will be displayed with the standard assembler error message.

Parameter Description

expression Expression that evaluates to true, false, or a numeric constant. The expression cannot contain forward references.

message Programmer-supplied error message, any text item.


Runtime.IF.htm

.IF

Syntax:

 .IF condition
ifstatements
[.ELSEIF] condition
elseifstatements
[.ELSE]
elsestatements
.ENDIF

For "condition" see Comparison run-time operators

Description

Used for clear coding of common control-flow blocks. Generates comparison and conditional jump instructions so that if <condition> is true, the processor executes the instructions following .IF until the next .ELSEIF, .ELSE, or .ENDIF. .IF statements can be nested.

The .ELSEIF statement is used to create a code block that is executed if the preceding .IF and .ELSEIF conditions are false, and the current .ELSEIF condition is true. There can be several .ELSEIF blocks within a .IF block. The .ELSEIF statement performs the same function as a .IF inside a .ELSE but does not create another nesting level of .IFs.

.ELSE specifies an alternate code block if the matching .IF and previous .ELSEIF expressions are false.

.ENDIF closes the current .IF, .ELSEIF, or .ELSE code block. The assembler optimizes to get the best possible code. For example,

.IF ax==0
performs the comparison with:
or ax,ax
which is more efficient than:
cmp ax, 0


LIST.htm

.LIST

Syntax:

 .LIST

Description

Enables listing of all source statements to the .LST file. The .LST file must first be enabled with a PWB MASM option or the /Fl command-line option. This directive is in effect by default.


LISTALL.htm

.LISTALL

Syntax:

 .LISTALL

Description

Enables listing of all statements to the .LST file. The .LST file must first be enabled with a PWB MASM option or the /Fl command-line option. This directive is equivalent to the combination of the .LIST, .LISTIF, and .LISTMACROALL directives.


LISTIF.htm

.LISTIF

Syntax:

 .LISTIF

Description

Enables listing of all statements in conditional blocks, even those in false blocks. This directive is in effect by default. The .LFCOND directive is a synonym of .LISTIF and is included for compatibility with previous versions of the assembler.


LISTMACRO.htm

.LISTMACRO

Syntax:

.LISTMACRO

Description

Enables an assembly listing file that includes macro expansion statements that generate code or data. Comments, equates, and segment definitions are not listed. This directive is in effect by default. The .LFCOND directive is a synonym of .LISTMACRO and is included for compatibility with previous versions of the assembler.


LISTMACROALL.htm

.LISTMACROALL

Syntax:

 .LISTMACROALL

Description

Enables listing of all source statements in a macro expansion, including normal comments but excluding macro comments. The .LALL directive is a synonym of .LISTMACROALL and is included for compatibility with previous versions of the assembler.


MODEL.htm

.MODEL

Syntax:

.MODEL memorymodel [,langtype] [,ostype] [,stackoption]

Description

Initializes the program memory model. Must be placed at the beginning of the source file before any other simplified segment directive. Generates ASSUME and GROUP statements used by the specified memory model. Also creates the predefined equates for the various simplified segments. The .MODEL directive can occur only once in a program.

If you use the langtype argument with .MODEL, nested procedures are not allowed.

Parameter Description

Mmemory model TINY, SMALL, COMPACT, MEDIUM, LARGE, HUGE, or FLAT. If you are writing an assembler routine for a high-level language, this option should match the memory model used by the compiler or interpreter. FLAT is valid only in .386 or .486 mode. You must use the /AT command-line option or /TINY linker option to assemble tiny-model programs.

langtype Any language type. Instructs the assembler to follow the naming, calling, and return conventions for the indicated language. This affects the PUBLIC, EXTERN, PROC, PROTO, and INVOKE directives.

ostype OS_DOS is the only option currently supported and is the default.

stackoption NEARSTACK (if SS equals DS) or FARSTACK (if SS is not equal to DS). NEARSTACK is the default. The stack is not part of DGROUP with the FARSTACK option. This affects the code generated by the .STARTUP directive.


MODEL directive.htm

.MODEL directive

.MODEL directive

Description

If the .MODEL directive is preceded by the .386 or .486 directive (or their privileged counterparts), the assembler uses 32-bit segments. If the .386 or .486 directive follows the .MODEL directive, the default 16-bit segments are used. The flat memory model uses 32-bit segments and must be preceded by a .386 or .486 directive.

32-bit segments are available only on the 80386/486 processors.


NOLIST.htm

.NOLIST

Syntax:

.NOLIST

Description

Suppresses program listing. Use in conjunction with .LIST to prevent a particular section of a source file from being listed. The .XLIST directive is a synonym for .NOLIST and is included for compatibility with previous versions of the assembler.


NOLISTIF.htm

.NOLISTIF

Syntax:

.NOLISTIF

Description

Turns off the listing of the lines in subsequent conditional blocks whose condition is false. The .SFCOND directive is a synonym for .NOLISTIF and is included for compatibility with previous versions of the assembler.


NOLISTMACRO.htm

.NOLISTMACRO

Syntax:

.NOLISTMACRO

Description

Suppresses listing of macro expansions in a listing file. Macro calls are listed, but the source code generated by the call is not. The .SALL directive is a synonym for .NOLISTMACRO and is included for compatibility with previous versions of the assembler.


RADIX.htm

.RADIX

Syntax:

 .RADIX expression

Description

Sets the default radix (base) for integer constants to the value of <expression>. The default radix at the start of assembly is 10.

The .RADIX directive does not affect floating-point constants or numbers that have explicit radix overrride tags:

Tag Base
H hexadecimal
O or Q octal
T decimal
Y binary
R floating point

With a radix of 10 or below, you can use the characters B (b) and D (d) as the radix override characters for base 2 and base 10, respectively.

The <expression> must evaluate to a decimal number in the range 2 to 16 and cannot contain forward references.

If the current radix in your code is greater than 10 decimal, MASM 6.1 allows the radix specifiers B (binary) and D (decimal) only in compatibility mode. You must change B to Y for binary, and D to T for decimal, since both B and D are legitimate hexadecimal values, making numbers such as 12D ambiguous. If you want to keep B and D as radix specifiers when the current radix is greater than 10, you must specify OPTION M510.


REPEAT.htm

REPEAT

Syntax:

 REPEAT expression
statements
ENDM

Description

Assembles a block of statements <expression> times. REPT is a synonym for REPEAT and is included for compatibility with previous versions of the assembler.

The <expression> parameter must evaluate to a numeric constant. This constant is evaluated during the first pass. The <statements> are any valid assembler statements.


TFCOND.htm

.TFCOND

Syntax:

.TFCOND

Description

Toggles the state of the assembler between .LISTIF and .NOLISTIF, determining whether or not false conditional blocks are included in assembler listings.


WHILE.htm

WHILE

Syntax:

 WHILE expression
statements
ENDM

Description

Marks a block of statements to be assembled repeatedly until <expression> is false (zero). The <expression> is a constant expression whose value is computed at assembly time.


ALIGN.htm

ALIGN

Syntax:

ALIGN [number]

Description

ALIGN aligns the next variable or instruction on an offset address that is a multiple of [expression]. The [number] parameter must be a power of 2 [1,2,4,8,...] less than or equal to the alignment of the current segment. If [number] is omitted, the alignment is determined by the align field of the preceding SEGMENT directive.

In a segment containing no instructions, the assembler pads each skipped byte with nulls [00h]. In a code segment, the assembler inserts a no-operation sequence [not necessarily NOP instructions] to fill the gap.

This directive is useful for optimizing data and instruction fetches on processors with 16 or 32 bit data paths.

EVEN is a synonym for ALIGN 2.


ASSUME.htm

ASSUME

Syntax:

 ASSUME segregister:seglocation [, segregister:seglocation]...

ASSUME dataregister:qualifiedtype
[, dataregister:qualifiedtype]...

ASSUME register:ERROR [, register:ERROR]...

ASSUME [register:]NOTHING [, register:NOTHING]...

Description

A general-purpose directive that allows the assembler to determine offsets, select the correct segment register, and verify certain register use assumptions at assembly.

The "ASSUME segregister:seglocation" syntax is used to inform the assembler of the current value of <segregister>. The assembler uses this information to calculate offsets correctly and to guard against segment selection errors. This directive does not generate code to change the value of <segregister>. The ASSUME directive is not necessary for the CS register, since CS is assumed to the current segment or group automatically. The <seglocation> can be any segment or group name, or an equivalent expression.

The "ASSUME dataregister:type" syntax informs the assembler that <dataregister> is subject to the constraints of <type>. If an assumed register is used incorrectly, the assembler generates an error. The <type> parameter must be the same size as <dataregister>.

ASSUME bx:WORD mov ax, [bx] ; Error--cannot dereference non-pointer
ASSUME bx:PTR WORD mov [bx], 10h ;
Assumes operand size is WORD mov [bx], al ;Error--cannot move byte into word memory
ASSUME al:WORD ; Error--al is only byte-sized
ASSUME bx:BYTE ; Error--bx is word-sized

The ASSUME directive can include ERROR, FLAT, or register:type. MASM 6.1 issues a warning when you specify ASSUME values for CS other than the current segment or group.

The "ASSUME register:ERROR" syntax causes the assembler to generate an error if <register> is later used explictly or implicitly. The OPATTR, .TYPE, and TYPE directives do not cause errors when referring to registers assumed to ERROR.

The "ASSUME register:NOTHING" syntax causes the assembler to remove all assumptions about <register>. ASSUME NOTHING removes all assumptions about all registers.

Use an ASSUME statement each time you load a known value into a segment register. Although not required, the ASSUME directive helps the assembler safeguard against segment selection errors and determine offsets. You may need to use instructions to initialize segment registers properly at run time.

If you use the ASSUME directive to set assumptions about a data register, it will override any assumptions for its subregisters. For example, ASSUME EDX:DGROUP will override assumptions for DL, DH, and DX.

Parameter Description

seg register CS, DS, ES, FS, GS, or SS. The assembler automatically maintains assumptions for the CS segment register.

seg location A segment address, another segment register, a group, or FLAT. You can find the segment address of a label by using the SEG operator. FLAT is the label of the single FLAT segment.

data register Any byte, word, or 32-bit register.

qualified type Any qualified type that will fit in <dataregister>.

register Any segment or data register.


Ascii Characters.htm

Ascii Characters

0 _ nul 16 _ dle ^P 32 48 0 64 @ 80 P 96 ` 112 p
1 _ soh ^A 17 _ dc1 ^Q 33 ! 49 1 65 A 81 Q 97 a 113 q
2 _ stx ^B 18 _ dc2 ^R 34 " 50 2 66 B 82 R 98 b 114 r
3 _ etx ^C 19 _ dc3 ^S 35 # 51 3 67 C 83 S 99 c 115 s
4 _ eot ^D 20 ¶ dc4 ^T 36 $ 52 4 68 D 84 T 100 d 116 t
5 _ enq ^E 21 § nak ^U 37 % 53 5 69 E 85 U 101 e 117 u
6 _ ack ^F 22 _ syn ^V 38 & 54 6 70 F 86 V 102 f 118 v
7 _ bel ^G 23 _ etb ^W 39 ' 55 7 71 G 87 W 103 g 119 w
8 _ bs ^H 24 _ can ^X 40 ( 56 8 72 H 88 X 104 h 120 x
9 _ tab ^I 25 _ em ^Y 41 ) 57 9 73 I 89 Y 105 i 121 y
10 _ lf ^J 26 _ eof ^Z 42 * 58 : 74 J 90 Z 106 j 122 z
11 _ vt ^K 27 _ esc ^[ 43 + 59 ; 75 K 91 [ 107 k 123 {
12 _ np ^L 28 _ fs ^\ 44 , 60 < 76 L 92 \ 108 l 124 |
13 _ cr ^M 29 _ gs ^] 45 - 61 = 77 M 93 ] 109 m 125 }
14 _ so ^N 30 - rs ^^ 46 . 62 > 78 N 94 ^ 110 n 126 ~
15 _ ¤ si ^O 31 us ^_ 47 / 63 ? 79 O 95 _ 111 o 127 

The extended ascii characters generally do not display correctly with windows fonts.

128 Ç 144 É 160 á 176 _ 192 + 208 - 224 _ 240 _
129 ü 145 æ 161 í 177 _ 193 - 209 - 225 ß 241 ±
130 é 146 Æ 162 ó 178 _ 194 - 210 - 226 _ 242 _
131 â 147 ô 163 ú 179 ¦ 195 + 211 + 227 ¶ 243 _
132 ä 148 ö 164 ñ 180 ¦ 196 - 212 + 228 _ 244 _
133 à 149 ò 165 Ñ 181 ¦ 197 + 213 + 229 _ 245 _
134 å 150 û 166 ª 182 ¦ 198 ¦ 214 + 230 µ 246 ÷
135 ç 151 ù 167 º 183 + 199 ¦ 215 + 231 _ 247 _
136 ê 152 ÿ 168 ¿ 184 + 200 + 216 + 232 _ 248 °
137 ë 153 Ö 169 _ 185 ¦ 201 + 217 + 233 _ 249 •
138 è 154 Ü 170 ¬ 186 ¦ 202 - 218 + 234 _ 250 ·
139 ï 155 ¢ 171 ½ 187 + 203 - 219 _ 235 _ 251 _
140 î 156 £ 172 ¼ 188 + 204 ¦ 220 _ 236 _ 252 n
141 ì 157 ¥ 173 ¡ 189 + 205 - 221 ¦ 237 _ 253 ²
142 Ä 158 P 174 « 190 + 206 + 222 _ 238 _ 254 _
143 Å 159 ƒ 175 » 191 + 207 - 223 _ 239 _ 255


CATSTR.htm

CATSTR

Syntax: @CatStr(string[, string...])

name CATSTR [textitem[, textitem...]]

Description

The @CatStr macro function concatenates one or more text items. The result can be used anywhere a text item is appropriate. The @CatStr function will not expand macros or expressions unless you use the expression operator (%).

The CATSTR directive concatenates strings and assigns the result to <name>. These two lines are equivalent:

language TEXTEQU @CatStr (<Quick>, <Pascal>)
language CATSTR <Quick>, <Pascal>

The <name> is a unique symbolic name, <string> is a text string, and <textitem> is a text item.


COMMENT.htm

COMMENT

Syntax:

COMMENT delimiter [text]
[text]
[text] delimiter [text]

Description

Ignores all text between delimiters or on the same line as a delimiter. The two comment delimiters can be on the same or different physical lines.

In the following code segment, the text inside the asterisks and the MOV instruction are ignored:

COMMENT * This text is ignored
by the assembler * mov ax, 10h

Parameter Description

delimiter First nonblank character following the COMMENT directive
text All text up to and including the line containing the next occurrence of the delimiter.


Calling Conventions.htm

Calling Conventions

C SYSCALL STDCALL BASIC FORTRAN PASCAL
+-------+-------+-------+-------+-------+-------+
Leading Underscore | X | | X | | | |
|-------+-------+-------+-------+-------+-------|
Capitalize All | | | | X | X | X |
|-------+-------+-------+-------+-------+-------|
Arguments Left to Right | | | | X | X | X |
|-------+-------+-------+-------+-------+-------|
Arguments Right to Left | X | X | X | | | |
|-------+-------+-------+-------+-------+-------|
Caller Stack Cleanup | X | | * | | | |
|-------+-------+-------+-------+-------+-------|
BP Saved | | | | X | X | X |
|-------+-------+-------+-------+-------+-------|
:VARARG Allowed | X | X | X | | | |
+-------+-------+-------+-------+-------+-------+

* The STDCALL language type uses caller stack cleanup if the :VARARG parameter is used. Otherwise, the called routine must clean up the stack.

The language type (langtype) determines the naming and calling conventions used by the assembler. This allows you to share code and data with modules written with other languages. Set the language type with the .MODEL or OPTION LANGTYPE: directives or with the /G<x> command-line option. Several directives allow you to specify a langtype parameter to temporarily override the language type.

You can use the /H command-line option to limit the length of names sent to the object file. Use this option to work with languages that limit the maximum length of identifiers.


Character Negation.htm

Character_negation

Syntax:

!character

Description

Treats <character> as a literal character rather than as an operator or a symbol. Used with special characters (<, >, ", ', %, ;, and comma) when the usual assembly language meaning of the character must be suppressed. A double exclamation point (!!) is treated as a single exclamation point. The escape character does not apply to strings in quotation marks or to backslashes at the end of a line.

For example:

<I!'m afraid I can!'t do that!!> = I'm afraid I can't do that!

<20!% !> 15!%> = 20% > 15%


Command Line Tools.htm

Command Line Tools


Comparison run-time operators.htm

Comparison run-time operators

Operator Meaning

== Equal
!= Not equal
> Greater than
>= Greater than or equal to
< Less than
<= Less than or equal to
& Bit test (format: expression & bitnumber)
! Logical NOT
&& Logical AND
|| Logical OR

CARRY? Carry bit set
OVERFLOW? Overflow bit set
PARITY? Parity bit set
SIGN? Sign bit set
ZERO? Zero bit set

The comparison run-time operators are used to make comparisons between variables, registers, and constants as the program is being executed. Use these operators to give conditions for conditional-control directives (.IF, .UNTIL, .WHILE). These operators can be combined with other run- time operators and parentheses to form complex conditions.

The conditional-control directives (.IF, .UNTIL, .WHILE) can also check the state of processor flags. The CARRY?, OVERFLOW?, PARITY?, SIGN?, and ZERO? flags can be used directly in a C-style expression.

For example:

.IF !PARITY? || ( AX == 0 )
;Execute body of block if parity
;flag is clear or if the AX
;register is zero
.ENDIF

Note: The expression is evaluated from left to right, so in this example, the state of the parity flag is checked before the AX comparison.


Conditional Assembly.htm

Conditional Assembly


DUMPBIN Options.htm

DUMPBIN Options

usage: DUMPBIN [options] [files]

Options

/ALL
/ARCH
/ARCHIVEMEMBERS
/DEPENDENTS
/DIRECTIVES
/DISASM
/EXPORTS
/FPO
/HEADERS
/IMPORTS
/LINENUMBERS
/LINKERMEMBER[:{1|2}]
/LOADCONFIG
/OUT:filename
/PDATA
/RAWDATA[:{NONE|BYTES|SHORTS|LONGS}[,#]]
/RELOCATIONS
/SECTION:name
/SUMMARY
/SYMBOLS

The DUMPBIN command line options are listed below. Some of the output each option provides is also listed.

/ALL Displays all available information except code disassembly. Use the /DISASM option to display disassembly. You can use /RAWDATA:NONE with the /ALL option to omit the raw binary details of the file.

Because the /ALL option is simply a combination of all the other options, an example is not needed.

/ARCHIVEMEMBERS Displays minimal information about member objects in a library.

The size of the output file depends on the number of object modules in the library. The following is part of the output from the Scrnsave.lib file:

Archive member name at 582: /0 ..\..\common\retail\scrnsave.obj
2FF359CC time/date Thu Jun 29 18:56:28 1995
uid
gid
100666 mode
214A size
correct header end

/DISASM Displays disassembly of code sections, using symbols if present in the file.

The following is part of the disassembly code from the Lib.exe file:

00401000: 8B 44 24 08 mov eax,dword ptr [esp+8]
00401004: 68 00 20 40 00 push 402000h
00401009: 8B 4C 24 08 mov ecx,dword ptr [esp+8]
0040100D: 50 push eax
0040100E: 51 push ecx
0040100F: E8 0C 00 00 00 call 00401020
00401014: 33 C0 xor eax,eax
00401016: C3 ret
00401017: CC int 3

/EXPORTS Displays all definitions exported from an executable file or DLL.

MFC40.DLL produces the following export information:

Section contains the following Exports for MFC40.DLL

0 characteristics
30733286 time date stamp Wed Oct 04 18:19:02 1995
0.00 version
1 ordinal base
5782 number of functions
4 number of names
ordinal hint name
2 0 DllCanUnloadNow (00096182)
1 1 DllGetClassObject (0009611E)
3 2 DllRegisterServer (000961DB)
4 3 DllUnregisterServer (00096242)

/FPO Displays frame pointer optimization (FPO) records.

One of the MFC libraries, Nafxis.lib, provided us with some examples of frame pointer optimization records:

FPO Data (1)
Use Has Frame
Address Proc Size Locals Prolog BP SEH Type Params
00000000 9 0 0 N N fpo 0
FPO Data (1)
Use Has Frame
Address Proc Size Locals Prolog BP SEH Type Params
00000000 11 0 0 N N fpo C
FPO Data (1)
Use Has Frame
Address Proc Size Locals Prolog BP SEH Type Params
00000000 3 0 0 N N fpo 0

/HEADERS Displays the file header and the header for each section. When used with a library, it displays the header for each member object.

This information was displayed from the Resource Compiler, Rc.exe:

FILE HEADER VALUES
14C machine (i386)
6 number of sections
306F7A22 time date stamp Sun Oct 01 22:35:30 1995
0 file pointer to symbol table
1D1 number of symbols
E0 size of optional header
302 characteristics
Executable
32 bit word machine
Debug information stripped
OPTIONAL HEADER VALUES
10B magic #
2.60 linker version
1E00 size of code
1E00 size of initialized data
0 size of uninitialized data
1144 address of entry point
1000 base of code
3000 base of data
----- new -----
2BB0000 image base
1000 section alignment
200 file alignment
3 subsystem (Windows CUI)
4.00 operating system version
4.00 image version
3.50 subsystem version
8000 size of image
400 size of headers
62C8 checksum
100000 size of stack reserve
1000 size of stack commit
100000 size of heap reserve
1000 size of heap commit
0 [ 0] address [size] of Export Directory
5000 [ 3C] address [size] of Import Directory
6000 [ 394] address [size] of Resource Directory
0 [ 0] address [size] of Exception Directory
0 [ 0] address [size] of Security Directory
7000 [ 21C] address [size] of Base Relocation Directory
3030 [ 38] address [size] of Debug Directory
0 [ 0] address [size] of Description Directory
0 [ 0] address [size] of Special Directory
0 [ 0] address [size] of Thread Storage Directory
0 [ 0] address [size] of Load Configuration Directory
268 [ 44] address [size] of Bound Import Directory
50A0 [ 64] address [size] of Import Address Table Directory
0 [ 0] address [size] of Reserved Directory
0 [ 0] address [size] of Reserved Directory
0 [ 0] address [size] of Reserved Directory
SECTION HEADER #1
.text name
1D24 virtual size
1000 virtual address
1E00 size of raw data
400 file pointer to raw data
0 file pointer to relocation table
3C20 file pointer to line numbers
0 number of relocations
37E number of line numbers
60000020 flags
Code
(no align specified)
Execute Read

/IMPORTS Displays all definitions imported to an executable file or DLL.

The output displayed here is similar to the /EXPORTS output.

/LINENUMBERS Displays COFF line numbers. Line numbers exist in an object file if it was compiled with the Program Database (/Zi), C7 Compatible (/Z7), or Line Numbers Only (/Zd) switches. An executable file or DLL contains COFF line numbers if it was linked with the Generate Debug Info (/DEBUG) and COFF Format (/DEBUGTYPE:COFF) options.

An application generated using AppWizard displays line information data such as the following:

LINENUMBERS #1
1E90 13 1ECD 13 1EF7 13 1F16 13 1F31 15
1F46 15 1F61 24 1F9A 27 1FD0 2A 2001 2B

/LINKERMEMBER[:{1|2}] Displays public symbols defined in a library. Specify the 1 argument to display symbols in object order, along with their offsets. Specify the 2 argument to display offsets and index numbers of objects, and then list the symbols in alphabetical order, along with the object index for each. To get both outputs, specify /LINKERMEMBER without the number argument.

Winmmm.lib, the Windows Multimedia library, was used to get the following sample of DUMPBIN output.

Archive member name at 8: /
2FB537E1 time/date Sat May 13 15:51:13 1995
uid
gid
0 mode
2864 size
correct header end
391 public symbols
556C _CloseDriver@12
58A0 _DefDriverProc@20
5BDC _DriverCallback@28
5F1C _DrvGetModuleHandle@4
626A _GetDriverModuleHandle@4
65C4 _NotifyCallbackData@20
6914 _OpenDriver@12
6C44 _PlaySound@12
6F70 _PlaySoundA@12
72A0 _PlaySoundW@12

/OUT:filename Specifies a filename for the output. By default, DUMPBIN displays the information to standard output.

/RAWDATA[:{BYTES|SHORTS|LONGS|NONE}[,number]] Displays the raw contents of each section in the file. The arguments control the format of the display, as shown below:

Argument Result
BYTES The default. Contents are displayed in hexadecimal bytes,
and also as ASCII characters if they have a printed
representation.
SHORTS Contents are displayed as hexadecimal words.
LONGS Contents are displayed as hexadecimal longwords.
NONE Raw data is suppressed. This argument is useful to control
the output of /ALL.
number Displayed lines are set to a width that holds <number> values
per line.

The information generated with this option is quite large, this is a small sample of output from an AppWizard application using the LONGS format:

RAW DATA #1
00000000 53EC8B55 00A15756 | E9004058 00000000 U[ASCII 239]_SVW[ASCII
237].|X@._...._
00000010 C95B5E5F EC8B55C3 | 5304EC83 4D895756 _^[++U[ASCII
239]_|[ASCII 226]_.SVW[ASCII 235]M_
00000020 3058B8FC 00E90040 | 5F000000 C3C95B5E n+X0@._.|..._^[++_

/RELOCATIONS Displays any relocations in the object or image.

Below is a small portion of the relocation output obtained from an AppWizard application:

BASE RELOCATIONS #6
1000 virtual address, B0 SizeOfBlock
7 HIGHLOW
22 HIGHLOW
36 HIGHLOW
67 HIGHLOW
89 HIGHLOW

/SECTION:section Restricts the output to information on the specified section.

/SUMMARY Displays minimal information about sections, including total size. This option is the default if no other option is specified.

Microsoft (R) COFF Binary File Dumper Version 3.00.5270
Copyright (C) Microsoft Corp 1992-1995. All rights reserved.
Dump of file tracer.exe
File Type: EXECUTABLE IMAGE
Summary
1000 .data
1000 .idata
1000 .rdata
1000 .reloc
1000 .rsrc
1000 .text

/SYMBOLS Displays the COFF symbol table. Symbol tables exist in all object files. A COFF symbol table appears in an image file only if it is linked with the Generate Debug Info and COFF Format options under Debug Info on the Debug category for the linker (or the /DEBUG and /DEBUGTYPE:COFF options on the command line).

An AppWizard application was used to obtain the following example:

COFF SYMBOL TABLE
000 000065D0 SECT5 notype Static | .rsrc$02
001 00000011 DEBUG notype Filename | .file
C:\code\test\testView.cpp
004 000041A0 SECT3 notype Static | $SG23289
005 00004018 SECT3 notype Static | _$S189$S23301
006 00004168 SECT3 notype Static | _THIS_FILE$S23282
007 00001E90 SECT1 notype Static | .text
Section length 2DE, #relocs 27, #linenums 22
009 00001EE2 SECT1 notype () Static | _$E188
00A 00001EF7 SECT1 notype () Static | _$E187
tag index 0000002E size 0000001F lines 000012DF next function 00000033
00C 000042AC SECT3 notype Static | __init_CTestView$S23291
00D 00003998 SECT2 notype Static | $T23440
00E 00003978 SECT2 notype Static | $T23438
00F 000039C0 SECT2 notype Static | $T23447
010 000039A0 SECT2 notype Static | $T23446
011 00000021 DEBUG notype Filename | .file

Created with the Personal Edition of HelpNDoc: Easily create Web Help sites


DUP.htm

DUP

Syntax:

count DUP (initialvalue [,initialvalue]...)

Description

Specifies <count> declarations of <initialvalue>. You can define arrays, buffers, and other data structures consisting of multiple data objects of the same size with the DUP operator. The <initialvalue> parameters must be inside parentheses. This operator can be used with data definition directives.

 The <count> parameter is the number of declarations of <initialvalue>. This parameter cannot be negative or forward-referenced. The <initialvalue> parameter is either the undefined data symbol (?), a string, a constant expression, or another DUP operator. The value or values of <initialvalue> are evaluated once before duplication. Separate multiple initial values with commas.

Ex :
name_1 DB 12 DUP ('A')
name_2 DB 4 DUP (?) , 6 DUP ('-*-') , 2 DUP (64) ; en suite
name_3 DB 5 DUP ( 3 DUP ('*')) ; imbriquée
name_4 DB 4 DUP ("pile")
table_1 DB 4 DUP (1,2,3,4,5) ; tableau de 20 octets

Ex :
ident1 EQU 'azerty'
name_4 DB 5 DUP (ident1,' *') ; 5 fois 'azerty *' en name_4

stdir db "C:",256 dup (0)

Ex :
HMAX_DIGITS = 128 ; Vu dans lib Irvine32.asm
Hinputarea BYTE HMAX_DIGITS dup(0),0
xbtable BYTE 0,1,2,3,4,5,6,7,8,9,7 DUP(0FFh),10,11,12,13,14,15

--------------------------------------------------------------------------------------

Syntax: count DUP (initialvalue [,initialvalue]...)

DUP (DUPliquer) signale à l'assembleur de DUPliquer l'instruction entre parenthéses

--------------------------------------------------------------------------------------


Data Types.htm

Data types

Syntax: [name] [S]BYTE initializer [, initializer]...

[name] [S]WORD initializer [, initializer]...

[name] [S]DWORD initializer [, initializer]...

[name] FWORD initializer [, initializer]...

[name] QWORD initializer [, initializer]...

[name] TBYTE initializer [, initializer]...

[name] REAL4 initializer [, initializer]...

[name] REAL8 initializer [, initializer]...

[name] REAL10 initializer [, initializer]...

Description

Integer
Type Abbr Size Range Types Allowed
+-------+-----+---------+------------+----------------------------------+
| BYTE | DB | 1 byte | -128 to | Character, String |
| | | | +255 | |
+-------+-----+---------+------------+----------------------------------+
| WORD | DW | 2 bytes | -32,768 to | 16-bit near ptr, 2 characters, |
| | | | +65,535 | double-byte character |
+-------+-----+---------+------------+----------------------------------+
| DWORD | DD | 4 bytes | -2Gig to | 16-bit far ptr, 32-bit near ptr, |
| | | | +4Gig-1 | 32-bit long word |
+-------+-----+---------+------------+----------------------------------+
| FWORD | DF | 6 bytes | -- | 32-bit far pointer |
+-------+-----+---------+------------+----------------------------------+
| QWORD | DQ | 8 bytes | -- | 64-bit long word |
+-------+-----+---------+------------+----------------------------------+
| TBYTE | DT |10 bytes | -- | BCD, 10-byte binary numbers |
+-------+-----+---------+------------+----------------------------------+
+-------+-----+---------+------------+----------------------------------+
| REAL4 | DD | 4 bytes | -- | Single-precision floating point |
+-------+-----+---------+------------+----------------------------------+
| REAL8 | DQ | 8 bytes | -- | Double-precision floating point |
+-------+-----+---------+------------+----------------------------------+
| REAL10| DT |10 bytes | -- | 10-byte floating point |
+-------+-----+---------+------------+----------------------------------+

These directives allocate and optionally initialize one or more bytes of global data. The S prefix indicates signed data, but this information is used internally by the assembler for comparisons used by control-flow directives and argument passing in INVOKE statements. CodeView also uses this information to specify the data format.

The abbreviations (such as DB, DD) are limited forms of the data-declaration directives; they cannot be used as types. They are included for compatibility with previous versions of the assembler.

String initializers, available with the BYTE directive, allocate a byte for each character of the string. The characters are stored with the leftmost character in the lowest memory location so that BYTE "WASHINGTON would be assembled to

57 41 53 48 49 4E 47 54 4F 4E "WASHINGTON"

Character initializers, however, are stored with the leftmost character in the highest memory location. They are also limited to the current expression size so that under the default OPTION EXPR32

DWORD "WASH"

would be assembled to

48 53 41 57 "HSAW"

and under OPTION EXPR16

WORD "WA"

would be assembled to

41 57 "AW"

Use the REAL4, REAL8, and REAL10 data types for floating-point data. They inform CodeView that the data is in floating-point format and cause the assembler to perform more stringent type checking.

Parameter Description

name Symbol name assigned to the variable. If no name is assigned, the memory space is allocated, but the starting address of the variable has no symbolic name.
initializer A type shown in the table above, constant integer expression, ?, or DUP expression. Separate multiple values with commas or use the DUP operator.


Debugging in MASM32.htm

Debugging in MASM32

This essay was written by the following author and is reproduced here for your convenience. It is a technique for programmers who own a copy of SoftICE.

Setting up MASM for use with SoftICE
------------------------------------
by Lucifer
Mon January 25, 1999

Well, I have had a pain trying to get masm produced executables to debug
correctly with SoftICE. After some kludging I've finally figured it out...

Its actually simple to do, but if you dont know what you're doing (or haven't
read your manual), its quite a pain. Set these options when you build your
project and you should have no problems debugging it.

Step 1 - Setting up The Assembler:
-----------------------------------
ML /COFF /Zi ...

Step 2 - Setting up The Linker:
-------------------------------
Link /SUBSYSTEM:WINDOWS /DEBUG /DEBUGTYPE:CV ...

Step 3 - Seting up SoftICE:

---------------------------
This batch file will translate the symbol information and package the source
code. This will allow you full symbolic and source level debugging.
It will then launch the debugger amd break on the module's entry point
(WinMain, DllMain, or DriverEntry). This batch file will completely replace
the use of Loader32.exe, giving quick and easy access to the debugger from
the command line.

rem DEBUG.BAT ----------------------
@echo off

nmsym /translate:source,package,always /source:. /load:execute,break %1

Now all you have to do is type "DEBUG MyProgram.exe" on the command line to
automatically load the source and symbols and begin debugging.

Step 4 - Setting up the Paths:
------------------------------
Now all you need to do is add your MASM bin directory to the PATH, as in:
SET PATH = %PATH%;C:\MASM\BIN

Step 5 - Using SoftICE to Debug:
--------------------------------

Once you have the program loaded into softice you can use the SRC command to toggle between source view, code view, and mixed mode...
You can also set breakpoints on your functions by typing BPX MyFunc.
BPM MyVar will break on access to a variable.
Of course, READ YOUR MANUAL so you really know what your doing...

NOTE: These settings haven't seemed to work for everybody... so if you have
problems, or know what I am doing wrong, please let me know.

-----------------------------------------------------------------------------

Copyright (C) 1999
lord-lucifer@usa.net

Created with the Personal Edition of HelpNDoc: Full-featured multi-format Help generator


ECHO.htm

ECHO

Syntax:

ECHO message

Description

Displays message during assembly. The message is usually output to the screen, but you can redirect it to a file or another device. This directive can help show which statements were assembled. %OUT is a synonym for ECHO and is included for compatibility.

The <message> is any line of ASCII characters up to but not including any comment on the line. If angle brackets are used to enclose <message>, the angle brackets are displayed. To perform macro substitution, put the macro substitution operator (%) at the beginning of the line. Use a separate ECHO directive for each line.

To output the time and date of assembly, insert this line in your source code:

% ECHO Assembled on @Date at @Time


EDITBIN Options.htm

EDITBIN Options

usage:

EDITBIN [options] [files]

Options

/BIND[:PATH=path]
/HEAP:reserve[,commit]
/LARGEADDRESSAWARE[:NO]
/NOLOGO
/REBASE[:[BASE=address][,BASEFILE][,DOWN]]
/RELEASE
/SECTION:name[=newname][,[[!]{cdeikomprsuw}][a{1248ptsx}]]
/STACK:reserve[,commit]
/SUBSYSTEM:{NATIVE|WINDOWS|CONSOLE|WINDOWSCE|POSIX}[,#[.##]]
/SWAPRUN:{[!]CD|[!]NET}
/VERSION:#[.#]
/WS:[!]AGGRESSIVE


END.htm

END

Syntax:

END [address]

Description

Marks the end of a source file and optionally indicates the program load address. The optional <address> is a label or expression identifying where program execution begins. You can define <address> only once in a program, usually in the main module.

You cannot specify <address> if you have used the .STARTUP directive, which automatically sets a start address. If you are linking with a high-level language, the start address is typically set by that language's compiler.

END also closes the last segment in the source file.


ENDM.htm

ENDM

Syntax:

ENDM

Description

Terminates macro and iterative blocks.


ENDS.htm

ENDS

Syntax:

name ENDS

Description

Marks the end of a segment or a structure definition previously started with SEGMENT, STRUCT, or UNION. To end a simplified segment (such as one started with .DATA), use the line

@CurSeg ENDS ;End current segment

A single .STACK statement opens and closes the stack segment, so you should not include an additional ENDS statement.


EQU.htm

EQU

Syntax: EQU TEXTEQU

Syntax: name EQU expression

name EQU <text>
name TEXTEQU textmacro
name TEXTEQU %expression

Description

The EQU directive assigns <expression> or <text> to <name>. Angle brackets indicate that <text> should not be evaluated as an expression.

EQU evaluates the numeric value of <expression> and assigns the resulting constant value to <name>. Unlike =, EQU does not allow numeric equates to be redefined. If <expression> cannot be evaluated, EQU treats <expression> as text.

The TEXTEQU directive acts like the EQU directive with text equates but performs macro substitution at assembly and does not require angle brackets. The TEXTEQU directive will also resolve the value of an expression preceded by a percent sign (%). The EQU directive does not perform macro substitution or expression evaluation for strings.

Text equates are limited to 255 characters. Text equates can be redefined to another value but not to a different type of symbol.

Parameter Description

name Symbolic name for <expression> or <text>

expression Variable or constant numeric expression (not a memory expression)

text String enclosed in angle brackets (<>)

textmacro A text macro (such as @Date) or a string enclosed in angle brackets (<>).

expression An expression preceded by a %.

Example

MASM EQU 5.1 + 0.9 ; Evaluates to 6.0
Msft EQU <Microsoft> ; String equate
libpath TEXTEQU @Environ(<LIB>) ; Text Macro Equate
endstr TEXTEQU %(endadr-staradr); String equate to numeric value


EXITM.htm

EXITM

Syntax:

EXITM [textitem]

Description

Terminates expansion of the current macro or repeat block and begins assembly of the next statement outside the block. If the EXITM directive is encountered in a nested macro block, the assembler returns to expanding the previous block level.

The <textitem> parameter is a text item that is returned to the calling statement. The <textitem> field is valid only with an EXITM directive at the end of a MACRO block.


EXTERNDEF.htm

EXTERNDEF

Syntax:

 EXTERNDEF [langtype] name:qualifiedtype
[, [langtype] name:qualifiedtype]...

EXTERN [langtype] name[(altID)]:qualifiedtype
[, [langtype] name[(altID)]:qualifiedtype]...

Description

The EXTERNDEF directive tells the assembler that one or more variables, symbols, data structures, or labels are defined in other modules. The behavior of the EXTERNDEF directive is determined by its context:

* If <name> is used in the current module but is not defined, <name> is made external. * If <name> is defined in the current module, it is made PUBLIC. * If <name> is neither used nor defined, the directive is ignored.

The EXTERNDEF directive allows you to put global data declarations in an include file without forcing the linker to pull in unneeded modules. Usually, you define <name> in one module and put the EXTERNDEF directive in a file that is included in all program modules. The PROTO directive automatically generates an EXTERNDEF for its related procedure.

EXTERN is a less flexible version of EXTERNDEF. It declares <name> as external whether or not it is used in the module. EXTRN is a synonym for EXTERN and is included for compatibility with previous versions of the assembler.

With the EXTERN directive, <name> can be followed by (altID), which allows the linker to select an alternate resolution for <name>. This is useful when creating library files.

Parameter Description

langtype A language type appropriate to <name>.

name A unique global symbolic name. Case mapping is overridden by OPTION CASEMAP.

qualifiedtype The qualified type to be given to <name>. Can also be ABS, which causes <name> to be imported as a constant. Does not have to match type given to <name> in original definition.

altID A unique global symbolic name to use as an alternate for <name>. Must be of the same type as <name>. The <altID> parameter cannot be declared as a <name> with an altID in an EXTERN statement in this or any other module.


FOR.htm

FOR

Syntax:

 FOR parameter[:REQ|:=default], <argument [,argument]...>
statements
ENDM

Description

Repeats <statements> once for each argument specified. The current argument replaces <parameter> in each iteration. IRP is a synonym for FOR and is included for compatibility with previous versions of the assembler.

Parameter Description

parameter A valid symbol name. If parameter appears in statements, it is replaced by a different argument in each iteration.

:REQ Optional tag for <parameter> causing an assembler error if <parameter> is given a blank argument.

:=default Optional tag for <parameter> causing <parameter> to be assigned <default> if given a blank argument.

argument Text, symbol, string, or numeric constant. Separate multiple iterations with commas. Angle brackets are required if a string <argument> includes spaces or commas. Leading spaces of string arguments are ignored.

statements Any valid assembler statements.


FORC.htm

FORC

Syntax:

 FORC parameter, <string>
statements
ENDM

Description

Repeats <statements> once for each character in the string. The character replaces <parameter> in each repetition. IRPC is a synonym for FORC and is included for compatibility with previous versions of the assembler.

Parameter Description

parameter A valid symbol name. If <parameter> appears in statements, then it is replaced by a different character each iteration.

string A literal string or a symbol defined with a string equate. All spaces are counted as characters. Angle brackets are required.

statements Any valid assembler statements.


Flat memory model.htm

Flat memory model

The flat memory model creates a program that contains one 32-bit segment for program data and program code. The code generated with the flat-model option will run only on 80386/486 processors. A .386 or .486 processor directive must precede the .MODEL directive that specifies the flat memory model.

This memory model causes the assembler to produce files with the .EXE extension.

All segment registers are automatically set to the same value with this memory model. The defaults in flat-model programs are NEAR code addressing and NEAR data addressing. The PROC distance is NEAR under the flat-model option. @CodeSize is 0, @DataSize is 0, and @Model is 7.

The FS and GS segment registers are not needed for flat-model programs. The .MODEL FLAT statement automatically generates this assumption:

ASSUME cs:FLAT, ds:FLAT, ss:FLAT, es:FLAT, fs:ERROR, gs:ERROR

When defining segments with the SEGMENT directive, you should use this ASSUME in your code.


GOTO.htm

GOTO

Syntax:

GOTO macrolabel

Description

Causes assembler to skip to <macrolabel>. The GOTO directive is only allowed inside a MACRO, FOR, FORC, REPEAT, or WHILE block. The <macrolabel> is only visible within the block.

Example

MACRO Instruments
IFNDEF Cymbal
GOTO Crash
ENDIF
-
-
-
:Crash
.ERR <Undefined symbol.>
-
-
-
ENDM


HIGH.htm

HIGH LOW

Syntax:

 HIGH expression
LOW expression

Description

The HIGH operator returns the high-order (most significant) byte of [expression] in two's-complement form. The LOW operator returns the low-order (least significant) byte of [expression] in two's- complement form. The [expression] must resolve to a constant or an OFFSET expression.


HIGHWORD.htm

HIGHWORD LOWWORD

Syntax:

 HIGHWORD expression
LOWWORD expression

Description

The HIGHWORD operator returns the high-order (most significant) word of <expression> in two's-complement form. The LOWWORD operator returns the low-order (least significant) word of <expression> in two's- complement form. The <expression> must resolve to a constant or an OFFSET expression.


IF.htm

IF

Syntax: IF cond expression
ifstatements
[ELSEIF] cond expression
elseifstatements
-
-
-
[ELSE]
elsestatements
ENDIF

Description

The IF block format can be used to create a source file that will generate a variety of programs, depending on constants or environment variables. For example, you can create a single source file that generates code for different memory models and operating environments. IF blocks can be nested up to 20 levels but cannot span include files or structure, union, or macro definitions.

The statements following the ELSE directive are assembled only if the preceding IF directive was found to be false (zero). Only one ELSE statement is allowed in each IF block, although there can be several ELSEIF statements.

IFcond is one of the conditional assembly directives beginning with "IF" (such as IF, IFE, and IFB). There is an optional ELSEIFcond corresponding to each IFcond.

The <ifstatements>, <elseifstatements>, and <elsestatements> are each a series of one or more assembly-code statements. The respective conditions determine which block is assembled, if any. The ELSE and ELSEIF blocks are optional.


INCLUDE.htm

INCLUDE

Syntax:

 INCLUDE filename

INCLUDE <filename>

Description

Inserts source code from <filename> into the current source file during assembly. If <filename> does not include a fully-specified path, the assembler searches the directory of the current file, the /I command-line include path or the PWB include path, and then the INCLUDE environment variable. Nested INCLUDE directives are allowed.

The <filename> parameter is an existing file containing valid assembly-language statements and directives. No default file extension is assumed. Angle brackets are required if the filename or path includes a backslash, semicolon, greater-than, less-than, single quotation marks, or double quotation marks.


INCLUDELIB.htm

INCLUDELIB

Syntax:

 INCLUDELIB libraryname

INCLUDELIB <libraryname>

Description

Informs the linker that the current module should be linked with the <libraryname>. If <path> is not given, the linker searches the current working directory, directories given in the ML or LINK library field, and then the LIB environment variable from the TOOLS.INI file.

The <libraryname> parameter is an existing file containing code in LIB format. If no extension is specified, the default extension .LIB is assumed. Angle brackets are required if the libraryname or path includes a backslash, semicolon, greater-than, less-than, single quotation marks, or double quotation marks.


INSTR.htm

INSTR

Syntax:

@InStr([position], string1, string2)

name INSTR [position,] textitem1, textitem2

Description

The @InStr macro function searches for the first occurrence of <string2> inside <string1> and returns the position of the first character of the match. The search begins at <position>, if you give that parameter. The @InStr function will not expand macros or expressions unless you use the expression operator (%).

The first character is indexed as 1. @InStr returns 0 if <string1> is not found.

The INSTR directive performs the same function as @InStr but assigns the result to <name>. These two lines are equivalent:

develop TEXTEQU @InStr (2, <MikeBobMichaelJim>, <Mi>)
develop INSTR 2, <MikeBobMichaelJim>, <Mi> ;develop is now 8

Parameter Description

name Name of the resulting constant.
position Starting character position of the search (default 1). Must be a positive integer.
string1 String being searched; any text.
string2 String to search for; any text.
textitem1 String being searched; any text item.
textitem2 String to search for; any text item.


INVOKE.htm

invoke

Syntax:

 INVOKE expression [,arguments]

Description

Automates the call interface to stack-based procedures. Handles all pushing of parameters onto the stack. Cleans up the stack when the procedure returns.

The <invokelist> is passed to the procedure according to the types given in that procedure's prototype. If necessary, the assembler will generate code to convert the elements of <invokelist> to the types specified in the prototype.

Parameter Description

expression Expression yielding address or label of procedure to be called. Must resolve to a valid address and cannot include any forward references.

arguments Sequential list of parameters passed. Can be register::register (for a register pair), expression, or ADDR label. ADDR label passes the address of <label> (segment and offset if DWORD, segment only if WORD) to the procedure.


LABEL.htm

LABEL

Syntax:

name LABEL qualifiedtype

Description

Creates a new label of a given type at a specified location by assigning the current location-counter value and the given type to <name>. The <qualifiedtype> parameter determines the type of data or call distance for the label. This directive does not allocate data.

Parameter Description

name Symbol assigned to the label.
qualifiedtype Any qualified type.


LENGTHOF.htm

Size operators

LENGTHOF variable

SIZEOF variable

SIZEOF type

LENGTH expression

SIZE expression

Description

The LENGTHOF operator returns the number of data items allocated for <variable>. The SIZEOF operator returns the total number of bytes allocated for <variable> or the size of <type> in bytes. For variables, SIZEOF is equal to the value of LENGTHOF times the number of bytes in each element.

The LENGTH and SIZE operators are allowed for compatibility with previous versions of the assembler. When applied to a data label, the LENGTH operator returns the number of elements created by the DUP operator; otherwise it returns 1. When applied to a data label, the SIZE operator returns the number of bytes allocated by the first initializer at the <variable> label.

The LENGTHOF and SIZEOF operators in MASM 6.1 handle arrays much more consistently. These operators return the number of data items and the number of bytes in an initializer.


LIB Options.htm

LIB Options

usage:

LIB [options] [files]

Options

/CONVERT
/DEBUGTYPE:CV
/DEF[:filename]
/EXPORT:symbol
/EXTRACT:membername
/INCLUDE:symbol
/LIBPATH:dir
/LIST[:filename]
/MACHINE:{ALPHA|ARM|IX86|MIPS|MIPS16|MIPSR41XX|PPC|SH3|SH4}
/NAME:filename
/NODEFAULTLIB[:library]
/NOLOGO
/OUT:filename
/REMOVE:membername
/SUBSYSTEM:{NATIVE|WINDOWS|CONSOLE|WINDOWSCE|POSIX}[,#[.##]]
/VERBOSE


LINK Options.htm

LINK Options

usage:

LINK [options] [files] [@commandfile]

Options

/ALIGN:#
/BASE:{address|@filename,key}
/COMMENT:comment
/DEBUG
/DEBUGTYPE:{CV|COFF}
/DEF:filename
/DEFAULTLIB:library
/DLL
/DRIVER[:{UPONLY|WDM}]
/ENTRY:symbol
/EXETYPE:DYNAMIC
/EXPORT:symbol
/FIXED[:NO]
/FORCE[:{MULTIPLE|UNRESOLVED}]
/GPSIZE:#
/HEAP:reserve[,commit]
/IMPLIB:filename
/INCLUDE:symbol
/INCREMENTAL:{YES|NO}
/LARGEADDRESSAWARE[:NO]
/LIBPATH:dir
/MACHINE:{ALPHA|ARM|IX86|MIPS|MIPS16|MIPSR41XX|PPC|SH3|SH4}
/MAP[:filename]
/MAPINFO:{EXPORTS|FIXUPS|LINES}
/MERGE:from=to
/NODEFAULTLIB[:library]
/NOENTRY
/NOLOGO
/OPT:{ICF[,iterations]|NOICF|NOREF|NOWIN98|REF|WIN98}
/ORDER:@filename
/OUT:filename
/PDB:{filename|NONE}
/PDBTYPE:{CON[SOLIDATE]|SEPT[YPES]}
/PROFILE
/RELEASE
/SECTION:name,[E][R][W][S][D][K][L][P][X]
/STACK:reserve[,commit]
/STUB:filename
/SUBSYSTEM:{NATIVE|WINDOWS|CONSOLE|WINDOWSCE|POSIX}[,#[.##]]
/SWAPRUN:{CD|NET}
/VERBOSE[:LIB]
/VERSION:#[.#]
/VXD
/WARN[:warninglevel]
/WINDOWSCE:{CONVERT|EMULATION}
/WS:AGGRESSIVE


LOCAL.htm

LOCAL

Syntax:

 LOCAL name [[count]][:qualifiedtype] [, name [[count]] [:qualifiedtype]]...

Description

Generates code to create one or more stack (automatic) variables, which can be accessed only within the current procedure. The assembler uses the same method used by high-level languages to create local variables.

The <name> parameter is the name of the variable, and <count> is an optional expression (which must appear in square brackets) indicating the number of elements to allocate. The <qualifiedtype> parameter is any qualified type appropriate to <name>. The default <qualifiedtype> is WORD in a 16-bit segment and DWORD in a 32-bit segment.

Once declared in a LOCAL statement, local variables can be referred to by name. The assembler translates references to these variables into references to their actual location on the stack using the BP indirect addressing mode.

The assembler will generate an error if you have already defined <name> as a label.

Example

LOCAL array[20]:BYTE


LROFFSET.htm

LROFFSET

Syntax:

LROFFSET expression

Description

Similar to OFFSET, but causes the offset to be resolved by the loader at run time. LROFFSET is usually applied to the offset of a function pointer. This run-time resolution allows Microsoft Windows to relocate code segments in real mode.

The <expression> is any label, variable, or other direct memory operand.

Example

INVOKE CreateRoutine, LROFFSET MyFunc, 0


Line Continuation.htm

Line continuation

Line Continuation
Syntax: text \
text

Description

Enables an assembly-language statement to continue on the next line, ignoring the line break. You can join any number of physical lines with this method. A backslash occurring inside a comment or string is not considered to be a line-continuation character. Logical lines cannot exceed a total of 512 characters.

Comments can appear to the right of the \. A backslash is not required on a line ending with a comma.


Literal Text.htm

Literal text

Syntax:

<text>

Description

Treats <text> as a single literal string.

Angle brackets are often used in macro calls and with the FOR directive to ensure that values in a parameter list are treated as a single parameter. For example,

MyMacro <one, two, three> ;Passes one argument to ; MyMacro
MyMacro one, two, three ;Passes three arguments to ; MyMacro

The assembler removes one set of angle brackets each time it inserts an argument into a macro expansion.

The <text> is any name, number, or expression. It can contain commas, spaces, tabs, or semicolons. The exclamation point (!) is an escape character that allows you to include special characters such as the semicolon, ampersand, and quotation marks.


Local Code Labels.htm

Local code labels

Syntax:

[instruction] @F
.
.
.
@@: [statement]
.
.
.
[instruction] @B

Description

The @@: label defines a local code label, which is in effect until the next instance of @@:. The @F and @B operands can be used in conditional and unconditional jump statements to jump to the next and previous @@: label respectively.

The @@: label is useful for defining a nearby jump point where a full label is not appropriate.

Example

cmp ax, 18h
jg @F
- ; Less than or equal
-
-
@@: ; Greater than

mov cx, 640 ; Set count

@@:
- ; Loop statements
-
-
loop @B ; Loop back


Location Counter.htm

Location counter

Syntax:

 $

Description

Equates to the current value of the location counter (current offset address). Equivalent to THIS NEAR.

Example

title BYTE "Space Mutants II"
level WORD 0
hiscore BYTE 20 DUP (?)
tablelen EQU $-title ;tablelen = 38

In compatibility mode, the current address operator ($) applied to a structure returns the offset of the first byte of the structure. When OPTION M510 is not enabled, $ returns the offset of the current field in the structure.


Logical Operators.htm

Logical operators

Syntax:

expression1 AND expression2

expression1 OR expression2

expression1 XOR expression2

NOT expression

expression SHL count

expression SHR count

Description

These operators perform logical manipulations of constant integer expressions. They return expressions of the size determined by the current expression size. Use the LOW and LOWWORD operators to return expressions of smaller sizes.

These operators should not be confused with their instruction counterparts. Operators cannot act on registers or memory.

Operand Description

expression Any constant integer expression in any valid radix.
count The number of bits to be shifted. Must be a constant positive integer. Bits shifted in are always 0.


MACRO.htm

MACRO

Syntax:

name MACRO [parameter[:tag]] [,parameter[:tag]]...]
[LOCAL varlist]
statements
[EXITM [textitem]]
ENDM

Description

Marks the beginning of a macro definition called <name> and takes optional parameters. The assembler generates the statements in the macro block each time the macro is called in source code. Macro procedures and macro functions can be nested up to 40 levels. Text macros may be nested up to 20 levels.

Macro procedures can be redefined at any time. The new definition affects any subsequent calls to this macro. Macro functions can only be redefined, if they have not been called yet.

Example

mymacro MACRO value:REQ, reg:=<AX>, options:VARARG
LOCAL returnval
-
-
-
EXITM returnval
ENDM

Parameter Description

name A unique symbol name. It can appear later in source code, to call the macro.

parameter A valid symbol name. Each parameter can appear in the statements and is replaced by the corresponding item in the argument list whenever the macro is called.

:

tag Either :REQ, :=default, or :VARARG. :REQ causes an assembler error if the parameter is given a blank argument. :=default causes <parameter> to be assigned <default> if given a null argument. :VARARG allows a variable number of arguments to be passed as a comma-separated list to <parameter>. If :VARARG is used, it must be applied only to the last parameter of the MACRO directive.

statements Any valid assembler statements.

value Optional return value for macro function.


MACRO LOCAL.htm

Macro local

Syntax:

LOCAL localname [,localname]...

Description

Declares a label or symbol for local use within a macro or iterative block. The assembler generates a different internal name for the symbol each time it expands the macro. The LOCAL directive allows you to call a macro that contains local jump statements and variable definitions without generating the same label each time the macro is expanded.

The <localname> parameter is the name of a label or symbol inside the macro. Inside the macro expansion, <localname> takes precedence over a global label or symbol with the same name.


MASK.htm

MASK

Syntax: MASK record

MASK recordfieldname

Description

Returns a bit mask for the bit positions in a record or record field. A bit in the mask contains a 1 if that bit corresponds to a field bit. All other bits contain 0.

The <record> parameter is the name of any record. The <recordfieldname> parameter is the name of any field in a record.


MASM High Level Syntax.htm

MASM High Level Syntax

MASM has a number of built in operators that allow a programmer to use C style evaluation and loop code when writing high level Windows code that interfaces with the operating system.

More often than not, low level algorithms do not use any of the high level operators as it would produce suboptimal instruction sequences for maximum performance but much of the high level code inherant in Windows suffers from complexity rather than speed considerations and it is here where the C style high level emulation code provides its biggest advantage.

The .IF syntax allows conditional testing in a manner that makes high level Windows code far easier to both read and write. The alternative using "cmp reg, var", "jne label" produces nightmares in terms of tracking the number of jumps and labels needed and it does not perform any better or assemble any smaller.

.if uMsg == WM_COMMAND
;code
.elseif uMsg == WM_PAINT
;code
.elseif uMsg == WM_CLOSE
etc ....

MASM also has loop code techniques for emulating high level coding where it can be used to improve readability and maintainance.

The "condition" is evaluated using the Comparison run-time operators

Test condition at start of loop

.WHILE condition
; code that changes "condition"
.endw

Test condition at end of loop

.REPEAT
; code that changes "condition"
.until condition

There are two methods of conditionally exiting the loops with the following operators with syntax variation depending on the task.

.BREAK
.BREAK .if condition
.CONTINUE
.CONTINUE .if condition

Example
mov eax, 100

.while eax > 0
sub eax, 1
.endw

msgloop:
invoke GetMessage, ADDR msg,NULL,0,0
.break .if eax == 0
invoke TranslateMessage, ADDR msg
invoke DispatchMessage,ADDR msg
jmp msgloop


ML.EXE Options.htm

ML.EXE 6.14 Options

Options

ML [ /options ] filelist [ /link linkoptions ]

/AT Enable tiny model (.COM file)
/Bl<linker> Use alternate linker
/c Assemble without linking
/Cp Preserve case of user identifiers
/Cu Map all identifiers to upper case
/Cx Preserve case in publics, externs
/coff generate COFF format object file
/D<name>[=text] Define text macro
/EP Output preprocessed listing to stdout
/F <hex> Set stack size (bytes)
/Fe<file> Name executable
/Fl[file] Generate listing
/Fm[file] Generate map
/Fo<file> Name object file
/FPi Generate 80x87 emulator encoding
/Fr[file] Generate limited browser info
/FR[file] Generate full browser info
/G<c|d|z> Use Pascal, C, or Stdcall calls
/H<number> Set max external name length
/I<name> Add include path
/link <linker options and libraries>
/nologo Suppress copyright message
/Sa Maximize source listing
/Sc Generate timings in listing
/Sf Generate first pass listing
/Sl<width> Set line width
/Sn Suppress symbol-table listing
/Sp<length> Set page length
/Ss<string> Set subtitle
/St<string> Set title
/Sx List false conditionals
/Ta<file> Assemble non-.ASM file
/w Same as /W0 /WX
/WX Treat warnings as errors
/W<number> Set warning level
/X Ignore INCLUDE environment path
/Zd Add line number debug info
/Zf Make all symbols public
/Zi Add symbolic debug info
/Zm Enable MASM 5.10 compatibility
/Zp[n] Set structure alignment
/Zs Perform syntax check only


Macro Expression.htm

Macro expression

Syntax:

 %expression

Description

Computes the value of <expression> and treats it as a text string. Use in macro calls when you need to pass the result of an expression rather than the actual expression to a macro. The <expression> can also be a text macro or a macro function.

When placed at the beginning of the line, % causes the calculation and substitution of all text macros on that line, including those inside angle brackets (<>). Macro function calls inside angle brackets (<>) are not expanded unless preceded by a %.


Macro Function ArgI.htm

Macro Function ArgI

;* @ArgI - Macro function returns an argument specified by number
;* from a VARARG list.
;*
;* Shows: Directives - FOR LOCAL EXITM
;* TEXTEQU =
;* Operator - EQ
;*
;* Params: index - one-based number of the argument to be returned
;* arglist - argument list

@ArgI MACRO index:REQ, arglist:VARARG
LOCAL count, retstr
count = 0
FOR arg, <arglist>
count = count + 1
IF count EQ index
retstr TEXTEQU <arg>
ENDIF
ENDM
EXITM retstr
ENDM


Macro Function Reverse Ordering.htm

Macro function reverse ordering

;* @ArgRev - Macro function returns a reversed order version of a
;* VARARG list.
;*
;* Shows: Operators - <> ! %
;* String directive - SUBSTR
;* Predefined function - @SizeStr
;*
;* Params: arglist - arguments to be reversed

@ArgRev MACRO arglist
LOCAL txt, arg
txt TEXTEQU <>
% FOR arg, arglist
txt CATSTR <arg>, <!,>, txt
ENDM
txt SUBSTR txt, 1, @SizeStr( %txt ) - 1
txt CATSTR <!<>, txt, <!>>
EXITM txt
ENDM


Macro Reference.htm

MACRO Reference

One of MASM's great strengths is that it is a MACRO assembler which allows it to perform pre-processing of the text before the assembler reads the code and assembles the code. This allows the MASM programmer to wrote MACRO procedures that can expand or modify the text of the source code so that the source code can be written in convenient ways that improve the speed, reliability and throughput in the development cycle.

MACROS are the MASM programmers secret weapon in code production. Not only does the MASM programmer have the normal pseudo high level syntax to use for clear coding of complex decision making code, the "invoke" syntax for more reliable API calls and other function style procedures but they also have an almost unlimited method of expanding this capacity by writing MACROS that perform specific tasks in code manipulation.

MACROS can be used for many thing from simple text replacement, small inline conversions where the stack overhead of a procedure is bigger than the size of the expanded macro, complex looped expansion of repetitive code and in fact almost anything that will package code in more usable ways.

Basic Syntax

MACRO
ENDM
EXITM

Loop operators

FOR
FORC
GOTO
REPEAT
WHILE

Conditional testing

IF
ELSEIF
ELSE
ENDIF

Misc

Literal Text
MACRO LOCAL
PUSHCONTEXT
POPCONTEXT
&parameter&
Relational Operators
VARARG (Macro)
Nested Macros

Examples

Macro Function Reverse Ordering
Macro Function ArgI

Pre-defined operators for macros


Memory model.htm

Memory model

Your choice of a memory model determines how memory is set up for program code and data. The following table shows attributes of the different memory models. Select a memory model for more information.

Code Data Segment Data and Code
Distance Distance Width Combined?
+---------+---------+--------+-------------+
Tiny | NEAR | NEAR | 16-bit | Yes |

+---------+---------+--------+-------------+
Small | NEAR | NEAR | 16-bit | No |
+---------+---------+--------+-------------+
Compact | NEAR | FAR | 16-bit | No |
+---------+---------+--------+-------------+
Medium | FAR | NEAR | 16-bit | No |
+---------+---------+--------+-------------+
Large | FAR | FAR | 16-bit | No |
+---------+---------+--------+-------------+

Huge | FAR | FAR | 16-bit | No |
+---------+---------+--------+-------------+
Flat | NEAR | NEAR | 32-bit | Yes |
+---------+---------+--------+-------------+

The OPTION SEGMENT and SEGMENT directives can override the default segment width.


Name Assignment.htm

Name Assignment

Syntax:

name = expression

Description

Creates or redefines a constant symbol by assigning the numeric value of [expression] to [name]. This equate can be used in subsequent statements as a symbolic constant and can be redefined at any time.

The [name] field must be either a unique name or one previously defined with =. The [expression] fieldis any valid constant expression. Resolved at definition by the assembler.


Nested Macros.htm

Nested macros

You can separate macro arguments with white space or with commas. This is the same as using OPTION OLDMACROS.

The assembler uses the following rules to handle ampersands:

1. If a sequence of ampersands is found, the first ampersand is removed.

2. If a macro parameter is found, it is replaced by the actual parameter string.

3. Inside quoted strings and text literals, the string is scanned from left to right for ampersands. For each ampersand:

* If the ampersand is preceded or followed by a parameter, the parameter is substituted and the ampersand removed.

* If the ampersand is preceded by a previously substituted parameter, the ampersand is removed.

* In all other cases, the ampersand is ignored.

The assembler performs parameter substitution at each level of nesting. Therefore, you must add an extra ampersand before or after a macro parameter for each level of MACRO nesting or FOR/FORC/REPEAT/WHILE nesting.


OFFSET.htm

OFFSET

Syntax:

 OFFSET expression

Description

Returns offset address of <expression> (usually a variable). The value returned by the OFFSET operator is an immediate operand. OFFSET can be applied to any immediate or memory expression except a register or segment.

The offset returned is relative to either the current group or segment. If there is both a current group and a current segment, the offset will have a group-relative default offset. This default can be changed with the M510 and OFFSET: options.

The OFFSET operator can accept an expression specifying a segment. In this case, the OFFSET operator returns the offset of the last byte of the given segment, relative to that segment's group. This value reflects the size of the given segment when the OFFSET operator is assembled.

The <expression> is any label, variable, segment, or other direct memory operand.


OPATTR.htm

OPATTR

Syntax:

 OPATTR expression

.TYPE expression

Description

The OPATTR operator returns a one-word constant defining the mode and scope of expression. If <expression> is not valid or is forward- referenced, OPATTR returns a 0. If <expression> is valid, a nonrelocatable word is returned. The .TYPE operator returns only the low byte (bits 0-7) of the OPATTR operator and is included for compatibility with previous versions of the assembler.

Bit Set If
Position <expression>

0 References a code label
1 Is a memory expression or has a relocatable data
label
2 Is an immediate expression
3 Uses direct memory addressing
4 Is a register expression
5 References no undefined symbols and is without error
6 Is an SS-relative memory expression
7 References an external label
8-10 Language type:

Bits Language

000 No language type
001 C
010 SYSCALL
011 STDCALL
100 Pascal
101 FORTRAN
110 Basic

All other bits (11-15) are undefined and reserved for future expansion.


OPTION CASEMAP.htm

OPTION CASEMAP

Syntax:

OPTION CASEMAP:maptype

Description

Controls the mapping of characters to uppercase. The <maptype> parameter can be ALL, NONE, or NOTPUBLIC, which correspond to the /Cu, /Cp, and /Cx command-line options. You can use this option only once per source file. The current language type, if any, will override <maptype>.

CASEMAP:NOTPUBLIC is the default. The CASEMAP option is set to ALL with the M510 option.


OPTION DOTNAME.htm

OPTION DOTNAME

Syntax:

 OPTION DOTNAME

OPTION NODOTNAME

Description

The DOTNAME option enables the use of the period (.) as the leading character in variable, label, macro, struct, union, and member names. NODOTNAME is the default. The DOTNAME option is enabled with the M510 option, since previous versions of the assembler recognized names with period prefixes.

The DOTNAME option does not have any effect on any of the reserved words. The use of the period in names is discouraged, as it can be confused with the field offset and structure operators.

If you don't want to use this directive in your source code, rename the identifiers whose names begin with a period.


OPTION EMULATOR.htm

OPTION EMULATOR

Syntax:

OPTION EMULATOR
OPTION NOEMULATOR

Description

Controls how floating-point instructions are generated. NOEMULATOR, the default, generates the coprocessor instructions directly. EMULATOR generates instructions as well as special fixup records for the linker so that the floating-point emulator can be used. This option is definable only once per source file.

To use this option, you must link your assembly-language module with an emulator library from a Microsoft high-level language.

OPTION EMULATOR is equivalent to the /FPi command-line option.


OPTION EXPR16.htm

OPTION EXPR16

Syntax:

OPTION EXPR16

Description

The EXPR32 option selects 32-bit expressions and arithmetic. The EXPR16 option selects 16-bit expressions and arithmetic. The default is EXPR32. The expression word size cannot be changed once it has been explicitly set.

These options do not affect the processor type, segment size, or registers used.

Under OPTION M510, EXPR16 is the default unless the module contains a .386 or greater processor-selection directive.

MASM 5.1 treats expressions as 16-bit words if you do not specify .386 or .386P directives. MASM 6.1 by default treats expressions as 32-bit words regardless of the CPU type. You can force MASM 6.1 to use the smaller expression size with the OPTION EXPR16 statement.

Unless your MASM 5.1 code specifies .386 or .386P, OPTION M510 also sets 16-bit expression size. You can selectively disable this by following OPTION M510 with the OPTION EXPR32 directive, which sets the size back to 32 bits. You cannot have both OPTION EXPR32 and OPTION EXPR16 in your program.

It may not be easy to determine the effect of changing from 16-bit inter- nal expression size to 32-bit size. In most cases, the 32-bit word size does not affect the MASM 5.1 code. However, problems may arise because of differences in intermediate values during evaluation of expressions. You can compare the files for differences by generating listing files with the /Fl and /Sa command-line options with and without OPTION EXPR16


OPTION LANGUAGE.htm

OPTION LANGUAGE

Syntax:

OPTION LANGUAGE:langtype

Description

Specifies the default language type to be used with many directives. The most recent OPTION LANGUAGE: or .MODEL directive determines the current language type. The <langtype> parameter is any language type.


OPTION LJMP.htm

OPTION LJMP

Syntax:

 OPTION LJMP

OPTION NOLJMP

Description

The LJMP option enables automatic conditional-jump lengthening. LJMP is the default.

Enabling LJMP allows the assembler to generate code that emulates a conditional jump of greater than -128 to +127 bytes. If the jump is within this range, no special code is generated. It does not affect unconditional jumps or the control-flow directives.

The assembler will generate an A6003 warning for a lengthened jump so that you can identify it for later optimization.


OPTION NOKEYWORD.htm

OPTION NOKEYWORD

Syntax:

OPTION NOKEYWORD:<keywordlist>

Description

Disables the recognition of the reserved words in <keywordlist> for the current module. The listed keywords can then be used as user-defined symbols. Keywords disabled with this directive cannot be reenabled. The <keywordlist> is a space-delimited list of reserved words; literal operands and predefined symbols are not allowed. The list of keywords must be enclosed in angle brackets (<>).

You can use this option to disable privileged instruction names or obsolete synonyms so they are free to be used as labels and variables. For example:

OPTION NOKEYWORD: <STR EXTRN IRPC>
STR BYTE 10 DUP (?)

MASM 6.1 has several new keywords that MASM 5.1 does not recognize as reserved. To resolve any conflicts, you can rename any offending symbols in your code, or selectively disable keywords with the OPTION NOKEYWORD directive.

The second option lets you retain the offending symbol names in your code by forcing MASM 6.1 to not recognize them as keywords. For example,

OPTION NOKEYWORD:<INVOKE STRUCT>

removes the keywords INVOKE and STRUCT from the assembler's list of reserved words. However, you cannot then use the keywords in their intended function, since the assembler will no longer recognize them.

Created with the Personal Edition of HelpNDoc: Easy EPub and documentation editor


OPTION NOSIGNEXTEND.htm

OPTION NOSIGNEXTEND

Syntax: OPTION NOSIGNEXTEND

Description

The NOSIGNEXTEND option disables the generation of the sign- extended form (83h) of the AND, OR, and XOR instructions. The NEC V25 and V35 microprocessors do not support this opcode.


OPTION OFFSET.htm

OPTION OFFSET

Syntax:

 OPTION OFFSET:offsettype

Description

Controls whether the OFFSET operator returns offsets relative to the current segment or group. OPTION OFFSET:GROUP causes OFFSET to return a group-relative offset if the label is in a segment that is part of a group. OPTION OFFSET:SEGMENT causes OFFSET to return a segment-relative offset. OPTION OFFSET:GROUP is the default.

The FLAT option causes fixups to be relative to the FLAT group.

OPTION M510 sets OPTION OFFSET:GROUP if a .MODEL directive has been used and OPTION OFFSET:SEGMENT otherwise. With previous versions of the assembler, the OFFSET type was SEGMENT with complete segment directives and GROUP with simplified segment directives.

The <offsettype> can be GROUP, SEGMENT, or FLAT.

When programming for the 80386 or 80486, the size of an OFFSET expression can be 2 bytes for a symbol in a USE16 segment, or 4 bytes for a symbol in a USE32 or FLAT segment. With OPTION M510, you can use a 32-bit OFFSET expression in a 16-bit context. Without OPTION M510, you must use the LOWWORD operator to convert the offset size.

With no .MODEL, MASM 5.1 computes offsets from the start of the segment, whereas MASM 6.1 computes offsets from the start of the group. (With .MODEL, MASM 5.1 also computes offsets from the start of the group.)

To force MASM 6.1 to emulate 5.1 behavior, specify either OFFSET:SEGMENT or OPTION M510. Both directives cause the assembler to compute offsets relative to the segment if you do not include .MODEL.

To selectively enable MASM 6.1 behavior, place the directive OPTION OFFSET:GROUP after OPTION M510. In this case, you should ensure each OFFSET statement has a segment override where appropriate.

When not in compatibility mode, the OPTION OFFSET directive determines whether the SEG operator returns a value relative to the group or segment. With OPTION M510, SEG is always segment-relative by default, regardless of the current value of OPTION OFFSET.


OPTION PROC.htm

OPTION PROC

Syntax:

OPTION PROC:visibility

Description

Sets the default procedure visibilty. The <visibility> parameter can be PRIVATE, PUBLIC, or EXPORT. If you do not use this option, the the default visibility will be PUBLIC.

With OPTION M510, the default <visibility> with no defined language type is PRIVATE. If you specify a language type in a .MODEL or OPTION LANGUAGE statement, the default <visibility> is PUBLIC.

Without a language type, MASM 5.1 makes procedures private to the module. By default, MASM 6.1 makes procedures public. You can explicitly change the default visibility to private with either OPTION M510, OPTION PROC:PRIVATE, or OPTION PROC:EXPORT.

To selectively enable MASM 6.1 behavior, place the directive OPTION PROC:PUBLIC after OPTION M510. You can override the default by adding the PUBLIC or PRIVATE keyword to selected procedures.


OPTION PROLOGUE.htm

OPTION PROLOGUE

Syntax:

 OPTION PROLOGUE:macroname

OPTION EPILOGUE:macroname

Description

PROLOGUE registers <macroname> as the macro function to be called when a prologue needs to be generated. EPILOGUE registers <macroname> as the macro procedure to be called when a RET or IRET instruction is encountered.

You can revert to the default prologue or epilogue by specifying PrologueDef or EpilogueDef as <macroname>. EPILOGUE code is generated only if the RET or IRET instruction terminating the PROC block has no operand. The RETN, RETF, and IRETF instructions do not cause the assembler to generate epilogue code.

To suppress generation of the prologue or epilogue code, give NONE as the <macroname>.

The assembler expects a macro definition of this form:

macroname MACRO procname, flags, argbytes, localbytes, <reglist>, userparms:VARARG

Parameter Description

procname Macro name for the procedure or NONE.

flags Word-size bit flag: (1=On, 0=Off)

Bits Description

0-2 Language type:
000 Not specified
001 C
010 SYSCALL
011 STDCALL
100 Pascal
101 Fortran
110 Basic
111 Reserved
3 Reserved
4 Caller restores stack
5 FAR procedure
6 PRIVATE procedure
7 EXPORT procedure
8 Epilogue caused by IRET instruction

All other bits are reserved for future use.

argbytes The total number of bytes used by PROC arguments.

localbytes The total number of bytes used by variables defined with the LOCAL directive inside the PROC block.

reglist Comma-delimited list of registers from the PROC directive USE option. This list is reversed in in the EPILOGUE directive. Angle brackets are passed.

userparms Passed the optional macroarglist from the PROC directive.


OPTION READONLY.htm

OPTION READONLY

Syntax:

 OPTION READONLY

OPTION NOREADONLY

Description

The READONLY option sets the READONLY attribute for subsequent code segments. Enables checking for instructions that explicitly modify segments or groups containing code. Useful for detecting self- modifying code. NOREADONLY is the default.

This option replaces the command-line /P option from previous versions of the assembler. Segments can be also be made read- only with the READONLY parameter of the SEGMENT directive.


OPTION SCOPED.htm

OPTION SCOPED

Syntax:

 OPTION SCOPED

OPTION NOSCOPED

Description

The SCOPED option causes a label (defined with the "label:" syntax) to be local to the procedure in which it is defined. Labels defined with the LABEL directive or the "label::" syntax are not affected by this option.

Using NOSCOPED will cause all labels to be global to the module. SCOPED is the default. The NOSCOPED option is enabled with the M510 option, if the .MODEL directive is used without a language type specification. Specifying .MODEL with a language type enables OPTION SCOPED.

Without a language type, MASM 5.1 assumes code labels in procedures have no scope--that is, the labels are not local to the procedure. When not in compatibility mode, MASM 6.1 always gives scope to code labels, even without a language type.

To force MASM 5.1 behavior, specify either OPTION M510 or OPTION NOSCOPED in your code. To selectively enable MASM 6.1 behavior, place the dir- ective OPTION SCOPED after OPTION M510.

To determine which labels require change, assemble the module without the OPTION NOSCOPED directive. For each reference to a label that is not local, the assembler generates error A2006.


OPTION SEGMENT.htm

OPTION SEGMENT

Syntax:

OPTION SEGMENT:segmentsize

Description

The SEGMENT:USE16 option selects 16-bit segments. The SEGMENT:USE32 option selects 32-bit segments. The SEGMENT:FLAT option selects the 32-bit flat segment. This option overrides the segment size set optionally set by the SEGMENT and .MODEL directives.

The default segment size is selected by the following rules:

* A .386 or higher processor selection directive selects USE32.

* A .MODEL FLAT statement selects FLAT. All other memory models select USE16.

* The OPTION SEGMENT: directive will override any other defaults.

* In all other cases, the default is USE16.


ORG.htm

ORG

Syntax:

 ORG expression

ORG $+expression

Description

Sets the location counter to a specific address, given by <expression>. The assembler implements this directive by adjusting the location counter.

ORG $+expression causes the assembler add <expression> bytes to the location counter. The <expression> must evaluate to a constant without forward references.

Inside a STRUCT block, the <expression> parameter is relative to the beginning of the structure. This can be used to create structure elements that refer to bytes lower in memory than the beginning of the structure.


PROC.htm

PROC

Syntax:

label PROC [distance] [langtype] [visibility]
[<prologuearg>]
[USES reglist] [,parameter [:tag]]...
[LOCAL varlist]
statements
label ENDP

Description

Defines a procedure called <label>. To use <parameter>, you must have previously specified a language type or used the <langtype> parameter. You should use a PROTO prototype before each procedure defined with the PROC directive. This ensures proper type checking and allows you to call the procedure with the INVOKE directive.

Procedures usually end with the RET instruction. You can remove data from the stack by specifying the number of bytes as a parameter of the RET instruction.

The assembler automatically generates PROLOGUE and EPILOGUE code to pass stack arguments properly to the procedure and clean up the stack after completion of the procedure. You can override the default prologue and epilogue code with user-defined macros by using the OPTION PROLOGUE: and OPTION EPILOGUE: directives. The RETF or IRETF instructions do not cause the assembler to generate epilogue code.

Procedures can be nested if they do not have parameters, local variables or the USES parameter and do not generate a new segment or group. You can avoid having to nest procedures by using the RETN and RETF instructions.

Local variables must be declared (using the LOCAL directive) before any instructions. There can be several LOCAL statements in a procedure.

Parameter Description

label Defines name for the procedure. Follows naming convention of <langtype>.

prologuearg Arguments to pass to the prologue procedure. With the default PROLOGUE and EPILOGUE, the FORCEFRAME argument generates a stack segment, even if one is not necessary. LOADDS causes the DS register to be saved in the PROLOGUE and restored in the EPILOGUE. Parameters must be separated by commas. Angle brackets are required but not passed.

distance NEAR, FAR, NEAR16, NEAR32, FAR16, or FAR32. Indicates the call distance of this procedure. If you choose NEAR or FAR, the assembler will select 16- or 32-bit NEAR or FAR depending on the current segment size. If you do not specify this option, the assembler determines the distance from the memory model and processor type. NEAR is the default if you do not use the .MODEL directive.

langtype Any valid language type. Determines naming style and calling convention.

visibility PRIVATE, PUBLIC, or EXPORT. Determines how the procedure is made available to other modules. PUBLIC is the standard default, but the default can be reset with the OPTION PROC directive. EXPORT implies PUBLIC and FAR and informs the linker that the procedure should be placed in the export entry table.

reglist List of registers that the prologue preserves on the stack and the epilogue restores on exit. Separate multiple registers with spaces.

parameter Procedure parameter. The assembler translates argument references into a direct reference to the stack location. Separate multiple arguments with commas.

tag Either a qualified type or VARARG. VARARG allows a variable number of arguments to be passed as a comma separated list to <argument>. If VARARG is used, it must be applied to the last parameter of the PROC directive. VARARG is only allowed with the C, SYSCALL, and STDCALL language types. If <tag> is omitted, the assembler defaults to WORD in a 16-bit segment or DWORD in a 32-bit segment.

statements Assembly-language statements and directives.


PROTO.htm

PROTO

Syntax:

label PROTO [distance] [langtype] [, [parameter]:tag]...

Description

Defines a prototype for a subsequent procedure. Informs the assembler about how many and what kind of arguments should be expected in a procedure definition. This allows the assembler to perform type checking on arguments.

If you define a prototype for all stack-based procedures defined with the PROC directive, you can place procedure prototypes in a separate include file. This is recommended when using procedures in a library file.

Parameter Description

label Defines name for the procedure. Must exactly match <label> in PROC definition.

distance NEAR, FAR, NEAR16, NEAR32, FAR16, or FAR32. Indicates the call distance of this procedure. If you choose NEAR or FAR, the assembler will select 16- or 32-bit NEAR and FAR depending on the processor directive in effect. If you do not specify this option, the assembler determines the distance from the memory model and processor type. NEAR is the default if you do not use the .MODEL directive.

langtype Any valid language type. Determines naming style and calling convention.

parameter Procedure parameter. The assembler translates argument references into a direct reference to the stack location. Separate multiple arguments with commas.

tag Either a qualified type or VARARG. VARARG allows a variable number of arguments to be passed as a comma separated list to <argument>. If VARARG is used, it must be applied to the last parameter of the PROC directive. VARARG is only allowed with the C, SYSCALL, and STDCALL language types.

Exemple ..

GIFLoadFile PROTO STDCALL :DWORD, :DWORD ; Vu dans inc dela LIB giflib


PTR.htm

PTR

Syntax:

qualifiedtype PTR expression
PTR qualifiedtype

Description

The first syntax treats <expression> as having the specified type. Type casting can be used with forward references or unlabeled addresses to specify a reference size, type, or distance.

The second syntax is used in defining qualified types.

The PTR keyword can also appear in qualified types to indicate that the type is a pointer variable.

The <qualifiedtype> can be any qualified type. The <expression> can be any valid expression. If <qualifiedtype> is a distance, <expression> cannot be a memory expresssion or a data label.

You can use a constant as the left operand to PTR in compatibility mode. Otherwise, you must use a type expression. With OPTION M510, a constant must have a value of 1 (BYTE), 2 (WORD), 4 (DWORD), 6 (FWORD), 8 (QWORD) or 10 (TBYTE). The assembler treats the constant as the parenthesized type. Note that the TYPE operator yields a type expression, but the SIZE operator yields a constant.

; With OPTION M510

MyData DW 0

mov WORD PTR [bx], 10 ; Legal
mov (TYPE MyData) PTR [bx], 10 ; Legal
mov (SIZE MyData) PTR [bx], 10 ; Legal
mov 2 ptr [bx], 10 ; Legal

; Without OPTION M510

MyData WORD 0

mov WORD PTR [bx], 10 ; Legal
mov (TYPE MyData) PTR [bx], 10 ; Legal
; mov (SIZE MyData) PTR [bx], 10 ; Illegal
; mov 2 PTR [bx], 10 ; Illegal

Example

mov ax, (MyStruct PTR [bx]).Username
fld TBYTE PTR MaxConvolution
INVOKE MyRoutine, PTR TempValue

Under MASM 5.1, applying the PTR operator to a data initializer de- termines the size of the data displayed by CodeView. You can still use PTR in this manner in MASM 6.1, but it does not affect CodeView typing. Defining pointers with the TYPEDEF directive allows CodeView to generate correct information.


PUBLIC.htm

PUBLIC

Syntax:

 PUBLIC [langtype] name [,[langtype] name]...

Description

Makes one or more variables available to other modules in the program. PUBLIC names can be forward referenced.

The following can be made PUBLIC:

* NEAR and FAR code labels and procedures
* Data created with user-defined types, BYTE, WORD, and other types
* Data created with user-defined structures, unions, and records
* Labels created with the LABEL directive
* Symbolic constants created with EQU or =

The PUBLIC directive is normally used with the EXTERN directive. The EXTERNDEF and COMM directives allow more flexibility in global data declaration than the PUBLIC and EXTERN directives. One use is illustrated below.

+----------------------------------+
| |
+-USER.ASM---+-----------+ +-TOOLS.ASM---+----------+
| | | |
| EXTERN global:WORD | | PUBLIC Global |
| | | Global WORD 5 |
+------------------------+ +------------------------+

Parameter Description

langtype Any language type. Used to control what format label names are sent to the linker.
name The name of a variable, label, or numeric equate defined within the current source file.


PURGE.htm

PURGE

Syntax:

PURGE macroname [, macroname]...

Description

Deletes one or more currently defined macros from memory. Use this directive if your system does not have enough memory to keep all the macros needed for a source file in memory at the same time. The macro skeleton will remain, but it will not expand.

A macro can remove itself if PURGE is on the last line of the macro. Redefining a macro automatically purges the previous definition. Calling a purged macro is legal, but the macro will act like a blank macro.


PUSHCONTEXT.htm

PUSHCONTEXT

Syntax:

 PUSHCONTEXT context

POPCONTEXT context

Description

PUSHCONTEXT stores the context information indicated in <context>.
POPCONTEXT restores the context information indicated in <context>.
You can nest PUSHCONTEXT directives up to 10 levels.

You can use these directives to save and restore the state of the assembler in include files and procedures.

<context> Items Saved

ASSUMES Register assumptions
RADIX Current default radix
LISTING Listing and cref flags
CPU CPU and coprocessor directives
ALL All of the above


Pentium Optimisation.htm

Pentium Optimisation

Pentium Optimization Cross-Reference by Instruction

---------------------------------------------------------------------------
replacement
instruction CPU's or action description/notes
---------------------------------------------------------------------------

aad (imm8) all AL = AL+(AH*imm8) If imm8 is blank uses 10.

AH = 0 AAD is almost always slower,

but only 2 bytes long.

aam (imm8) all AH = AL/imm8 Same as AAD.

AL = AL MOD imm8

add 16-bit lea reg, [reg+reg+disp]
Use LEA to add
base + index + displacement
Also preserves flags;

for example:

add bx, 4

can be replaced by:

lea bx, [bx+4]

when the flags must not
be changed.

add 32-bit lea reg, [reg+reg*scale+disp]

Use LEA to add
base + scaled index + disp
Also preserves flags.
(See previous example).
The 32-bit form of LEA
is much more powerful
than the 16-bit version

because of the scaling
and the fact that almost
all of the 8 General purpose
registers can be used
as base and index registers.

and reg, reg Pent test reg, reg Use TEST instead of AND

on the Pentium because
fewer register conflict
will result in better pairing

bswap Pent ror eax, 16 Pairs in U pipe, BSWAP
doesn't pair.
disadvantage: modifies flags
(Not a direct replacement)

call dest1 286+ push offset dest2 When CALL is followed by
jmp dest2 jmp dest1 a JMP, change the return
address to the JMP destination.

call dest1 all jmp dest1 When a CALL is followed by a
ret RET, the CALL can be replaced

by a JMP.

cbw 386+ mov ah, 0 When you know AL < 128
use MOV AH, 0 for speed.
But use CBW for smaller
code size.

cdq 486+ xor edx, edx When you know EAX is positive

Faster, better pairing.
disadvantage: modifies flags
Pent mov edx, eax When EAX value could be
sar edx, 31 positive or negative
because of better pairing

cmp mem, reg 286 cmp reg, mem reg, mem is 1 cycle faster

cmp reg, mem 386 cmp mem, reg mem, reg is 1 cycle faster

dec reg16 lea reg16, [reg16 - 1] Use to preserve flags
for BX, BP, DI, SI

dec reg32 lea reg32, [reg32 - 1] Use to preserve flags
for EAX, EBX, ECX, EDX
EDI, ESI, EBP

div <op> 8088 shr accum, 1 When <op> resolves to 2, use
shift for division.
(use CL for 4, 8, etc.)

div <op> 186+ shr accum, n When <op> resolves to a power
of 2 use shifts for division.

enter imm16, 0 286+ push bp ENTER is always slower

mov bp, sp and 4 bytes in length
sub sp, imm16 if imm16 = 0 then push/mov
is smaller
386+ push ebp
32-bit mov ebp, esp
sub esp, imm16

inc reg16 lea reg16, [reg16 + 1] Use to preserve flags
for BX, BP, DI, SI

inc reg32 lea reg32, [reg32 + 1] Use to preserve flags
for EAX, EBX, ECX, EDX
EDI, ESI, EBP

jcxz <dest>: 486+ test cx, cx JCXZ is faster and
je <dest>: smaller on 8088-286.
On the 386 it is the

about the same speed
486+ test ecx, ecx Never use JCXZ on 486
je <dest>: or Pentium except for
compactness

lea reg, mem 8088-286 mov reg, OFFSET mem MOV reg, imm is faster
on 8088 - 286. 386+
they are the same.

Note: There are many uses for LEA, see: add, inc, dec, mov, mul

leave 486+ mov sp, bp LEAVE is only 1 byte
pop bp long and is faster
on the 186-386. The
mov esp, ebp MOV/POP is much faster
pop ebp on 486 and Pentium

lodsb 486+ mov al, [si] LODS is only 1 byte long
inc si and is faster on 8088-386,
much slower on the 486.
On the Pentium the MOV/INC
or MOV/ADD instructions
pair, taking only 1 cycle.

lodsw 486+ mov ax, [si] see lodsb
add si, 2

lodsd 486+ mov eax, [esi] see lodsb
add esi, 4

loop <dest>: 386+ dec cx LOOP is faster and
jnz <dest>: smaller on 8088-286.
on 386+ DEC/JNZ is

loopd <dest>: dec ecx much faster. On the Pentium
jnz <dest>: the DEC/JNZ instructions
pair taking only 1 cycle.

loopXX <dest>: 486+ je $+5 The 3 replacement
instructions
( XX = e,ne,z or nz) dec cx are much faster on the 486+.

jnz <dest>: LOOPxx is smaller and
faster on 8088-286

loopdXX <dest>: 486+ je $+5 The speed is about the
dec ecx same on the 386.
jnz <dest>:

mov reg2, reg1 286+ lea reg2, [reg1+n] LEA is faster, smaller and
followed by: preserves flags. This is a

inc/dec/add/sub reg2 way to do a MOV and ADD/SUB
of a constant, n.

mov acc, reg all xchg acc, reg Use XCHG for smaller code
when one of the registers
final value can be ignored.
Note that acc = AL, AX or EAX.

mov mem, 1 Pent lea bx, mem Displacement/immediate does
mov [bx], 1 not pair. LEA/MOV can be used
if other code can be placed
inbetween to prevent AGI's.
mov ax, 1 MOV/MOV may be easier to pair.
mov mem, ax

mov [bx+2], 1 Pent mov ax, 1 Better pairing because
mov [bx+2], ax displacement/immediate
instructions do not pair.
lea bx, [bx+2]
mov [bx], 1

movsb 486+ mov al, [si] MOVS is faster and
inc si smaller to move a single

mov [di], al byte, word or dword
inc di on the 8088-386.
On the 486+ the MOV/INC
method is faster.
NOTE: REP MOVS is always
faster to move a large block.

movsw 486+ mov ax, [si] see MOVSB

add si, 2
mov [di], ax
add di, 2

movsd 486+ mov eax, [esi] see MOVSB
add esi, 4
mov [edi], eax
add edi, 4

movzx r16, rm8 486+ xor bx, bx MOVZX is faster and
mov bl, al smaller on the 386.

On the 486+ XOR/MOV

movzx r32, rm8 486+ xor ebx, ebx is faster. Possible
mov bl, al pairing on the Pentium.
(source can be reg or mem)

movzx r32, rm16 486+ xor ebx, ebx disadvantage: modifies flags
mov bx, ax

mul n 8088+ shl ax, cl Use shifts or ADDs instead of

multiply when n is a power of
2.

mul n Pent add ax, ax ADD is better than single
shift because it pairs better.

mul 32-bit lea Use LEA to multiply by
2, 3, 4, 5, 7, 8, 9

lea eax, [eax+eax*4] (ex: multiply EAX * 5)
LEA is better than SHL on the
Pentium because it pairs in
both pipes, SHL pairs only in
the U pipe.

or reg, reg Pent test reg, reg Better pairing because

OR writes to register.
(This is for src = dest.)

pop mem 486+ pop reg Faster on 486+
mov mem, reg Better pairing on Pentium

push mem 486+ mov reg, mem Faster on 486
push reg Better pairing on Pentium

pushf 486+ rcr reg, 1 To save only the carry flag
use a rotate (RCR or RCL)
or into a register. RCR and RCL
are pairiable (U pipe only)

rcl reg, 1 and take 1 cycle. PUSHF is
slow and not pairable.

popf 486+ rcl reg, 1 To restore only the carry
flag.
See PUSHF.
or
rcr reg, 1

rep scasb Pent loop1: REP SCAS is faster and
mov al, [di] smaller on 8088-486.
inc di Expanded code is faster

cmp al, reg2 on Pentium due to pairing.
je exit
dec cx
jnz loop1
exit:

shl reg, 1 Pent add reg, reg ADD pairs better. SHL
only pairs in the U pipe.

stosb 486+ mov [di], al STOS is faster and smaller

inc di on the 8088-286, and the same
speed on the 386. On the 486+

stosw 486+ mov [di], ax the MOV/INC is slightly
add di, 2 faster.

stosd 486+ mov [edi], eax REP STOS is faster on 8088-
add edi, 4 386.

MOV/INC or MOV/ADD is faster
on the 486+
Note: use LEA SI, [SI+n]
to advance LEA without
changing the flags.

xchg all Use xchg acc, reg to do a

1 byte MOV when one register
can be ignored.

xchg reg1, reg2 Pent push reg1 pushes and pops are 1 cycle
push reg2 faster on Pentium due to
pop reg1 pairing.
pop reg2
disadvantage: uses stack

Pent mov reg3, reg1 Faster and better pairing
mov reg1, reg2 if reg3 is available.
mov reg2, reg3

xlatb 486+ mov bh, 0 XLAT is faster and smaller
mov bl, al on 8088-386. MOV's are faster
mov al, [bx] on 486+. Best to rearrange

instructions to prevent AGI's

xlatb 486+ xor ebx, ebx and get pairing on Pentium.
mov bl, al Force high part of BX/EBX
mov al, [ebx] to zero outside of loop.
disadvantage: modifies flags


Processor Flags.htm

Processor Flags

1 1
8 5 7 0
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|A|V|R|0|N|IO-|O|D|I|T|S|Z|0|A|0|P|1|C| -- Layout of flags register
|C|M|F| |F|PL |F|F|F|F|F|F| |F| |F| |F|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Flag If set:

CF Carry Carry or borrow to destination operand
PF Parity Even parity in low-order byte of result
AF Aux. Carry Carry or borrow to low four-order bits
ZF Zero Result equal to 0
SF Sign Result has negative sign
TF Trap Switches to single-step mode
IF Interrupt Enables interrupts (disables if cleared)
DF Direction String operations process down rather than up
OF Overflow Result too large or small for destination
IOPL I/O I/O Privilege Level for IN, INS, OUT, OUTS, Priv CLI, STI (286+)
NF Nested Task Instruction caused nested task switch (286+)
RF Resume Debug faults disabled during instruction execution (386+)
VM Virtual 8086 Currently executing 8086 code on virtual processor (386+)
AC Alignment Data aligned to four-byte boundary (486+) Check


RECORD.htm

RECORD

Syntax:

recordname RECORD field [, field]...

Description

Declares a record template of one or more specified bit fields but does not allocate storage for the template. Separate multiple fields with a comma.

Records can be used as constants or expressions. They are treated as a BYTE or WORD with 16-bit expressions and as a BYTE, WORD, or DWORD with 32-bit expressions. The sum of the widths for all fields must not exceed the expression width.

Once a record template is declared, you can use it to define record variables or constants, in which each field not initialized assumes the default value. Records are defined with the following syntaxes:

[name1] recordname {[initializer1] [, initializer2]...}
[name1] recordname <[initializer1] [, initializer2]...>

Use of <recordname> is similar to the other variable definition directives (such as BYTE and WORD). Curly braces or angle brackets are required even if no initializers are given.

If a record constant appears as part of an expression in a control flow directive (such as .IF or .WHILE), you must use curly braces instead of angle brackets to enclose the fields.

The assembler will treat the name of a record field without the MASK or WIDTH operators as the bit number of the first bit of the record field.

Parameter Description

recordname A unique symbolic name.

field Each field is in the form

fieldname:width[= expression]

where <width> is a constant giving the width of the field (in bits) and <expression> optionally sets an initial or default value.


Radix Specifiers.htm

RADIX SPECIFIERS

Name Base Specifier Digits

Binary 2 Y or B 0 1
Octal 8 Q or O 0 1 2 3 4 5 6 7
Decimal 10 T or D 0 1 2 3 4 5 6 7 8 9
Hexadecimal 16 H 0 1 2 3 4 5 6 7 8 9 A B C D E F
Floating- point 10 R 0 1 2 3 4 5 6 7 8 9 . E + -

To indicate the radix of a constant, place the specifier at the end of the number. Specifiers and hexadecimal digits can be uppercase or lowercase.

Hexadecimal numbers must always start with a decimal digit (0-9). If the first digit is one of the letters A to F, prefix the number with a leading 0 to distinguish it from a symbolic name.

If the current default radix, specified by the .RADIX directive, is 10 or less, B and D are treated as radix overrides. B and D are treated as hexadecimal digits if the default radix is above 11 or above 13, respectively.

Floating-point constants may be used as initializers only with the REAL4, REAL8, REAL10, DWORD, QWORD, and TBYTE directives. Floating- point constants can be represented with an optional exponent or a decimal point.

Example

INVOKE MyRoutine, 01001010Y, 43H, 75, 0AFH
mole REAL4 6.023E+23
pi REAL8 3.1415927
Xenon REAL10 54R


Register Summary.htm

register summary

Register Summary

The E register prefix refers to the full 32-bit register (386+)

Accumulator [E]AX (AH/AL) Multiply, divide, I/O, fast arithmetic
Base [E]BX (BH/BL) Pointer to base address (data segment)
Counter [E]CX (CH/CL) Count for loops, repeats, and shifts
Data [E]DX (DH/DL) Multiply, divide, and I/O

Source Index [E]SI Source string and index pointer
Destination Index [E]DI Destination string and index pointer
Base Pointer [E]BP Pointer to stack base address
Stack Pointer [E]SP Pointer to top of stack

Flags [E]<Flags> Processor flags
Instruction Pointer [E]IP Memory location of current instruction

Code Segment CS Segment containing program code
Data Segment DS Segment containing program data
Stack Segment SS Segment for stack operations
Extra Segment ES Extra program data segment
" FS Extra program data segment (386+)
" GS Extra program data segment (386+)

Control Registers CR(0-3) Paging, caching, and protection (386+)
Debug Registers DR(0-7) Data and instruction breakpoints (386+)
Test Registers TR(3-7) Testing the TLB and cache (386+)

Global Descriptor GDTR Address and limit of GDT (286+)
Local Descriptor LDTR Address, limit, and selector of LDT (286+)
Interrupt Descriptor IDTR Address and limit of IDT (286+)
Task Register TR Address, limit, selector, and attributes of current task


Relational Operators.htm

Relational Operators

Syntax:

expression1 EQ expression2

expression1 NE expression2

expression1 GT expression2

expression1 LT expression2

expression1 GE expression2

expression1 LE expression2

Description

The EQ, NE, GT, LT, GE, and LE relational operators determine if two constant expressions or data labels (in the same segment) are equal, not equal, greater than, less than, greater than or equal, or less than or equal to each other. The comparison returns true (-1) or false (0).

These operators work only with assembler symbols and constants; they cannot be used to evaluate registers or memory locations. Use comparison run-time operators with the .IF, .ELSEIF, .WHILE, and .UNTIL directives.


SHORT.htm

SHORT

Syntax:

SHORT label

Description

Forces <label> type to SHORT. Normally, the assembler selects short jumps and branches when possible, but SHORT can be used to generate an error if a short jump to <label> is not possible. It disables any automatic conditional-jump lengthening (OPTION LJMP).

Short labels can be used in JMP instructions when the distance is less than 128 bytes from the start of the next instruction. This saves a byte of memory and reduces the number of clock cycles used.


SIZESTR.htm

SIZESTR

Syntax:

@SizeStr(string)

name SIZESTR textitem

Description

The @SizeStr macro function returns the length of a text item in characters. The @SizeStr function will not expand macros or expressions unless you use the expression operator (%). A zero indicates a null (empty) string.

The SIZESTR directive performs the same function but assigns the result to <name>. These two lines are equivalent:

namelength TEXTEQU @SizeStr(<Denise>)
namelength SIZESTR <Denise>
;namelength is 6

The <name> is a unique symbolic name, <string> is a string, and <textitem> must be a text item.


STRUCT.htm

STRUCT

Syntax:

name STRUCT [alignment] [, NONUNIQUE]
fielddeclarations
name ENDS

Description

Declares a structure as a new data type. STRUC is a synonym for STRUCT and is included for compatibility.

Once a structure name is declared, you can use it to define variables in which each field not initialized assumes the default value:

[name] structname <[initializer [, initializer]...]>
or
[name] structname { \
[initializer] \
[, initializer]... \
}
or
[name] structname constant DUP ({[initializer[, initializer]...]})

Curly braces or angle brackets are required even if no initializers are given. The DUP operator can be used to make duplicate initializations. Structures may be nested.

You must refer to structure members in the format structurename.membername or with a pointer to a structure followed by the .membername tag. You can use multiple sequential membernames to specify elements of nested structures.

The NONUNIQUE parameter requies elements of the structure to be accessed only by their fully specified names.

The ORG directive has a special meaning inside a STRUCT block.

Parameter Description

name A unique symbolic name for the structure.

alignment 1, 2, or 4. Byte boundary to align structure fields. The default is 1.

fielddeclarations Any valid data definitions (using BYTE, WORD, etc.) with initial values. Can also be another previously defined structure or a user-defined type. Field names do not need to be unique; you can reuse the same name in multiple structures. Some other directives are allowed in this field; see the BNF Appendix in the MASM Programmer's Guide.

initializer Data initializer for structure field.


SUBSTR.htm

SUBSTR

Syntax:

@SubStr(string, start [,length])

name SUBSTR textitem, start [,length]

Description

The @SubStr macro function extracts specified characters from a text item. If <length> is not given, the function will return all characters to the right of (and including) the character pointed to by <start>. The @SubStr function will not expand macros or expressions unless you use the expression operator (%).

The SUBSTR directive performs the same function but assigns the result to <name>. These two lines are equivalent:

country TEXTEQU @SUBSTR (<AndorraMonacoLuxembourg>,8,6)
country SUBSTR <AndorraMonacoLuxembourg>,8,6
;country is <Monaco>

Parameter Description

name A unique symbolic name.
string A string to extract characters from.
textitem A text item to extract characters from.
start Starting position of substring; the first character is idexed as 1. Must be a positive integer constant.
length Number of characters to extract. Must be a positive integer constant.


Stack of 80-bit Data Registers.htm

Stack of 80-bit Data Registers

79 78 63 62 0
+-+---------+---------------------------------------+
ST +-+---------+---------------------------------------+
ST(1) +-+---------+---------------------------------------+
ST(2) +-+---------+---------------------------------------+
ST(3) +-+---------+---------------------------------------+
ST(4) +-+---------+---------------------------------------+
ST(5) +-+---------+---------------------------------------+
ST(6) +-+---------+---------------------------------------+
ST(7) +-+---------+---------------------------------------+
| | '- Mantissa
| '- Exponent
'- Sign

Tag Word Format

15 8 7 0
+--+--+--+--+--+--+--+--++--+--+--+--+--+--+--+--+
|TAG7 |TAG6 |TAG5 |TAG4 ||TAG3 |TAG2 |TAG1 |TAG0 |

+--+--+--+--+--+--+--+--++--+--+--+--+--+--+--+--+

TAG--Tag values of Data Register Stack
00 = Valid
01 = Zero
10 = Invalid, infinity, or denormalized
11 = Empty

Control Registers

+----------+
Control Word +----------+ Each word is 16 or 32
Status Word +----------+ bits, depending on
Tag Word +----------+ segment mode. Total

Instruction Pointer + + size of state is 14
+----------+ bytes in 16-bit mode
Operand Pointer + + or 28 bytes in 32-bit
+----------+ mode.

Total size of environment is 94 bytes in 16-bit mode or 108 bytes in 32-bit mode.

When DOS loads an .EXE program, it sets registers as follows:

Register Points to

ES Segment of Program Segment Prefix (PSP)

DS Segment of PSP
CS:IP CS:IP address in EXE header
SS:SP SS:SP address in EXE header

When DOS loads a COM program, it sets all segment registers to the beginning of the program, and IP to 100H.

Created with the Personal Edition of HelpNDoc: iPhone web sites made easy


THIS.htm

THIS

Syntax:

THIS qualifiedtype

Description

Returns an operand of <qualifiedtype> with offset and segment values equal to the current location-counter value. THIS can be used with EQU or = to create labels and variables. THIS NEAR is equivalent to $.

These two lines are equivalent:

tag1 EQU THIS BYTE
tag1 LABEL BYTE

The <qualifiedtype> can be any qualified type.


TYPE.htm

TYPE

Syntax:

 TYPE expression

Description

The TYPE operator returns a value and size and distance attributes appropriate to <expression>. You can use the constant returned by TYPE directly or use the attributes returned by TYPE. For example, you can use the returned attribute to specify a type for PTR.

<expression> Returns

Variable Number of bytes allocated for each element
Structure Total number of bytes in the structure
Constant 0
Code label Distance
Register Size of register in bytes


TYPEDEF.htm

TYPEDEF

Syntax:

name TYPEDEF qualifiedtype

name TYPEDEF PROTO prototypelist

Description

Defines a new type or creates a synonym for an already defined type. The TYPEDEF directive associates <name> with a type, and, once defined, the symbol can be used anywhere a type can be used or as a data declaration directive. The <qualifiedtype> parameter can specify a pointer to a qualified type. The TYPEDEF PROTO syntax defines a prototype type.

Once a type is defined, you can use it to define variables. Use is similar to the other variable definition directives (like BYTE and WORD).

Parameter Description

qualifiedtype Any qualified type. Can include a type previously defined by a TYPEDEF directive, but recursive definitions are not allowed.
prototypelist List of parameters for procedure prototype. Uses the same syntax as the PROTO directive.


TYPEDEF Directive.htm

TYPEDEF Directive

Description

Use TYPEDEF to

* Define types for procedure arguments in PROC, PROTO, and INVOKE statements.

* Define types used in high-level expressions such as .IF, WHILE, and .REPEAT.

* Define pointer types so that CodeView can give appropriate information about the pointer.

* Define the types for procedure arguments in procedure prototypes.

Typical TYPEDEFS

CHAR TYPEDEF BYTE ; Rename an existing type
PCHAR TYPEDEF PTR CHAR ; Create a pointer type
PWORD TYPEDEF PTR WORD ; Create a pointer type
PPWORD TYPEDEF PTR PWORD ; Create a complex pointer type
PMYSTRUCT TYPEDEF PTR MYSTRUCT ; Create pointer type to structure or union
PPROTO TYPEDEF PROTO \
NEAR C arg1:byte arg2:word ; Define proc prototype
PFUNCT TYPEDEF PTR PPROTO ; Define pointer to proc
; prototype
Typical uses of TYPEDEFs:

user CHAR "Jill" ; Use new type as initializer
Puser PCHAR user ; Initialize a pointer
task PROC myvar:PMYSTRUCT ; Pass pointer to structure
EXTERNDEF ppw:PPWORD ; Define external with user type
proctbl PFUNC Up, Down, Home ; Initialize procedure table
-
-
-
INVOKE proctbl[bx], pos ; Call procedure from table


UNION.htm

UNION

Syntax:

name UNION [alignment] [, NONUNIQUE]
fielddeclarations
[name] ENDS

Description

Declares a union as a new data type. Allows the same memory locations to be overlapped with different types. Identical to STRUCT except that each member has a 0 offset. The size of the union is the size of the largest member of the union.

Unions can be used to store one type of data in some circumstances and another type in a different situation. Unions also allow you to store data as one data type and then read it as another. Unions are initialized by using the union name as a data declaration directive. You only need to initialize a union for one data type.

You must refer to union members by their member names. The LABEL directive allows you to refer to the entire union as a unit.

The first-level definition of a union must include the <name> label preceding the ENDS. In nested unions, terminate the block with a ENDS statement without the <name> label.

The <alignment> field determines the byte alignment of any structures. This field can be 1, 2, or 4. The default is 1, unless overridden by the /Zp command-line option or the ALIGN or EVEN directives.

The NONUNIQUE parameter allows elements of the union to be accessed only by their fully specified names.

Some directives are allowed in the <fielddeclarations> field; see the BNF Appendix in the MASM Programmer's Guide.

Example

EXTENDCHAR UNION
ascii BYTE ? ; Define a union of byte and
kanji WORD ? ; word
EXTENDCHAR ENDS

initial EXTENDCHAR <J> ; Create a union variable
mov al, initial.ascii ; Move byte-length data
mov bx, initial.kanji ; Move word-length data


USES.htm

USES

Syntax:

USES reglist

Description

An optional keyword used with PROC. Generates code to push the value of registers that should be preserved (and that will be altered by your procedure) on the stack and pop them off when the procedure returns.

The <reglist> parameter is a list of one or more registers. Separate multiple registers with spaces.


Using invoke.htm

Using invoke

Why use invoke ?
Popular legend has it that true low level assembler is written only at the mnemonic level and the rest is for people who do not properly understand what low level programming is about. The problem is for people who espouse this view is that they never produce anything much and when they do, it is usually of little consequence.

Few would understand that assembler is actually a high level language. At the hardware level, you only have opcodes and with the Intel x86 series of processors, the basic unit is a BYTE so when you use a mnemonic, you are using a high level simulation of a family of opodes that differ depending on the way the operands are arranged.

For people who are of such a robust disposition that they want to write in REAL low level code, the editor in MASM32 has the capacity to write hex directly as ascii text and save it to disk as a binary file. For the rest who want to write fast, reliable minimum size code and get it done in one lifetime, MASM has a pseudo high level syntax that has an exact correlation to code written the old hard way but without the errors, mysterious crashes and unresolvable bugs.

The traditional notation for calling procedures is the "push" parameter, "call" syntax. MASM has an alternative method of calling procedures which has many advantages in terms of both coding speed and reliability. A procedure called by INVOKE is type checked against a prototype of the same name for parameter size and number.

Traditional

push offset par4
push par3
push offset par2
push par1
call FunctionName
mov retval, eax

Invoke

invoke FunctionName,par1,ADDR par2,par3,ADDR par4
mov retval, eax

If there was an advantage in doing a function call the old way, you would bother but in this example, both assemble to the identical code but while the invoke syntax has reliable error checking against the prototype for the function that is called, the old way does not so if you put the wrong number of parameters or some other normal error, it will assemble but will crash when run.


VARARG (Macro).htm

VARARG

VARARG (Macro)

The VARARG attribute allows you to pass a variable number of arguments to a macro. The macro parameter will be passed a comma-separated list of values (or a blank if no values are given) when called. You can apply the VARARG attribute only to the last parameter in a macro definition.

You can use the FOR directive to handle macro parameters with the VARARG attribute. The following macro function calculates the number of arguments in a VARARG parameter:

@ArgCount MACRO parmlist:VARARG
LOCAL count
count = 0
FOR parm, <parmlist>
count = count + 1 ; Count the parameters
ENDM
EXITM count
ENDM

This example button links to a macro that allows you to access an argument by its number.


VARARG (Proc).htm

VARARG

VARARG (Proc)

The VARARG attribute allows you to pass a variable number of arguments to a procedure. The VARARG parameter receives a near pointer to an array of WORD elements (DWORD if a far address is passed). You can apply the VARARG attribute only to the last parameter in a procedure definition. You can only use VARARG in procedures when the C, SYSCALL, or STDCALL language types are in effect.

addup PROTO NEAR C, parmcount:WORD, parmvalues:VARARG

invoke addup, 3, 5, 2, 4

addup PROC NEAR C, parmcount:WORD, parmvalues:VARARG
xor ax, ax
xor bx, bx
mov cx, parmcount

.REPEAT
add ax, parmvalues[bx]
inc bx
inc bx
.UNTILCXZ

ret

addup ENDP


WIDTH.htm

WIDTH

Syntax:

WIDTH {recordfieldname|record}

Description

Returns width (in bits) allocated for a record or record field.

The <recordfieldname> is the name of any field defined in any record. The <record> is the name of any defined record.


[ELSE]IF.htm

[ELSE]IF

Syntax:

 [ELSE]IF expression

[ELSE]IFE expression

Description

IF causes assembly of a block of statements if expression is true (nonzero). IFE causes assembly of a block of statements if expression is false (zero).

The <expression> must resolve to a constant and contain no forward references.


[ELSE]IFB.htm

[ELSE]IFB

Syntax:

 [ELSE]IFB expression

[ELSE]IFNB expression

Description

IFB causes assembly of a block of statements if <expression> is blank. IFNB causes assembly of a block of statements if <expression> is not blank. The <expression> field is any name, number, or expression; typically, it is the name of a parameter of a macro.

Within a macro, a parameter name is replaced by an empty string if you call the macro without giving a corresponding argument. IFB and IFNB let you define default behavior when an argument is missing, but the :REQ and :=default MACRO parameters are preferred.


[ELSE]IFDEF.htm

[ELSE]IFDEF

Syntax: [ELSE]IFDEF name

[ELSE]IFNDEF name

Description

IFDEF causes assembly of a block of statements if <name> is a previously defined symbol. IFNDEF causes assembly of a block of statements if name has not been defined.

You can define symbols on the command line or in the Macro Assembler Global Options dialog box.

Use of this feature with the IFDEF and IFNDEF directives lets you control which statements are assembled from the command line.


[ELSE]IFDIF[I].htm

[ELSE]IFDIF[I]

Syntax:

 [ELSE]IFDIF[I] textitem1, textitem2

[ELSE]IFIDN[I] textitem1, textitem2

Description

Causes assembly of a block of statements depending on whether two textitems are different or identical. IFDIF assembles the block if <textitem1> and <textitem2> are different. IFIDN assembles the block if they are the same. IFDIFI and IFIDNI do the same actions but are not case sensitive.

The <textitem1> and <textitem2> parameters are text items.


ampersand.htm

The ampersand character "&"

Syntax:

&parameter&

Description

Operator used within a macro or a repeat block; enables parameter substitution for <parameter>. Two parameters can be joined to form one symbol. You can join any number of parameters with the ampersand operator.

You can also use this operator to force parameter substitution in a quoted string. For this reason, if you want an ampersand to be included in a string, you must use the string escape character (!) before the &.

Use ampersands (&) only around macro parameters, in quoted strings, and inside angle brackets (<>). Each parameter to be substituted must have one ampersand on the left and right. If an ampersand is adjacent to white space, it can be omitted as long as one ampersand is next to each parameter to be substituted.

Example:

Guard MACRO Prisonernum:REQ, Prisonername:=Anonymous
ECHO <Number &Prisonernum has arrived at &@Time.>
EXITM Prisonernum&&Prisonername
ENDM

Badge Guard 2


text.htm

Normal and macro end of line comments

Syntax:

; comment text
;; macro comment text

Description

The single semicolon treats <text> to the end of the line as a comment. The double semicolon treats <text> to the end of the line as a macro comment. In a listing file, macro comments appear with the macro definition, not with the macro expansion.

Comments must follow all other fields in a statement line.


Bare Hex Opcodes And Mnemonics

This list include opcodes that are not in the main listing.

NOTE : There are redundancies in the Intel instruction set which show in this list as duplication of both hex opcodes and mnemonics.

More detailed reference can be found in the Intel Architecture Software Developer's Manual Volume 2 : Instruction Set Reference found in the file "24319101.PDF" from Intel.

00 ADD
01 ADD
02 ADD
03 ADD
04 ADD
05 ADD
06 PUSH
07 POP
08 OR
09 OR
0A OR
0B OR
0C OR
0D OR
0E PUSH
0F 00 LLDT
0F 00 LTR
0F 00 SLDT
0F 00 STR
0F 00 VERR
0F 00 VERW
0F 01 INVLPG
0F 01 LGDT
0F 01 LIDT
0F 01 LMSW
0F 01 SGDT
0F 01 SIDT
0F 01 SMSW
0F 01 SMSW
0F 02 LAR
0F 03 LSL
0F 08 INVD
0F 09 WBINVD
0F 0B UD2
0F 20 MOV
0F 21 MOV
0F 22 MOV
0F 23 MOV
0F 30 WRMSR
0F 31 RDTSC
0F 32 RDMSR
0F 33 RDPMC
0F 40 CMOVO
0F 41 CMOVNO
0F 42 CMOVB
0F 42 CMOVC
0F 42 CMOVNAE
0F 43 CMOVAE
0F 43 CMOVNB
0F 43 CMOVNC
0F 44 CMOVE
0F 44 CMOVZ
0F 45 CMOVNE
0F 45 CMOVNZ
0F 46 CMOVBE
0F 46 CMOVNA
0F 47 CMOVA
0F 47 CMOVNBE
0F 48 CMOVS
0F 49 CMOVNS
0F 4A CMOVP
0F 4A CMOVPE
0F 4B CMOVNP
0F 4B CMOVPO
0F 4C CMOVL
0F 4C CMOVNGE
0F 4D CMOVGE
0F 4D CMOVNL
0F 4E CMOVLE
0F 4E CMOVNG
0F 4F CMOVG
0F 4F CMOVNLE
0F 60 PUNPCKLBW
0F 61 PUNPCKLWD
0F 62 PUNPCKLDQ
0F 63 PACKSSWB
0F 64 PCMPGTB
0F 65 PCMPGTW
0F 66 PCMPGTD
0F 67 PACKUSWB
0F 68 PUNPCKHBW
0F 69 PUNPCKHWD
0F 6A PUNPCKHDQ
0F 6B PACKSSDW
0F 6E MOVD
0F 6F MOVQ
0F 71 PSLLW
0F 71 PSRAW
0F 71 PSRLW
0F 72 PSLLD
0F 72 PSRAD
0F 72 PSRLD
0F 73 PSLLQ
0F 73 PSRLQ
0F 74 PCMPEQB
0F 75 PCMPEQW
0F 76 PCMPEQD
0F 77 EMMS
0F 7E MOVD
0F 7F MOVQ
0F 80 JO
0F 81 JNO
0F 82 JB
0F 82 JC
0F 82 JNAE
0F 83 JAE
0F 83 JNB
0F 83 JNC
0F 84 JE
0F 84 JZ
0F 85 JNE
0F 85 JNZ
0F 86 JBE
0F 86 JNA
0F 87 JA
0F 87 JNBE
0F 88 JS
0F 89 JNS
0F 8A JP
0F 8A JPE
0F 8B JNP
0F 8B JPO
0F 8C JL
0F 8C JNGE
0F 8D JGE
0F 8D JNL
0F 8E JLE
0F 8E JNG
0F 8F JG
0F 8F JNLE
0F 90 SETO
0F 91 SETNO
0F 92 SETB
0F 92 SETC
0F 92 SETNAE
0F 93 SETAE
0F 93 SETNB
0F 93 SETNC
0F 94 SETE
0F 94 SETZ
0F 95 SETNE
0F 95 SETNZ
0F 96 SETBE
0F 96 SETNA
0F 97 SETA
0F 97 SETNBE
0F 98 SETS
0F 99 SETNS
0F 9A SETP
0F 9A SETPE
0F 9B SETNP
0F 9B SETPO
0F 9C SETL
0F 9C SETNGE
0F 9D SETGE
0F 9D SETNL
0F 9E SETLE
0F 9E SETNG
0F 9F SETG
0F 9F SETNLE
0F A0 PUSH
0F A1 POP
0F A3 BT
0F A4 SHLD
0F A5 SHLD
0F A8 PUSH
0F A9 POP
0F AA RSM
0F AB BTS
0F AC SHRD
0F AD SHRD
0F AF IMUL
0F B0 CMPXCHG
0F B1 CMPXCHG
0F B2 LSS
0F B3 BTR
0F B4 LFS
0F B5 LGS
0F B6 MOVZX
0F B7 MOVZX
0F BA BT
0F BA BTC
0F BA BTR
0F BA BTS
0F BB BTC
0F BC BSF
0F BD BSR
0F BE MOVSX
0F BF MOVSX
0F C0 XADD
0F C1 XADD
0F C7 CMPXCHG8B
0F C8 BSWAP
0F D1 PSRLW
0F D2 PSRLD
0F D3 PSRLQ
0F D8 PSUBUSB
0F D9 PSUBUSW
0F DB PAND
0F DC PADDUSB
0F DD PADDUSW
0F DF PANDN
0F E1 PSRAW
0F E2 PSRAD
0F E5 PMULHW
0F E8 PSUBSB
0F E9 PSUBSW
0F EB POR
0F EC PADDSB
0F ED PADDSW
0F EF PXOR
0F F1 PSLLW
0F F2 PSLLD
0F F3 PSLLQ
0F F5 PMADDWD
0F F8 PSUBB
0F F9 PSUBW
0F FA PSUBD
0F FC PADDB
0F FD PADDW
0F FE PADDD
10 ADC
11 ADC
12 ADC
13 ADC
14 ADC
15 ADC
16 PUSH
17 POP
18 SBB
19 SBB
1A SBB
1B SBB
1C SBB
1D SBB
1E PUSH
1F POP
20 AND
21 AND
22 AND
23 AND
24 AND
25 AND
27 DAA
28 SUB
29 SUB
2A SUB
2B SUB
2C SUB
2D SUB
2F DAS
30 XOR
31 XOR
32 XOR
33 XOR
34 XOR
35 XOR
37 AAA
38 CMP
39 CMP
3A CMP
3B CMP
3C CMP
3D CMP
3F AAS
40 INC
48 DEC
50 PUSH
58 POP
60 PUSHA
60 PUSHAD
61 POPA
61 POPAD
62 BOUND
63 ARPL
68 PUSH
69 IMUL
6A PUSH
6B IMUL
6C INS
6C INSB
6D INS
6D INSD
6D INSW
6E OUTS
6E OUTSB
6F OUTS
6F OUTSD
6F OUTSW
70 JO
71 JNO
72 JB
72 JC
72 JNAE
73 JAE
73 JNB
73 JNC
74 JE
74 JZ
75 JNE
75 JNZ
76 JBE
76 JNA
77 JA
77 JNBE
78 JS
79 JNS
7A JP
7A JPE
7B JNP
7B JPO
7C JL
7C JNGE
7D JGE
7D JNL
7E JLE
7E JNG
7F JG
7F JNLE
80 ADC
80 ADD
80 AND
80 CMP
80 OR
80 SBB
80 SUB
80 XOR
81 ADC
81 ADD
81 AND
81 CMP
81 OR
81 SBB
81 SUB
81 XOR
83 ADC
83 ADD
83 AND
83 CMP
83 OR
83 SBB
83 SUB
83 XOR
84 TEST
85 TEST
86 XCHG
87 XCHG
88 MOV
89 MOV
8A MOV
8B MOV
8B MOV
8C MOV
8D LEA
8E MOV
8F POP
90 NOP
90 XCHG
98 CBW
98 CWDE
99 CDQ
99 CWD
9A CALL
9A CALL
9B D9 FSTCW
9B D9 FSTENV
9B DB E2 FCLEX
9B DB E3 FINIT
9B DD FSAVE
9B DD FSTSW
9B DF E0 FSTSW
9B FWAIT
9B WAIT
9C PUSHF
9C PUSHFD
9D POPF
9D POPFD
9E SAHF
9F LAHF
A0 MOV
A1 MOV
A2 MOV
A3 MOV
A4 MOVS
A4 MOVSB
A5 MOVS
A5 MOVSD
A5 MOVSW
A6 CMPS
A6 CMPSB
A7 CMPS
A7 CMPSD
A7 CMPSW
A8 TEST
A9 TEST
AA STOS
AA STOSB
AB STOS
AB STOSD
AB STOSW
AC LODS
AC LODSB
AD LODS
AD LODSD
AD LODSW
AE SCAS
AE SCASB
AF SCAS
AF SCASD
AF SCASW
B0 MOV
B8 MOV
C0 RCL
C0 RCR
C0 ROL
C0 ROR
C0 SAL
C0 SAR
C0 SHL
C0 SHR
C1 RCL
C1 RCR
C1 ROL
C1 ROR
C1 SAL
C1 SAR
C1 SHL
C1 SHR
C2 RET
C3 RET
C4 LES
C5 LDS
C6 MOV
C7 MOV
C8 00 ENTER
C8 01 ENTER
C8 ENTER
C9 LEAVE
CA RET
CC INT
CD INT
CE INTO
CF IRET
CF IRETD
D0 RCL
D0 RCR
D0 ROL
D0 ROR
D0 SAL
D0 SAR
D0 SHL
D0 SHR
D1 RCL
D1 RCR
D1 ROL
D1 ROR
D1 SAL
D1 SAR
D1 SHL
D1 SHR
D2 RCL
D2 RCR
D2 ROL
D2 ROR
D2 SAL
D2 SAR
D2 SHL
D2 SHR
D3 RCL
D3 RCR
D3 ROL
D3 ROR
D3 SAL
D3 SAR
D3 SHL
D3 SHR
D4 (No mnemonic)
D4 0A AAM
D5 (No mnemonic)
D5 0A AAD
D7 XLAT
D7 XLATB
D8 C0 FADD
D8 C8 FMUL
D8 D0 FCOM
D8 D1 FCOM
D8 D8 FCOMP
D8 D9 FCOMP
D8 E0 FSUB
D8 E8 FSUBR
D8 F0 FDIV
D8 F8 FDIVR
D8 FADD
D8 FCOM
D8 FCOMP
D8 FDIV
D8 FDIVR
D8 FMUL
D8 FSUB
D8 FSUBR
D9 C0 FLD
D9 C8 FXCH
D9 C9 FXCH
D9 D0 FNOP
D9 E0 FCHS
D9 E1 FABS
D9 E4 FTST
D9 E8 FLD1
D9 E9 FLDL2T
D9 EA FLDL2E
D9 EB FLDPI
D9 EC FLDLG2
D9 ED FLDLN2
D9 EE FLDZ
D9 F0 F2XM1
D9 F2 FPTAN
D9 F3 FPATAN
D9 F4 FXTRACT
D9 F5 FPREM1
D9 F6 FDECSTP
D9 F7 FINCSTP
D9 F9 FYL2XP1
D9 FA FSQRT
D9 FB FSINCOS
D9 FC FRNDINT
D9 FD FSCALE
D9 FE FSIN
D9 FF FCOS
D9 FLD
D9 FLDCW
D9 FLDENV
D9 FNSTCW
D9 FNSTENV
D9 FST
D9 FSTP
DA C0 FCMOVB
DA C8 FCMOVE
DA D0 FCMOVBE
DA D8 FCMOVU
DA E9 FUCOMPP
DA FIADD
DA FICOM
DA FICOMP
DA FIDIV
DA FIDIVR
DA FIMUL
DA FISUB
DA FISUBR
DB C0 FCMOVNB
DB C8 FCMOVNE
DB D0 FCMOVNBE
DB D8 FCMOVNU
DB E2 FNCLEX
DB E3 FNINIT
DB E8 FUCOMI
DB F0 FCOMI
DB FILD
DB FIST
DB FISTP
DB FLD
DB FSTP
DC C0 FADD
DC C8 FMUL
DC E0 FSUBR
DC E8 FSUB
DC F0 FDIVR
DC F8 FDIV
DC FADD
DC FCOM
DC FCOMP
DC FDIV
DC FDIVR
DC FMUL
DC FSUB
DC FSUBR
DD C0 FFREE
DD D0 FST
DD D8 FSTP
DD E0 FUCOM
DD E1 FUCOM
DD E8 FUCOMP
DD E9 FUCOMP
DD FLD
DD FNSAVE
DD FNSTSW
DD FRSTOR
DD FST
DD FSTP
DE C0 FADDP
DE C1 FADDP
DE C8 FMULP
DE C9 FMULP
DE D9 FCOMPP
DE E0 FSUBRP
DE E1 FSUBRP
DE E8 FSUBP
DE E9 FSUBP
DE F0 FDIVRP
DE F1 FDIVRP
DE F8 FDIVP
DE F9 FDIVP
DE FIADD
DE FICOM
DE FICOMP
DE FIDIV
DE FIDIVR
DE FIMUL
DE FISUB
DE FISUBR
DF E0 FNSTSW
DF E8 FUCOMIP
DF F0 FCOMIP
DF FBLD
DF FBSTP
DF FILD
DF FIST
DF FISTP
E0 LOOPNE
E0 LOOPNZ
E1 LOOPE
E1 LOOPZ
E2 LOOP
E3 JCXZ
E3 JECXZ
E4 IN
E5 IN
E6 OUT
E7 OUT
E8 CALL
E9 JMP
EA JMP
EB JMP
EC IN
ED IN
EE OUT
EF OUT
F0 LOCK
F2 A6 REPNE
F2 A7 REPNE
F2 AE REPNE
F2 AF REPNE
F3 6C REP
F3 6D REP
F3 6E REP
F3 6F REP
F3 A4 REP
F3 A5 REP
F3 A6 REPE
F3 A7 REPE
F3 AA REP
F3 AB REP
F3 AC REP
F3 AD REP
F3 AE REPE
F3 AF REPE
F4 HLT
F5 CMC
F6 DIV
F6 IDIV
F6 IMUL
F6 MUL
F6 NEG
F6 NOT
F6 TEST
F7 DIV
F7 IDIV
F7 IMUL
F7 MUL
F7 NEG
F7 NOT
F7 TEST
F8 CLC
F9 STC
FA CLI
FC CLD
FD STD
FE DEC
FE INC
FF CALL
FF DEC
FF INC
FF JMP
FF PUSH


AAA - Ascii Adjust for Addition

Usage: AAA

Modifies flags: AF CF (OF,PF,SF,ZF undefined)

Changes contents of AL to valid unpacked decimal. The high order
nibble is zeroed.

Clocks Size
Operands 808x 286 386 486 Bytes
none 8 3 4 3 1

37 AAA ASCII adjust AL after addition


AAD - Ascii Adjust for Division

Usage: AAD

Modifies flags: SF ZF PF (AF,CF,OF undefined)

Used before dividing unpacked decimal numbers. Multiplies AH by
10 and the adds result into AL. Sets AH to zero. This instruction
is also known to have an undocumented behavior.
AL := 10*AH+AL
AH := 0

Clocks Size
Operands 808x 286 386 486 Bytes
none 60 14 19 14 2

D5 0A AAD ASCII adjust AX before division
D5 ib (No mnemonic) Adjust AX before division to number base imm8


AAM - Ascii Adjust for Multiplication

Usage: AAM

Modifies flags: PF SF ZF (AF,CF,OF undefined)

AH := AL / 10
AL := AL mod 10
Used after multiplication of two unpacked decimal numbers, this
instruction adjusts an unpacked decimal number. The high order
nibble of each byte must be zeroed before using this instruction.
This instruction is also known to have an undocumented behavior.

Clocks Size
Operands 808x 286 386 486 Bytes
none 83 16 17 15 2

D4 0A AAM ASCII adjust AX after multiply
D4 ib (No mnemonic) Adjust AX after multiply to number base imm8


AAS - Ascii Adjust for Subtraction

Usage: AAS

Modifies flags: AF CF (OF,PF,SF,ZF undefined)

Corrects result of a previous unpacked decimal subtraction in AL.
High order nibble is zeroed.

Clocks Size
Operands 808x 286 386 486 Bytes
none 8 3 4 3 1

3F AAS ASCII adjust AL after subtraction


ADC - Add With Carry

Usage: ADC dest,src

Modifies flags: AF CF OF SF PF ZF

Sums two binary operands placing the result in the destination.
If CF is set, a 1 is added to the destination.

Clocks Size
Operands 808x 286 386 486 Bytes
reg,reg 3 2 2 1 2
mem,reg 16+EA 7 7 3 2-4 (W88=24+EA)
reg,mem 9+EA 7 6 2 2-4 (W88=13+EA)
reg,immed 4 3 2 1 3-4
mem,immed 17+EA 7 7 3 3-6 (W88=23+EA)
accum,immed 4 3 2 1 2-3

14 ib ADC AL, imm8 Add with carry imm8 to AL
15 iw ADC AX, imm16 Add with carry imm16 to AX
15 id ADC EAX, imm32 Add with carry imm32 to EAX
80 /2 ib ADC r/m8, imm8 Add with carry imm8 to r/m8
81 /2 iw ADC r/m16,imm16 Add with carry imm16 to r/m16
81 /2 id ADC r/m32,imm32 Add with CF imm32 to r/m32
83 /2 ib ADC r/m16,imm8 Add with CF sign-extended imm8 to r/m16
83 /2 ib ADC r/m32,imm8 Add with CF sign-extended imm8 into r/m32
10 / r ADC r/m8,r8 Add with carry byte register to r/m8
11 / r ADC r/m16,r16 Add with carry r16 to r/m16
11 / r ADC r/m32,r32 Add with CF r32 to r/m32
12 / r ADC r8,r/m8 Add with carry r/m8 to byte register
13 / r ADC r16,r/m16 Add with carry r/m16 to r16
13 / r ADC r32,r/m32 Add with CF r/m32 to r32


ADD - Arithmetic Addition

Usage: ADD dest,src

Modifies flags: AF CF OF PF SF ZF

Adds "src" to "dest" and replacing the original contents of "dest".
Both operands are binary.

Clocks Size
Operands 808x 286 386 486 Bytes
reg,reg 3 2 2 1 2
mem,reg 16+EA 7 7 3 2-4 (W88=24+EA)
reg,mem 9+EA 7 6 2 2-4 (W88=13+EA)
reg,immed 4 3 2 1 3-4
mem,immed 17+EA 7 7 3 3-6 (W88=23+EA)
accum,immed 4 3 2 1 2-3

04 ib ADD AL, imm8 Add imm8 to AL
05 iw ADD AX, imm16 Add imm16 to AX
05 id ADD EAX, imm32 Add imm32 to EAX
80 /0 ib ADD r/m8,imm8 Add imm8 to r/m8
81 /0 iw ADD r/m16,imm16 Add imm16 to r/m16
81 /0 id ADD r/m32,imm32 Add imm32 to r/m32
83 /0 ib ADD r/m16,imm8 Add sign-extended imm8 to r/m16
83 /0 ib ADD r/m32,imm8 Add sign-extended imm8 to r/m32
00 / r ADD r/m8,r8 Add r8 to r/m8
01 / r ADD r/m16,r16 Add r16 to r/m16
01 / r ADD r/m32,r32 Add r32 to r/m32
02 / r ADD r8,r/m8 Add r/m8 to r8
03 / r ADD r16,r/m16 Add r/m16 to r16
03 / r ADD r32,r/m32 Add r/m32 to r32


AND - Logical And

Usage: AND dest,src

Modifies flags: CF OF PF SF ZF (AF undefined)

Performs a logical AND of the two operands replacing the destination
with the result.

Clocks Size
Operands 808x 286 386 486 Bytes
reg,reg 3 2 2 1 2
mem,reg 16+EA 7 7 3 2-4 (W88=24+EA)
reg,mem 9+EA 7 6 1 2-4 (W88=13+EA)
reg,immed 4 3 2 1 3-4
mem,immed 17+EA 7 7 3 3-6 (W88=23+EA)
accum,immed 4 3 2 1 2-3

24 ib AND AL, imm8 AL AND imm8
25 iw AND AX, imm16 AX AND i mm16
25 id AND EAX, imm32 EAX AND imm32
80 /4 ib AND r/m8,imm8 r/m8 AND imm8
81 /4 iw AND r/m16,imm16 r/m16 AND imm16
81 /4 id AND r/m32,imm32 r/m32 AND imm32
83 /4 ib AND r/m16,imm8 r/m16 AND imm8 (sign-extended)
83 /4 ib AND r/m32,imm8 r/m32 AND imm8 (sign-extended)
20 /r AND r/m8,r8 r/m8 AND r8
21 / r AND r/m16,r16 r/m16 AND r16
21 / r AND r/m32,r32 r/m32 AND r32
22 / r AND r8,r/m8 r8 AND r/m8
23 / r AND r16,r/m16 r16 AND r/m16
23 / r AND r32,r/m32 r32 AND r/m32


ARPL - Adjusted Requested Privilege Level of Selector (286+ PM)

Usage: ARPL dest,src
(286+ protected mode)

Modifies flags: ZF

Compares the RPL bits of "dest" against "src". If the RPL bits
of "dest" are less than "src", the destination RPL bits are set
equal to the source RPL bits and the Zero Flag is set. Otherwise
the Zero Flag is cleared.

Clocks Size
Operands 808x 286 386 486 Bytes
reg,reg - 10 20 9 2
mem,reg - 11 21 9 4

63 / r ARPL r/m16,r16 Adjust RPL of r/m16 to not less than RPL of r16


BOUND - Array Index Bound Check (80188+)

Usage: BOUND src,limit

Modifies flags: None

Array index in source register is checked against upper and lower
bounds in memory source. The first word located at "limit" is
the lower boundary and the word at "limit+2" is the upper array bound.
Interrupt 5 occurs if the source value is less than or higher than
the source.

Clocks Size
Operands 808x 286 386 486 Bytes
reg16,mem32 - nj=13 nj=10 7 2
reg32,mem64 - nj=13 nj=10 7 2
- nj = no jump taken

62 / r BOUND r16,m16&16
62 / r BOUND r32,m32&32


BSF - Bit Scan Forward (386+)

Usage: BSF dest,src

Modifies flags: ZF

Scans source operand for first bit set. Sets ZF if a bit is found
set and loads the destination with an index to first set bit. Clears
ZF is no bits are found set. BSF scans forward across bit pattern
(0-n) while BSR scans in reverse (n-0).

Clocks Size
Operands 808x 286 386 486 Bytes
reg,reg - - 10+3n 6-42 3
reg,mem - - 10+3n 7-43 3-7
reg32,reg32 - - 10+3n 6-42 3-7
reg32,mem32 - - 10+3n 7-43 3-7

0F BC BSF r16,r/m16 Bit scan forward on r/m16
0F BC BSF r32,r/m32 Bit scan forward on r/m32


BSR - Bit Scan Reverse (386+)

Usage: BSR dest,src

Modifies flags: ZF

Scans source operand for first bit set. Sets ZF if a bit is found
set and loads the destination with an index to first set bit. Clears
ZF is no bits are found set. BSF scans forward across bit pattern
(0-n) while BSR scans in reverse (n-0).

Clocks Size
Operands 808x 286 386 486 Bytes
reg,reg - - 10+3n 6-103 3
reg,mem - - 10+3n 7-104 3-7
reg32,reg32 - - 10+3n 6-103 3-7
reg32,mem32 - - 10+3n 7-104 3-7

0F BD BSR r16,r/m16 Bit scan reverse on r/m16
0F BD BSR r32,r/m32 Bit scan reverse on r/m32


BSWAP - Byte Swap (486+)

Usage: BSWAP reg32

Modifies flags: none

Changes the byte order of a 32 bit register from big endian to
little endian or vice versa. Result left in destination register
is undefined if the operand is a 16 bit register.

Clocks Size
Operands 808x 286 386 486 Bytes
reg32 - - - 1 2

0F C8+ rd BSWAP r32 Reverses the byte order of a 32-bit register.


BT - Bit Test (386+)

Usage: BT dest,src

Modifies flags: CF

The destination bit indexed by the source value is copied into the
Carry Flag.

Clocks Size
Operands 808x 286 386 486 Bytes
reg16,immed8 - - 3 3 4-8
mem16,immed8 - - 6 6 4-8
reg16,reg16 - - 3 3 3-7
mem16,reg16 - - 12 12 3-7

0F A3 BT r/m16,r16 Store selected bit in CF flag
0F A3 BT r/m32,r32 Store selected bit in CF flag
0F BA /4 ib BT r/m16,imm8 Store selected bit in CF flag
0F BA /4 ib BT r/m32,imm8 Store selected bit in CF flag


BTC - Bit Test with Compliment (386+)

Usage: BTC dest,src

Modifies flags: CF

The destination bit indexed by the source value is copied into the
Carry Flag after being complimented (inverted).

Clocks Size
Operands 808x 286 386 486 Bytes
reg16,immed8 - - 6 6 4-8
mem16,immed8 - - 8 8 4-8
reg16,reg16 - - 6 6 3-7
mem16,reg16 - - 13 13 3-7

0F BB BTC r/m16,r16 Store selected bit in CF flag and complement
0F BB BTC r/m32,r32 Store selected bit in CF flag and complement
0F BA /7 ib BTC r/m16,imm8 Store selected bit in CF flag and complement
0F BA /7 ib BTC r/m32,imm8 Store selected bit in CF flag and complement


BTR - Bit Test with Reset (386+)

Usage: BTR dest,src

Modifies flags: CF

The destination bit indexed by the source value is copied into the
Carry Flag and then cleared in the destination.

Clocks Size
Operands 808x 286 386 486 Bytes
reg16,immed8 - - 6 6 4-8
mem16,immed8 - - 8 8 4-8
reg16,reg16 - - 6 6 3-7
mem16,reg16 - - 13 13 3-7

0F B3 BTR r/m16,r16 Store selected bit in CF flag and clear
0F B3 BTR r/m32,r32 Store selected bit in CF flag and clear
0F BA /6 ib BTR r/m16,imm8 Store selected bit in CF flag and clear
0F BA /6 ib BTR r/m32,imm8 Store selected bit in CF flag and clear


BTS - Bit Test and Set (386+)

Usage: BTS dest,src

Modifies flags: CF

The destination bit indexed by the source value is copied into the
Carry Flag and then set in the destination.

Clocks Size
Operands 808x 286 386 486 Bytes
reg16,immed8 - - 6 6 4-8
mem16,immed8 - - 8 8 4-8
reg16,reg16 - - 6 6 3-7
mem16,reg16 - - 13 13 3-7

0F AB BTS r/m16,r16 Store selected bit in CF flag and set
0F AB BTS r/m32,r32 Store selected bit in CF flag and set
0F BA /5 ib BTS r/m16,imm8 Store selected bit in CF flag and set
0F BA /5 ib BTS r/m32,imm8 Store selected bit in CF flag and set


CALL - Procedure Call

Usage: CALL destination

Modifies flags: None

Pushes Instruction Pointer (and Code Segment for far calls) onto
stack and loads Instruction Pointer with the address of proc-name.
Code continues with execution at CS:IP.

Clocks
Operands 808x 286 386 486
rel16 (near, IP relative) 19 7 7+m 3
rel32 (near, IP relative) - - 7+m 3
reg16 (near, register indirect) 16 7 7+m 5
reg32 (near, register indirect) - - 7+m 5
mem16 (near, memory indirect) - 21+EA 11 10+m 5
mem32 (near, memory indirect) - - 10+m 5
ptr16:16 (far, full ptr supplied) 28 13 17+m 18
ptr16:32 (far, full ptr supplied) - - 17+m 18
ptr16:16 (far, ptr supplied, prot. mode) - 26 34+m 20
ptr16:32 (far, ptr supplied, prot. mode) - - 34+m 20
m16:16 (far, indirect) 37+EA 16 22+m 17
m16:32 (far, indirect) - - 22+m 17
m16:16 (far, indirect, prot. mode) - 29 38+m 20
m16:32 (far, indirect, prot. mode) - - 38+m 20
ptr16:16 (task, via TSS or task gate) - 177 TS 37+TS
m16:16 (task, via TSS or task gate) - 180/185 5+TS 37+TS
m16:32 (task) - - TS 37+TS
m16:32 (task) - - 5+TS 37+TS
ptr16:16 (gate, same privilege) - 41 52+m 35
ptr16:32 (gate, same privilege) - - 52+m 35
m16:16 (gate, same privilege) - 44 56+m 35
m16:32 (gate, same privilege) - - 56+m 35
ptr16:16 (gate, more priv, no parm) - 82 86+m 69
ptr16:32 (gate, more priv, no parm) - - 86+m 69
m16:16 (gate, more priv, no parm) - 83 90+m 69
m16:32 (gate, more priv, no parm) - - 90+m 69
ptr16:16 (gate, more priv, x parms) - 86+4x 94+4x+m 77+4x
ptr16:32 (gate, more priv, x parms) - - 94+4x+m 77+4x
m16:16 (gate, more priv, x parms) - 90+4x 98+4x+m 77+4x
m16:32 (gate, more priv, x parms) - - 98+4x+m 77+4x

E8 cw CALL rel16 Call near, relative, displacement relative to next instruction
E8 cd CALL rel32 Call near, relative, displacement relative to next instruction
FF /2 CALL r/m16 Call near, absolute indirect, address given in r/m16
FF /2 CALL r/m32 Call near, absolute indirect, address given in r/m32
9A cd CALL ptr16:16 Call far, absolute, address given in operand
9A cp CALL ptr16:32 Call far, absolute, address given in operand
FF /3 CALL m16:16 Call far, absolute indirect, address given in m16:16
FF /3 CALL m16:32 Call far, absolute indirect, address given in m16:32


CBW - Convert Byte to Word

Usage: CBW

Modifies flags: None

Converts byte in AL to word Value in AX by extending sign of AL
throughout register AH.

Clocks Size
Operands 808x 286 386 486 Bytes
none 2 2 3 3 1

98 CBW AX sign-extend of AL


CDQ - Convert Double to Quad (386+)

Usage: CDQ

Modifies flags: None

Converts signed DWORD in EAX to a signed quad word in EDX:EAX by
extending the high order bit of EAX throughout EDX

Clocks Size
Operands 808x 286 386 486 Bytes
none - - 2 3 1

99 CDQ EDX:EAX


CLC - Clear Carry

Usage: CLC

Modifies flags: CF

Clears the Carry Flag.

Clocks Size
Operands 808x 286 386 486 Bytes
none 2 2 2 2 1

F8 CLC Clear CF flag


CLD - Clear Direction Flag

Usage: CLD

Modifies flags: DF

Clears the Direction Flag causing string instructions to increment
the SI and DI index registers.

Clocks Size
Operands 808x 286 386 486 Bytes
none 2 2 2 2 1

FC CLD Clear DF flag


CLI - Clear Interrupt Flag (disable)

Usage: CLI

Modifies flags: IF

Disables the maskable hardware interrupts by clearing the Interrupt
flag. NMI's and software interrupts are not inhibited.

Clocks Size
Operands 808x 286 386 486 Bytes
none 2 2 3 5 1

FA CLI Clear interrupt flag; interrupts disabled when interrupt


CLTS - Clear Task Switched Flag (286+ privileged)

Usage: CLTS

Modifies flags: None

Clears the Task Switched Flag in the Machine Status Register. This
is a privileged operation and is generally used only by operating
system code.

Clocks Size
Operands 808x 286 386 486 Bytes
none - 2 5 7 2

0F 06 CLTS Clears TS flag in CR0


CMC - Complement Carry Flag

Usage: CMC

Modifies flags: CF

Toggles (inverts) the Carry Flag

Clocks Size
Operands 808x 286 386 486 Bytes
none 2 2 2 2 1

F5 CMC Complement CF flag


CMP - Compare

Usage: CMP dest,src

Modifies flags: AF CF OF PF SF ZF

Subtracts source from destination and updates the flags but does
not save result. Flags can subsequently be checked for conditions.

Clocks Size
Operands 808x 286 386 486 Bytes
reg,reg 3 2 2 1 2
mem,reg 9+EA 7 5 2 2-4 (W88=13+EA)
reg,mem 9+EA 6 6 2 2-4 (W88=13+EA)
reg,immed 4 3 2 1 3-4
mem,immed 10+EA 6 5 2 3-6 (W88=14+EA)
accum,immed 4 3 2 1 2-3

3C ib CMP AL, imm8 Compare imm8 with AL
3D iw CMP AX, imm16 Compare imm16 with AX
3D id CMP EAX, imm32 Compare imm32 with EAX
80 /7 ib CMP r/m8, imm8 Compare imm8 with r/m8
81 /7 iw CMP r/m16, imm16 Compare imm16 with r/m16
81 /7 id CMP r/m32,imm32 Compare imm32 with r/m32
83 /7 ib CMP r/m16,imm8 Compare imm8 with r/m16
83 /7 ib CMP r/m32,imm8 Compare imm8 with r/m32
38 / r CMP r/m8,r8 Compare r8 with r/m8
39 / r CMP r/m16,r16 Compare r16 with r/m16
39 / r CMP r/m32,r32 Compare r32 with r/m32
3A / r CMP r8,r/m8 Compare r/m8 with r8
3B / r CMP r16,r/m16 Compare r/m16 with r16
3B / r CMP r32,r/m32 Compare r/m32 with r32


CMPS - Compare String (Byte, Word or Doubleword)

Usage: CMPS dest,src
CMPSB
CMPSW
CMPSD (386+)

Modifies flags: AF CF OF PF SF ZF

Subtracts destination value from source without saving results.
Updates flags based on the subtraction and the index registers
(E)SI and (E)DI are incremented or decremented depending on the
state of the Direction Flag. CMPSB inc/decrements the index
registers by 1, CMPSW inc/decrements by 2, while CMPSD increments
or decrements by 4. The REP prefixes can be used to process
entire data items.

Clocks Size
Operands 808x 286 386 486 Bytes
dest,src 22 8 10 8 1 (W88=30)

A6 CMPS m8, m8
A7 CMPS m16, m16
A7 CMPS m32, m32
A6 CMPSB
A7 CMPSW
A7 CMPSD


CMPXCHG - Compare and Exchange

Usage: CMPXCHG dest,src (486+)

Modifies flags: AF CF OF PF SF ZF

Compares the accumulator (8-32 bits) with "dest". If equal the
"dest" is loaded with "src", otherwise the accumulator is loaded
with "dest".

Clocks Size
Operands 808x 286 386 486 Bytes
reg,reg - - - 6 2
mem,reg - - - 7 2
- add 3 clocks if the "mem,reg" comparison fails

0F B0/ r CMPXCHG r/m8,r8
0F B1/ r CMPXCHG r/m16,r16 Compare AX with r/m16
0F B1/ r CMPXCHG r/m32,r32 Compare EAX with r/m32


CWD - Convert Word to Doubleword

Usage: CWD

Modifies flags: None

Extends sign of word in register AX throughout register DX forming
a doubleword quantity in DX:AX.

Clocks Size
Operands 808x 286 386 486 Bytes
none 5 2 2 3 1

99 CWD DX:AX


CWDE - Convert Word to Extended Doubleword (386+)

Usage: CWDE

Modifies flags: None

Converts a signed word in AX to a signed doubleword in EAX by
extending the sign bit of AX throughout EAX.

Clocks Size
Operands 808x 286 386 486 Bytes
none - - 3 3 1

98 CWDE EAX sign-extend of AX


DAA - Decimal Adjust for Addition

Usage: DAA

Modifies flags: AF CF PF SF ZF (OF undefined)

Corrects result (in AL) of a previous BCD addition operation.
Contents of AL are changed to a pair of packed decimal digits.

Clocks Size
Operands 808x 286 386 486 Bytes
none 4 3 4 2 1

27 DAA Decimal adjust AL after addition


DAS - Decimal Adjust for Subtraction

Usage: DAS

Modifies flags: AF CF PF SF ZF (OF undefined)

Corrects result (in AL) of a previous BCD subtraction operation.
Contents of AL are changed to a pair of packed decimal digits.

Clocks Size
Operands 808x 286 386 486 Bytes
none 4 3 4 2 1

2F DAS Decimal adjust AL after subtraction


DEC - Decrement

Usage: DEC dest

Modifies flags: AF OF PF SF ZF

Unsigned binary subtraction of one from the destination.

Clocks Size
Operands 808x 286 386 486 Bytes
reg8 3 2 2 1 2
mem 15+EA 7 6 3 2-4
reg16/32 3 2 2 1 1

FE /1 DEC r/m8 Decrement r/m8 by 1
FF /1 DEC r/m16 Decrement r/m16 by 1
FF /1 DEC r/m32 Decrement r/m32 by 1
48+rw DEC r16 Decrement r16 by 1
48+rd DEC r32 Decrement r32 by 1


DIV - Divide

Usage: DIV src

Modifies flags: (AF,CF,OF,PF,SF,ZF undefined)

Unsigned binary division of accumulator by source. If the source
divisor is a byte value then AX is divided by "src" and the quotient
is placed in AL and the remainder in AH. If source operand is a word
value, then DX:AX is divided by "src" and the quotient is stored in AX
and the remainder in DX.

Clocks Size
Operands 808x 286 386 486 Bytes
reg8 80-90 14 14 16 2
reg16 144-162 22 22 24 2
reg32 - - 38 40 2
mem8 (86-96)+EA 17 17 16 2-4
mem16 (150-168)+EA 25 25 24 2-4 (W88=158-176+EA)
mem32 - - 41 40 2-4

F6 /6 DIV r/m8 Unsigned divide AX by r/m8
F7 /6 DIV r/m16 Unsigned divide DX:AX by r/m16; AX
F7 /6 DIV r/m32 Unsigned divide EDX:EAX by r/m32 doubleword


ENTER - Make Stack Frame (80188+)

Usage: ENTER locals,level

Modifies flags: None

Modifies stack for entry to procedure for high level language.

Operand "locals" specifies the amount of storage to be allocated
on the stack. "Level" specifies the nesting level of the routine.
Paired with the LEAVE instruction, this is an efficient method of
entry and exit to procedures.

Clocks Size
Operands 808x 286 386 486 Bytes
immed16,0 - 11 10 14 4
immed16,1 - 15 12 17 4
immed16,immed8 - 12+4(n-1) 15+4(n-1) 17+3n 4

C8 iw 00 ENTER imm16,0 Create a stack frame for a procedure
C8 iw 01 ENTER imm16,1 Create a nested stack frame for a procedure
C8 iw ib ENTER imm16,imm8 Create a nested stack frame for a procedure


ESC - Escape

Usage: ESC immed,src

Modifies flags: None

Provides access to the data bus for other resident processors.
The CPU treats it as a NOP but places memory operand on bus.

Clocks Size
Operands 808x 286 386 486 Bytes
immed,reg 2 9-20 ? 2
immed,mem 2 9-20 ? 2-4

D8h xxh ESC 0
D9h xxh ESC 1
DAh xxh ESC 2
DBh xxh ESC 3
DCh xxh ESC 4
DDh xxh ESC 5
DEh xxh ESC 6
DFh xxh ESC 7


HLT - Halt CPU

Usage: HLT

Modifies flags: None

Halts CPU until RESET line is activated, NMI or maskable interrupt
received. The CPU becomes dormant but retains the current CS:IP
for later restart.

Clocks Size
Operands 808x 286 386 486 Bytes
none 2 2 5 4 1

F4 HLT Halt


IDIV - Signed Integer Division

Usage: IDIV src

Modifies flags: (AF,CF,OF,PF,SF,ZF undefined)

Signed binary division of accumulator by source. If source is a
byte value, AX is divided by "src" and the quotient is stored in
AL and the remainder in AH. If source is a word value, DX:AX is
divided by "src", and the quotient is stored in AL and the
remainder in DX.

Clocks Size
Operands 808x 286 386 486 Bytes
reg8 101-112 17 19 19 2
reg16 165-184 25 27 27 2
reg32 - - 43 43 2
mem8 (107-118)+EA 20 22 20 2-4
mem16 (171-190)+EA 38 30 28 2-4 (W88=175-194)
mem32 - - 46 44 2-4

F6 /7 IDIV r/m8 Signed divide
F7 /7 IDIV r/m16 Signed divide
F7 /7 IDIV r/m32 Signed divide


IMUL - Signed Multiply

Usage: IMUL src
IMUL src,immed (286+)
IMUL dest,src,immed8 (286+)
IMUL dest,src (386+)

Modifies flags: CF OF (AF,PF,SF,ZF undefined)

Signed multiplication of accumulator by "src" with result placed
in the accumulator. If the source operand is a byte value, it
is multiplied by AL and the result stored in AX. If the source
operand is a word value it is multiplied by AX and the result is
stored in DX:AX. Other variations of this instruction allow
specification of source and destination registers as well as a
third immediate factor.

Clocks Size
Operands 808x 286 386 486 Bytes
reg8 80-98 13 9-14 13-18 2
reg16 128-154 21 9-22 13-26 2
reg32 - - 9-38 12-42 2
mem8 86-104 16 12-17 13-18 2-4
mem16 134-160 24 12-25 13-26 2-4
mem32 - - 12-41 13-42 2-4
reg16,reg16 - - 9-22 13-26 3-5
reg32,reg32 - - 9-38 13-42 3-5
reg16,mem16 - - 12-25 13-26 3-5
reg32,mem32 - - 12-41 13-42 3-5
reg16,immed - 21 9-22 13-26 3
reg32,immed - 21 9-38 13-42 3-6
reg16,reg16,immed - 2 9-22 13-26 3-6
reg32,reg32,immed - 21 9-38 13-42 3-6
reg16,mem16,immed - 24 12-25 13-26 3-6
reg32,mem32,immed - 24 12-41 13-42 3-6

F6 /5 IMUL r/m8 AXª AL * r/m byte
F7 /5 IMUL r/m16 DX:AX ª AX * r/m word
F7 /5 IMUL r/m32 EDX:EAX ª EAX * r/m doubleword
0F AF / r IMUL r16,r/m16 word register
0F AF / r IMUL r32,r/m32 doubleword register
6B / r ib IMUL r16,r/m16,imm8 word register
6B / r ib IMUL r32,r/m32,imm8 doubleword register byte
6B / r ib IMUL r16,imm8 word register
6B / r ib IMUL r32,imm8 doubleword register
69 / r iw IMUL r16,r/ m16,imm16
69 / r id IMUL r32,r/ m32,imm32
69 / r iw IMUL r16,imm16 word register ª r/m16 * immediate word
69 / r id IMUL r32,imm32 doubleword register ª r/m32 * immediate doubleword


IN - Input Byte or Word From Port

Usage: IN accum,port

Modifies flags: None

A byte, word or dword is read from "port" and placed in AL, AX or
EAX respectively. If the port number is in the range of 0-255
it can be specified as an immediate, otherwise the port number
must be specified in DX. Valid port ranges on the PC are 0-1024,
though values through 65535 may be specified and recognized by
third party vendors and PS/2's.

Clocks Size
Operands 808x 286 386 486 Bytes
accum,immed8 10/14 5 12 14 2
accum,immed8 (PM) 6/26 8/28/27 2
accum,DX 8/12 5 13 14 1
accum,DX (PM) 7/27 8/28/27 1
- 386+ protected mode timings depend on privilege levels.
first number is the timing if: CPL ¢ IOPL
second number is the timing if: CPL > IOPL or in VM 86 mode (386)
CPL • IOPL (486)
third number is the timing when: virtual mode on 486 processor
- 486 virtual mode always requires 27 cycles

E4 ib IN AL, imm8 Input byte from imm8 I/O port address into AL
E5 ib IN AX, imm8 Input byte from imm8 I/O port address into AX
E5 ib IN EAX, imm8 Input byte from imm8 I/O port address into EAX
EC IN AL,DX Input byte from I/O port in DX into AL
ED IN AX,DX Input word from I/O port in DX into AX
ED IN EAX,DX Input doubleword from I/O port in DX into EAX


INC - Increment

Usage: INC dest

Modifies flags: AF OF PF SF ZF

Adds one to destination unsigned binary operand.

Clocks Size
Operands 808x 286 386 486 Bytes
reg8 3 2 2 1 2
reg16 3 2 2 1 1
reg32 3 2 2 1 1
mem 15+EA 7 6 3 2-4 (W88=23+EA)

FE /0 INC r/m8 Increment r/m byte by 1
FF /0 INC r/m16 Increment r/m word by 1
FF /0 INC r/m32 Increment r/m doubleword by 1
40+ rw INC r16 Increment word register by 1
40+ rd INC r32 Increment doubleword register by 1


INS - Input String from Port (80188+)

Usage: INS dest,port
INSB
INSW
INSD (386+)

Modifies flags: None

Loads data from port to the destination ES:(E)DI (even if a
destination operand is supplied). (E)DI is adjusted by the size
of the operand and increased if the Direction Flag is cleared and
decreased if the Direction Flag is set. For INSB, INSW, INSD no
operands are allowed and the size is determined by the mnemonic.

Clocks Size
Operands 808x 286 386 486 Bytes
dest,port - 5 15 17 1
dest,port (PM) - 5 9/29 10/32/30 1
none - 5 15 17 1
none (PM) - 5 9/29 10/32/30 1
- 386+ protected mode timings depend on privilege levels.
first number is the timing if: CPL ¢ IOPL
second number is the timing if: CPL > IOPL
third number is the timing if: virtual mode on 486 processor

6C INS m8, DX
6D INS m16, DX
6D INS m32, DX


INT - Interrupt

Usage: INT num

Modifies flags: TF IF

Initiates a software interrupt by pushing the flags, clearing the
Trap and Interrupt Flags, pushing CS followed by IP and loading
CS:IP with the value found in the interrupt vector table. Execution
then begins at the location addressed by the new CS:IP

Clocks Size
Operands 808x 286 386 486 Bytes
3 (constant) 52/72 23+m 33 26 2
3 (prot. mode, same priv.) - 40+m 59 44 2
3 (prot. mode, more priv.) - 78+m 99 71 2
3 (from VM86 to PL 0) - - 119 82 2
3 (prot. mode via task gate) - 167+m TS 37+TS 2
immed8 51/71 23+m 37 30 1
immed8 (prot. mode, same priv.) - 40+m 59 44 1
immed8 (prot. mode, more priv.) - 78+m 99 71 1
immed8 (from VM86 to PL 0) - - 119 86 1
immed8 (prot. mode, via task gate) - 167+m TS 37+TS 1

CC INT 3 Interrupt 3 trap to debugger
CD ib INT imm8 Interrupt vector number specified by immediate byte


INTO - Interrupt on Overflow

Usage: INTO

Modifies flags: IF TF

If the Overflow Flag is set this instruction generates an INT 4
which causes the code addressed by 0000:0010 to be executed.

Clocks Size
Operands 808x 286 386 486 Bytes
none: jump 53/73 24+m 35 28 1
no jump 4 3 3 3
(prot. mode, same priv.) - - 59 46 1
(prot. mode, more priv.) - - 99 73 1
(from VM86 to PL 0) - - 119 84 1
(prot. mode, via task gate) - TS 39+TS 1

CE INTO Interrupt 4 if overflow flag is 1


INVD - Invalidate Cache (486+)

Usage: INVD

Modifies flags: none

Flushes CPU internal cache. Issues special function bus cycle
which indicates to flush external caches. Data in write-back
external caches is lost.

Clocks Size
Operands 808x 286 386 486 Bytes
none - - - 4 2

0F 08 INVD Flush internal caches; initiate flushing of external caches.


INVLPG - Invalidate Translation Look-Aside Buffer Entry (486+)

Usage: INVLPG

Modifies flags: none

Invalidates a single page table entry in the Translation
Look-Aside Buffer. Intel warns that this instruction may be
implemented differently on future processors.

Clocks Size
Operands 808x 286 386 486 Bytes
none - - - 12 2
- timing is for TLB entry hit only.

0F 01/7 INVLPG


IRET/IRETD - Interrupt Return

Usage: IRET
IRETD (386+)

Modifies flags: AF CF DF IF PF SF TF ZF

Returns control to point of interruption by popping IP, CS
and then the Flags from the stack and continues execution at
this location. CPU exception interrupts will return to the
instruction that cause the exception because the CS:IP placed
on the stack during the interrupt is the address of the offending
instruction.

Clocks Size
Operands 808x 286 386 486 Bytes
iret 32/44 17+m 22 15 1
iret (prot. mode) - 31+m 38 15 1
iret (to less privilege) - 55+m 82 36 1
iret (different task, NT=1) - 169+m TS TS+32 1
iretd - - 22/38 15 1
iretd (to less privilege) - - 82 36 1
iretd (to VM86 mode) - - 60 15 1
iretd (different task, NT=1) - - TS TS+32 1
- 386 timings are listed as real-mode/protected-mode

CF IRET Interrupt return (16-bit operand size)
CF IRETD Interrupt return (32-bit operand size)


Jxx - Jump Instructions Table

Mnemonic Meaning Jump Condition
JA Jump if Above CF=0 and ZF=0
JAE Jump if Above or Equal CF=0
JB Jump if Below CF=1
JBE Jump if Below or Equal CF=1 or ZF=1
JC Jump if Carry CF=1
JCXZ Jump if CX Zero CX=0
JE Jump if Equal ZF=1
JG Jump if Greater (signed) ZF=0 and SF=OF
JGE Jump if Greater or Equal (signed) SF=OF
JL Jump if Less (signed) SF != OF
JLE Jump if Less or Equal (signed) ZF=1 or SF != OF
JMP Unconditional Jump unconditional
JNA Jump if Not Above CF=1 or ZF=1
JNAE Jump if Not Above or Equal CF=1
JNB Jump if Not Below CF=0
JNBE Jump if Not Below or Equal CF=0 and ZF=0
JNC Jump if Not Carry CF=0
JNE Jump if Not Equal ZF=0
JNG Jump if Not Greater (signed) ZF=1 or SF != OF
JNGE Jump if Not Greater or Equal (signed) SF != OF
JNL Jump if Not Less (signed) SF=OF
JNLE Jump if Not Less or Equal (signed) ZF=0 and SF=OF
JNO Jump if Not Overflow (signed) OF=0
JNP Jump if No Parity PF=0
JNS Jump if Not Signed (signed) SF=0
JNZ Jump if Not Zero ZF=0
JO Jump if Overflow (signed) OF=1
JP Jump if Parity PF=1
JPE Jump if Parity Even PF=1
JPO Jump if Parity Odd PF=0
JS Jump if Signed (signed) SF=1
JZ Jump if Zero ZF=1

Clocks Size
Operands 808x 286 386 486 Bytes
Jx: jump 16 7+m 7+m 3 2
no jump 4 3 3 1
Jx near-label - - 7+m 3 4
no jump - - 3 1
- It's a good programming practice to organize code so the
expected case is executed without a jump since the actual
jump takes longer to execute than falling through the test.
- see JCXZ and JMP for their respective timings

77 cb JA rel8 Jump short if above (CF=0 and ZF=0)
73 cb JAE rel8 Jump short if above or equal (CF=0)
72 cb JB rel8 Jump short if below (CF=1)
76 cb JBE rel8 Jump short if below or equal (CF=1 or ZF=1)
72 cb JC rel8 Jump short if carry (CF=1)
E3 cb JCXZ rel8 Jump short if CX register is 0
E3 cb JECXZ rel8 Jump short if ECX register is 0
74 cb JE rel8 Jump short if equal (ZF=1)
7F cb JG rel8 Jump short if greater (ZF=0 and SF=OF)
7D cb JGE rel8 Jump short if greater or equal (SF=OF)
7C cb JL rel8 Jump short if less (SF<>OF)
7E cb JLE rel8 Jump short if less or equal (ZF=1 or SF<>OF)
76 cb JNA rel8 Jump short if not above (CF=1 or ZF=1)
72 cb JNAE rel8 Jump short if not above or equal (CF=1)
73 cb JNB rel8 Jump short if not below (CF=0)
77 cb JNBE rel8 Jump short if not below or equal (CF=0 and ZF=0)
73 cb JNC rel8 Jump short if not carry (CF=0)
75 cb JNE rel8 Jump short if not equal (ZF=0)
7E cb JNG rel8 Jump short if not greater (ZF=1 or SF<>OF)
7C cb JNGE rel8 Jump short if not greater or equal (SF<>OF)
7D cb JNL rel8 Jump short if not less (SF=OF)
7F cb JNLE rel8 Jump short if not less or equal (ZF=0 and SF=OF)
71 cb JNO rel8 Jump short if not overflow (OF=0)
7B cb JNP rel8 Jump short if not parity (PF=0)
79 cb JNS rel8 Jump short if not sign (SF=0)
75 cb JNZ rel8 Jump short if not zero (ZF=0)
70 cb JO rel8 Jump short if overflow (OF=1)
7A cb JP rel8 Jump short if parity (PF=1)
7A cb JPE rel8 Jump short if parity even (PF=1)
7B cb JPO rel8 Jump short if parity odd (PF=0)
78 cb JS rel8 Jump short if sign (SF=1)
74 cb JZ rel8 Jump short if zero (ZF = 1)
0F 87 cw/cd JA rel16/32 Jump near if above (CF=0 and ZF=0)
0F 83 cw/cd JAE rel16/32 Jump near if above or equal (CF=0)
0F 82 cw/cd JB rel16/32 Jump near if below (CF=1)
0F 86 cw/cd JBE rel16/32 Jump near if below or equal (CF=1 or ZF=1)
0F 82 cw/cd JC rel16/32 Jump near if carry (CF=1)
0F 84 cw/cd JE rel16/32 Jump near if equal (ZF=1)
0F 84 cw/cd JZ rel16/32 Jump near if 0 (ZF=1)
0F 8F cw/cd JG rel16/32 Jump near if greater (ZF=0 and SF=OF)
0F 8D cw/cd JGE rel16/32 Jump near if greater or equal (SF=OF)
0F 8C cw/cd JL rel16/32 Jump near if less (SF<>OF)
0F 8E cw/cd JLE rel16/32 Jump near if less or equal (ZF=1 or SF<>OF)
0F 86 cw/cd JNA rel16/32 Jump near if not above (CF=1 or ZF=1)
0F 82 cw/cd JNAE rel16/32 Jump near if not above or equal (CF=1)
0F 83 cw/cd JNB rel16/32 Jump near if not below (CF=0)
0F 87 cw/cd JNBE rel16/32 Jump near if not below or equal (CF=0 and ZF=0)
0F 83 cw/cd JNC rel16/32 Jump near if not carry (CF=0)
0F 85 cw/cd JNE rel16/32 Jump near if not equal (ZF=0)
0F 8E cw/cd JNG rel16/32 Jump near if not greater (ZF=1 or SF<>OF)
0F 8C cw/cd JNGE rel16/32 Jump near if not greater or equal (SF<>OF)
0F 8D cw/cd JNL rel16/32 Jump near if not less (SF=OF)
0F 8F cw/cd JNLE rel16/32 Jump near if not less or equal (ZF=0 and SF=OF)
0F 81 cw/cd JNO rel16/32 Jump near if not overflow (OF=0)
0F 8B cw/cd JNP rel16/32 Jump near if not parity (PF=0)
0F 89 cw/cd JNS rel16/32 Jump near if not sign (SF=0)
0F 85 cw/cd JNZ rel16/32 Jump near if not zero (ZF=0)
0F 80 cw/cd JO rel16/32 Jump near if overflow (OF=1)
0F 8A cw/cd JP rel16/32 Jump near if parity (PF=1)
0F 8A cw/cd JPE rel16/32 Jump near if parity even (PF=1)
0F 8B cw/cd JPO rel16/32 Jump near if parity odd (PF=0)
0F 88 cw/cd JS rel16/32 Jump near if sign (SF=1)
0F 84 cw/cd JZ rel16/32 Jump near if 0 (ZF=1)


JCXZ/JECXZ - Jump if Register (E)CX is Zero

Usage: JCXZ label
JECXZ label (386+)

Modifies flags: None

Causes execution to branch to "label" if register CX is zero. Uses
unsigned comparision.

Clocks Size
Operands 808x 286 386 486 Bytes
label: jump 18 8+m 9+m 8 2
no jump 6 4 5 5

E3 cb JCXZ rel8 Jump short if CX register is 0
E3 cb JECXZ rel8 Jump short if ECX register is 0


JMP - Unconditional Jump

Usage: JMP target

Modifies flags: None

Unconditionally transfers control to "label". Jumps by default
are within -32768 to 32767 bytes from the instruction following
the jump. NEAR and SHORT jumps cause the IP to be updated while FAR
jumps cause CS and IP to be updated.

Clocks
Operands 808x 286 386 486
rel8 (relative) 15 7+m 7+m 3
rel16 (relative) 15 7+m 7+m 3
rel32 (relative) - - 7+m 3
reg16 (near, register indirect) 11 7+m 7+m 5
reg32 (near, register indirect) - - 7+m 5
mem16 (near, mem indirect) 18+EA 11+m 10+m 5
mem32 (near, mem indirect) 24+EA 15+m 10+m 5
ptr16:16 (far, dword immed) - - 12+m 17
ptr16:16 (far, PM dword immed) - - 27+m 19
ptr16:16 (call gate, same priv.) - 38+m 45+m 32
ptr16:16 (via TSS) - 175+m TS 42+TS
ptr16:16 (via task gate) - 180+m TS 43+TS
mem16:16 (far, indirect) - - 43+m 13
mem16:16 (far, PM indirect) - - 31+m 18
mem16:16 (call gate, same priv.) - 41+m 49+m 31
mem16:16 (via TSS) - 178+m 5+TS 41+TS
mem16:16 (via task gate) - 183+m 5+TS 42+TS
ptr16:32 (far, 6 byte immed) - - 12+m 13
ptr16:32 (far, PM 6 byte immed) - - 27+m 18
ptr16:32 (call gate, same priv.) - - 45+m 31
ptr16:32 (via TSS) - - TS 42+TS
ptr16:32 (via task state) - - TS 43+TS
m16:32 (far, address at dword) - - 43+m 13
m16:32 (far, address at dword) - - 31+m 18
m16:32 (call gate, same priv.) - - 49+m 31
m16:32 (via TSS) - - 5+TS 41+TS
m16:32 (via task state) - - 5+TS 42+TS

EB cb JMP rel8 Jump short, relative, displacement relative to next instruction
E9 cw JMP rel16 Jump near, relative, displacement relative to next instruction
E9 cd JMP rel32 Jump near, relative, displacement relative to next instruction
FF /4 JMP r/m16 Jump near, absolute indirect, address given in r/m16
FF /4 JMP r/m32 Jump near, absolute indirect, address given in r/m32
EA cd JMP ptr16:16 Jump far, absolute, address given in operand
EA cp JMP ptr16:32 Jump far, absolute, address given in operand
FF /5 JMP m16:16 Jump far, absolute indirect, address given in m16:16
FF /5 JMP m16:32 Jump far, absolute indirect, address given in m16:32


LAHF - Load Register AH From Flags

Usage: LAHF

Modifies flags: None

Copies bits 0-7 of the flags register into AH. This includes flags
AF, CF, PF, SF and ZF other bits are undefined.
AH := SF ZF xx AF xx PF xx CF

Clocks Size
Operands 808x 286 386 486 Bytes
none 4 2 2 3 1

9F LAHF Load: AH = EFLAGS(SF:ZF:0:AF:0:PF:1:CF)


LAR - Load Access Rights (286+ protected)

Usage: LAR dest,src

Modifies flags: ZF

The high byte of the of the destination register is overwritten by
the value of the access rights byte and the low order byte is zeroed
depending on the selection in the source operand. The Zero Flag is
set if the load operation is successful.

Clocks Size
Operands 808x 286 386 486 Bytes
reg16,reg16 - 14 15 11 3
reg32,reg32 - - 15 11 3
reg16,mem16 - 16 16 11 3-7
reg32,mem32 - - 16 11 3-7

0F 02 / r LAR r16,r/m16 r16 ª r/m16 masked by FF00H
0F 02 / r LAR r32,r/m32 r32 ª r/m32 masked by 00FxFF00H


LDS - Load Pointer Using DS

Usage: LDS dest,src

Modifies flags: None

Loads 32-bit pointer from memory source to destination register
and DS. The offset is placed in the destination register and the
segment is placed in DS. To use this instruction the word at the
lower memory address must contain the offset and the word at the
higher address must contain the segment. This simplifies the loading
of far pointers from the stack and the interrupt vector table.

Clocks Size
Operands 808x 286 386 486 Bytes
reg16,mem32 16+EA 7 7 6 2-4
reg,mem (PM) - - 22 12 5-7

C5 / r LDS r16,m16:16 Load DS: r16 with far pointer from memory
C5 / r LDS r32,m16:32 Load DS: r32 with far pointer from memory


LEA - Load Effective Address

Usage: LEA dest,src

Modifies flags: None

Transfers offset address of "src" to the destination register.

Clocks Size
Operands 808x 286 386 486 Bytes
reg,mem 2+EA 3 2 1 2-4
- the MOV instruction can often save clock cycles when used in
place of LEA on 8088 processors

8D / r LEA r16,m Store effective address for m in register r16
8D / r LEA r32,m Store effective address for m in register r32


LEAVE - Restore Stack for Procedure Exit (80188+)

Usage: LEAVE

Modifies flags: None

Releases the local variables created by the previous ENTER
instruction by restoring SP and BP to their condition before
the procedure stack frame was initialized.

Clocks Size
Operands 808x 286 386 486 Bytes
none - 5 4 5 1

C9 LEAVE Set SP to BP, then pop BP
C9 LEAVE Set ESP to EBP, then pop EBP


LES - Load Pointer Using ES

Usage: LES dest,src

Modifies flags: None

Loads 32-bit pointer from memory source to destination register
and ES. The offset is placed in the destination register and the
segment is placed in ES. To use this instruction the word at the
lower memory address must contain the offset and the word at the
higher address must contain the segment. This simplifies the loading
of far pointers from the stack and the interrupt vector table.

Clocks Size
Operands 808x 286 386 486 Bytes
reg,mem 16+EA 7 7 6 2-4 (W88=24+EA)
reg,mem (PM) - - 22 12 5-7

C4 / r LES r16,m16:16 Load ES: r16 with far pointer from memory
C4 / r LES r32,m16:32 Load ES: r32 with far pointer from memory


LFS - Load Pointer Using FS (386+)

Usage: LFS dest,src

Modifies flags: None

Loads 32-bit pointer from memory source to destination register
and FS. The offset is placed in the destination register and the
segment is placed in FS. To use this instruction the word at the
lower memory address must contain the offset and the word at the
higher address must contain the segment. This simplifies the loading
of far pointers from the stack and the interrupt vector table.

Clocks Size
Operands 808x 286 386 486 Bytes
reg,mem - - 7 6 5-7
reg,mem (PM) - - 22 12 5-7

0F B4 / r LFS r16,m16:16 Load FS: r16 with far pointer from memory
0F B4 / r LFS r32,m16:32 Load FS: r32 with far pointer from memory


LGDT - Load Global Descriptor Table (286+ privileged)

Usage: LGDT src

Modifies flags: None

Loads a value from an operand into the Global Descriptor Table
(GDT) register.

Clocks Size
Operands 808x 286 386 486 Bytes
mem64 - 11 11 11 5

0F 01 /2 LGDT m16&32 Load m into GDTR


LIDT - Load Interrupt Descriptor Table (286+ privileged)

Usage: LIDT src

Modifies flags: None

Loads a value from an operand into the Interrupt Descriptor Table
(IDT) register.

Clocks Size
Operands 808x 286 386 486 Bytes
mem64 - 12 11 11 5

0F 01 /3 LIDT m16&32 Load m into IDTR


LGS - Load Pointer Using GS (386+)

Usage: LGS dest,src

Modifies flags: None

Loads 32-bit pointer from memory source to destination register
and GS. The offset is placed in the destination register and the
segment is placed in GS. To use this instruction the word at the
lower memory address must contain the offset and the word at the
higher address must contain the segment. This simplifies the loading
of far pointers from the stack and the interrupt vector table.

Clocks Size
Operands 808x 286 386 486 Bytes
reg,mem - - 7 6 5-7
reg,mem (PM) - - 22 12 5-7

0F B5 / r LGS r16,m16:16 Load GS: r16 with far pointer from memory
0F B5 / r LGS r32,m16:32 Load GS: r32 with far pointer from memory


LLDT - Load Local Descriptor Table (286+ privileged)

Usage: LLDT src

Modifies flags: None

Loads a value from an operand into the Local Descriptor Table
Register (LDTR).

Clocks Size
Operands 808x 286 386 486 Bytes
reg16 - 17 20 11 3
mem16 - 19 24 11 5

0F 00 /2 LLDT r/m16 Load segment selector r/m16 into LDTR


LMSW - Load Machine Status Word (286+ privileged)

Usage: LMSW src

Modifies flags: None

Loads the Machine Status Word (MSW) from data found at "src"

Clocks Size
Operands 808x 286 386 486 Bytes
reg16 - 3 10 13 3
mem16 - 6 13 13 5

0F 01 /6 LMSW r/m16 Loads r/m16 in machine status word of CR0


LOCK - Lock Bus

Usage: LOCK
LOCK: (386+ prefix)

Modifies flags: None

This instruction is a prefix that causes the CPU assert bus lock
signal during the execution of the next instruction. Used to
avoid two processors from updating the same data location. The
286 always asserts lock during an XCHG with memory operands. This
should only be used to lock the bus prior to XCHG, MOV, IN and
OUT instructions.

Clocks Size
Operands 808x 286 386 486 Bytes
none 2 0 0 1 1

F0 LOCK Asserts LOCK# signal


LODS - Load String (Byte, Word or Double)

Usage: LODS src
LODSB
LODSW
LODSD (386+)

Modifies flags: None

Transfers string element addressed by DS:SI (even if an operand is
supplied) to the accumulator. SI is incremented based on the size
of the operand or based on the instruction used. If the Direction
Flag is set SI is decremented, if the Direction Flag is clear SI
is incremented. Use with REP prefixes.

Clocks Size
Operands 808x 286 386 486 Bytes
src 12/16 5 5 5 1

AC LODS m8 Load byte at address DS:(E)SI into AL
AD LODS m16 Load word at address DS:(E)SI into AX
AD LODS m32 Load doubleword at address DS:(E)SI into EAX
AC LODSB Load byte at address DS:(E)SI into AL
AD LODSW Load word at address DS:(E)SI into AX
AD LODSD Load doubleword at address DS:(E)SI into EAX


LOOP - Decrement CX and Loop if CX Not Zero

Usage: LOOP label

Modifies flags: None

Decrements CX by 1 and transfers control to "label" if CX is not
Zero. The "label" operand must be within -128 or 127 bytes of the
instruction following the loop instruction

Clocks Size
Operands 808x 286 386 486 Bytes
label: jump 18 8+m 11+m 6 2
no jump 5 4 ? 2

E2 cb LOOP rel8 Decrement count; jump short if count = 0


LOOPE/LOOPZ - Loop While Equal / Loop While Zero

Usage: LOOPE label
LOOPZ label

Modifies flags: None

Decrements CX by 1 (without modifying the flags) and transfers
control to "label" if CX != 0 and the Zero Flag is set. The
"label" operand must be within -128 or 127 bytes of the instruction
following the loop instruction.

Clocks Size
Operands 808x 286 386 486 Bytes
label: jump 18 8+m 11+m 9 2
no jump 5 4 ? 6

E1 cb LOOPE
E1 cb LOOPZ


LOOPNZ/LOOPNE - Loop While Not Zero / Loop While Not Equal

Usage: LOOPNZ label
LOOPNE label

Modifies flags: None

Decrements CX by 1 (without modifying the flags) and transfers
control to "label" if CX != 0 and the Zero Flag is clear. The
"label" operand must be within -128 or 127 bytes of the instruction
following the loop instruction.

Clocks Size
Operands 808x 286 386 486 Bytes
label: jump 19 8+m 11+m 9 2
no jump 5 4 ? 6

E0 cb LOOPNE
E0 cb LOOPNZ


LSL - Load Segment Limit (286+ protected)

Usage: LSL dest,src

Modifies flags: ZF

Loads the segment limit of a selector into the destination register
if the selector is valid and visible at the current privilege level.
If loading is successful the Zero Flag is set, otherwise it is
cleared.

Clocks Size
Operands 808x 286 386 486 Bytes
reg16,reg16 - 14 20/25 10 3
reg32,reg32 - - 20/25 10 3
reg16,mem16 - 16 21/26 10 5
reg32,mem32 - - 21/26 10 5
- 386 times are listed "byte granular" / "page granular"

0F 03 / r LSL r16,r/m16 Load: r16 ª segment limit, selector r/m16
0F 03 / r LSL r32,r/m32 Load: r32 ª segment limit, selector r/m32)


LSS - Load Pointer Using SS (386+)

Usage: LSS dest,src

Modifies flags: None

Loads 32-bit pointer from memory source to destination register
and SS. The offset is placed in the destination register and the
segment is placed in SS. To use this instruction the word at the
lower memory address must contain the offset and the word at the
higher address must contain the segment. This simplifies the loading
of far pointers from the stack and the interrupt vector table.

Clocks Size
Operands 808x 286 386 486 Bytes
reg,mem - - 7 6 5-7
reg,mem (PM) - - 22 12 5-7

0F B2 / r LSS r16,m16:16 Load SS: r16 with far pointer from memory
0F B2 / r LSS r32,m16:32 Load SS: r32 with far pointer from memory


LTR - Load Task Register (286+ privileged)

Usage: LTR src

Modifies flags: None

Loads the current task register with the value specified in "src".

Clocks Size
Operands 808x 286 386 486 Bytes
reg16 - 17 23 20 3
mem16 - 19 27 20 5

0F 00 /3 LTR r/m16 Load r/m16 into task register


MOV - Move Byte or Word

Usage: MOV dest,src

Modifies flags: None

Copies byte or word from the source operand to the destination
operand. If the destination is SS interrupts are disabled except
on early buggy 808x CPUs. Some CPUs disable interrupts if the
destination is any of the segment registers

Clocks Size
Operands 808x 286 386 486 Bytes
reg,reg 2 2 2 1 2
mem,reg 9+EA 3 2 1 2-4 (W88=13+EA)
reg,mem 8+EA 5 4 1 2-4 (W88=12+EA)
mem,immed 10+EA 3 2 1 3-6 (W88=14+EA)
reg,immed 4 2 2 1 2-3
mem,accum 10 3 2 1 3 (W88=14)
accum,mem 10 5 4 1 3 (W88=14)
segreg,reg16 2 2 2 3 2
segreg,mem16 8+EA 5 5 9 2-4 (W88=12+EA)
reg16,segreg 2 2 2 3 2
mem16,segreg 9+EA 3 2 3 2-4 (W88=13+EA)
reg32,CR0/CR2/CR3 - - 6 4
CR0,reg32 - - 10 16
CR2,reg32 - - 4 4 3
CR3,reg32 - - 5 4 3
reg32,DR0/DR1/DR2/DR3 - 22 10 3
reg32,DR6/DR7 - - 22 10 3
DR0/DR1/DR2/DR3,reg32 - 22 11 3
DR6/DR7,reg32 - - 16 11 3
reg32,TR6/TR7 - - 12 4 3
TR6/TR7,reg32 - - 12 4 3
reg32,TR3 3
TR3,reg32 6
- when the 386 special registers are used all operands are 32 bits

88 / r MOV r/m8,r8 Move r8 to r/m8
89 / r MOV r/m16,r16 Move r16 to r/m16
89 / r MOV r/m32,r32 Move r32 to r/m32
8A / r MOV r8,r/m8 Move r/m8 to r8
8B / r MOV r16,r/m16 Move r/m16 to r16
8B / r MOV r32,r/m32 Move r/m32 to r32
8C / r MOV r/m16,Sreg** Move segment register to r/m16
8E / r MOV Sreg,r/m16** Move r/m16 to segment register
A0 MOV AL, moffs8* Move byte at ( seg:offset) to AL
A1 MOV AX, moffs16* Move word at ( seg:offset) to AX
A1 MOV EAX, moffs32* Move doubleword at ( seg:offset) to EAX
A2 MOV moffs8*,AL Move AL to ( seg:offset)
A3 MOV moffs16*,AX Move AX to ( seg:offset)
A3 MOV moffs32*,EAX Move EAX to ( seg:offset)
B0+ rb MOV r8,imm8 Move imm8 to r8
B8+ rw MOV r16,imm16 Move imm16 to r16
B8+ rd MOV r32,imm32 Move imm32 to r32
C6 / 0 MOV r/m8,imm8 Move imm8 to r/m8
C7 / 0 MOV r/m16,imm16 Move imm16 to r/m16
C7 / 0 MOV r/m32,imm32 Move imm32 to r/m32
0F 22 / r MOV CR0, r32 Move r32 to CR0
0F 22 / r MOV CR2, r32 Move r32 to CR2
0F 22 / r MOV CR3, r32 Move r32 to CR3
0F 22 / r MOV CR4, r32 Move r32 to CR4
0F 20 / r MOV r32,CR0 Move CR0 to r32
0F 20 / r MOV r32,CR2 Move CR2 to r32
0F 20 / r MOV r32,CR3 Move CR3 to r32
0F 20 / r MOV r32,CR4 Move CR4 to r32
0F 21/ r MOV r32, DR0-DR7 Move debug register to r32
0F 23 / r MOV DR0-DR7, r32 Move r32 to debug register


MOVS - Move String (Byte or Word)

Usage: MOVS dest,src
MOVSB
MOVSW
MOVSD (386+)

Modifies flags: None

Copies data from addressed by DS:SI (even if operands are given) to
the location ES:DI destination and updates SI and DI based on the
size of the operand or instruction used. SI and DI are incremented
when the Direction Flag is cleared and decremented when the Direction
Flag is Set. Use with REP prefixes.

Clocks Size
Operands 808x 286 386 486 Bytes
dest,src 18 5 7 7 1 (W88=26)

A4 MOVS m8, m8 Move byte at address DS:(E)SI to address ES:(E)DI
A5 MOVS m16, m16 Move word at address DS:(E)SI to address ES:(E)DI
A5 MOVS m32, m32 Move doubleword at address DS:(E)SI to address ES:(E)DI
A4 MOVSB Move byte at address DS:(E)SI to address ES:(E)DI
A5 MOVSW Move word at address DS:(E)SI to address ES:(E)DI
A5 MOVSD Move doubleword at address DS:(E)SI to address ES:(E)DI


MOVSX - Move with Sign Extend (386+)

Usage: MOVSX dest,src

Modifies flags: None

Copies the value of the source operand to the destination register
with the sign extended.

Clocks Size
Operands 808x 286 386 486 Bytes
reg,reg - - 3 3 3
reg,mem - - 6 3 3-7

0F BE / r MOVSX r16,r/m8 Move byte to word with sign-extension
0F BE / r MOVSX r32,r/m8 Move byte to doubleword, sign-extension
0F BF / r MOVSX r32,r/m16 Move word to doubleword, sign-extension


MOVZX - Move with Zero Extend (386+)

Usage: MOVZX dest,src

Modifies flags: None

Copies the value of the source operand to the destination register
with the zeroes extended.

Clocks Size
Operands 808x 286 386 486 Bytes
reg,reg - - 3 3 3
reg,mem - - 6 3 3-7

0F B6 / r MOVZX r16,r/m8 Move byte to word with zero-extension
0F B6 / r MOVZX r32,r/m8 Move byte to doubleword, zero-extension
0F B7 / r MOVZX r32,r/m16 Move word to doubleword, zero-extension


MUL - Unsigned Multiply

Usage: MUL src

Modifies flags: CF OF (AF,PF,SF,ZF undefined)

Unsigned multiply of the accumulator by the source. If "src" is
a byte value, then AL is used as the other multiplicand and the
result is placed in AX. If "src" is a word value, then AX is
multiplied by "src" and DX:AX receives the result. If "src" is
a double word value, then EAX is multiplied by "src" and EDX:EAX
receives the result. The 386+ uses an early out algorithm which
makes multiplying any size value in EAX as fast as in the 8 or 16
bit registers.

Clocks Size
Operands 808x 286 386 486 Bytes
reg8 70-77 13 9-14 13-18 2
reg16 118-113 21 9-22 13-26 2
reg32 - - 9-38 13-42 2-4
mem8 (76-83)+EA 16 12-17 13-18 2-4
mem16 (124-139)+EA 24 12-25 13-26 2-4
mem32 - - 12-21 13-42 2-4

F6 /4 MUL r/m8 Unsigned multiply (AX ª AL * r/m8)
F7 /4 MUL r/m16 Unsigned multiply (DX:AX ª AX * r/m16)
F7 /4 MUL r/m32 Unsigned multiply (EDX:EAX ª EAX * r/m32)


NEG - Two's Complement Negation

Usage: NEG dest

Modifies flags: AF CF OF PF SF ZF

Subtracts the destination from 0 and saves the 2s complement of
"dest" back into "dest".

Clocks Size
Operands 808x 286 386 486 Bytes
reg 3 2 2 1 2
mem 16+EA 7 6 3 2-4 (W88=24+EA)

F6 /3 NEG r/m8 Two's complement negate r/m8
F7 /3 NEG r/m16 Two's complement negate r/m16
F7 /3 NEG r/m32 Two's complement negate r/m32


NOP - No Operation (90h)

Usage: NOP

Modifies flags: None

This is a do nothing instruction. It results in occupation of both
space and time and is most useful for patching code segments.
(This is the original XCHG AL,AL instruction)

Clocks Size
Operands 808x 286 386 486 Bytes
none 3 3 3 1 1

90 NOP No operation


NOT - One's Compliment Negation (Logical NOT)

Usage: NOT dest

Modifies flags: None

Inverts the bits of the "dest" operand forming the 1s complement.

Clocks Size
Operands 808x 286 386 486 Bytes
reg 3 2 2 1 2
mem 16+EA 7 6 3 2-4 (W88=24+EA)

F6 /2 NOT r/m8 Reverse each bit of r/m8
F7 /2 NOT r/m16 Reverse each bit of r/m16
F7 /2 NOT r/m32 Reverse each bit of r/m32


OR - Inclusive Logical OR

Usage: OR dest,src

Modifies flags: CF OF PF SF ZF (AF undefined)

Logical inclusive OR of the two operands returning the result in
the destination. Any bit set in either operand will be set in the
destination.

Clocks Size
Operands 808x 286 386 486 Bytes
reg,reg 3 2 2 1 2
mem,reg 16+EA 7 7 3 2-4 (W88=24+EA)
reg,mem 9+EA 7 6 2 2-4 (W88=13+EA)
reg,immed 4 3 2 1 3-4
mem8,immed8 17+EA 7 7 3 3-6
mem16,immed16 25+EA 7 7 3 3-6
accum,immed 4 3 2 1 2-3

0C ib OR AL, imm8 AL OR imm8
0D iw OR AX, imm16 AX OR imm16
0D id OR EAX, imm32 EAX OR imm32
80 /1 ib OR r/m8,imm8 r/m8 OR imm8
81 /1 iw OR r/m16,imm16 r/m16 OR imm16
81 /1 id OR r/m32,imm32 r/m32 OR imm32
83 /1 ib OR r/m16,imm8 r/m16 OR imm8 (sign-extended)
83 /1 ib OR r/m32,imm8 r/m32 OR imm8 (sign-extended)
08 / r OR r/m8,r8 r/m8 OR r8
09 / r OR r/m16,r16 r/m16 OR r16
09 / r OR r/m32,r32 r/m32 OR r32
0A / r OR r8,r/m8 r8 OR r/m8
0B / r OR r16,r/m16 r16 OR r/m16
0B / r OR r32,r/m32 r32 OR r/m32


OUT - Output Data to Port

Usage: OUT port,accum

Modifies flags: None

Transfers byte in AL,word in AX or dword in EAX to the specified
hardware port address. If the port number is in the range of 0-255
it can be specified as an immediate. If greater than 255 then the
port number must be specified in DX. Since the PC only decodes 10
bits of the port address, values over 1023 can only be decoded by
third party vendor equipment and also map to the port range 0-1023.

Clocks Size
Operands 808x 286 386 486 Bytes
immed8,accum 10/14 3 10 16 2
immed8,accum (PM) - - 4/24 11/31/29 2
DX,accum 8/12 3 11 16 1
DX,accum (PM) - - 5/25 10/30/29 1
- 386+ protected mode timings depend on privilege levels.
first number is the timing when: CPL ¢ IOPL
second number is the timing when: CPL > IOPL
third number is the timing when: virtual mode on 486 processor

E6 ib OUT imm8, AL Output byte in AL to I/O port address imm8
E7 ib OUT imm8, AX Output word in AX to I/O port address imm8
E7 ib OUT imm8, EAX Output doubleword in EAX to I/O port address imm8
EE OUT DX, AL Output byte in AL to I/O port address in DX
EF OUT DX, AX Output word in AX to I/O port address in DX
EF OUT DX, EAX Output doubleword in EAX to I/O port address in DX


OUTS - Output String to Port (80188+)

Usage: OUTS port,src
OUTSB
OUTSW
OUTSD (386+)

Modifies flags: None

Transfers a byte, word or doubleword from "src" to the hardware
port specified in DX. For instructions with no operands the "src"
is located at DS:SI and SI is incremented or decremented by the
size of the operand or the size dictated by the instruction format.
When the Direction Flag is set SI is decremented, when clear, SI is
incremented. If the port number is in the range of 0-255 it can
be specified as an immediate. If greater than 255 then the port
number must be specified in DX. Since the PC only decodes 10 bits
of the port address, values over 1023 can only be decoded by third
party vendor equipment and also map to the port range 0-1023.

Clocks Size
Operands 808x 286 386 486 Bytes
port,src - 5 14 17 1
port,src (PM) - - 8/28 10/32/30 1
- 386+ protected mode timings depend on privilege levels.
first number is the timing when: CPL ¢ IOPL
second number is the timing when: CPL > IOPL
third number is the timing when: virtual mode on 486 processor

6E OUTS DX, m8
6F OUTS DX, m16
6F OUTS DX, m32
6E OUTSB
6F OUTSW
6F OUTSD


POP - Pop Word off Stack

Usage: POP dest

Modifies flags: None

Transfers word at the current stack top (SS:SP) to the destination
then increments SP by two to point to the new stack top. CS is not
a valid destination.

Clocks Size
Operands 808x 286 386 486 Bytes
reg16 8 5 4 4 1
reg32 4 - - 4 1
segreg 8 5 7 3 1
mem16 17+EA 5 5 6 2-4
mem32 5 - - 6 2-4

8F /0 POP m16 Pop top of stack into m16; increment stack pointer
8F /0 POP m32 Pop top of stack into m32; increment stack pointer
58+ rw POP r16 Pop top of stack into r16; increment stack pointer
58+ rd POP r32 Pop top of stack into r32; increment stack pointer
1F POP DS Pop top of stack into DS; increment stack pointer
07 POP ES Pop top of stack into ES; increment stack pointer
17 POP SS Pop top of stack into SS; increment stack pointer
0F A1 POP FS Pop top of stack into FS; increment stack pointer
0F A9 POP GS Pop top of stack into GS; increment stack pointer


POPA/POPAD - Pop All Registers onto Stack (80188+)

Usage: POPA
POPAD (386+)

Modifies flags: None

Pops the top 8 words off the stack into the 8 general purpose 16/32
bit registers. Registers are popped in the following order: (E)DI,
(E)SI, (E)BP, (E)SP, (E)DX, (E)CX and (E)AX. The (E)SP value popped
from the stack is actually discarded.

Clocks Size
Operands 808x 286 386 486 Bytes
none - 19 24 9 1

61 POPA Pop DI, SI, BP, BX, DX, CX, and AX
61 POPAD Pop EDI, ESI, EBP, EBX, EDX, ECX, and EAX


POPF/POPFD - Pop Flags off Stack

Usage: POPF
POPFD (386+)

Modifies flags: all flags

Pops word/doubleword from stack into the Flags Register and then
increments SP by 2 (for POPF) or 4 (for POPFD).

Clocks Size
Operands 808x 286 386 486 Bytes
none 8/12 5 5 9 1 (W88=12)
none (PM) - - 5 6 1

9D POPF Pop top of stack into lower 16 bits of EFLAGS
9D POPFD Pop top of stack into EFLAGS


PUSH - Push Word onto Stack

Usage: PUSH src
PUSH immed (80188+ only)

Modifies flags: None

Decrements SP by the size of the operand (two or four, byte values
are sign extended) and transfers one word from source to the stack
top (SS:SP).

Clocks Size
Operands 808x 286 386 486 Bytes
reg16 11/15 3 2 1 1
reg32 - - 2 1 1
mem16 16+EA 5 5 4 2-4 (W88=24+EA)
mem32 - - 5 4 2-4
segreg 10/14 3 2 3 1
immed - 3 2 1 2-3

FF /6 PUSH r/m16 Push r/m16
FF /6 PUSH r/m32 Push r/m32
50+ rw PUSH r16 Push r16
50+ rd PUSH r32 Push r32
6A PUSH imm8 Push imm8
68 PUSH imm16 Push imm16
68 PUSH imm32 Push imm32
0E PUSH CS Push CS
16 PUSH SS Push SS
1E PUSH DS Push DS
06 PUSH ES Push ES
0F A0 PUSH FS Push FS
0F A8 PUSH GS Push GS


PUSHA/PUSHAD - Push All Registers onto Stack (80188+)

Usage: PUSHA
PUSHAD (386+)

Modifies flags: None

Pushes all general purpose registers onto the stack in the following
order: (E)AX, (E)CX, (E)DX, (E)BX, (E)SP, (E)BP, (E)SI, (E)DI. The
value of SP is the value before the actual push of SP.

Clocks Size
Operands 808x 286 386 486 Bytes
none - 19 24 11 1

60 PUSHA Push AX, CX, DX, BX, original SP, BP, SI, and DI
60 PUSHAD Push EAX, ECX, EDX, EBX, original ESP, EBP, ESI, and EDI


PUSHF/PUSHFD - Push Flags onto Stack

Usage: PUSHF
PUSHFD (386+)

Modifies flags: None

Transfers the Flags Register onto the stack. PUSHF saves a 16 bit
value while PUSHFD saves a 32 bit value.

Clocks Size
Operands 808x 286 386 486 Bytes
none 10/14 3 4 4 1
none (PM) - - 4 3 1

9C PUSHF Push lower 16 bits of EFLAGS
9C PUSHFD Push EFLAGS


RCL - Rotate Through Carry Left

Usage: RCL dest,count

Modifies flags: CF OF

.-. .---------------.
.--|C|<----|7 <---------- 0|<-.
| '-' '---------------' |
'-----------------------------'
Rotates the bits in the destination to the left "count" times with
all data pushed out the left side re-entering on the right. The
Carry Flag holds the last bit rotated out.

Clocks Size
Operands 808x 286 386 486 Bytes
reg,1 2 2 9 3 2
mem,1 15+EA 7 10 4 2-4 (W88=23+EA)
reg,CL 8+4n 5+n 9 8-30 2
mem,CL 20+EA+4n 8+n 10 9-31 2-4 (W88=28+EA+4n)
reg,immed8 - 5+n 9 8-30 3
mem,immed8 - 8+n 10 9-31 3-5

D0 /2 RCL r/m8,1 Rotate 9 bits (CF, r/m8) left once
D2 /2 RCL r/m8,CL Rotate 9 bits (CF, r/m8) left CL times
C0 /2 ib RCL r/m8,imm8 Rotate 9 bits (CF, r/m8) left imm8 times
D1 /2 RCL r/m16,1 Rotate 17 bits (CF, r/m16) left once
D3 /2 RCL r/m16,CL Rotate 17 bits (CF, r/m16) left CL times
C1 /2 ib RCL r/m16,imm8 Rotate 17 bits (CF, r/m16) left imm8 times
D1 /2 RCL r/m32,1 Rotate 33 bits (CF, r/m32) left once
D3 /2 RCL r/m32,CL Rotate 33 bits (CF, r/m32) left CL times
C1 /2 ib RCL r/m32,imm8 Rotate 33 bits (CF, r/m32) left imm8 times


RCR - Rotate Through Carry Right

Usage: RCR dest,count

Modifies flags: CF OF

.---------------. .-.
.->|7 ----------> 0|---->|C|--.
| '---------------' '-' |
'-----------------------------'
Rotates the bits in the destination to the right "count" times with
all data pushed out the right side re-entering on the left. The
Carry Flag holds the last bit rotated out.

Clocks Size
Operands 808x 286 386 486 Bytes
reg,1 2 2 9 3 2
mem,1 15+EA 7 10 4 2-4 (W88=23+EA)
reg,CL 8+4n 5+n 9 8-30 2
mem,CL 20+EA+4n 8+n 10 9-31 2-4 (W88=28+EA+4n)
reg,immed8 - 5+n 9 8-30 3
mem,immed8 - 8+n 10 9-31 3-5

D0 /3 RCR r/m8,1 Rotate 9 bits (CF, r/m8) right once
D2 /3 RCR r/m8,CL Rotate 9 bits (CF, r/m8) right CL times
C0 /3 ib RCR r/m8,imm8 Rotate 9 bits (CF, r/m8) right imm8 times
D1 /3 RCR r/m16,1 Rotate 17 bits (CF, r/m16) right once
D3 /3 RCR r/m16,CL Rotate 17 bits (CF, r/m16) right CL times
C1 /3 ib RCR r/m16,imm8 Rotate 17 bits (CF, r/m16) right imm8 times
D1 /3 RCR r/m32,1 Rotate 33 bits (CF, r/m32) right once
D3 /3 RCR r/m32,CL Rotate 33 bits (CF, r/m32) right CL times
C1 /3 ib RCR r/m32,imm8 Rotate 33 bits (CF, r/m32) right imm8 times


REP - Repeat String Operation

Usage: REP

Modifies flags: None

Repeats execution of string instructions while CX != 0. After
each string operation, CX is decremented and the Zero Flag is
tested. The combination of a repeat prefix and a segment override
on CPU's before the 386 may result in errors if an interrupt occurs
before CX=0. The following code shows code that is susceptible to
this and how to avoid it:
again: rep movs byte ptr ES:[DI],ES:[SI] ; vulnerable instr.
jcxz next ; continue if REP successful
loop again ; interrupt goofed count
next:

Clocks Size
Operands 808x 286 386 486 Bytes
none 2 2 2 1

F3 6C REP INS r/m8, DX Input (E)CX bytes from port DX into ES:[(E)DI]
F3 6D REP INS r/m16,DX Input (E)CX words from port DX into ES:[(E)DI]
F3 6D REP INS r/m32,DX Input (E)CX doublewords from port DX into ES:[(E)DI]
F3 A4 REP MOVS m8,m8 Move (E)CX bytes from DS:[(E)SI] to ES:[(E)DI]
F3 A5 REP MOVS m16,m16 Move (E)CX words from DS:[(E)SI] to ES:[(E)DI]
F3 A5 REP MOVS m32,m32 Move (E)CX doublewords from DS:[(E)SI] to ES:[(E)DI]
F3 6E REP OUTS DX, r/m8 Output (E)CX bytes from DS:[(E)SI] to port DX
F3 6F REP OUTS DX, r/m16 Output (E)CX words from DS:[(E)SI] to port DX
F3 6F REP OUTS DX, r/m32 Output (E)CX doublewords from DS:[(E)SI] to port DX
F3 AC REP LODS AL Load (E)CX bytes from DS:[(E)SI] to AL
F3 AD REP LODS AX Load (E)CX words from DS:[(E)SI] to AX
F3 AD REP LODS EAX Load (E)CX doublewords from DS:[(E)SI] to EAX
F3 AA REP STOS m8 Fill (E)CX bytes at ES:[(E)DI] with AL
F3 AB REP STOS m16 Fill (E)CX words at ES:[(E)DI] with AX
F3 AB REP STOS m32 Fill (E)CX doublewords at ES:[(E)DI] with EAX


REPE/REPZ - Repeat Equal / Repeat Zero

Usage: REPE
REPZ

Modifies flags: None

Repeats execution of string instructions while CX != 0 and the Zero
Flag is set. CX is decremented and the Zero Flag tested after
each string operation. The combination of a repeat prefix and a
segment override on processors other than the 386 may result in
errors if an interrupt occurs before CX=0.

Clocks Size
Operands 808x 286 386 486 Bytes
none 2 2 2 1

F3 A6 REPE CMPS m8,m8 Find nonmatching bytes in ES:[(E)DI] and DS:[(E)SI]
F3 A7 REPE CMPS m16,m16 Find nonmatching words in ES:[(E)DI] and DS:[(E)SI]
F3 A7 REPE CMPS m32,m32 Find nonmatching doublewords in ES:[(E)DI] and DS:[(E)SI]
F3 AE REPE SCAS m8 Find non-AL byte starting at ES:[(E)DI]
F3 AF REPE SCAS m16 Find non-AX word starting at ES:[(E)DI]
F3 AF REPE SCAS m32 Find non-EAX doubleword starting at ES:[(E)DI]


REPNE/REPNZ - Repeat Not Equal / Repeat Not Zero

Usage: REPNE
REPNZ

Modifies flags: None

Repeats execution of string instructions while CX != 0 and the Zero
Flag is clear. CX is decremented and the Zero Flag tested after
each string operation. The combination of a repeat prefix and a
segment override on processors other than the 386 may result in
errors if an interrupt occurs before CX=0.

Clocks Size
Operands 808x 286 386 486 Bytes
none 2 2 2 1

F2 A6 REPNE CMPS m8,m8 Find matching bytes in ES:[(E)DI] and DS:[(E)SI]
F2 A7 REPNE CMPS m16,m16 Find matching words in ES:[(E)DI] and DS:[(E)SI]
F2 A7 REPNE CMPS m32,m32 Find matching doublewords in ES:[(E)DI] and DS:[(E)SI]
F2 AE REPNE SCAS m8 Find AL, starting at ES:[(E)DI]
F2 AF REPNE SCAS m16 Find AX, starting at ES:[(E)DI]
F2 AF REPNE SCAS m32 Find EAX, starting at ES:[(E)DI]


RET/RETF - Return From Procedure

Usage: RET nBytes
RETF nBytes
RETN nBytes

Modifies flags: None

Transfers control from a procedure back to the instruction address
saved on the stack. "n bytes" is an optional number of bytes to
release. Far returns pop the IP followed by the CS, while near
returns pop only the IP register.

Clocks Size
Operands 808x 286 386 486 Bytes
retn 16/20 11+m 10+m 5 1
retn immed 20/24 11+m 10+m 5 3
retf 26/34 15+m 18+m 13 1
retf (PM, same priv.) - 32+m 18 1
retf (PM, lesser priv.) - 68 33 1
retf immed 25/33 15+m 18+m 14 3
retf immed (PM, same priv.) 32+m 17 1
retf immed (PM, lesser priv.) 68 33 1

C3 RET Near return to calling procedure
CB RET Far return to calling procedure
C2 iw RET imm16 Near return to calling procedure and pop imm16 bytes from stack
CA iw RET imm16 Far return to calling procedure and pop imm16 bytes from stack


ROL - Rotate Left

Usage: ROL dest,count

Modifies flags: CF OF

.-. .---------------.
|C|<-.--|7 <---------- 0|<-.
'-' | '---------------' |
'---------------------'
Rotates the bits in the destination to the left "count" times with
all data pushed out the left side re-entering on the right. The
Carry Flag will contain the value of the last bit rotated out.

Clocks Size
Operands 808x 286 386 486 Bytes
reg,1 2 2 3 3 2
mem,1 15+EA 7 7 4 2-4 (W88=23+EA)
reg,CL 8+4n 5+n 3 3 2
mem,CL 20+EA+4n 8+n 7 4 2-4 (W88=28+EA+4n)
reg,immed8 - 5+n 3 2 3
mem,immed8 - 8+n 7 4 3-5

D0 /0 ROL r/m8,1 Rotate 8 bits r/m8 left once
D2 /0 ROL r/m8,CL Rotate 8 bits r/m8 left CL times
C0 /0 ib ROL r/m8,imm8 Rotate 8 bits r/m8 left imm8 times
D1 /0 ROL r/m16,1 Rotate 16 bits r/m16 left once
D3 /0 ROL r/m16,CL Rotate 16 bits r/m16 left CL times
C1 /0 ib ROL r/m16,imm8 Rotate 16 bits r/m16 left imm8 times
D1 /0 ROL r/m32,1 Rotate 32 bits r/m32 left once
D3 /0 ROL r/m32,CL Rotate 32 bits r/m32 left CL times
C1 /0 ib ROL r/m32,imm8 Rotate 32 bits r/m32 left imm8 times


ROR - Rotate Right

Usage: ROR dest,count

Modifies flags: CF OF

.---------------. .-.
.->|7 ----------> 0|--.->|C|
| '---------------' | '-'
'---------------------'
Rotates the bits in the destination to the right "count" times with
all data pushed out the right side re-entering on the left. The
Carry Flag will contain the value of the last bit rotated out.

Clocks Size
Operands 808x 286 386 486 Bytes
reg,1 2 2 3 3 2
mem,1 15+EA 7 7 4 2-4 (W88=23+EA)
reg,CL 8+4n 5+n 3 3 2
mem,CL 20+EA+4n 8+n 7 4 2-4 (W88=28+EA+4n)
reg,immed8 - 5+n 3 2 3
mem,immed8 - 8+n 7 4 3-5

D0 /1 ROR r/m8,1 Rotate 8 bits r/m8 right once
D2 /1 ROR r/m8,CL Rotate 8 bits r/m8 right CL times
C0 /1 ib ROR r/m8,imm8 Rotate 8 bits r/m16 right imm8 times
D1 /1 ROR r/m16,1 Rotate 16 bits r/m16 right once
D3 /1 ROR r/m16,CL Rotate 16 bits r/m16 right CL times
C1 /1 ib ROR r/m16,imm8 Rotate 16 bits r/m16 right imm8 times
D1 /1 ROR r/m32,1 Rotate 32 bits r/m32 right once
D3 /1 ROR r/m32,CL Rotate 32 bits r/m32 right CL times
C1 /1 ib ROR r/m32,imm8 Rotate 32 bits r/m32 right imm8 times


SAHF - Store AH Register into FLAGS

Usage: SAHF

Modifies flags: AF CF PF SF ZF

Transfers bits 0-7 of AH into the Flags Register. This includes
AF, CF, PF, SF and ZF.

Clocks Size
Operands 808x 286 386 486 Bytes
none 4 2 3 2 1

9E SAHF 2 Loads SF, ZF, AF, PF, and CF from AH into EFLAGS register


SAL/SHL - Shift Arithmetic Left / Shift Logical Left

Usage: SAL dest,count
SHL dest,count

Modifies flags: CF OF PF SF ZF (AF undefined)

.-. .---------------. .-.
|C|<----|7 <---------- 0|<----|0|
'-' '---------------' '-'
Shifts the destination left by "count" bits with zeroes shifted
in on right. The Carry Flag contains the last bit shifted out.

Clocks Size
Operands 808x 286 386 486 Bytes
reg,1 2 2 3 3 2
mem,1 15+EA 7 7 4 2-4 (W88=23+EA)
reg,CL 8+4n 5+n 3 3 2
mem,CL 20+EA+4n 8+n 7 4 2-4 (W88=28+EA+4n)
reg,immed8 - 5+n 3 2 3
mem,immed8 - 8+n 7 4 3-5

D0 /4 SAL r/m8,1 Multiply r/m8 by 2, once
D2 /4 SAL r/m8,CL Multiply r/m8 by 2, CL times
C0 /4 ib SAL r/m8,imm8 Multiply r/m8 by 2, imm8 times
D1 /4 SAL r/m16,1 Multiply r/m16 by 2, once
D3 /4 SAL r/m16,CL Multiply r/m16 by 2, CL times
C1 /4 ib SAL r/m16,imm8 Multiply r/m16 by 2, imm8 times
D1 /4 SAL r/m32,1 Multiply r/m32 by 2, once
D3 /4 SAL r/m32,CL Multiply r/m32 by 2, CL times
C1 /4 ib SAL r/m32,imm8 Multiply r/m32 by 2, imm8 times


SAR - Shift Arithmetic Right

Usage: SAR dest,count

Modifies flags: CF OF PF SF ZF (AF undefined)

.---------------. .-.
.--|7 ----------> 0|---->|C|
| '---------------' '-'
'---^
Shifts the destination right by "count" bits with the current sign
bit replicated in the leftmost bit. The Carry Flag contains the
last bit shifted out.

Clocks Size
Operands 808x 286 386 486 Bytes
reg,1 2 2 3 3 2
mem,1 15+EA 7 7 4 2-4 (W88=23+EA)
reg,CL 8+4n 5+n 3 3 2
mem,CL 20+EA+4n 8+n 7 4 2-4 (W88=28+EA+4n)
reg,immed8 - 5+n 3 2 3
mem,immed8 - 8+n 7 4 3-5

D0 /7 SAR r/m8,1 Signed divide* r/m8 by 2, once
D2 /7 SAR r/m8,CL Signed divide* r/m8 by 2, CL times
C0 /7 ib SAR r/m8,imm8 Signed divide* r/m8 by 2, imm8 times
D1 /7 SAR r/m16,1 Signed divide* r/m16 by 2, once
D3 /7 SAR r/m16,CL Signed divide* r/m16 by 2, CL times
C1 /7 ib SAR r/m16,imm8 Signed divide* r/m16 by 2, imm8 times
D1 /7 SAR r/m32,1 Signed divide* r/m32 by 2, once
D3 /7 SAR r/m32,CL Signed divide* r/m32 by 2, CL times
C1 /7 ib SAR r/m32,imm8 Signed divide* r/m32 by 2, imm8 times


SBB - Subtract with Borrow/Carry

Usage: SBB dest,src

Modifies flags: AF CF OF PF SF ZF

Subtracts the source from the destination, and subtracts 1 extra if
the Carry Flag is set. Results are returned in "dest".

Clocks Size
Operands 808x 286 386 486 Bytes
reg,reg 3 2 2 1 2
mem,reg 16+EA 7 6 3 2-4 (W88=24+EA)
reg,mem 9+EA 7 7 2 2-4 (W88=13+EA)
reg,immed 4 3 2 1 3-4
mem,immed 17+EA 7 7 3 3-6 (W88=25+EA)
accum,immed 4 3 2 1 2-3

1C ib SBB AL, imm8 Subtract with borrow imm8 from AL
1D iw SBB AX, imm16 Subtract with borrow imm16 from AX
1D id SBB EAX, imm32 Subtract with borrow imm32 from EAX
80 /3 ib SBB r/m8,imm8 Subtract with borrow imm8 from r/m8
81 /3 iw SBB r/m16,imm16 Subtract with borrow imm16 from r/m16
81 /3 id SBB r/m32,imm32 Subtract with borrow imm32 from r/m32
83 /3 ib SBB r/m16,imm8 Subtract with borrow sign-extended imm8 from r/m16
83 /3 ib SBB r/m32,imm8 Subtract with borrow sign-extended imm8 from r/m32
18 / r SBB r/m8,r8 Subtract with borrow r8 from r/m8
19 / r SBB r/m16,r16 Subtract with borrow r16 from r/m16
19 / r SBB r/m32,r32 Subtract with borrow r32 from r/m32
1A / r SBB r8,r/m8 Subtract with borrow r/m8 from r8
1B / r SBB r16,r/m16 Subtract with borrow r/m16 from r16
1B / r SBB r32,r/m32 Subtract with borrow r/m32 from r32


SCAS - Scan String (Byte, Word or Doubleword)

Usage: SCAS string
SCASB
SCASW
SCASD (386+)

Modifies flags: AF CF OF PF SF ZF

Compares value at ES:DI (even if operand is specified) from the
accumulator and sets the flags similar to a subtraction. DI is
incremented/decremented based on the instruction format (or operand size)
and the state of the Direction Flag. Use with REP prefixes.

Clocks Size
Operands 808x 286 386 486 Bytes
string 15 7 7 6 1 (W88=19)

AE SCAS m8 Compare AL with byte at ES:(E)DI and set status flags
AF SCAS m16 Compare AX with word at ES:(E)DI and set status flags
AF SCAS m32 Compare EAX with doubleword at ES(E)DI and set status flags
AE SCASB Compare AL with byte at ES:(E)DI and set status flags
AF SCASW Compare AX with word at ES:(E)DI and set status flags
AF SCASD Compare EAX with doubleword at ES:(E)DI and set status flags


SETAE/SETNB - Set if Above or Equal / Set if Not Below (386+)

Usage: SETAE dest
SETNB dest
(unsigned, 386+)

Modifies flags: none

Sets the byte in the operand to 1 if the Carry Flag is clear
otherwise sets the operand to 0.

Clocks Size
Operands 808x 286 386 486 Bytes
reg8 - - 4 3 3
mem8 - - 5 4 3

0F 97 SETA r/m8 Set byte if above (CF=0 and ZF=0)
0F 93 SETAE r/m8 Set byte if above or equal (CF=0)


SETB/SETNAE - Set if Below / Set if Not Above or Equal (386+)

Usage: SETB dest
SETNAE dest
(unsigned, 386+)

Modifies flags: none

Sets the byte in the operand to 1 if the Carry Flag is set
otherwise sets the operand to 0.

Clocks Size
Operands 808x 286 386 486 Bytes
reg8 - - 4 3 3
mem8 - - 5 4 3

0F 92 SETB r/m8 Set byte if below (CF=1)
0F 92 SETNAE r/m8 Set byte if not above or equal (CF=1)


SETBE/SETNA - Set if Below or Equal / Set if Not Above (386+)

Usage: SETBE dest
SETNA dest
(unsigned, 386+)

Modifies flags: none

Sets the byte in the operand to 1 if the Carry Flag or the Zero
Flag is set, otherwise sets the operand to 0.

Clocks Size
Operands 808x 286 386 486 Bytes
reg8 - - 4 3 3
mem8 - - 5 4 3

0F 96 SETBE r/m8 Set byte if below or equal (CF=1 or ZF=1)
0F 96 SETNA r/m8 Set byte if not above (CF=1 or ZF=1)


SETE/SETZ - Set if Equal / Set if Zero (386+)

Usage: SETE dest
SETZ dest

Modifies flags: none

Sets the byte in the operand to 1 if the Zero Flag is set,
otherwise sets the operand to 0.

Clocks Size
Operands 808x 286 386 486 Bytes
reg8 - - 4 3 3
mem8 - - 5 4 3

0F 94 SETE r/m8 Set byte if equal (ZF=1)
0F 94 SETZ r/m8 Set byte if zero (ZF=1)


SETNE/SETNZ - Set if Not Equal / Set if Not Zero (386+)

Usage: SETNE dest
SETNZ dest

Modifies flags: none

Sets the byte in the operand to 1 if the Zero Flag is clear,
otherwise sets the operand to 0.

Clocks Size
Operands 808x 286 386 486 Bytes
reg8 - - 4 3 3
mem8 - - 5 4 3

0F 95 SETNE r/m8 Set byte if not equal (ZF=0)
0F 95 SETNZ r/m8 Set byte if not zero (ZF=0)


SETL/SETNGE - Set if Less / Set if Not Greater or Equal (386+)

Usage: SETL dest
SETNGE dest
(signed, 386+)

Modifies flags: none

Sets the byte in the operand to 1 if the Sign Flag is not equal
to the Overflow Flag, otherwise sets the operand to 0.

Clocks Size
Operands 808x 286 386 486 Bytes
reg8 - - 4 3 3
mem8 - - 5 4 3

0F 9C SETL r/m8 Set byte if less (SF<>OF)
0F 9C SETNGE r/m8 Set if not greater or equal (SF<>OF)


SETGE/SETNL - Set if Greater or Equal / Set if Not Less (386+)

Usage: SETGE dest
SETNL dest
(signed, 386+)

Modifies flags: none

Sets the byte in the operand to 1 if the Sign Flag equals the
Overflow Flag, otherwise sets the operand to 0.

Clocks Size
Operands 808x 286 386 486 Bytes
reg8 - - 4 3 3
mem8 - - 5 4 3

0F 9D SETGE r/m8 Set byte if greater or equal (SF=OF)
0F 9D SETNL r/m8 Set byte if not less (SF=OF)


SETLE/SETNG - Set if Less or Equal / Set if Not greater or Equal (386+)

Usage: SETLE dest
SETNG dest
(signed, 386+)

Modifies flags: none

Sets the byte in the operand to 1 if the Zero Flag is set or the
Sign Flag is not equal to the Overflow Flag, otherwise sets the
operand to 0.

Clocks Size
Operands 808x 286 386 486 Bytes
reg8 - - 4 3 3
mem8 - - 5 4 3

0F 9E SETLE r/m8 Set byte if less or equal (ZF=1 or SF<>OF)
0F 9E SETNG r/m8 Set byte if not greater (ZF=1 or SF<>OF)


SETG/SETNLE - Set if Greater / Set if Not Less or Equal (386+)

Usage: SETG dest
SETNLE dest
(signed, 386+)

Modifies flags: none

Sets the byte in the operand to 1 if the Zero Flag is clear or the
Sign Flag equals to the Overflow Flag, otherwise sets the operand
to 0.

Clocks Size
Operands 808x 286 386 486 Bytes
reg8 - - 4 3 3
mem8 - - 5 4 3

0F 9F SETG r/m8 Set byte if greater (ZF=0 and SF=OF)
0F 9F SETNLE r/m8 Set byte if not less or equal (ZF=0 and SF=OF)


SETS - Set if Signed (386+)

Usage: SETS dest

Modifies flags: none

Sets the byte in the operand to 1 if the Sign Flag is set, otherwise
sets the operand to 0.

Clocks Size
Operands 808x 286 386 486 Bytes
reg8 - - 4 3 3
mem8 - - 5 4 3

0F 98 SETS r/m8 Set byte if sign (SF=1)


SETNS - Set if Not Signed (386+)

Usage: SETNS dest

Modifies flags: none

Sets the byte in the operand to 1 if the Sign Flag is clear,
otherwise sets the operand to 0.

Clocks Size
Operands 808x 286 386 486 Bytes
reg8 - - 4 3 3
mem8 - - 5 4 3

0F 99 SETNS r/m8 Set byte if not sign (SF=0)


SETC - Set if Carry (386+)

Usage: SETC dest

Modifies flags: none

Sets the byte in the operand to 1 if the Carry Flag is set,
otherwise sets the operand to 0.

Clocks Size
Operands 808x 286 386&nbSETC - Set if Carry (386+)sp; 486 Bytes
reg8 - - 4 3 3
mem8 - - 5 4 3

0F 92 SETC r/m8 Set if carry (CF=1)


SETNC - Set if Not Carry (386+)

Usage: SETNC dest

Modifies flags: none

Sets the byte in the operand to 1 if the Carry Flag is clear,
otherwise sets the operand to 0.

Clocks Size
Operands 808x 286 386 486 Bytes
reg8 - - 4 3 3
mem8 - - 5 4 3

0F 93 SETNC r/m8 Set byte if not carry (CF=0)


SETO - Set if Overflow (386+)

Usage: SETO dest

Modifies flags: none

Sets the byte in the operand to 1 if the Overflow Flag is set,
otherwise sets the operand to 0.

Clocks Size
Operands 808x 286 386 486 Bytes
reg8 - - 4 3 3
mem8 - - 5 4 3

0F 90 SETO r/m8 Set byte if overflow (OF=1)


SETNO - Set if Not Overflow (386+)

Usage: SETNO dest

Modifies flags: none

Sets the byte in the operand to 1 if the Overflow Flag is clear,
otherwise sets the operand to 0.

Clocks Size
Operands 808x 286 386 486 Bytes
reg8 - - 4 3 3
mem8 - - 5 4 3

0F 91 SETNO r/m8 Set byte if not overflow (OF=0)


SETP/SETPE - Set if Parity / Set if Parity Even (386+)

Usage: SETP dest
SETPE dest

Modifies flags: none

Sets the byte in the operand to 1 if the Parity Flag is set,
otherwise sets the operand to 0.

Clocks Size
Operands 808x 286 386 486 Bytes
reg8 - - 4 3 3
mem8 - - 5 4 3

0F 9A SETP r/m8 Set byte if parity (PF=1)
0F 9A SETPE r/m8 Set byte if parity even (PF=1)


SETNP/SETPO - Set if No Parity / Set if Parity Odd (386+)

Usage: SETNP dest
SETPO dest

Modifies flags: none

Sets the byte in the operand to 1 if the Parity Flag is clear,
otherwise sets the operand to 0.

Clocks Size
Operands 808x 286 386 486 Bytes
reg8 - - 4 3 3
mem8 - - 5 4 3

0F 9B SETNP r/m8 Set byte if not parity (PF=0)
0F 9B SETPO r/m8 Set byte if parity odd (PF=0)


SGDT - Store Global Descriptor Table (286+ privileged)

Usage: SGDT dest

Modifies flags: none

Stores the Global Descriptor Table (GDT) Register into the
specified operand.

Clocks Size
Operands 808x 286 386 486 Bytes
mem64 - 11 9 10 5

0F 01 /0 SGDT m Store GDTR to m


SIDT - Store Interrupt Descriptor Table (286+ privileged)

Usage: SIDT dest

Modifies flags: none

Stores the Interrupt Descriptor Table (IDT) Register into the
specified operand.

Clocks Size
Operands 808x 286 386 486 Bytes
mem64 - 12 9 10 5

0F 01 /1 SIDT m Store IDTR to m


SHL - Shift Logical Left

Usage: SAL dest,count
SHL dest,count

Modifies flags: CF OF PF SF ZF (AF undefined)

.-. .---------------. .-.
|C|<----|7 <---------- 0|<----|0|
'-' '---------------' '-'
Shifts the destination left by "count" bits with zeroes shifted
in on right. The Carry Flag contains the last bit shifted out.

Clocks Size
Operands 808x 286 386 486 Bytes
reg,1 2 2 3 3 2
mem,1 15+EA 7 7 4 2-4 (W88=23+EA)
reg,CL 8+4n 5+n 3 3 2
mem,CL 20+EA+4n 8+n 7 4 2-4 (W88=28+EA+4n)
reg,immed8 - 5+n 3 2 3
mem,immed8 - 8+n 7 4 3-5

D0 /4 SHL r/m8,1 Multiply r/m8 by 2, once
D2 /4 SHL r/m8,CL Multiply r/m8 by 2, CL times
C0 /4 ib SHL r/m8,imm8 Multiply r/m8 by 2, imm8 times
D1 /4 SHL r/m16,1 Multiply r/m16 by 2, once
D3 /4 SHL r/m16,CL Multiply r/m16 by 2, CL times
C1 /4 ib SHL r/m16,imm8 Multiply r/m16 by 2, imm8 times
D1 /4 SHL r/m32,1 Multiply r/m32 by 2, once
D3 /4 SHL r/m32,CL Multiply r/m32 by 2, CL times
C1 /4 ib SHL r/m32,imm8 Multiply r/m32 by 2, imm8 times


SHR - Shift Logical Right

Usage: SHR dest,count

Modifies flags: CF OF PF SF ZF (AF undefined)

.-. .---------------. .-.
|0|---->|7 ----------> 0|---->|C|
'-' '---------------' '-'
Shifts the destination right by "count" bits with zeroes shifted
in on the left. The Carry Flag contains the last bit shifted out.

Clocks Size
Operands 808x 286 386 486 Bytes
reg,1 2 2 3 2
mem,1 15+EA 7 7 2-4 (W88=23+EA)
reg,CL 8+4n 5+n 3 2
mem,CL 20+EA+4n 8+n 7 2-4 (W88=28+EA+4n)
reg,immed8 - 5+n 3 3
mem,immed8 - 8+n 7 3-5

D0 /5 SHR r/m8,1 Unsigned divide r/m8 by 2, once
D2 /5 SHR r/m8,CL Unsigned divide r/m8 by 2, CL times
C0 /5 ib SHR r/m8,imm8 Unsigned divide r/m8 by 2, imm8 times
D1 /5 SHR r/m16,1 Unsigned divide r/m16 by 2, once
D3 /5 SHR r/m16,CL Unsigned divide r/m16 by 2, CL times
C1 /5 ib SHR r/m16,imm8 Unsigned divide r/m16 by 2, imm8 times
D1 /5 SHR r/m32,1 Unsigned divide r/m32 by 2, once
D3 /5 SHR r/m32,CL Unsigned divide r/m32 by 2, CL times
C1 /5 ib SHR r/m32,imm8 Unsigned divide r/m32 by 2, imm8 times


SHLD/SHRD - Double Precision Shift (386+)

Usage: SHLD dest,src,count
SHRD dest,src,count

Modifies flags: CF PF SF ZF (OF,AF undefined)

SHLD shifts "dest" to the left "count" times and the bit positions
opened are filled with the most significant bits of "src". SHRD
shifts "dest" to the right "count" times and the bit positions
opened are filled with the least significant bits of the second
operand. Only the 5 lower bits of "count" are used.

Clocks Size
Operands 808x 286 386 486 Bytes
reg16,reg16,immed8 - - 3 2 4
reg32,reg32,immed8 - - 3 2 4
mem16,reg16,immed8 - - 7 3 6
mem32,reg32,immed8 - - 7 3 6
reg16,reg16,CL - - 3 3 3
reg32,reg32,CL - - 3 3 3
mem16,reg16,CL - - 7 4 5
mem32,reg32,CL - - 7 4 5

0F A4 SHLD r/m16,r16,imm8
0F A5 SHLD r/m16,r16,CL
0F A4 SHLD r/m32,r32,imm8
0F A5 SHLD r/m32,r32,CL
0F AC SHRD r/m16,r16,imm8
0F AD SHRD r/m16,r16,CL
0F AC SHRD r/m32,r32,imm8
0F AD SHRD r/m32,r32,CL


SLDT - Store Local Descriptor Table (286+ privileged)

Usage: SLDT dest

Modifies flags: none

Stores the Local Descriptor Table (LDT) Register into the
specified operand.

Clocks Size
Operands 808x 286 386 486 Bytes
reg16 - 2 2 2 3
mem16 - 2 2 3 5

0F 00 /0 SLDT r/m16 Stores segment selector from LDTR in r/m16
0F 00 /0 SLDT r/m32 Store segment selector from LDTR in low-order 16 bits of


SMSW - Store Machine Status Word (286+ privileged)

Usage: SMSW dest

Modifies flags: none

Store Machine Status Word (MSW) into "dest".

Clocks Size
Operands 808x 286 386 486 Bytes
reg16 - 2 10 2 3
mem16 - 3 3 3 5

0F 01 /4 SMSW r/m16 Store machine status word to r/m16
0F 01 /4 SMSW r32/m16 Store machine status word in low-order 16 bits of r32/m16;


STC - Set Carry

Usage: STC

Modifies flags: CF

Sets the Carry Flag to 1.

Clocks Size
Operands 808x 286 386 486 Bytes
none 2 2 2 2 1

F9 STC Set CF flag


STD - Set Direction Flag

Usage: STD

Modifies flags: DF

Sets the Direction Flag to 1 causing string instructions to
auto-decrement SI and DI instead of auto-increment.

Clocks Size
Operands 808x 286 386 486 Bytes
none 2 2 2 2 1

FD STD Set DF flag


STI - Set Interrupt Flag (Enable Interrupts)

Usage: STI

Modifies flags: IF

Sets the Interrupt Flag to 1, which enables recognition of all
hardware interrupts. If an interrupt is generated by a hardware
device, an End of Interrupt (EOI) must also be issued to enable
other hardware interrupts of the same or lower priority.

Clocks Size
Operands 808x 286 386 486 Bytes
none 2 2 2 5 1

FB STI Set interrupt flag; external, maskable interrupts enabled at the end of the next instruction


STOS - Store String (Byte, Word or Doubleword)

Usage: STOS dest
STOSB
STOSW
STOSD

Modifies flags: None

Stores value in accumulator to location at ES:(E)DI (even if operand
is given). (E)DI is incremented/decremented based on the size of
the operand (or instruction format) and the state of the Direction
Flag. Use with REP prefixes.

Clocks Size
Operands 808x 286 386 486 Bytes
dest 11 3 4 5 1 (W88=15)

AA STOS m8 Store AL at address ES:(E)DI
AB STOS m16 Store AX at address ES:(E)DI
AB STOS m32 Store EAX at address ES:(E)DI
AA STOSB Store AL at address ES:(E)DI
AB STOSW Store AX at address ES:(E)DI
AB STOSD Store EAX at address ES:(E)DI


STR - Store Task Register (286+ privileged)

Usage: STR dest

Modifies flags: None

Stores the current Task Register to the specified operand.

Clocks Size
Operands 808x 286 386 486 Bytes
reg16 - 2 2 2 3
mem16 - 3 2 3 5

0F 00 /1 STR r/m16 Stores segment selector from TR in r/m16


SUB - Subtract

Usage: SUB dest,src

Modifies flags: AF CF OF PF SF ZF

The source is subtracted from the destination and the result is
stored in the destination.

Clocks Size
Operands 808x 286 386 486 Bytes
reg,reg 3 2 2 1 2
mem,reg 16+EA 7 6 3 2-4 (W88=24+EA)
reg,mem 9+EA 7 7 2 2-4 (W88=13+EA)
reg,immed 4 3 2 1 3-4
mem,immed 17+EA 7 7 3 3-6 (W88=25+EA)
accum,immed 4 3 2 1 2-3

2C ib SUB AL, imm8 Subtract imm8 from AL
2D iw SUB AX, imm16 Subtract imm16 from AX
2D id SUB EAX, imm32 Subtract imm32 from EAX
80 /5 ib SUB r/m8,imm8 Subtract imm8 from r/m8
81 /5 iw SUB r/m16,imm16 Subtract imm16 from r/m16
81 /5 id SUB r/m32,imm32 Subtract imm32 from r/m32
83 /5 ib SUB r/m16,imm8 Subtract sign-extended imm8 from r/m16
83 /5 ib SUB r/m32,imm8 Subtract sign-extended imm8 from r/m32
28 / r SUB r/m8,r8 Subtract r8 from r/m8
29 / r SUB r/m16,r16 Subtract r16 from r/m16
29 / r SUB r/m32,r32 Subtract r32 from r/m32
2A / r SUB r8,r/m8 Subtract r/m8 from r8
2B / r SUB r16,r/m16 Subtract r/m16 from r16
2B / r SUB r32,r/m32 Subtract r/m32 from r32


TEST - Test For Bit Pattern

Usage: TEST dest,src

Modifies flags: CF OF PF SF ZF (AF undefined)

Performs a logical AND of the two operands updating the flags
register without saving the result.

Clocks Size
Operands 808x 286 386 486 Bytes
reg,reg 3 2 1 1 2
reg,mem 9+EA 6 5 1 2-4 (W88=13+EA)
mem,reg 9+EA 6 5 2 2-4 (W88=13+EA)
reg,immed 5 3 2 1 3-4
mem,immed 11+EA 6 5 2 3-6
accum,immed 4 3 2 1 2-3

A8 ib TEST AL, imm8 AND imm8 with AL; set SF, ZF, PF according to result
A9 iw TEST AX, imm16 AND imm16 with AX; set SF, ZF, PF according to result
A9 id TEST EAX, imm32 AND imm32 with EAX; set SF, ZF, PF according to result
F6 /0 ib TEST r/m8,imm8 AND imm8 with r/m8; set SF, ZF, PF according to result
F7 /0 iw TEST r/m16,imm16 AND imm16 with r/m16; set SF, ZF, PF according to result
F7 /0 id TEST r/m32,imm32 AND imm32 with r/m32; set SF, ZF, PF according to result
84 / r TEST r/m8,r8 AND r8 with r/m8; set SF, ZF, PF according to result
85 / r TEST r/m16,r16 AND r16 with r/m16; set SF, ZF, PF according to result
85 / r TEST r/m32,r32 AND r32 with r/m32; set SF, ZF, PF according to result


VERR - Verify Read (286+ protected)

Usage: VERR src

Modifies flags: ZF

Verifies the specified segment selector is valid and is readable
at the current privilege level. If the segment is readable,
the Zero Flag is set, otherwise it is cleared.

Clocks Size
Operands 808x 286 386 486 Bytes
reg16 - 14 10 11 3
mem16 - 16 11 11 5

0F 00 /4 VERR r/m16 Set ZF=1 if segment specified with r/m16 can be read


VERW - Verify Write (286+ protected)

Usage: VERW src

Modifies flags: ZF

Verifies the specified segment selector is valid and is ratable
at the current privilege level. If the segment is writable,
the Zero Flag is set, otherwise it is cleared.

Clocks Size
Operands 808x 286 386 486 Bytes
reg16 - 14 15 11 3
mem16 - 16 16 11 5

0F 00 /5 VERW r/m16 Set ZF=1 if segment specified with r/m16 can be written


WAIT/FWAIT - Event Wait

Usage: WAIT
FWAIT

Modifies flags: None

CPU enters wait state until the coprocessor signals it has finished
its operation. This instruction is used to prevent the CPU from
accessing memory that may be temporarily in use by the coprocessor.
WAIT and FWAIT are identical.

Clocks Size
Operands 808x 286 386 486 Bytes
none 4 3 6+ 1-3 1

9B WAIT Check pending unmasked floating-point exceptions.
9B FWAIT Check pending unmasked floating-point exceptions.


WBINVD - Write-Back and Invalidate Cache (486+)

Usage: WBINVD

Modifies flags: None

Flushes internal cache, then signals the external cache to write
back current data followed by a signal to flush the external cache.

Clocks Size
Operands 808x 286 386 486 Bytes
none - - - 5 2

0F 09 WBINVD Write back and flush Internal caches; initiate writing-back


XCHG - Exchange

Usage: XCHG dest,src

Modifies flags: None

Exchanges contents of source and destination.

Clocks Size
Operands 808x 286 386 486 Bytes
reg,reg 4 3 3 3 2
mem,reg 17+EA 5 5 5 2-4 (W88=25+EA)
reg,mem 17+EA 5 5 3 2-4 (W88=25+EA)
accum,reg 3 3 3 3 1
reg,accum 3 3 3 3 1

90+ rw XCHG AX, r16 Exchange r16 with AX
90+ rw XCHG r16,AX Exchange AX with r16
90+ rd XCHG EAX, r32 Exchange r32 with EAX
90+ rd XCHG r32,EAX Exchange EAX with r32
86 / r XCHG r/m8,r8 Exchange r8 (byte register) with byte from r/m8
86 / r XCHG r8,r/m8 Exchange byte from r/m8 with r8 (byte register)
87 / r XCHG r/m16,r16 Exchange r16 with word from r/m16
87 / r XCHG r16,r/m16 Exchange word from r/m16 with r16
87 / r XCHG r/m32,r32 Exchange r32 with doubleword from r/m32
87 / r XCHG r32,r/m32 Exchange doubleword from r/m32 with r32


XLAT/XLATB - Translate

Usage: XLAT translation-table
XLATB (masm 5.x)

Modifies flags: None

Replaces the byte in AL with byte from a user table addressed by
BX. The original value of AL is the index into the translate table.
The best way to discripe this is MOV AL,[BX+AL]

Clocks Size
Operands 808x 286 386 486 Bytes
table offset 11 5 5 4 1

D7 XLAT m8 Set AL to memory byte DS:[(E)BX + unsigned AL]
D7 XLATB Set AL to memory byte DS:[(E)BX + unsigned AL]


XOR - Exclusive OR

Usage: XOR dest,src

Modifies flags: CF OF PF SF ZF (AF undefined)

Performs a bitwise exclusive OR of the operands and returns
the result in the destination.

Clocks Size
Operands 808x 286 386 486 Bytes
reg,reg 3 2 2 1 2
mem,reg 16+EA 7 6 3 2-4 (W88=24+EA)
reg,mem 9+EA 7 7 2 2-4 (W88=13+EA)
reg,immed 4 3 2 1 3-4
mem,immed 17+EA 7 7 3 3-6 (W88=25+EA)
accum,immed 4 3 2 1 2-3

34 ib XOR AL, imm8 AL XOR imm8
35 iw XOR AX, imm16 AX XOR imm16
35 id XOR EAX, imm32 EAX XOR imm32
80 /6 ib XOR r/m8,imm8 r/m8 XOR imm8
81 /6 iw XOR r/m16,imm16 r/m16 XOR imm16
81 /6 id XOR r/m32,imm32 r/m32 XOR imm32
83 /6 ib XOR r/m16,imm8 r/m16 XOR imm8 (sign-extended)
83 /6 ib XOR r/m32,imm8 r/m32 XOR imm8 (sign-extended)
30 / r XOR r/m8,r8 r/m8 XOR r8
31 / r XOR r/m16,r16 r/m16 XOR r16
31 / r XOR r/m32,r32 r/m32 XOR r32
32 / r XOR r8,r/m8 r8 XOR r/m8
33 / r XOR r16,r/m16 r8 XOR r/m8
33 / r XOR r32,r/m32 r8 XOR r/m8


AvailableFunctions.htm

Available Functions

FpuLib Copyright Raymond Filiatreault 2002 - 2007

Conversion Functions

FpuAtoFL | Converts a decimal string to a REAL10 number
FpuFLtoA | Converts a REAL10 number to a decimal string

Arithmetic Functions

FpuAdd | Adds two numbers
FpuSub | Subtracts one number from another
FpuMul | Multiplies one number by another
FpuDiv | Divides one number by another
FpuSqrt | Extracts the square root of a positive number
FpuXexpY | Raises a positive number by an exponent
FpuAbs | Returns the absolute value of a number
FpuChs | Changes the sign of a number
FpuRound | Rounds a number to the nearest integer
FpuTrunc | Discards the decimal portion of a number

Logarithmic Functions

FpuLogx | Returns the base 10 logarithm of a positive number
FpuLnx | Returns the Napierian logarithm of a positive number
FpuTexpX | Returns the number 10 raised to a power (common antilog)
FpuEexpX | Returns the Napierian constant e raised to a power (Napierian antilog)

Trigonometric Functions

FpuSin | Returns the sine of an angle
FpuCos | Returns the cosine of an angle
FpuTan | Returns the tangent of an angle
FpuArcsin | Returns the angle corresponding to a sine value
FpuArccos | Returns the angle corresponding to a cosine value
FpuArctan | Returns the angle corresponding to a tangent value

Hyperbolic Functions

FpuSinh | Returns the hyperbolic sine of a number
FpuCosh | Returns the hyperbolic cosine of a number
FpuTanh | Returns the hyperbolic tangent of a number
FpuArcsinh | Returns the number corresponding to a hyperbolic sine
FpuArccosh | Returns the number corresponding to a hyperbolic cosine
FpuArctanh | Returns the number corresponding to a hyperbolic tangent

Miscellaneous Functions

FpuSize | Returns the exponent of scientific notation
FpuComp | Compares two numbers
FpuExam | Checks REAL10 for its validity, its sign, a value of zero, an absolute value less than 1, and/or a value of infinity
FpuState | Returns a null-terminated string listing the content of the FPU registers


index.htm

FpuLib Help
Copyright Raymond Filiatreault 2002 - 2007

This library contains functions to perform high precision floating point computations with the FPU coprocessor, without the need to learn all the intricacies of the coding syntax and limitations of the FPU. The obvious drawback is some code overhead to decipher the meaning of parameters. In most cases however, the speed should not be affected significantly when compared to directly programming the FPU.

Original release. December 2002

Modified January 2004 to free all registers required by the function to avoid any potential FPU stack overflow.

Modified March 2004 to preserve all FPU registers while avoiding any stack overflow. Also corrected a minor flaw in the FpuSize function and added the FpuState function.

Modified January 2005 to trash the FPU’s ST(7) data register whenever necessary to prevent reporting an error if a register is not available for returning a result on the FPU.

Updated this Help file May 2006 to cover the addition of a parameter for the FpuState function.

Design Philosophy
Sources of Errors
Available Functions
FPU Constants
Example
Legal
Acknowledgement

Prepared by Raymond Filiatreault.


Legal.htm

Legal

This library of functions may be used free of charge for personal non-commercial use. The library functions may not be used for any commercial program (including shareware) without the express permission from the author.

The author retains all copyright to the library and the source code of the modules.

The author may be reached at rayfil@hotmail.com

Prepared by Raymond Filiatreault.


Acknowledgement.htm

Acknowledgement

This library would never have been possible without the timely help and encouragement from Steve Hutchesson (hutch) during my early attempts with Win32 programming. My initial impression of it was like trying to learn a dozen alien dialects with instructions written in hieroglyphs. I was therefore enthusiastic when Steve invited me to prepare this library of functions for the FPU.

Thank you Steve.

Raymond Filiatreault


Designphilosophy.htm

Design Philosophy

The philosophy adopted for the design of the library was to make it as flexible as possible without making it overly complex and/or cumbersome.

Only REAL10 (80-bit) numbers are allowed as floating point numbers. The reasoning was that the FPU performs all its operations strictly on 80-bit numbers. Any other type of number used by the FPU is first converted to the 80-bit format. Therefore there is no significant advantage in FPU speed performance when using SHORT REAL (32-bit) or LONG REAL (64-bit) floating point numbers. The only disadvantage is a minimal increase in memory storage requirements.

Only LONG (32-bit) integers (DWORD) are allowed for operations with the library functions. Although CHAR (BYTES) and SHORT integers (WORD) could be allowed with some FPU instructions, they can be easily sign extended for the purpose of these functions. However, although only values from memory can be retrieved by the FPU, the functions were designed to directly accept integer values (either immediate or CPU register content) as input where integers may be used.

There are two widely used constants (π and e) which can be loaded directly on the FPU. They can be coded as input parameters in all functions where they may be used.

Unless a source parameter was specified as being in the TOP data register, the original Fpulib was designed to initialize the FPU to prevent any potential stack overflow. This destroyed any data which may have been present in the other FPU registers. This was revised later to destroy only the data (if any) in the registers which were necessary to perform the function. This latest version will not destroy any of the existing data, except possibly the data in the ST(7) register.

Whenever a result is specified to be returned on the FPU, it would replace a source parameter which would have been identified as having been in the TOP data register. If no source is identified as being on the FPU, its ST7 data register must then be free if the result must be returned on the FPU. Otherwise, the function will trash that register in order to free it for the returned value.

Whenever a result is specified to be returned to a memory location, any source parameter identified as having been on the FPU may or may not be preserved. See the description of each function. (As a general guide, such source would not be preserved when used for a computation.)

The only function which performs a thorough checking of the input is the one for converting an alphanumeric decimal string to a REAL10 number. None of the other functions verify the adequacy of the input. If a source parameter is not identified or if the FPU reports an invalid operation, EAX is simply returned with zero indicating an error. No error description is provided.

See also Sources of Errors .

Prepared by Raymond Filiatreault.


Example.htm

Example

This example makes use of some of the library functions to compute the monthly payments on a loan (such as a mortgage) according to the following equation:

where:

P = principal (mortgage)
R = interest rate for each period (expressed as a decimal)
N = number of periods (generally number of months for a mortgage)
PMT = payment for each period (generally monthly payments for a mortgage)

This example assumes that some input from a user has already been obtained as alphanumeric strings for the loan principal, the annual interest rate (%) and the term of the loan (years). That input is then converted to REAL10 values and corrected to the units required for the computation. The result is then computed and converted to its decimal representation with two decimal places ready for display.

The code also presumes that the interest on the loan can be compounded on a monthly basis. This simplifies the process by being able to simply divide the annual interest rate by 12. (Several more operations would have been required if the interest could only have been compounded on a semi-annual or annual basis.)

The entire source code of a fully functional demo is provided for assembly with MASM32 (the Fpu.lib and Fpu.inc files must be in the required sub-folders). Simply copy and paste it into your editor, modify the MASM32 path if necessary, save it and compile it. Or you may like to design your own “dialog box” to get user input and use the code as a procedure to prepare the results.

No error checking is included in this demo. It would be wise to add some if you use it as a procedure.

; ##########################################

.486
.model flat, stdcall
option casemap :none ; case sensitive

; ##########################################

include \masm32\include\windows.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
include \masm32\include\Fpu.inc

includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\Fpu.lib

; ##########################################

.data

mortgage dt 0
monthly_rate dt 0
months dt 0
temp_real dt 0
loan_inp db "92500",0
rate_inp db "6.75",0
year_inp db "20",0
result db 25 dup(0)

.code

start:

;convert loan principal input to REAL10 and store it

invoke FpuAtoFL, ADDR loan_inp, ADDR mortgage, DEST_MEM

;convert yearly interest (%) rate input to REAL10 and store it as a monthly fractional rate

invoke FpuAtoFL,ADDR rate_inp, 0, DEST_FPU
invoke FpuDiv, 0, 1200, ADDR monthly_rate, SRC1_FPU or SRC2_DIMM

;convert term of loan (years) input to REAL10 and store it as months

invoke FpuAtoFL, ADDR year_inp, 0, DEST_FPU
invoke FpuMul, 0, 12, ADDR months, SRC1_FPU or SRC2_DIMM

;compute the (1+R) portion, keeping it on the FPU, and then the (1+R)N term
;and storing it as a temporary REAL10 value

invoke FpuAdd, ADDR monthly_rate, 1, 0, SRC1_REAL or SRC2_DIMM or DEST_FPU
invoke FpuXexpY, 0, ADDR months, ADDR temp_real, SRC1_FPU or SRC2_REAL

;compute the denominator of the equation and leave it on the FPU

invoke FpuSub, ADDR temp_real, 1, 0, SRC1_REAL or SRC2_DIMM or DEST_FPU

;divide the (1+R)N term by that denominator and leave on the FPU

invoke FpuDiv, ADDR temp_real, 0, 0, SRC1_REAL or SRC2_FPU or DEST_FPU

;multiply by the other terms and leave answer on the FPU

invoke FpuMul, 0, ADDR monthly_rate, 0, SRC1_FPU or SRC2_REAL or DEST_FPU
invoke FpuMul, 0, ADDR mortgage, 0, SRC1_FPU or SRC2_REAL or DEST_FPU

;convert result to alphanumeric with 2 decimals and display

invoke FpuFLtoA, 0, 2, ADDR result, SRC1_FPU or SRC2_DIMM
invoke MessageBox, 0, ADDR result, 0, MB_OK

invoke ExitProcess, 0

end start

; ##########################################

Prepared by Raymond Filiatreault.


FpuAbs.htm

FpuAbs

The FpuAbs function returns the absolute value of an 80-bit REAL number at the specified destination.

|Src| → Dest

FpuAbs (

lpSrc //pointer to source parameter (Src)
lpDest //pointer to destination of result
uID //ID flags for source and destination
)

Parameters

lpSrc

This points to an 80-bit REAL number either in memory or on the FPU according to the content of uID. (This parameter is ignored if uID indicates that the value is already on the FPU.)

lpDest

This points to a TBYTE where the 80-bit REAL result will be returned. The result can instead be retained on the FPU according to the content of uID. (This parameter is ignored if uID indicates that the result should remain on the FPU.)

uID

One of the SRC1_? flags must be OR'ed with one of the DEST_? flags. (The DEST flag does not need to be OR’ed if the destination is in memory; that is the default destination.)

uID Flag Meaning
SRC1_FPU Src is already on the FPU
SRC1_REAL Src is a pointer to an 80-bit REAL number
DEST_FPU The result remains on the FPU
DEST_MEM lpDest is a pointer to a TBYTE
(this is the default and does not need to be indicated)

Return Values:

If the source is considered a valid REAL number, its absolute value will be transferred to the specified destination and EAX will be non-zero.
If the function fails, EAX will be zero and the specified source and destination will not be modified.

When the source is from the FPU, it will be discarded if the function succeeds; it would be replaced by the result when it is specified to be returned on the FPU. If the source is not from the FPU but the result must be returned on the FPU, the FPU’s ST7 data register must be free; otherwise, the content of that register will be trashed in order to return the required result.

All other FPU registers and all the CPU registers (except EAX) are preserved.

Remarks:

The source parameter MUST be an 80-bit REAL number. (The absolute value of integers can be easily obtained with CPU instructions.)

Example:

invoke FpuAbs, 0, 0, SRC1_FPU or DEST_FPU

In this example, the 80-bit REAL number already on the FPU will be replaced by its absolute value if no error is reported. (Both 1st and 2nd parameters are ignored.)

Prepared by Raymond Filiatreault.


FpuAdd.htm

FpuAdd

The FpuAdd function adds two numbers and returns the result as an 80-bit REAL number at the specified destination.

Src1 + Src2 → Dest

FpuAdd (

lpSrc1 // pointer to, or value of, 1st parameter
lpSrc2 // pointer to, or value of, 2nd parameter
lpDest // pointer to destination of result
uID // ID flags for sources and destination
)

Parameters

lpSrc1

This either points to an 80-bit REAL number or to a DWORD integer, or is an immediate DWORD integer or one of the FPU constants:
FPU_PI or FPU_NAPIER (see FPU Constants for description),
all according to the content of uID. (This parameter is ignored if uID indicates that the value is already on the FPU.)

lpSrc2

This either points to an 80-bit REAL number or to a DWORD integer, or is an immediate DWORD integer or one of the FPU constants:
FPU_PI or FPU_NAPIER,
all according to the content of uID. (This parameter is ignored if uID indicates that the value is already on the FPU.)

lpDest

This points to a TBYTE where the 80-bit REAL result of the addition will be returned. The result can instead be retained on the FPU according to the content of uID. (This parameter is ignored if uID indicates that the result should remain on the FPU.)

uID

Only one of the SRC1_? flags must be OR'ed with only one of the SRC2_? flags and OR'ed with one of the DEST_? flags. (The DEST flag does not need to be OR’ed if the destination is in memory; that is the default destination.)

uID Flag Meaning
SRC1_FPU Src1 is already on the FPU
SRC1_REAL Src1 is a pointer to an 80-bit REAL number
SRC1_DMEM Src1 is a pointer to a 32-bit signed integer
SRC1_DIMM Src1 is a 32-bit signed integer
SRC1_CONST Src1 is one of the special FPU constants
SRC2_FPU Src2 is already on the FPU
SRC2_REAL Src2 is a pointer to an 80-bit REAL number
SRC2_DMEM Src2 is a pointer to a 32-bit signed integer
SRC2_DIMM Src2 is a 32-bit signed integer
SRC2_CONST Src2 is one of the special FPU constants
DEST_FPU The result remains on the FPU
DEST_MEM lpDest is a pointer to a TBYTE
(this is the default and does not need to be indicated)

Return Values:

If the result is considered a valid REAL number, it will be transferred to the specified destination and EAX will be non-zero.
If the function fails, EAX will be zero and the specified sources and destination will not be modified.

When a source is from the FPU, it will be discarded if the function succeeds; it would be replaced by the result when it is specified to be returned on the FPU. If no source is from the FPU but the result must be returned on the FPU, the FPU’s ST7 data register must be free; otherwise, the content of that register will be trashed in order to return the required result.

All other FPU registers and all the CPU registers (except EAX) are preserved.

Remarks:

Because these library functions allow only one value to be retained on the FPU, identifying both sources as being on the FPU will result in adding the FPU value to itself.

Example:

invoke FpuAdd, ADDR Src1, eax, ADDR Dest, SRC1_REAL or SRC2_DIMM

In this example, the 80-bit REAL number from the TBYTE memory variable labeled Src1 is added with the DWORD integer in EAX, and the result is transferred as an 80-bit REAL to the TBYTE memory variable labeled Dest.

Prepared by Raymond Filiatreault.


FpuArccos.htm

FpuArccos

The FpuArccos function returns the angle expressed in degrees or radians corresponding to the cosine value provided as the source.

acos(Src) → Dest

FpuArccos (

lpSrc //pointer to the cosine value (Src)
lpDest //pointer to destination of result
uID //ID flags for source, angle type, and destination
)

Parameters

lpSrc

This parameter points to an 80-bit REAL number according to the content of uID. (This parameter is ignored if uID indicates that the value is already on the FPU.)

lpDest

This points to a TBYTE where the 80-bit REAL angle value will be returned. The result can instead be retained on the FPU according to the content of uID. (This parameter is ignored if uID indicates that the result should remain on the FPU.)

uID

One of the SRC1_? flags must be OR'ed with one of the ANG_? Flags and OR’ed with one of the DEST_? flags. (The ANG flag does not need to be OR’ed if the angle is required in degrees; that is the default type. The DEST flag does not need to be OR’ed if the destination is in memory; that is the default destination.)

uID Flag Meaning
SRC1_FPU Src is already on the FPU
SRC1_REAL Src is a pointer to an 80-bit REAL number
ANG_RAD The value of the angle will be returned in radians
ANG_DEG The value of the angle will be returned in degrees
(this is the default and does not need to be indicated)
DEST_FPU The result remains on the FPU
DEST_MEM lpDest is a pointer to a TBYTE
(this is the default and does not need to be indicated)

Return Values:

If the result is considered a valid REAL number, it will be transferred to the specified destination and EAX will be non-zero.
If the function fails, EAX will be zero and the specified sources and destination will not be modified.

When a source is from the FPU, it will be discarded if the function succeeds; it would be replaced by the result when it is specified to be returned on the FPU. If no source is from the FPU but the result must be returned on the FPU, the FPU’s ST7 data register must be free; otherwise, the content of that register will be trashed in order to return the required result.

All other FPU registers and all the CPU registers (except EAX) are preserved.

Remarks:

The source parameter must have a value within the range of -1 to +1 inclusive. Otherwise, the function will fail and return with the error code.

Positive values of the cosine will result in angles within the range of 0 - ½π radians (0-90 degrees). Negative values of the cosine will result in angles within the range of ½π - π radians (90-180 degrees).

If the angle with the corresponding cosine is known to be in the other two quadrants (i.e. in the 180-360 degree range), its value must be subtracted from 360 to get the required result.

Similarly, if the angle in radians needs to be adjusted for the other two quadrants, its value must be subtracted from 2π to get the required result

Example:

invoke FpuArccos, ADDR Src, ADDR Dest, SRC1_REAL or ANG_RAD

In this example, the cosine value is identified as being the 80-bit REAL at the TBYTE memory variable labeled Src. The resulting angle in radians will be stored at the TBYTE memory variable labeled Dest if the function succeeds. All FPU registers would be preserved.

Prepared by Raymond Filiatreault.


FpuArccosh.htm

FpuArccosh

The FpuArccosh function returns the number corresponding to a hyperbolic cosine value.

acosh(Src) → Dest

FpuArccosh (

lpSrc //pointer to, or value of, source number (Src)
lpDest //pointer to destination of result
uID //ID flags for source, and destination
)

Parameters

lpSrc

This either points to an 80-bit REAL number or to a DWORD integer, or is an immediate DWORD integer, all according to the content of uID. (This parameter is ignored if uID indicates that the value is already on the FPU.)

lpDest

This points to a TBYTE where the 80-bit REAL hyperbolic arccosine value will be returned. The result can instead be retained on the FPU according to the content of uID. (This parameter is ignored if uID indicates that the result should remain on the FPU.)

uID

Only one of the SRC1_? flags must be OR'ed with one of the DEST_? flags. (The DEST flag does not need to be OR’ed if the destination is in memory; that is the default destination.)

uID Flag Meaning
SRC1_FPU Src is already on the FPU
SRC1_REAL Src is a pointer to an 80-bit REAL number
SRC1_DMEM Src is a pointer to a 32-bit signed integer
SRC1_DIMM Src is a 32-bit signed integer
DEST_FPU The result remains on the FPU
DEST_MEM lpDest is a pointer to a TBYTE
(this is the default and does not need to be indicated)

Return Values:

If the result is considered a valid REAL number, it will be transferred to the specified destination and EAX will be non-zero.
If the function fails, EAX will be zero and the specified sources and destination will not be modified.

When a source is from the FPU, it will be discarded if the function succeeds; it would be replaced by the result when it is specified to be returned on the FPU. If no source is from the FPU but the result must be returned on the FPU, the FPU’s ST7 data register must be free; otherwise, the content of that register will be trashed in order to return the required result.

All other FPU registers and all the CPU registers (except EAX) are preserved.

Remarks:

Hyperbolic cosine values can only be positive and greater than or equal to 1. Only such values (except infinity) are thus acceptable as the source parameter for this function. The result will also be always returned positive although negative numbers can generate the same hyperbolic cosine values. If the negative result may be required, simply change its sign.

Example:

invoke FpuArccosh, 0, 0, SRC1_FPU or DEST_FPU

In this example, the value already on the FPU is replaced by its hyperbolic arccosine if the function succeeds. Both the 1st and 2nd parameters are ignored.

Prepared by Raymond Filiatreault.


FpuArcsin.htm

FpuArcsin

The FpuArcsin function returns the angle expressed in degrees or radians corresponding to the sine value provided as the source.

asin(Src) → Dest

FpuArcsin (

lpSrc //pointer to the sine value (Src)
lpDest //pointer to destination of result
uID //ID flags for source, angle type, and destination
)

Parameters

lpSrc

This parameter points to an 80-bit REAL number according to the content of uID. (This parameter is ignored if uID indicates that the value is already on the FPU.)

lpDest

This points to a TBYTE where the 80-bit REAL angle value will be returned. The result can instead be retained on the FPU according to the content of uID. (This parameter is ignored if uID indicates that the result should remain on the FPU.)

uID

One of the SRC1_? flags must be OR'ed with one of the ANG_? Flags and OR’ed with one of the DEST_? flags. (The ANG flag does not need to be OR’ed if the angle is required in degrees; that is the default type. The DEST flag does not need to be OR’ed if the destination is in memory; that is the default destination.)

uID Flag Meaning
SRC1_FPU Src is already on the FPU
SRC1_REAL Src is a pointer to an 80-bit REAL number
ANG_RAD The value of the angle will be returned in radians
ANG_DEG The value of the angle will be returned in degrees
(this is the default and does not need to be indicated)
DEST_FPU The result remains on the FPU
DEST_MEM lpDest is a pointer to a TBYTE
(this is the default and does not need to be indicated)

Return Values:

If the result is considered a valid REAL number, it will be transferred to the specified destination and EAX will be non-zero.
If the function fails, EAX will be zero and the specified sources and destination will not be modified.

When a source is from the FPU, it will be discarded if the function succeeds; it would be replaced by the result when it is specified to be returned on the FPU. If no source is from the FPU but the result must be returned on the FPU, the FPU’s ST7 data register must be free; otherwise, the content of that register will be trashed in order to return the required result.

All other FPU registers and all the CPU registers (except EAX) are preserved.

Remarks:

The source parameter must have a value within the range of -1 to +1 inclusive. Otherwise, the function will fail and return with the error code.

Negative values of a sine yield negative values of the corresponding angle. If the angle is specified to be in radians, it remains as is with a value between -½π and +½π inclusive. If the angle is specified to be in degrees, the negative values are modified to the 270-360 degree range; positive values remain in the 0-90 degree range.
If the angle with the corresponding sine is known to be in the other two quadrants (i.e. in the 90-270 degree range), its value must be subtracted from 180 to get the required result; this may lead to a negative angle which would require the addition of 360 to get it in the 0-360 positive range.
Similarly, if the angle in radians needs to be adjusted for the other two quadrants, its value must be subtracted from π to get the required result.

Example:

invoke FpuArcsin, 0, ADDR Dest, SRC1_FPU

In this example, the 1st parameter is ignored since the sine value is identified as being already on the FPU. The resulting angle in degrees will be stored at the TBYTE memory variable labeled Dest and the source parameter would be removed from the FPU if the function succeeds.

Prepared by Raymond Filiatreault.


FpuArcsinh.htm

FpuArcsinh

The FpuArcsinh function returns the number corresponding to a hyperbolic sine value.
asinh(Src) → Dest

FpuSinh (

lpSrc //pointer to, or value of, source number (Src)
lpDest //pointer to destination of result
uID //ID flags for source, and destination
)

Parameters

lpSrc

This either points to an 80-bit REAL number or to a DWORD integer, or is an immediate DWORD integer, all according to the content of uID. (This parameter is ignored if uID indicates that the value is already on the FPU.)

lpDest

This points to a TBYTE where the 80-bit REAL hyperbolic arcsine value will be returned. The result can instead be retained on the FPU according to the content of uID. (This parameter is ignored if uID indicates that the result should remain on the FPU.)

uID

Only one of the SRC1_? flags must be OR'ed with one of the DEST_? flags. (The DEST flag does not need to be OR’ed if the destination is in memory; that is the default destination.)

uID Flag Meaning
SRC1_FPU Src is already on the FPU
SRC1_REAL Src is a pointer to an 80-bit REAL number
SRC1_DMEM Src is a pointer to a 32-bit signed integer
SRC1_DIMM Src is a 32-bit signed integer
DEST_FPU The result remains on the FPU
DEST_MEM lpDest is a pointer to a TBYTE
(this is the default and does not need to be indicated)

Return Values:

If the result is considered a valid REAL number, it will be transferred to the specified destination and EAX will be non-zero.
If the function fails, EAX will be zero and the specified sources and destination will not be modified.

When a source is from the FPU, it will be discarded if the function succeeds; it would be replaced by the result when it is specified to be returned on the FPU. If no source is from the FPU but the result must be returned on the FPU, the FPU’s ST7 data register must be free; otherwise, the content of that register will be trashed in order to return the required result.

All other FPU registers and all the CPU registers (except EAX) are preserved.

Remarks:

All valid positive and negative values (except infinity) are acceptable as the source parameter for this function.

Example:

invoke FpuArcsinh, ADDR Src, ADDR Dest, SRC1_REAL

In this example, the hyperbolic arcsine of the 80-bit REAL number from the TBYTE memory variable labeled Src will be stored as an 80-bit REAL number at the TBYTE memory variable labeled Dest if the function succeeds.

Prepared by Raymond Filiatreault.


FpuArctan.htm

FpuArctan

The FpuArctan function returns the angle expressed in degrees or radians corresponding to the tangent value provided as the source.

atan(Src) → Dest

FpuArctan (

lpSrc //pointer to the tangent value (Src)
lpDest //pointer to destination of result
uID //ID flags for source, angle type, and destination
)

Parameters

lpSrc

This parameter points to an 80-bit REAL number according to the content of uID. (This parameter is ignored if uID indicates that the value is already on the FPU.)

lpDest

This points to a TBYTE where the 80-bit REAL angle value will be returned. The result can instead be retained on the FPU according to the content of uID. (This parameter is ignored if uID indicates that the result should remain on the FPU.)

uID

One of the SRC1_? flags must be OR'ed with one of the ANG_? Flags and OR’ed with one of the DEST_? flags. (The ANG flag does not need to be OR’ed if the angle is required in degrees; that is the default type. The DEST flag does not need to be OR’ed if the destination is in memory; that is the default destination.)

uID Flag Meaning
SRC1_FPU Src is already on the FPU
SRC1_REAL Src is a pointer to an 80-bit REAL number
ANG_RAD The value of the angle will be returned in radians
ANG_DEG The value of the angle will be returned in degrees
(this is the default and does not need to be indicated)
DEST_FPU The result remains on the FPU
DEST_MEM lpDest is a pointer to a TBYTE
(this is the default and does not need to be indicated)

Return Values:

If the result is considered a valid REAL number, it will be transferred to the specified destination and EAX will be non-zero.
If the function fails, EAX will be zero and the specified sources and destination will not be modified.

When a source is from the FPU, it will be discarded if the function succeeds; it would be replaced by the result when it is specified to be returned on the FPU. If no source is from the FPU but the result must be returned on the FPU, the FPU’s ST7 data register must be free; otherwise, the content of that register will be trashed in order to return the required result.

All other FPU registers and all the CPU registers (except EAX) are preserved.

Remarks:

All positive and negative numbers (including the +/- infinity values) are acceptable as a source parameter for this function.
Negative values of a tangent yield negative values of the corresponding angle. If the angle is specified to be in radians, it remains as is with a value between -½π and +½π inclusive. If the angle is specified to be in degrees, the negative values are modified to the 270-360 degree range; positive values remain in the 0-90 degree range.

If the angle with the corresponding tangent is known to be in the other two quadrants (i.e. in the 90-270 degree range), a value of 180 will need to be added to the result.

Similarly, if the angle in radians needs to be adjusted for the other two quadrants, the value of π must be added to it.

Example:

In the following example, the value of the angle formed by two vectors at right angle is computed. The value of the vector opposite the angle is available as an 80-bit REAL at the TBYTE variable labeled Opp and the value of the vector adjacent to the angle is available as an 80-bit REAL at the TBYTE variable labeled Adj. The resulting angle in degrees will be stored as an 80-bit REAL at the TBYTE variable labeled Dest if no error is reported.

Invoke FpuDiv, ADDR Opp, ADDR Adj, 0, SRC1_REAL or SRC2_REAL or DEST_FPU
invoke FpuArctan, 0, ADDR Dest, SRC1_FPU

The first function computes the tangent, leaving the result on the FPU (the FPU’s ST7 data register must be free or will be trashed). The second function computes the corresponding angle and stores the result expressed in degrees.

Prepared by Raymond Filiatreault.


FpuArctanh.htm

FpuArctanh

The FpuArctanh function returns the number corresponding to a hyperbolic tangent value.

atanh(Src) → Dest

FpuArctanh (

lpSrc //pointer to the source value (Src)
lpDest //pointer to destination of result
uID //ID flags for source, and destination
)

Parameters

lpSrc

This parameter points to an 80-bit REAL number according to the content of uID. (This parameter is ignored if uID indicates that the value is already on the FPU.)

lpDest

This points to a TBYTE where the 80-bit REAL hyperbolic arctangent value will be returned. The result can instead be retained on the FPU according to the content of uID. (This parameter is ignored if uID indicates that the result should remain on the FPU.)

uID

Only one of the SRC1_? flags must be OR'ed with one of the DEST_? flags. (The DEST flag does not need to be OR’ed if the destination is in memory; that is the default destination.)

uID Flag Meaning
SRC1_FPU Src is already on the FPU
SRC1_REAL Src is a pointer to an 80-bit REAL number
DEST_FPU The result remains on the FPU
DEST_MEM lpDest is a pointer to a TBYTE
(this is the default and does not need to be indicated)

Return Values:

If the result is considered a valid REAL number, it will be transferred to the specified destination and EAX will be non-zero.
If the function fails, EAX will be zero and the specified sources and destination will not be modified.

When a source is from the FPU, it will be discarded if the function succeeds; it would be replaced by the result when it is specified to be returned on the FPU. If no source is from the FPU but the result must be returned on the FPU, the FPU’s ST7 data register must be free; otherwise, the content of that register will be trashed in order to return the required result.

All other FPU registers and all the CPU registers (except EAX) are preserved.

Remarks:

The source parameter for this function must be within the range of -1 to +1 exclusive.

Example:

invoke FpuArctanh, ADDR Src, 0, SRC1_REAL or DEST_FPU

In this example, the hyperbolic arctangent of the 80-bit REAL number from the TBYTE memory variable labeled Src will be computed and remain on the FPU if the function succeeds. The 2nd parameter is ignored.

Prepared by Raymond Filiatreault.


FpuAtoFL.htm

FpuAtoFL

The FpuAtoFL converts an alphanumeric decimal string to an 80-bit REAL number.

FpuAtoFL (

lpszSrc //pointer to a null-terminated string
lpDest //pointer to destination of result
uID //ID flag for destination
)

Parameters

lpSrc

This points to the null-terminated alphanumeric decimal representation of the number. Leading spaces are disregarded. The string can be in regular notation or in scientific notation. Characters other than those allowed between the leading sign or leading digit and the terminating zero will return an immediate error. A maximum of 18 digits (excluding all leading 0's and trailing decimal 0's, and excluding the digits of the exponent in scientific notation) is permitted. The only permitted decimal delimiter is the period (“.”) but is not a necessity for integer values. Decimal digits are not a necessity either. The exponent in scientific notation can be preceded with “e” or “E”. That exponent must be within the +/-4931 range. The “+” sign is not necessary for positive exponents.

lpDest

This points to a TBYTE where the 80-bit REAL result of the conversion will be returned. The result can instead be retained on the FPU according to the content of uID. (This parameter is ignored if uID indicates that the result should remain on the FPU.)

uID

Only one of the DEST_? flags needs to be indicated.

uID Flag Meaning
DEST_FPU The result remains on the FPU
DEST_MEM lpDest is a pointer to a TBYTE

Return Values:

If the result is considered a valid REAL number, it will be transferred to the specified destination and EAX will be non-zero.
If the function fails, EAX will be zero and the specified destination will not be modified.

If the result must be returned on the FPU, the FPU’s ST7 data register must be free; otherwise, the content of that register will be trashed in order to return the required result.

All other FPU registers and all the CPU registers (except EAX) are preserved.

Example:

invoke FpuAtoFL, ADDR Src, 0, DEST_FPU

In this example, the alphanumeric decimal number pointed to by the memory variable labeled Src is converted to an 80-bit REAL number and retained on the FPU.

Prepared by Raymond Filiatreault.


FpuChs.htm

FpuChs

The FpuChs function changes the sign of an 80-bit REAL number and returns it at the specified destination.

-Src → Dest

FpuChs (

lpSrc //pointer to source parameter (Src)
lpDest //pointer to destination of result
uID //ID flags for source and destination
)

Parameters

lpSrc

This points to an 80-bit REAL number either in memory or on the FPU according to the content of uID. (This parameter is ignored if uID indicates that the value is already on the FPU.)

lpDest

This points to a TBYTE where the 80-bit REAL result will be returned. The result can instead be retained on the FPU according to the content of uID. (This parameter is ignored if uID indicates that the result should remain on the FPU.)

uID

One of the SRC1_? flags must be OR'ed with one of the DEST_? flags. (The DEST flag does not need to be OR’ed if the destination is in memory; that is the default destination.)

uID Flag Meaning
SRC1_FPU Src is already on the FPU
SRC1_REAL Src is a pointer to an 80-bit REAL number
DEST_FPU The result remains on the FPU
DEST_MEM lpDest is a pointer to a TBYTE
(this is the default and does not need to be indicated)

Return Values:

If the source is considered a valid REAL number, its absolute value will be transferred to the specified destination and EAX will be non-zero.
If the function fails, EAX will be zero and the specified source and destination will not be modified.

When the source is from the FPU, it will be discarded if the function succeeds; it would be replaced by the result when it is specified to be returned on the FPU. If the source is not from the FPU but the result must be returned on the FPU, the FPU’s ST7 data register must be free; otherwise, the content of that register will be trashed in order to return the required result.

All other FPU registers and all the CPU registers (except EAX) are preserved.

Remarks:

The source parameter MUST be an 80-bit REAL number. (The sign of integers can be changed easily with CPU instructions.)

Example:

invoke FpuChs, 0, ADDR Dest, SRC1_FPU

In this example, the 1st parameter is ignored and the sign of the 80-bit REAL value already on the FPU is changed; the result is stored at the TBYTE memory variable labeled Dest if no error is reported.

Prepared by Raymond Filiatreault.


FpuComp.htm

FpuComp

The FpuComp function compares the 1st parameter to the 2nd parameter and returns the result as coded bits in the EAX register.

FpuComp (

lpSrc1 // pointer to, or value of, 1st parameter
lpSrc2 // pointer to, or value of, 2nd parameter
uID // ID flags for sources and destination
)

Parameters

lpSrc1

This either points to an 80-bit REAL number or to a DWORD integer, or is an immediate DWORD integer or one of the FPU constants:
FPU_PI or FPU_NAPIER (see FPU Constants for description),
all according to the content of uID. (This parameter is ignored if uID indicates that the value is already on the FPU.)

lpSrc2

This either points to an 80-bit REAL number or to a DWORD integer, or is an immediate DWORD integer or one of the FPU constants:
FPU_PI or FPU_NAPIER,
all according to the content of uID. (This parameter is ignored if uID indicates that the value is already on the FPU.)

uID

Only one of the SRC1_? flags must be OR'ed with only one of the SRC2_? flags.

uID Flag Meaning
SRC1_FPU Src1 is already on the FPU
SRC1_REAL Src1 is a pointer to an 80-bit REAL number
SRC1_DMEM Src1 is a pointer to a 32-bit signed integer
SRC1_DIMM Src1 is a 32-bit signed integer
SRC1_CONST Src1 is one of the special FPU constants
SRC2_FPU Src2 is already on the FPU
SRC2_REAL Src2 is a pointer to an 80-bit REAL number
SRC2_DMEM Src2 is a pointer to a 32-bit signed integer
SRC2_DIMM Src2 is a 32-bit signed integer
SRC2_CONST Src2 is one of the special FPU constants

Return Values:

If either of the source numbers is considered invalid by the FPU, or cannot be compared such as a value of infinity, EAX returns with zero.

Otherwise, the result of the comparison is returned as a coded bit in EAX which can be tested with the following constants defined in the Fpu.inc file:

CMP_EQU Src1 = Src2 if bit is set
CMP_GREATER Src1 > Src2 if bit is set
CMP_LOWER Src1 < Src2 if bit is set

Note: The FPU performs a signed comparison; negative numbers are smaller than positive numbers. All the FPU registers and all the CPU registers (except EAX) are preserved. If one of the sources was on the FPU, its value would be preserved.

Example:

invoke FpuComp,0,10,SRC1_FPU or SRC2_DIMM
or eax,eax
jz error_handler
test eax,CMP_EQU or CMP_GREATER
jz lower_than_10

In this example, the value already on the FPU is compared to the immediate value of 10. Then EAX is first checked for a non-comparable parameter (only the value on the FPU could be at fault in this example) and the code branching off to the error handler if necessary. Finally, EAX is tested for equal-or-greater and the jump made if the value on the FPU is lower than 10.

Prepared by Raymond Filiatreault.


FPUConstants.htm

FPU Constants

Two widely used constants are made available with the FPU, the value of pi (π = 3.14159...) and the value of the Napierian constant (e = 2.71828...). They can be used where permitted as the source for a number by specifying one of the following constants instead of a pointer to a REAL10 or an integer, and identifying it as such.

Constant / Meaning

FPU_PI

The value of π. This constant needs to be used in numerous computations such as those related to the circle or sphere.

For information, that constant is loaded on the FPU with the following instruction:

fldpi

FPU_NAPIER

The value of e. Although this constant is not directly available from the FPU as the one above, it is generated internally with a few FPU instructions when specified as a parameter.

For information, that constant is loaded on the FPU with the following instructions:

fld1
fldl2e
fsub st,st(1)
f2xm1
fadd st,st(1)
fscale
fxch
fstp st(1)

Prepared by Raymond Filiatreault.


FpuCos.htm

FpuCos

The FpuCos function returns the cosine of an angle expressed in degrees or radians.

cos(Src) → Dest

FpuCos (

lpSrc //pointer to, or value of, angle (Src)
lpDest //pointer to destination of result
uID //ID flags for source, angle type, and destination
)

Parameters

lpSrc

This either points to an 80-bit REAL number or to a DWORD integer, or is an immediate DWORD integer, all according to the content of uID. (This parameter is ignored if uID indicates that the value is already on the FPU.)

lpDest

This points to a TBYTE where the 80-bit REAL cosine value will be returned. The result can instead be retained on the FPU according to the content of uID. (This parameter is ignored if uID indicates that the result should remain on the FPU.)

uID

Only one of the SRC1_? flags must be OR'ed with one of the ANG_? Flags and OR’ed with one of the DEST_? flags. (The ANG flag does not need to be OR’ed if the angle is in degrees; that is the default type. The DEST flag does not need to be OR’ed if the destination is in memory; that is the default destination.)

uID Flag Meaning
SRC1_FPU Src is already on the FPU
SRC1_REAL Src is a pointer to an 80-bit REAL number
SRC1_DMEM Src1 is a pointer to a 32-bit signed integer
SRC1_DIMM Src1 is a 32-bit signed integer
ANG_RAD The value of the angle is expressed in radians
ANG_DEG The value of the angle is expressed in degrees
(this is the default and does not need to be indicated)
DEST_FPU The result remains on the FPU
DEST_MEM lpDest is a pointer to a TBYTE
(this is the default and does not need to be indicated)

Return Values:

If the result is considered a valid REAL number, it will be transferred to the specified destination and EAX will be non-zero.
If the function fails, EAX will be zero and the specified sources and destination will not be modified.

When a source is from the FPU, it will be discarded if the function succeeds; it would be replaced by the result when it is specified to be returned on the FPU. If no source is from the FPU but the result must be returned on the FPU, the FPU’s ST7 data register must be free; otherwise, the content of that register will be trashed in order to return the required result.

All other FPU registers and all the CPU registers (except EAX) are preserved.

Remarks:

All positive and negative numbers except infinity are acceptable for this function.

Example:

invoke FpuCos, 0, 0, SRC1_FPU or ANG_RAD or DEST_FPU

In this example, the cosine of the 80-bit REAL already on the FPU and expressed in radians is computed and is retained on the FPU if no error is reported, both the 1st and 2nd parameters being ignored.

Prepared by Raymond Filiatreault.


FpuCosh.htm

FpuCosh

The FpuCosh function returns the hyperbolic cosine of a number.
cosh(Src) → Dest

FpuCosh (

lpSrc //pointer to, or value of, source number (Src)
lpDest //pointer to destination of result
uID //ID flags for source, and destination
)

Parameters

lpSrc

This either points to an 80-bit REAL number or to a DWORD integer, or is an immediate DWORD integer, all according to the content of uID. (This parameter is ignored if uID indicates that the value is already on the FPU.)

lpDest

This points to a TBYTE where the 80-bit REAL hyperbolic cosine value will be returned. The result can instead be retained on the FPU according to the content of uID. (This parameter is ignored if uID indicates that the result should remain on the FPU.)

uID

Only one of the SRC1_? flags must be OR'ed with one of the DEST_? flags. (The DEST flag does not need to be OR’ed if the destination is in memory; that is the default destination.)

uID Flag Meaning
SRC1_FPU Src is already on the FPU
SRC1_REAL Src is a pointer to an 80-bit REAL number
SRC1_DMEM Src is a pointer to a 32-bit signed integer
SRC1_DIMM Src is a 32-bit signed integer
DEST_FPU The result remains on the FPU
DEST_MEM lpDest is a pointer to a TBYTE
(this is the default and does not need to be indicated)

Return Values:

If the result is considered a valid REAL number, it will be transferred to the specified destination and EAX will be non-zero.
If the function fails, EAX will be zero and the specified sources and destination will not be modified.

When a source is from the FPU, it will be discarded if the function succeeds; it would be replaced by the result when it is specified to be returned on the FPU. If no source is from the FPU but the result must be returned on the FPU, the FPU’s ST7 data register must be free; otherwise, the content of that register will be trashed in order to return the required result.

All other FPU registers and all the CPU registers (except EAX) are preserved.

Remarks:

All positive and negative numbers are acceptable for this function. However, very large absolute values of that number may exceed the limits of the FPU and return a value of infinity. This would not be considered as an invalid operation and would not return the error code, but the returned result may not be usable with other library functions.

Example:

invoke FpuCosh, 0, 0, SRC1_FPU or DEST_FPU

In this example, the 1st and 2nd parameters are ignored and the hyperbolic cosine of the 80-bit REAL number already on the FPU will replace it if the function succeeds.

Prepared by Raymond Filiatreault.


FpuDiv.htm

FpuDiv

The FpuDiv function divides the first parameter by the second one and returns the result as an 80-bit REAL number at the specified destination.

Src1 ÷ Src2 → Dest

FpuDiv (

lpSrc1 // pointer to, or value of, 1st parameter
lpSrc2 // pointer to, or value of, 2nd parameter
lpDest // pointer to destination of result
uID // ID flags for sources and destination
)

Parameters

lpSrc1

This either points to an 80-bit REAL number or to a DWORD integer, or is an immediate DWORD integer or one of the FPU constants:
FPU_PI or FPU_NAPIER (see FPU Constants for description),
all according to the content of uID. (This parameter is ignored if uID indicates that the value is already on the FPU.)

lpSrc2

This either points to an 80-bit REAL number or to a DWORD integer, or is an immediate DWORD integer or one of the FPU constants:
FPU_PI or FPU_NAPIER,
all according to the content of uID. (This parameter is ignored if uID indicates that the value is already on the FPU.)

lpDest

This points to a TBYTE where the 80-bit REAL result of the division will be returned. The result can instead be retained on the FPU according to the content of uID. (This parameter is ignored if uID indicates that the result should remain on the FPU.)

uID

Only one of the SRC1_? flags must be OR'ed with only one of the SRC2_? flags and OR'ed with one of the DEST_? flags. (The DEST flag does not need to be OR’ed if the destination is in memory; that is the default destination.)

uID Flag Meaning
SRC1_FPU Src1 is already on the FPU
SRC1_REAL Src1 is a pointer to an 80-bit REAL number
SRC1_DMEM Src1 is a pointer to a 32-bit signed integer
SRC1_DIMM Src1 is a 32-bit signed integer
SRC1_CONST Src1 is one of the special FPU constants
SRC2_FPU Src2 is already on the FPU
SRC2_REAL Src2 is a pointer to an 80-bit REAL number
SRC2_DMEM Src2 is a pointer to a 32-bit signed integer
SRC2_DIMM Src2 is a 32-bit signed integer
SRC2_CONST Src2 is one of the special FPU constants
DEST_FPU The result remains on the FPU
DEST_MEM lpDest is a pointer to a TBYTE
(this is the default and does not need to be indicated)

Return Values:

If the result is considered a valid REAL number, it will be transferred to the specified destination and EAX will be non-zero.
If the function fails, EAX will be zero and the specified sources and destination will not be modified.

When a source is from the FPU, it will be discarded if the function succeeds; it would be replaced by the result when it is specified to be returned on the FPU. If no source is from the FPU but the result must be returned on the FPU, the FPU’s ST7 data register must be free; otherwise, the content of that register will be trashed in order to return the required result.

All other FPU registers and all the CPU registers (except EAX) are preserved.

Remarks:

Because these library functions allow only one value to be retained on the FPU, identifying both sources as being on the FPU will result in dividing the FPU value by itself, leaving 1 as the answer.

Dividing by zero is not considered an invalid operation and would NOT return the error code 0 in EAX. However, the result is a special FPU value interpreted as equal to infinity.

Example:

invoke FpuDiv, 1, eax, ADDR Dest, SRC1_DIMM or SRC2_DIMM

In this example, the value of 1 is divided by the DWORD signed integer in EAX (yielding its reciprocal), and the result is transferred as an 80-bit REAL to the TBYTE memory variable labeled Dest.

Prepared by Raymond Filiatreault.


FpuEexpX.htm

FpuEexpX

The FpuEexpX function raises the Napierian constant e (2.71828...) by an exponent. (It could also be considered as returning the Napierian antilogarithm of a number.)

e^(Src) → Dest

FpuEexpX (

lpSrc //pointer to, or value of, exponent parameter (Src)
lpDest //pointer to destination of result
uID //ID flags for source and destination
)

Parameters

lpSrc

This either points to an 80-bit REAL number or to a DWORD integer, or is an immediate DWORD integer or one of the FPU constants:
FPU_PI or FPU_NAPIER (see FPU Constants for description),
all according to the content of uID. (This parameter is ignored if uID indicates that the value is already on the FPU.)

lpDest

This points to a TBYTE where the 80-bit REAL result will be returned. The result can instead be retained on the FPU according to the content of uID. (This parameter is ignored if uID indicates that the result should remain on the FPU.)

uID

Only one of the SRC1_? flags must be OR’ed with one of the DEST_? flags. (The DEST flag does not need to be OR’ed if the destination is in memory; that is the default destination.)

uID Flag Meaning
SRC1_FPU Src is already on the FPU
SRC1_REAL Src is a pointer to an 80-bit REAL number
SRC1_DMEM Src1 is a pointer to a 32-bit signed integer
SRC1_DIMM Src1 is a 32-bit signed integer
SRC1_CONST Src1 is one of the special FPU constants
DEST_FPU The result remains on the FPU
DEST_MEM lpDest is a pointer to a TBYTE
(this is the default and does not need to be indicated)

Return Values:

If the result is considered a valid REAL number, it will be transferred to the specified destination and EAX will be non-zero.
If the function fails, EAX will be zero and the specified sources and destination will not be modified.

When a source is from the FPU, it will be discarded if the function succeeds; it would be replaced by the result when it is specified to be returned on the FPU. If no source is from the FPU but the result must be returned on the FPU, the FPU’s ST7 data register must be free; otherwise, the content of that register will be trashed in order to return the required result.

All other FPU registers and all the CPU registers (except EAX) are preserved.

Remarks:

Very large positive values of the source exponent may exceed the limits of the FPU and return a value of infinity. This would not be considered as an invalid operation and would not return the error code. However that return value may not be usable with other library functions.

Example:

invoke FpuEexpX, 0, 0, SRC1_FPU or DEST_FPU

In this example, the Napierian constant e is raised by the exponent already on the FPU and the result is retained on the FPU if no error is reported. Both 1st and 2nd parameters are ignored.

Prepared by Raymond Filiatreault.


FpuExam.htm

FpuExam

The FpuExam function examines an 80-bit REAL number for its validity, its sign, a value of zero, an absolute value less than 1, and a value of infinity.

FpuExam (

lpSrc // pointer to source parameter
uID // ID flags for source
)

Parameters

lpSrc

This parameter points to an 80-bit REAL number according to the content of uID. (This parameter is ignored if uID indicates that the value is already on the FPU.)

uID

Only one of the SRC1_? flags must be used.

uID Flag Meaning
SRC1_FPU Src1 is already on the FPU
SRC1_REAL Src1 is a pointer to an 80-bit REAL number

Return Values:

The result of the examination is returned as coded bits in EAX which can be tested with the following constants defined in the Fpu.inc file:

XAM_VALID Src = valid 80-bit REAL if bit is set
XAM_ZERO Src = zero if bit is set
XAM_NEG Src = negative if bit is set
XAM_SMALL Src = absolute value less than 1 if bit is set
XAM_INFINIT Src = infinity if bit is set

All the FPU registers and all the CPU registers (except EAX) are preserved. If the source was on the FPU, its value would be preserved.

Example:

invoke FpuExam, 0, SRC1_FPU
test eax,XAM_ZERO or XAM_NEG
jz above_zero

In this example, the 1st parameter is ignored and the 80-bit REAL number already on the FPU is examined, the result being returned in EAX. It is then tested to verify if equal to zero or negative and the jump taken if greater than zero.

Prepared by Raymond Filiatreault.


FpuFLtoA.htm

FpuFLtoA

The FpuFLtoA function converts an 80-bit REAL number to its alphanumeric decimal representation (either in decimal format or scientific notation) and returns the result as a null-terminated string at the specified destination.

FpuFLtoA (

lpSrc1 // pointer to an 80-bit REAL number
lpSrc2 // pointer to, or value of, 2nd parameter
lpszDest // pointer to destination of result
uID // ID flags for sources and format
)

Parameters

lpSrc1

This points to an 80-bit REAL number. (This parameter is ignored if uID indicates that the value is already on the FPU.)

lpSrc2

This either points to a DWORD integer in memory, or is an immediate DWORD integer according to the content of uID.
The low byte of the low word of the integer indicates the number of decimal digits to be returned in the result. The total number of integer digits and decimal digits cannot exceed 16. Otherwise, the number of decimal digits will be reduced accordingly. (Note that at least one integer digit is always returned.)
The high byte of the low word of the integer indicates the number of characters before the decimal point, spaces being used for padding. This number cannot exceed 17 (16 digits + sign); it would otherwise be reduced to 17. (This byte is ignored if uID indicates that the result must be returned in the scientific format.)
The high word of this parameter is ignored.

lpszDest

This points to a memory location where the result will be returned. It must be large enough to hold the number of characters returned. At most, it may have 17 characters before the decimal point, one decimal point, 15 decimal digits, and the terminating zero (for a maximum of 34 characters).

uID

One of the SRC1_? flags must be OR'ed with only one of the SRC2_? flags and OR’ed with one of the STR_? flags. (The STR_REG flag does not need to be OR’ed if the string must be returned in decimal format; that is the default.)

uID Flag Meaning
SRC1_FPU Src1 is already on the FPU
SRC1_REAL Src1 is a pointer to an 80-bit REAL number
SRC2_DMEM Src2 is a pointer to a 32-bit signed integer
SRC2_DIMM Src2 is a 32-bit signed integer
STR_REG The string must be returned in decimal format
STR_SCI The string must be returned in scientific notation

Return Values:

If the source is considered a valid REAL number, the converted string will be transferred to the specified destination and EAX will be non-zero.
If the function fails, EAX will be zero and the null-terminated string ERROR will be placed at the specified destination.
The source is never modified, whether it is in memory or on the FPU.

If the number is greater than or equal to 1016, the result will be returned in scientific notation (with the specified number of decimals) regardless of the STR flag. If the number is equal to zero, it is simply returned as an ASCII “0" and a terminating zero regardless of the STR flag.

All the FPU registers and all the CPU registers (except EAX) are preserved.

Example:

invoke FpuFLtoA, 0, 4, ADDR Dest, SRC1_FPU or SRC2_DIMM

In this example, the 80-bit REAL number is taken from the FPU (ignoring the 1st parameter) and the null-terminated alphanumeric decimal string is written in decimal format with 4 decimal digits at the destination identified as the memory variable labeled Dest.

Prepared by Raymond Filiatreault.


FpuLnx.htm

FpuLnx

The FpuLnx function returns the natural (Napierian) logarithm of a positive non-zero number.
ln(Src) → Dest

FpuLnx (

lpSrc //pointer to, or value of, source parameter (Src)
lpDest //pointer to destination of result
uID //ID flags for source and destination
)

Parameters

lpSrc

This either points to an 80-bit REAL number or to a DWORD integer, or is an immediate DWORD integer or one of the FPU constants:
FPU_PI or FPU_NAPIER (see FPU Constants for description),
all according to the content of uID. (This parameter is ignored if uID indicates that the value is already on the FPU.)

lpDest

This points to a TBYTE where the 80-bit REAL logarithm will be returned. The result can instead be retained on the FPU according to the content of uID. (This parameter is ignored if uID indicates that the result should remain on the FPU.)

uID

Only one of the SRC1_? flags must be OR’ed with one of the DEST_? flags. (The DEST flag does not need to be OR’ed if the destination is in memory; that is the default destination.)

uID Flag Meaning
SRC1_FPU Src is already on the FPU
SRC1_REAL Src is a pointer to an 80-bit REAL number
SRC1_DMEM Src1 is a pointer to a 32-bit signed integer
SRC1_DIMM Src1 is a 32-bit signed integer
SRC1_CONST Src1 is one of the special FPU constants
DEST_FPU The result remains on the FPU
DEST_MEM lpDest is a pointer to a TBYTE
(this is the default and does not need to be indicated)

Return Values:

If the result is considered a valid REAL number, it will be transferred to the specified destination and EAX will be non-zero.
If the function fails, EAX will be zero and the specified sources and destination will not be modified.

When a source is from the FPU, it will be discarded if the function succeeds; it would be replaced by the result when it is specified to be returned on the FPU. If no source is from the FPU but the result must be returned on the FPU, the FPU’s ST7 data register must be free; otherwise, the content of that register will be trashed in order to return the required result.

All other FPU registers and all the CPU registers (except EAX) are preserved.

Remarks:

The source parameter MUST be a positive non-zero number. Negative or zero values will result in an invalid operation and the function will fail.

Example:

invoke FpuLnx, eax, 0, SRC1_DIMM or DEST_FPU

In this example, the natural logarithm of the 32-bit signed integer in EAX is retained on the FPU as an 80-bit REAL value if no error is reported. The 2nd parameter is ignored.

Prepared by Raymond Filiatreault.


FpuLogx.htm

FpuLogx

The FpuLogx function returns the common (base 10) logarithm of a positive non-zero number.
log(Src) → Dest

FpuLogx (

lpSrc //pointer to, or value of, source parameter (Src)
lpDest //pointer to destination of result
uID //ID flags for source and destination
)

Parameters

lpSrc

This either points to an 80-bit REAL number or to a DWORD integer, or is an immediate DWORD integer or one of the FPU constants:
FPU_PI or FPU_NAPIER (see FPU Constants for description),
all according to the content of uID. (This parameter is ignored if uID indicates that the value is already on the FPU.)

lpDest

This points to a TBYTE where the 80-bit REAL logarithm will be returned. The result can instead be retained on the FPU according to the content of uID. (This parameter is ignored if uID indicates that the result should remain on the FPU.)

uID

Only one of the SRC1_? flags must be OR’ed with one of the DEST_? flags. (The DEST flag does not need to be OR’ed if the destination is in memory; that is the default destination.)

uID Flag Meaning
SRC1_FPU Src is already on the FPU
SRC1_REAL Src is a pointer to an 80-bit REAL number
SRC1_DMEM Src1 is a pointer to a 32-bit signed integer
SRC1_DIMM Src1 is a 32-bit signed integer
SRC1_CONST Src1 is one of the special FPU constants
DEST_FPU The result remains on the FPU
DEST_MEM lpDest is a pointer to a TBYTE
(this is the default and does not need to be indicated)

Return Values:

If the result is considered a valid REAL number, it will be transferred to the specified destination and EAX will be non-zero.
If the function fails, EAX will be zero and the specified sources and destination will not be modified.

When a source is from the FPU, it will be discarded if the function succeeds; it would be replaced by the result when it is specified to be returned on the FPU. If no source is from the FPU but the result must be returned on the FPU, the FPU’s ST7 data register must be free; otherwise, the content of that register will be trashed in order to return the required result.

All other FPU registers and all the CPU registers (except EAX) are preserved.

Remarks:

The source parameter MUST be a positive non-zero number. Negative or zero values will result in an invalid operation and the function will fail.

Example:

invoke FpuLogx, ADDR Src, 0, SRC1_REAL or DEST_FPU

In this example, the common (base 10) logarithm of the 80-bit REAL identified as the memory variable labeled Scr is computed and is retained on the FPU if no error is reported. The second parameter is ignored.

Prepared by Raymond Filiatreault.


FpuMul.htm

FpuMul

The FpuMul function multiplies two numbers and returns the result as an 80-bit REAL number at the specified destination.

Src1 × Src2 → Dest

FpuMul (

lpSrc1 // pointer to, or value of, 1st parameter
lpSrc2 // pointer to, or value of, 2nd parameter
lpDest // pointer to destination of result
uID // ID flags for sources and destination
)

Parameters

lpSrc1

This either points to an 80-bit REAL number or to a DWORD integer, or is an immediate DWORD integer or one of the FPU constants:
FPU_PI or FPU_NAPIER (see FPU Constants for description),
all according to the content of uID. (This parameter is ignored if uID indicates that the value is already on the FPU.)

lpSrc2

This either points to an 80-bit REAL number or to a DWORD integer, or is an immediate DWORD integer or one of the FPU constants:
FPU_PI or FPU_NAPIER,
all according to the content of uID. (This parameter is ignored if uID indicates that the value is already on the FPU.)

lpDest

This points to a TBYTE where the 80-bit REAL result of the multiplication will be returned. The result can instead be retained on the FPU according to the content of uID. (This parameter is ignored if uID indicates that the result should remain on the FPU.)

uID

Only one of the SRC1_? flags must be OR'ed with only one of the SRC2_? flags and OR'ed with one of the DEST_? flags. (The DEST flag does not need to be OR’ed if the destination is in memory; that is the default destination.)

uID Flag Meaning
SRC1_FPU Src1 is already on the FPU
SRC1_REAL Src1 is a pointer to an 80-bit REAL number
SRC1_DMEM Src1 is a pointer to a 32-bit signed integer
SRC1_DIMM Src1 is a 32-bit signed integer
SRC1_CONST Src1 is one of the special FPU constants
SRC2_FPU Src2 is already on the FPU
SRC2_REAL Src2 is a pointer to an 80-bit REAL number
SRC2_DMEM Src2 is a pointer to a 32-bit signed integer
SRC2_DIMM Src2 is a 32-bit signed integer
SRC2_CONST Src2 is one of the special FPU constants
DEST_FPU The result remains on the FPU
DEST_MEM lpDest is a pointer to a TBYTE
(this is the default and does not need to be indicated)

Return Values:

If the result is considered a valid REAL number, it will be transferred to the specified destination and EAX will be non-zero.
If the function fails, EAX will be zero and the specified sources and destination will not be modified.

When a source is from the FPU, it will be discarded if the function succeeds; it would be replaced by the result when it is specified to be returned on the FPU. If no source is from the FPU but the result must be returned on the FPU, the FPU’s ST7 data register must be free; otherwise, the content of that register will be trashed in order to return the required result.

All other FPU registers and all the CPU registers (except EAX) are preserved.

Remarks:

Because these library functions allow only one value to be retained on the FPU, identifying both sources as being on the FPU will result in multiplying the FPU value by itself. This may be occasionally useful.

Example:

Assuming that the radius of a circle would be an 80-bit REAL number in the TBYTE memory variable labeled Radius, the following sequence would compute the area of the circle and leave the result on the FPU:

invoke FpuMul, ADDR Radius, ADDR Radius, 0, SRC1_REAL or SRC2_REAL or DEST_FPU
invoke FpuMul, FPU_PI, 0, 0, SRC1_CONST or SRC2_FPU or DEST_FPU

Prepared by Raymond Filiatreault.


FpuRound.htm

FpuRound

The FpuRound function rounds an 80-bit REAL number to its nearest integer value.

round(Src) → Dest

FpuRound (

lpSrc //pointer to source parameter (Src)
lpDest //pointer to destination of result
uID //ID flags for source and destination
)

Parameters

lpSrc

This points to an 80-bit REAL number either in memory or on the FPU according to the content of uID. (This parameter is ignored if uID indicates that the value is already on the FPU.)

lpDest

This points to a TBYTE where the result can be stored as an 80-bit REAL number or points to a DWORD where the result can be stored as a 32-bit LONG integer. The result can instead be retained on the FPU, all according to the content of uID. (This parameter is ignored if uID indicates that the result should remain on the FPU.)

uID

One of the SRC1_? flags must be OR'ed with one of the DEST_? flags. (The DEST flag does not need to be OR’ed if the destination is in memory; that is the default destination.)

uID Flag Meaning
SRC1_FPU Src is already on the FPU
SRC1_REAL Src is a pointer to an 80-bit REAL number
DEST_FPU The result remains on the FPU
DEST_IMEM lpDest is a pointer to a DWORD
DEST_MEM lpDest is a pointer to a TBYTE
(this is the default and does not need to be indicated)

Return Values:

If the source is considered a valid REAL number, its absolute value will be transferred to the specified destination and EAX will be non-zero.
If the function fails, EAX will be zero and the specified source and destination will not be modified.

When the source is from the FPU, it will be discarded if the function succeeds; it would be replaced by the result when it is specified to be returned on the FPU. If the source is not from the FPU but the result must be returned on the FPU, the FPU’s ST7 data register must be free; otherwise, the content of that register will be trashed in order to return the required result.

All other FPU registers and all the CPU registers (except EAX) are preserved.

Remarks:

The source parameter MUST be an 80-bit REAL number. (Integers are already rounded.)

Example:

invoke FpuRound, 0, ADDR Dest, SRC1_FPU or DEST_IMEM

In this example, the 1st parameter is ignored and the 80-bit REAL number already on the FPU will be rounded to its nearest integer; the result will be stored as a 32-bit LONG integer at the DWORD memory variable labeled Dest.

Prepared by Raymond Filiatreault.


FpuSin.htm

FpuSin

The FpuSin function returns the sine of an angle expressed in degrees or radians.

sin(Src) → Dest

FpuSin (

lpSrc //pointer to, or value of, angle (Src)
lpDest //pointer to destination of result
uID //ID flags for source, angle type, and destination
)

Parameters

lpSrc

This either points to an 80-bit REAL number or to a DWORD integer, or is an immediate DWORD integer, all according to the content of uID. (This parameter is ignored if uID indicates that the value is already on the FPU.)

lpDest

This points to a TBYTE where the 80-bit REAL sine value will be returned. The result can instead be retained on the FPU according to the content of uID. (This parameter is ignored if uID indicates that the result should remain on the FPU.)

uID

Only one of the SRC1_? flags must be OR'ed with one of the ANG_? Flags and OR’ed with one of the DEST_? flags. (The ANG flag does not need to be OR’ed if the angle is in degrees; that is the default type. The DEST flag does not need to be OR’ed if the destination is in memory; that is the default destination.)

uID Flag Meaning
SRC1_FPU Src is already on the FPU
SRC1_REAL Src is a pointer to an 80-bit REAL number
SRC1_DMEM Src1 is a pointer to a 32-bit signed integer
SRC1_DIMM Src1 is a 32-bit signed integer
ANG_RAD The value of the angle is expressed in radians
ANG_DEG The value of the angle is expressed in degrees
(this is the default and does not need to be indicated)
DEST_FPU The result remains on the FPU
DEST_MEM lpDest is a pointer to a TBYTE
(this is the default and does not need to be indicated)

Return Values:

If the result is considered a valid REAL number, it will be transferred to the specified destination and EAX will be non-zero.
If the function fails, EAX will be zero and the specified sources and destination will not be modified.

When a source is from the FPU, it will be discarded if the function succeeds; it would be replaced by the result when it is specified to be returned on the FPU. If no source is from the FPU but the result must be returned on the FPU, the FPU’s ST7 data register must be free; otherwise, the content of that register will be trashed in order to return the required result.

All other FPU registers and all the CPU registers (except EAX) are preserved.

Remarks:

All positive and negative numbers except infinity are acceptable for this function.

Example:

invoke FpuSin, ADDR Src, 0, SRC1_REAL or ANG_RAD or DEST_FPU

In this example, the sine of the 80-bit REAL number at the TBYTE memory variable labeled Scr and expressed in radians is computed and is retained on the FPU if no error is reported, the 2nd parameter being ignored.

Prepared by Raymond Filiatreault.


FpuSinh.htm

FpuSinh

The FpuSinh function returns the hyperbolic sine of a number.
sinh(Src) → Dest

FpuSinh (

lpSrc //pointer to, or value of, source number (Src)
lpDest //pointer to destination of result
uID //ID flags for source, and destination
)

Parameters

lpSrc

This either points to an 80-bit REAL number or to a DWORD integer, or is an immediate DWORD integer, all according to the content of uID. (This parameter is ignored if uID indicates that the value is already on the FPU.)

lpDest

This points to a TBYTE where the 80-bit REAL hyperbolic sine value will be returned. The result can instead be retained on the FPU according to the content of uID. (This parameter is ignored if uID indicates that the result should remain on the FPU.)

uID

Only one of the SRC1_? flags must be OR'ed with one of the DEST_? flags. (The DEST flag does not need to be OR’ed if the destination is in memory; that is the default destination.)

uID Flag Meaning
SRC1_FPU Src is already on the FPU
SRC1_REAL Src is a pointer to an 80-bit REAL number
SRC1_DMEM Src is a pointer to a 32-bit signed integer
SRC1_DIMM Src is a 32-bit signed integer
DEST_FPU The result remains on the FPU
DEST_MEM lpDest is a pointer to a TBYTE
(this is the default and does not need to be indicated)

Return Values:

If the result is considered a valid REAL number, it will be transferred to the specified destination and EAX will be non-zero.
If the function fails, EAX will be zero and the specified sources and destination will not be modified.

When a source is from the FPU, it will be discarded if the function succeeds; it would be replaced by the result when it is specified to be returned on the FPU. If no source is from the FPU but the result must be returned on the FPU, the FPU’s ST7 data register must be free; otherwise, the content of that register will be trashed in order to return the required result.

All other FPU registers and all the CPU registers (except EAX) are preserved.

Remarks:

All positive and negative numbers are acceptable for this function. However, very large absolute values of that number may exceed the limits of the FPU and return a value of infinity. This would not be considered as an invalid operation and would not return the error code, but the returned result may not be usable with other library functions.

Example:

invoke FpuSinh, 0, ADDR Dest, SRC1_FPU

In this example, the 1st parameter is ignored and the hyperbolic sine of the 80-bit REAL number already on the FPU will be returned as an 80-bit REAL number at the TBYTE memory variable labeled Dest if no error is reported. The source operand would be removed from the FPU if the function succeeds.

Prepared by Raymond Filiatreault.


FpuSize.htm

FpuSize

The FpuSize function returns the exponent of a number as would be expressed in scientific notation.

size(Src) → Dest

FpuSize (

lpSrc //pointer to, or value of, source parameter (Src)
lpDest //pointer to destination of result
uID //ID flags for source and destination
)

Parameters

lpSrc

This either points to an 80-bit REAL number or to a DWORD integer, or is an immediate DWORD integer, all according to the content of uID. (This parameter is ignored if uID indicates that the value is already on the FPU.)

lpDest

This must point to a 32-bit LONG integer memory variable where the exponent will be returned.

uID

Only one of the SRC1_? flags must be used

uID Flag Meaning
SRC1_FPU Src is already on the FPU
SRC1_REAL Src is a pointer to an 80-bit REAL number
SRC1_DMEM Src1 is a pointer to a 32-bit signed integer
SRC1_DIMM Src1 is a 32-bit signed integer

Return Values:

If the source is considered a valid non-zero number, its size will be transferred to the specified destination and EAX will be non-zero.

If the source is equal to zero, a value of -0 (80000000h) will be returned to the specified destination and EAX will be non-zero.

Otherwise, EAX will be zero and the specified destination will not be modified.

All the FPU registers and all the CPU registers (except EAX) are preserved. (If the source was on the FPU, its value on the FPU is preserved.)

Remarks:

The sign of the source number is disregarded with this function. Negative results (including the negative zero) indicate absolute values less than 1, while positive results indicate absolute values higher than 1.

Example:

invoke FpuSize, 0, ADDR Dest, SRC1_FPU

In this example, the 1st parameter is ignored and the size of the 80-bit REAL already on the FPU is returned to the LONG integer memory variable labeled Dest, the source 80-bit REAL value being preserved on the FPU if no error is reported.

Prepared by Raymond Filiatreault.


FpuSqrt.htm

FpuSqrt

The FpuSqrt function extracts the square root of a positive number.

sqrt(Src) → Dest

FpuSqrt (

lpSrc //pointer to, or value of, source parameter (Src)
lpDest //pointer to destination of result
uID //ID flags for source and destination
)

Parameters

lpSrc

This either points to an 80-bit REAL number or to a DWORD integer, or is an immediate DWORD integer or one of the FPU constants:
FPU_PI or FPU_NAPIER (see FPU Constants for description),
all according to the content of uID. (This parameter is ignored if uID indicates that the value is already on the FPU.)

lpDest

This points to a TBYTE where the 80-bit REAL result of the square root will be returned. The result can instead be retained on the FPU according to the content of uID. (This parameter is ignored if uID indicates that the result should remain on the FPU.)

uID

Only one of the SRC1_? flags must be OR’ed with one of the DEST_? flags. (The DEST flag does not need to be OR’ed if the destination is in memory; that is the default destination.)

uID Flag Meaning
SRC1_FPU Src is already on the FPU
SRC1_REAL Src is a pointer to an 80-bit REAL number
SRC1_DMEM Src1 is a pointer to a 32-bit signed integer
SRC1_DIMM Src1 is a 32-bit signed integer
SRC1_CONST Src1 is one of the special FPU constants
DEST_FPU The result remains on the FPU
DEST_MEM lpDest is a pointer to a TBYTE
(this is the default and does not need to be indicated)

Return Values:

If the result is considered a valid REAL number, it will be transferred to the specified destination and EAX will be non-zero.
If the function fails, EAX will be zero and the specified sources and destination will not be modified.

When a source is from the FPU, it will be discarded if the function succeeds; it would be replaced by the result when it is specified to be returned on the FPU. If no source is from the FPU but the result must be returned on the FPU, the FPU’s ST7 data register must be free; otherwise, the content of that register will be trashed in order to return the required result.

All other FPU registers and all the CPU registers (except EAX) are preserved.

Remarks:

The source parameter MUST be a positive number. Trying to extract the square root of a negative number on the FPU will result in an invalid operation and the function will fail.

Example:

invoke FpuSqrt, edx, 0, SRC1_DIMM or DEST_FPU

In this example, the square root of the 32-bit signed integer in EDX is extracted and the 80-bit REAL result is retained on the FPU (ignoring the 2nd parameter) if no error is reported.

Prepared by Raymond Filiatreault.


FpuState.htm

FpuState

The FpuState function returns a null-terminated string listing the content of the FPU registers to a memory buffer.

FpuState (

lpszDest // pointer to memory buffer
uID // ID flags for source
)

Parameters

lpszDest

This points to a memory location where the string will be returned. It must be large enough to hold the number of characters returned. A buffer size of 432 bytes would be sufficient.

uID

Reference number allocated by the programmer to identify the area of the code from where the function has been called.

Return Values:

All the FPU registers and all the CPU registers are preserved.

The returned string is formatted as shown below when displayed in a Message Box:

Fields in the Control Word (RC and PC) and the Status Word (TOP) which would contain more than 1 bit have those bits grouped together.

The exception flags in the Status Word have an upper case letter if set or a lower case letter if clear.

The individual tags of the Tag Word are positioned to reflect the order of the data registers based on ST0.

The IP is the address of the last FPU instruction before using this function. The OA is the address of the memory operand if one was used by that last FPU instruction. The IP may not be of much use if a separate section of a program is used to handle exceptions and prepare error reports. The uID has been included as a parameter to circumvent this problem.

Example:

invoke FpuState, ADDR Dest, 12

In this example, the formatted string would be returned in the buffer labeled Dest. The 12 could be the 12th instance of calling the function in the program (The ID is always returned in the string as a decimal number.)

Prepared by Raymond Filiatreault.


FpuSub.htm

FpuSub

The FpuSub function subtracts the second parameter from the first one and returns the result as an 80-bit REAL number at the specified destination.

Src1 - Src2 → Dest

FpuSub (

lpSrc1 // pointer to, or value of, 1st parameter
lpSrc2 // pointer to, or value of, 2nd parameter
lpDest // pointer to destination of result
uID // ID flags for sources and destination
)

Parameters

lpSrc1

This either points to an 80-bit REAL number or to a DWORD integer, or is an immediate DWORD integer or one of the FPU constants:
FPU_PI or FPU_NAPIER (see FPU Constants for description),
all according to the content of uID. (This parameter is ignored if uID indicates that the value is already on the FPU.)

lpSrc2

This either points to an 80-bit REAL number or to a DWORD integer, or is an immediate DWORD integer or one of the FPU constants:
FPU_PI or FPU_NAPIER,
all according to the content of uID. (This parameter is ignored if uID indicates that the value is already on the FPU.)

lpDest

This points to a TBYTE where the 80-bit REAL result of the subtraction will be returned. The result can instead be retained on the FPU according to the content of uID. (This parameter is ignored if uID indicates that the result should remain on the FPU.)

uID

Only one of the SRC1_? flags must be OR'ed with only one of the SRC2_? flags and OR'ed with one of the DEST_? flags. (The DEST flag does not need to be OR’ed if the destination is in memory; that is the default destination.)

uID Flag Meaning
SRC1_FPU Src1 is already on the FPU
SRC1_REAL Src1 is a pointer to an 80-bit REAL number
SRC1_DMEM Src1 is a pointer to a 32-bit signed integer
SRC1_DIMM Src1 is a 32-bit signed integer
SRC1_CONST Src1 is one of the special FPU constants
SRC2_FPU Src2 is already on the FPU
SRC2_REAL Src2 is a pointer to an 80-bit REAL number
SRC2_DMEM Src2 is a pointer to a 32-bit signed integer
SRC2_DIMM Src2 is a 32-bit signed integer
SRC2_CONST Src2 is one of the special FPU constants
DEST_FPU The result remains on the FPU
DEST_MEM lpDest is a pointer to a TBYTE
(this is the default and does not need to be indicated)

Return Values:

If the result is considered a valid REAL number, it will be transferred to the specified destination and EAX will be non-zero.
If the function fails, EAX will be zero and the specified sources and destination will not be modified.

When a source is from the FPU, it will be discarded if the function succeeds; it would be replaced by the result when it is specified to be returned on the FPU. If no source is from the FPU but the result must be returned on the FPU, the FPU’s ST7 data register must be free; otherwise, the content of that register will be trashed in order to return the required result.

All other FPU registers and all the CPU registers (except EAX) are preserved.

Remarks:

Because these library functions allow only one value to be retained on the FPU, identifying both sources as being on the FPU will result in subtracting the FPU value from itself, leaving 0 as the answer.

Example:

invoke FpuSub, 0, 100, 0, SRC1_FPU or SRC2_DIMM or DEST_FPU

In this example, the 1st parameter is ignored because its value is identified as being on the FPU. Thus, 100 is subtracted from the 80-bit REAL number already on the FPU, and the result is retained on the FPU, ignoring the 3rd parameter.

Prepared by Raymond Filiatreault.


FpuTan.htm

FpuTan

The FpuTan function returns the tangent of an angle expressed in degrees or radians.

tan(Src) → Dest

FpuTan (

lpSrc //pointer to, or value of, angle (Src)
lpDest //pointer to destination of result
uID //ID flags for source, angle type, and destination
)

Parameters

lpSrc

This either points to an 80-bit REAL number or to a DWORD integer, or is an immediate DWORD integer, all according to the content of uID. (This parameter is ignored if uID indicates that the value is already on the FPU.)

lpDest

This points to a TBYTE where the 80-bit REAL tangent value will be returned. The result can instead be retained on the FPU according to the content of uID. (This parameter is ignored if uID indicates that the result should remain on the FPU.)

uID

Only one of the SRC1_? flags must be OR'ed with one of the ANG_? Flags and OR’ed with one of the DEST_? flags. (The ANG flag does not need to be OR’ed if the angle is in degrees; that is the default type. The DEST flag does not need to be OR’ed if the destination is in memory; that is the default destination.)

uID Flag Meaning
SRC1_FPU Src is already on the FPU
SRC1_REAL Src is a pointer to an 80-bit REAL number
SRC1_DMEM Src1 is a pointer to a 32-bit signed integer
SRC1_DIMM Src1 is a 32-bit signed integer
ANG_RAD The value of the angle is expressed in radians
ANG_DEG The value of the angle is expressed in degrees
(this is the default and does not need to be indicated)
DEST_FPU The result remains on the FPU
DEST_MEM lpDest is a pointer to a TBYTE
(this is the default and does not need to be indicated)

Return Values:

If the result is considered a valid REAL number, it will be transferred to the specified destination and EAX will be non-zero.
If the function fails, EAX will be zero and the specified sources and destination will not be modified.

When a source is from the FPU, it will be discarded if the function succeeds; it would be replaced by the result when it is specified to be returned on the FPU. If no source is from the FPU but the result must be returned on the FPU, the FPU’s ST7 data register must be free; otherwise, the content of that register will be trashed in order to return the required result.

All other FPU registers and all the CPU registers (except EAX) are preserved.

Remarks:

All positive and negative numbers except infinity are acceptable for this function.

Example:

invoke FpuTan, edx, ADDR Dest, SRC1_DIMM

In this example, the tangent of the 32-bit signed integer in EDX expressed in degrees is computed and transferred to the TBYTE memory variable labeled Dest if no error is reported.

Prepared by Raymond Filiatreault.


FpuTanh.htm

FpuTanh

The FpuTanh function returns the hyperbolic tangent of a number.
tanh(Src) → Dest

FpuTanh (

lpSrc //pointer to, or value of, source number (Src)
lpDest //pointer to destination of result
uID //ID flags for source, and destination
)

Parameters

lpSrc

This either points to an 80-bit REAL number or to a DWORD integer, or is an immediate DWORD integer, all according to the content of uID. (This parameter is ignored if uID indicates that the value is already on the FPU.)

lpDest

This points to a TBYTE where the 80-bit REAL hyperbolic tangent value will be returned. The result can instead be retained on the FPU according to the content of uID. (This parameter is ignored if uID indicates that the result should remain on the FPU.)

uID

Only one of the SRC1_? flags must be OR'ed with one of the DEST_? flags. (The DEST flag does not need to be OR’ed if the destination is in memory; that is the default destination.)

uID Flag Meaning
SRC1_FPU Src is already on the FPU
SRC1_REAL Src is a pointer to an 80-bit REAL number
SRC1_DMEM Src is a pointer to a 32-bit signed integer
SRC1_DIMM Src is a 32-bit signed integer
DEST_FPU The result remains on the FPU
DEST_MEM lpDest is a pointer to a TBYTE
(this is the default and does not need to be indicated)

Return Values:

If the result is considered a valid REAL number, it will be transferred to the specified destination and EAX will be non-zero.
If the function fails, EAX will be zero and the specified sources and destination will not be modified.

When a source is from the FPU, it will be discarded if the function succeeds; it would be replaced by the result when it is specified to be returned on the FPU. If no source is from the FPU but the result must be returned on the FPU, the FPU’s ST7 data register must be free; otherwise, the content of that register will be trashed in order to return the required result.

All other FPU registers and all the CPU registers (except EAX) are preserved.

Remarks:

All valid positive and negative numbers except infinity are acceptable for this function. However, the hyperbolic tangent rapidly approaches the values of 1 (or -1) with increasing numbers. A source value of ±23 already saturates the first 19 decimal places of the result with 9's.

The hyperbolic tangent is computed from the division of two exponential numbers. If a source value larger than approx. ±11300 is used, such exponential numbers would reach a value of “infinity” and their division would result in an invalid operation.

Example:

invoke FpuTanh, ADDR Src, 0, SRC1_REAL or DEST_FPU

In this example, the hyperbolic tangent of the 80-bit REAL number from the TBYTE memory variable labeled Src will be retained on the FPU if the function succeeds. The 2nd parameter is thus ignored.

Prepared by Raymond Filiatreault.


FpuTexpX.htm

FpuTexpX

The FpuTexpX function raises the number 10 by an exponent. (It could also be considered as returning the common antilogarithm of a number.)

10^(Src) → Dest

FpuTexpX (

lpSrc //pointer to, or value of, exponent parameter (Src)
lpDest //pointer to destination of result
uID //ID flags for source and destination
)

Parameters

lpSrc

This either points to an 80-bit REAL number or to a DWORD integer, or is an immediate DWORD integer or one of the FPU constants:
FPU_PI or FPU_NAPIER (see FPU Constants for description),
all according to the content of uID. (This parameter is ignored if uID indicates that the value is already on the FPU.)

lpDest

This points to a TBYTE where the 80-bit REAL result will be returned. The result can instead be retained on the FPU according to the content of uID. (This parameter is ignored if uID indicates that the result should remain on the FPU.)

uID

Only one of the SRC1_? flags must be OR’ed with one of the DEST_? flags. (The DEST flag does not need to be OR’ed if the destination is in memory; that is the default destination.)

uID Flag Meaning
SRC1_FPU Src is already on the FPU
SRC1_REAL Src is a pointer to an 80-bit REAL number
SRC1_DMEM Src1 is a pointer to a 32-bit signed integer
SRC1_DIMM Src1 is a 32-bit signed integer
SRC1_CONST Src1 is one of the special FPU constants
DEST_FPU The result remains on the FPU
DEST_MEM lpDest is a pointer to a TBYTE
(this is the default and does not need to be indicated)

Return Values:

If the result is considered a valid REAL number, it will be transferred to the specified destination and EAX will be non-zero.
If the function fails, EAX will be zero and the specified sources and destination will not be modified.

When a source is from the FPU, it will be discarded if the function succeeds; it would be replaced by the result when it is specified to be returned on the FPU. If no source is from the FPU but the result must be returned on the FPU, the FPU’s ST7 data register must be free; otherwise, the content of that register will be trashed in order to return the required result.

All other FPU registers and all the CPU registers (except EAX) are preserved.

Remarks:

Very large positive values of the source exponent may exceed the limits of the FPU and return a value of infinity. This would not be considered as an invalid operation and would not return the error code. However that return value may not be usable with other library functions.

Example:

invoke FpuTexpX, ADDR Src, 0, SRC1_REAL or DEST_FPU

In this example, the number 10 is raised by the 80-bit REAL exponent located at the TBYTE memory variable labeled Scr and the result is retained on the FPU if no error is reported. The 2nd parameter is ignored.

Prepared by Raymond Filiatreault.


FpuTrunc.htm

FpuTrunc

The FpuTrunc function returns the integer part of an 80-bit REAL number after discarding the fractional part.

trunc(Src) → Dest

FpuTrunc (

lpSrc //pointer to source parameter (Src)
lpDest //pointer to destination of result
uID //ID flags for source and destination
)

Parameters

lpSrc

This points to an 80-bit REAL number either in memory or on the FPU according to the content of uID. (This parameter is ignored if uID indicates that the value is already on the FPU.)

lpDest

This points to a TBYTE where the result can be stored as an 80-bit REAL number or points to a DWORD where the result can be stored as a 32-bit LONG integer. The result can instead be retained on the FPU, all according to the content of uID. (This parameter is ignored if uID indicates that the result should remain on the FPU.)

uID

One of the SRC1_? flags must be OR'ed with one of the DEST_? flags. (The DEST flag does not need to be OR’ed if the destination is in memory; that is the default destination.)

uID Flag Meaning
SRC1_FPU Src is already on the FPU
SRC1_REAL Src is a pointer to an 80-bit REAL number
DEST_FPU The result remains on the FPU
DEST_IMEM lpDest is a pointer to a DWORD
DEST_MEM lpDest is a pointer to a TBYTE
(this is the default and does not need to be indicated)

Return Values:

If the source is considered a valid REAL number, its absolute value will be transferred to the specified destination and EAX will be non-zero.
If the function fails, EAX will be zero and the specified source and destination will not be modified.

When the source is from the FPU, it will be discarded if the function succeeds; it would be replaced by the result when it is specified to be returned on the FPU. If the source is not from the FPU but the result must be returned on the FPU, the FPU’s ST7 data register must be free; otherwise, the content of that register will be trashed in order to return the required result.

All other FPU registers and all the CPU registers (except EAX) are preserved.

Remarks:

The source parameter MUST be an 80-bit REAL number. (Integers are already truncated.)

Example:

invoke FpuTrunc, ADDR Src, 0, SRC1_REAL or DEST_FPU

In this example, the source is an 80-bit REAL at memory variable labeled Scr and its truncated value will be retained on the FPU (as an 80-bit REAL number), ignoring the 2nd parameter.

Prepared by Raymond Filiatreault.


FpuXexpY.htm

FpuXexpY

The FpuXexpY function raises a positive number (first parameter) by an exponent (second parameter).

Src1^Src2 → Dest

FpuXexpY (

lpSrc1 // pointer to, or value of, base parameter (Src1)
lpSrc2 // pointer to, or value of, exponent parameter (Src2)
lpDest // pointer to destination of result
uID // ID flags for sources and destination
)

Parameters

lpSrc1

This either points to an 80-bit REAL number or to a DWORD integer, or is an immediate DWORD integer or one of the FPU constants:
FPU_PI or FPU_NAPIER (see FPU Constants for description),
all according to the content of uID. (This parameter is ignored if uID indicates that the value is already on the FPU.)

lpSrc2

This either points to an 80-bit REAL number or to a DWORD integer, or is an immediate DWORD integer or one of the FPU constants:
FPU_PI or FPU_NAPIER,
all according to the content of uID. (This parameter is ignored if uID indicates that the value is already on the FPU.)

lpDest

This points to a TBYTE where the 80-bit REAL result of the function will be returned. The result can instead be retained on the FPU according to the content of uID. (This parameter is ignored if uID indicates that the result should remain on the FPU.)

uID

Only one of the SRC1_? flags must be OR'ed with only one of the SRC2_? flags and OR'ed with one of the DEST_? flags. (The DEST flag does not need to be OR’ed if the destination is in memory; that is the default destination.)

uID Flag Meaning
SRC1_FPU Src1 is already on the FPU
SRC1_REAL Src1 is a pointer to an 80-bit REAL number
SRC1_DMEM Src1 is a pointer to a 32-bit signed integer
SRC1_DIMM Src1 is a 32-bit signed integer
SRC1_CONST Src1 is one of the special FPU constants
SRC2_FPU Src2 is already on the FPU
SRC2_REAL Src2 is a pointer to an 80-bit REAL number
SRC2_DMEM Src2 is a pointer to a 32-bit signed integer
SRC2_DIMM Src2 is a 32-bit signed integer
SRC2_CONST Src2 is one of the special FPU constants
DEST_FPU The result remains on the FPU
DEST_MEM lpDest is a pointer to a TBYTE
(this is the default and does not need to be indicated)

Return Values:

If the result is considered a valid REAL number, it will be transferred to the specified destination and EAX will be non-zero.
If the function fails, EAX will be zero and the specified sources and destination will not be modified.

When a source is from the FPU, it will be discarded if the function succeeds; it would be replaced by the result when it is specified to be returned on the FPU. If no source is from the FPU but the result must be returned on the FPU, the FPU’s ST7 data register must be free; otherwise, the content of that register will be trashed in order to return the required result.

All other FPU registers and all the CPU registers (except EAX) are preserved.

Remarks:

The source base parameter MUST be a positive number. Trying to raise a negative number by an exponent on the FPU will result in an invalid operation and the function will fail.

Very large positive values of the source exponent with a source base parameter greater than 1 may exceed the limits of the FPU and return a value of infinity. A similar situation could arise with very large negative values of the source exponent coupled with a source base parameter smaller than 1. This would not be considered as an invalid operation and would not return the error code. However that return value may not be usable with other library functions.

Although the Napier constant e can be specified as the source for the base parameter, raising that constant to a power can also be performed with the FpuEexpX function.

Example:

invoke FpuXexpY, ADDR Src1, 0, ADDR Dest, SRC1_REAL or SRC2_FPU

In this example, the base number is an 80-bit REAL identified by the TBYTE memory variable labeled Src1 and the exponent is already on the FPU (ignoring the 2nd parameter). The 80-bit REAL result is returned to the TBYTE memory variable labeled Dest.

Prepared by Raymond Filiatreault.


SourcesOfErrors.htm

Sources of Errors

Errors in the use of these library functions are all reported by returning 0 in EAX. It is the user’s responsibility to verify this return code to avoid a proliferation of errors whenever in doubt. The types of errors are too numerous to provide more specific error codes or messages.

Some of the potential errors are listed below. That list must not be considered as exhaustive considering the complexity of the library and other external factors. Passed parameters must be accepted as is by the functions because of the impossibility of type checking.

The following errors will generate an immediate error code within the function.

* A source parameter is identified as being on the FPU but the FPU is empty.

* A source parameter is identified as a type not allowed by the function.

* An 80-bit REAL source parameter is not considered by the FPU as being a valid one.

* A negative number is used as a parameter for a function which only allows a positive number for that parameter.

* A source parameter has a value outside the range allowable by the function.

Some other errors may not immediately return the error code in EAX but the returned result would be erroneous, possibly generating the error code with other functions when used as a parameter.

Dividing by 0 does NOT return the error code but the result is a special valid number treated by the FPU as equal to infinity. Using that result as a source parameter for other functions may then result in the error code being generated.

A source parameter is identified as being an 80-bit REAL number or a LONG integer at the specified memory address but a different type resides at that address (while still being considered as acceptable data by the FPU). The erroneous result could thus be propagated through other functions without ever generating the error code.

Prepared by Raymond Filiatreault.

S


MASM32 Library Reference
Copyright (c) The MASM32 project 1998-2007

MASM32.LIB is a collection of procedures to supply additional functionality to the MASM32 project. Each procedure has been written as a seperate module to prevent any granularity problems

The full source code for the MASM32 library is in the M32LIB directory in MASM32.

To use these procedures your code needs to include both the following two (2) lines in your main assembler file.

     include \masm32\include\masm32.inc
     includelib \masm32\lib\masm32.lib
Categories of library procedures.

Arithmetic
Command Line
Conversions
Extended Functions
Custom Control
Encryption Components
Floating Point Conversions
File Functions
Console Mode Functions
Graphics Primitives
Image Functions
Memory Functions
String Sorting
Recommendations with string sorts
C Style Character Testing
Parsing Functions
 Search Functions
         Pre-Built Dialogs
Sorting Functions
Clipboard Functions
Zero Terminated String Functions
Obsolete String Functions
System Dialogs
Window Framing Functions
Path Functions
Rich Edit Functions
Misc
Array Functions
Unicode String Functions
Unicode Common Dialogs
Hex to Binary Conversions
In Memory Text Read and Write
Tokenisers


Arithmetic

Arithmetic Procedures
GetPercent
IntDiv
IntMul
IntSqrt


Array Functions

arr_add | Add an integer to every member of a DWORD array
arr_mul | Multiply every member of a DWORD array by an integer
arr_sub | Subtract an integer from every member of a DWORD array
create_array | Create an array of pointers to a user defined array


C Style Character Testing

isalpha
isalphanum
islower
isnumber
isupper


Clipboard Functions

GetClipboardText | Get text from clipboard.
SetClipboardText | Write text to clipboard.


Command Line

Command Line Procedures
ArgCL
ArgClC
GetCL
getcl_ex


Console Mode Functions

ClearScreen
locate
StdIn
StdOut
StripLF
StdErr
Clear screen and place cursor at start Set X Y location of cursor
Get input from console
Output text at current location
Strip CRLF from StdIn result
Output text to standard out.


Conversions

atodw
htodw
dwtoa
dw2hex
dw2ah
udw2str
ustr2dw
ltoa
atol
Convert ascii number to DWORD Convert HEX string to DWORD
Convert DWORD to ascii string
Convert DWORD to hex string
Convert DWORD to ascii hex
Convert unsigned DWORD to string
Convert string to unsigned DWORD
Convert signed DWORD to ascii string
Convert ascii string to signed DWORD


Custom Control

BmpButton


Encryption Components

Notes On Encryption
XorData
RolData
RorData


Extended Functions

This range of procedures are aimed at applications that must stream output data at very high speed. Where there is a matching normal procedure and the required conversion is not highly speed critical, it is a better choice for size efficiency reasons.

atodw_ex
byt2bin_ex
dw2bin_ex
dw2hex_ex
wrd2bin_ex
hexflip32
bin2byte_ex


File Functions

exist filesize
read_disk_file
write_disk_file
LoadList
Test if file exists Get the disk file size
Read disk file into buffer
Write disk file from buffer
Load files into a list box


Floating Point Conversions
StrToFloat
FloatToStr/2


Graphics Primitives

circle
line


Hex to Binary Conversions

bin2hex
hex2bin


Image Functions

DisplayBmp
DisplayIcon
VerticalTile
BitmapFromFile
BitmapFromResource
BitmapFromMemory


In Memory Text Read and Write

readline
writeline
tstline
parse_line


Memory Functions

Malloc
Free
MemCopy
memfill
CreateMMF
CloseMMF
cmpmem
Allocate memory by the iMalloc method Free memory allocated by the iMalloc method
Copy memory from one address to another
Fill memory with a specified 4 bytes
Create a memory mapped file
Close a memory mapped file
Compare two addresses of equal length


Misc

a2wc | Convert ANSI string to UNICODE string
shell | Run a program synchronously
shell_ex | Extended version with priority control
wshell | An alternative technique run a program synchronously
nrandom | Generate a random integer within a range
IPtoString | Convert a DWORD IP to string
StripRangeI | Inclusive strip characters between 2 supplied characters
StripRangeX | Exclusive strip characters between 2 supplied characters
testreg | Test if a zero terminated string is a register
AsciiDump | Dump any byte sequence to assembler DB format
HexDump | Convert any byte sequence to a hex dump
byte_count | Write the count of every byte in a source to an array
load_drives | Load a list box with drive and volume data


Obsolete String Functions

The following string function names have been remapped as follows in the MASM32.INC file. Code written with the obsolete name will work exactly as before with no modification required.

lnstr     equ <szLen>
cmpstr    equ <szCmp>
cmpsi     equ <szCmpi>
revstr    equ <szRev>
lcase     equ <szLower>
ucase     equ <szUpper>
ltrim     equ <szLtrim>
rtrim     equ <szRtrim>
trim      equ <szTrim>
lstr      equ <szLeft>
rstr      equ <szRight>
midstr    equ <szMid>


Parsing Functions

ArgByNumber | Optional streaming or single argument mode parser
readline | Read a single line of text from a zero terminated source
decomment | Strip comments from a single line of code
get_ml | Get next single or multiline statement with comments stripped
create_array | Create an array of user defined size and member count
parse_line | Tokenise source text and load into a string array
lfcnt | Return the number of line feeds in a zero terminated text


Path Functions

GetAppPath
NameFromPath
GetPathOnly


Pre-Built Dialogs

AboutBox
GetFile
GetIP
GetTextInput


Recommendations with string sorts

These are the component string sorting algorithms that were used in the development of the two main string sorting algorithms.
There are 7 string sorting algorithms presented here that are rated according to their usefulness. Some have been used for the two sorts above while others have been used in their development. They have been written and optimised by hand in assembler and the string comparison code has been written directly inline to maximise the speed of each algorithm. They are useful within the following described boundaries.

Speed
-----
1. Quick Sort
2. Shell Sort
3. CISORT
4. CCSORT
5. Comb Sort
6. Insertion sort
7. Bubble Sort

Flexibility
-----------
1. CISORT No known quadratic behaviour
2. CCSORT No known quadratic behaviour
3. Comb Sort No known quadratic behaviour
4. Shell Sort Only fails on low range large count data
5. Quick Sort Fails on ordered and low range data
6. Insertion sort Only suitable for preordered data
7. Bubble Sort Only suitable for preordered data

CISORT
CISORT is a hybrid COMB / INSERTION that utilises the highly predictable performance of a COMB sort preordering pass and the speed of an INSERTION sort on pre-ordered data. It has been designed to be a SAFE sort that can be used with general purpose data that is not pre-known in its ordering. It has no known orderings weaknesses that force it into quadratic behaviour on any tested form of data.

CCSORT
CCSORT is a hybrid COMB / COCKTAIL SHAKER sort that is faster than a COMB sort because of the bi-directional bubble sort addressing the problem of "turtles" but it is slower than the hybrib COMB / INSERTION sort. It has been designed to be a SAFE sort that can be used with general purpose data that is not pre-known in its ordering. It has no known orderings weaknesses that force it into quadratic behaviour on any tested form of data.

QUICK Sort
A QUICK sort is the fastest available sort for data that is randomly distributed. Its speed advantage over other classic designs justifies using it where the data is known to be randomly ordered. It will fail if the data is pre-ordered or if the range of data is very limited in relation to the member count to be sorted. It normally fails due to exceeding the available stack memory from excess recursion depth.

SHELL Sort
The variation presented is an Incerpi-Sedgewick Shell sort that uses a predefined gap table. While it is faster than other variants of a SHELL sort, it is not as fast as a QUICK sort but it is a lot more robust with pre-ordered or unusually ordered data. The only tested data format that will force it into quadratic behaviour is very low range repetitive data with a large member count.

COMB sort
A COMB sort is an O(n log n) time complexity sort that can be used for general purpose sorting. It is susceptable to data elements that are at the high end of the data in the direction of the sweep which take many operations to correctly place. These are commonly referred to as turtles.

INSERTION Sort
An INSERTION sort is too slow to use by itself but it has a very useful characteristic of being fast on near ordered data that makes it suitable to use with hybrid sorts. It is also very fast on small data counts which makes it useful for modifying other sorting algorithms.

BUBBLE sort
Except for very small member counts, a bubble sort is far too slow by itself to be useful.


Rich Edit Functions

RichEd1
RichEd2
Read_File_In
Write_To_Disk


Search Functions

InString
BinSearch
Boyer Moore Algorithms
WordCount
partial


Sorting Functions

Sorting Overview
Quick Sort
Comb Sort


String Sorting
assort proc arr:DWORD,cnt:DWORD,rdi:DWORD ; ascending version
dssort proc arr:DWORD,cnt:DWORD,rdi:DWORD ; descending version

Description
There are two master sorting algorithms presented here which are hybrids of different sorting technologies.

Parameters
1. arr The starting address of the array of string pointers.
2. cnt The number of members in the array of pointers.
3. rdi A recursion depth limiter.

Important
There must not be any NULL pointers in the array of pointers passed to any of the string sorting procedures as the string comparison code is not designed to handle this situation. The string comparisons occur at a critical speed related area in the sorting algorithms and to add the code to test for NULL pointers would incur a substantial performance penalty. A NULL pointer in this context is a string address that has ascii ZERO as its first character. If the array loading code is at risk of setting a pointer to a NULL value, it must be filtered to prevent this from happening.
The MASM32 library has a pair of tokenisers that can be used to load an array of pointers to either lines of text or individual words under the topic Tokenisers

Return Value
The return values are designed to give some useful feedback about the arrangement of the data being sorted. If EAX returns zero then the data was highly random in nature and was sorted by the quick sort component of the algorithm.

If the data is already sorted or near ordered or has unusual arrangements like a very high number of repetitions of a limited number of variations, it will exceed the preset recursion depth for the quick sort and will be finished by a hybrid comb / insertion sort.

Comments
There are three seperate sorting algorithms that can be used by the two master sorting procedures. The first level is a very high speed quick sort which is ideally suited for highly random data. If the data is already sorted or ordered in such a way that a quick sort will be too slow, it determines the decay by the recursion depth of the quick sort and switches over to another hybrid sort that is highly insensitive to data arrangement to finish off the sorting.

The second sort is a hybrid comb sort which has very predictable performance to preorder the data which is then passed to an insertion sort which is very fast on near ordered data.
The strategy is to maximise the performance for the most common data which is usually random in nature and switch over to the high safety version if the quick sort decays into quadratic behaviour.

The recursion depth setting is set to a default of 100 if the "rdi" parameter is set to zero, otherwise it can be set manually to whatever depth is required based on some knowledge of the arrangement of the data being sorted. If the quick sort reaches the depth set in the "rdi" parameter, it exits and returns a value indicating that it has failed due to recursion depth. This is the trigger to run the high safety sort if the quick sort fails.

The following string sorting algorithms were used in the development of the above two string sorts. Some are components of the main hybrid while others were part of the testing and development. With the exception of the bubble sort, most are useful within understood limitations.

All of the string sorts below have been manually optimised for speed and the critical string comparison code has been written inline to avoid the extra call and branch overhead from using an external procedure to perform the comparisons.

; --------------------------------------------------
; high speed quick sort with recursion depth limiter
; This algorithm is used by the above hybrid.
; --------------------------------------------------
asqsort PROTO :DWORD,:DWORD,:DWORD,:DWORD,:DWORD
dsqsort PROTO :DWORD,:DWORD,:DWORD,:DWORD,:DWORD

; -----------------------------------------------------
; comb / insertion sort hybrid used by the above hybrid.
; -----------------------------------------------------
; args are,
; 1. pointer array address
; 2. Member count. Do NOT correct for zero based index.

acisort PROTO :DWORD,:DWORD
dcisort PROTO :DWORD,:DWORD

; -----------------------------------
; insertion sort for the above hybrid
; -----------------------------------
; args are,
; 1. pointer array address
; 2. Member count. Do NOT correct for zero based index.

aissort PROTO :DWORD,:DWORD
dissort PROTO :DWORD,:DWORD

; ----------------------------------------------
; high safety margin comb / cocktail shaker sort
; ----------------------------------------------
; args are,
; 1. pointer array address
; 2. Member count. Do NOT correct for zero based index.

ccsorta PROTO :DWORD,:DWORD
ccsortd PROTO :DWORD,:DWORD

; ---------------------------------------------
; The following 3 string sort algorithms were
; used in the development of the above versions.
; Within some data format limitations, they are
; useful string sorting algorithms.
; 1. Quick sort is fast on random data but can
; fail due to recursion depth on some data formats.
; 2. Shell sort is more robust but can be forced
; into quadratic behaviour with deliberately
; structured data.
; 3. Comb sort is robust and reliable but both the
; CCSORT and CISORT are faster and more consistent.
; ---------------------------------------------
; Quick string sort
; -----------------
; args are,
; 1. pointer array address
; 2. ZERO as lower array index
; 3. Member count MINUS 1

qssorta PROTO :DWORD,:DWORD,:DWORD
qssortd PROTO :DWORD,:DWORD,:DWORD

; -----------------
; Shell string sort
; -----------------
; args are,
; 1. pointer array address
; 2. ZERO as lower array index
; 3. Member count MINUS 1

ssorta PROTO :DWORD,:DWORD,:DWORD
ssortd PROTO :DWORD,:DWORD,:DWORD

; ----------------
; Comb string sort
; ----------------
; args are,
; 1. pointer array address
; 2. Member count. Do NOT correct for zero based index.

cstsorta PROTO :DWORD,:DWORD
cstsortd PROTO :DWORD,:DWORD

; -----------------------
; traditional bubble sort
; -----------------------
; args are,
; 1. pointer array address
; 2. ZERO as lower array index
; 3. Member count MINUS 1

bstsorta PROTO :DWORD,:DWORD,:DWORD
bstsortd PROTO :DWORD,:DWORD,:DWORD

 Recommendations with string sorts


System Dialogs

BrowseForFolder
ColorDialog
FontDialog
PageSetupDialog
PrintDialog
OpenFileDialog
SaveFileDialog


Tokenisers

Two basic designs are presented here, one that tokenises words in a source file and the other that tokenises lines in a text file. Both forms are "in place" tokenisers which means they modify the input text data rather than allocate the extra memory and extra processing time to copy each token into a variable length string array.

The advantage of using an "in place" tokeniser is that it is much faster than the additional allocation and additional processor time copying the data on a token by token basis. Application can be as diverse as parsing a script, creating an array of pointers to words or lines of text for sorting or creating an "overkill" command line parser.

If modifying the original text data is a problem, you can copy the original data to another memory buffer and pass the memory buffer to either procedure.

ltok | Tokenise lines of text "in place" in a text file.
wtok | Tokenise words "in place" in a text file.


Unicode Common Dialogs

ucOpenFileDialog
ucSaveFileDialog


Unicode String Functions

NOTE that while many of these procedures are similar to their ASCII versions, there are differences in some procedures in terms of return values and mode of operation. You should check the documentation for each procedure to ensure that you use it as it was designed so that you get predictable results.

ucappend
ucArgByNum
ucCatStr
ucCmdTail
ucCmp
ucCopy
ucFind
ucGetCL
ucgetline
ucLeft
ucLen
ucLower
ucLtrim
ucMid
ucMonoSpace
ucMultiCat
ucRemove
ucRep
ucRev
ucRight
ucRtrim
ucUpper
ucWcnt


Window Framing Functions

Frame3D
FrameWindow
FrameCtrl
Fram eGrp
Low level framing procedure Draw frame around Window
Draw frame around a control
Frame a group of controls


sz String Functions

Zero Terminated String Functions

These procedures are for working with ascii/ansi zero terminated strings.

szappend | Append zero terminated string to buffer
szLen | Length of zero terminated string
szCopy | Copy zero terminated string
szCmp | Case sensitive string comparison
szCmpi | Case insensitive string comparison
Cmpi | Case insensitive comparison without length argument
szRev | Reverse characters in string
szLower | Convert string to lower case
szUpper | Convert string to upper case
szTrim | Left and right trim string
szLtrim | Left trim string
szRtrim | Right trim string
szCatStr | Concantenate two strings
szMultiCat | Concantenate multiple strings
szMonoSpace | Format a string with single spaces and trimmed ends
szLeft | Get a count of characters from left side of string
szRep | Replace text in a zero terminated string
szRight | Get a count of characters from right side of string
szRemove | Remove substring from source string
szMid | Get a count of characters from middle of string
StrLen | Agner Fog's DWORD string length procedure
InString | Find substring in zero terminated source string
wordreplace | Whole word replace
szWcnt | Count the occurrence of text in a zero terminated string


Flat memory Model

A program written in native 32 bit Windows format is created in what is called FLAT memory model which has a single segment that contains both code and data. The programs must be run on a 386 or higher processor.

Differing from earlier 16 bit code that used combined segment and offset addressing with a 64k segment limit, FLAT memory model works only in offsets and has a range of 4 gigabytes. This makes assembler easier to write and the code is generally a lot faster.

All segment registers are automatically set to the same value with this memory model and this means that segment / offset addressing must NOT be used in 32 bit programs that run in 32 bit Windows.
For programmers who have written code in DOS, a 32 bit Windows PE executable file is similar in some respects to a dos COM file, they have a single segment that can contain both code and data and they both work directly in offsets, neither use Segment / Offset addressing.

The defaults in flat-model programs are NEAR code addressing and NEAR data addressing within the range of 4 gigabytes.

The FS and GS segment registers are not normally used in application programs but are used in some instances by the operating system.


Protected Mode Memory

In real mode operating systems such as DOS, it was possible to overwrite sections of the operating system code if a program was not correctly written and this would crash the operating system and the computer required a reboot to run again.

If you were writing code that wrote directly to the CGA video memory area starting at B800 hex and the code had an loop error in it, it could overwrite the entire area above it until the maximum address range in DOS was reached. This overwrote everything including the BIOS settings in memory.

Protected mode memory is designed to prevent this from happening. A protected mode memory manager controls the address range that an application can write to and it will terminate the application if it tries to write in an address range that it does not have access to.

This style of memory management was available in 16 bit Windows but because of the method that 16 bit Windows simulated multitasking, it was possible to overwrite sections of memory that were owned by other applications or the operating system before the errant program crashed.

Depending on what was overwritten in the operating system, some other program that had no errors in it would call an operating system function and both the program and the operating system would crash, more often than not you received the "Blue screen of death" which at least told you something but if you were writing code and made a real mess of it, you received the "Black screen of death", an instant black screen and locked up machine which told you absolutely nothing.

Changes in hardware and the use of hardware based multitasking in 32 bit Windows made protected mode memory managers more reliable. The fundamentals of writing code in a protected mode operating system is to only read and write to memory that you application has access to.

Because assembler allows you to read and write to almost any address range, you need to take precautions on how you handle the addresses that you read and write to. If you allocate a 10k buffer to read to but you try and read 20k, when the address goes past the end of the 10k buffer, you will get a page read fault. You can also get into trouble if you incorrectly dereference a variable in a register and try and read or write to that address as it will be out of the address range that your program has access to.

Page read and write faults are exceptions that are passed from the operating system to the application that makes the error, if the exception is not handled by the application, the operating system closes the application. This offers some measure of protection from applications that make address range errors.

In a multitasking operating system, if this style of protection was not available when multiple programs were running, one program could overwrite the memory of another program that was running which would crash the other running program. The same problem would occur with operating system code, a program that overwrote part of the operating system code would crash the operating system.


Instruction Operands

Operands are the parameters that are used with assembler mnemonics. A mnemonic can have from zero to three operands. With a logical or arithmetic mnemonic with two operands, the right operand is the source and the left operand is the destination.

    mnemonic destination, source

Example
    mov eax, 1

MOV is the reserved name for a family of opcodes that perform similar functions.

EAX is the destination operand.

1 is the source operand.

This operation copies the operand "1" into the operand "EAX".

It should be noted that other assemblers for other processors do not use this order of operands.


Opcodes and Mnemonics

At the hardware level in an Intel or compatible processor, instructions are are built into the circuitry and are called "opcodes" . While information can be written at a BIT level, the normal minimum data size is a BYTE.

Code can be written at a BYTE level in HEX notation in a HEX editor but it is a particularly complex method of writing code as it involves knowing a very large number of opcodes and having to handle a peculiarity of Intel processors where numerical data is stored in reverse order to character data.

To copy a 32 bit value (56 A7 00 FE) into the eax register, you will find the opcode, A1 (MOV EAX) followed by (FE 00 A7 56).

    A1 FE 00 A7 56

To facilitate writing low level code, a system was developed many years ago where groups of similar opcodes were given names that made them a lot more convenient to use. The names are referred to as mnemonics. This is the system used in modern 32 bit assembler.

A mnemonic is a reserved name of a family of opcodes that perform similar tasks in the processor. The actual opcodes are different depending on the size and type of operands being used. For example, with the MOV mnemonic,

    mov eax, Var1     opcode = A1
    mov Var1, eax     opcode = A3

The mnemonics give you a far more intuitive way of writing opcodes without any loss in precision. There is an exact correlation between what you write in mnemonics and what you get as finished opcodes.


Registers

Registers are conceptually a special working area within the processor that are faster than memory operands and are designed to work with the processors opcodes.

Registers in an Intel or compatible processor are a very limited resource when writing assembler, you have eight general purpose registers, EAX, EBX, ECX, EDX, ESI, EDI, ESP and EBP. In most instances ESP and EBP should be left alone as they are mainly used for entry and exit of procedures.

This means affectively, you have six 32 bit registers to write you code with plus any other memory locations that are useful in the procedure. ESI and EDI can be used in the normal manner in most instances but neither can be accessed at a BYTE level, you can read the low WORD of ESI as SI and the low WORD of EDI as DI.

Understanding the size of registers and the data that you can place in them is very important when using assembler. A 32 bit Intel or compatible processor has three native data sizes that can be used by the normal integer instructions, BYTE, WORD and DWORD corresponding to 8 bit, 16 bit and 32 bit.

This can be shown in HEX notation.
    BYTE    00
    WORD    00 00
    DWORD   00 00 00 00

In terms of registers, this corresponds to the three sizes that can be addressed with the normal integer registers. Intel and compatible processors are backwards compatible with older code that uses 8 and 16 bit registers and it is done by accessing any of the general purpose registers in three different ways. Using the EAX register as an example,

    8 bit  = AL or AH
    16 bit = AX
    32 bit = EAX
This is the schematic of a general purpose 32 bit register.

This schematic is easier to understand at a bit level. Reading from the right side, you have 32 bits in the register, bits 0 to 31. Because of the bit positions for each piece of data that can be accessed in a 32 bit register,AL is called the LOW byte, AH is called the HIGH byte and AX is called the LOW word.

To read the first BYTE in the register (bits 0 to 7) you use,

    mov byteval, al; move 1st byte size value in to variable.

To read the second BYTE in the register (bits 8 to 15) you use,

    mov byteval, ah; move 2nd byte size value into a variable.

If you want to read the first WORD in the register (bits 0 to 15) you use,

    mov wordval, ax; move 1st word size value into a variable.

To get at bits 16 to 31, you must rotate the bits in the register so they can be accessed by the previous instructions. Rotating a 32 bit register in either direction by 16 bits move the LOW 16 bits into the HIGH 16 bits and the HIGH 16 bits into the low 16 bits of the register.

    rol eax, 16   ; rotate EAX by 16 bits
      or
    ror eax, 16   ; rotate EAX by 16 bits

You cannot put a different size piece of data into a register than its correct size and you cannot mix different register sizes,

    mov eax, cl   ; this fails as eax is 32 bit, cl is 8 bit

 If you need to put the value in CL into a 32 bit register, you must convert it first using a number of different techniques,

    movzx eax, cl ; zero extend unsigned integer
    movsx eax, cl ; sign extend signed integer

 In some instances you can use,

    xor eax, eax  ; clear eax
    mov al, cl    ; copy cl into al

 and there are some older mnemonics that will do the conversions,

    mov al, cl    ; copy cl into al
    cbw           ; convert BYTE in AL to WORD in AX
    cwde          ; convert WORD in AX to DWORD in EAX


Data Types In Registers

There are three basic types of operands that can be placed in a register, immediate, memory or another register.

An IMMEDIATE operand is usually a number but it can also be a string literal in the form "a" which is converted by the assembler to its ASCII equivalent.
    mov al, "a"      ; string literal
    mov edx, 0       ; numeric immediate

A MEMORY operand is an address in memory of some form of data.
    mov al,  [esi]   ; copy byte at address in ESI into AL
    mov edx, lpMemvar; copy variable address into EDX

A REGISTER operand is a register with a value in it.
    mov ecx, edx     ; copy EDX into ECX

The actions that can be performed are determined by the available opcodes, trying to move one memory operand into another directly does not work because there is no opcode in the processor to do it.
    mov mVar, lpMem  ; this fails, no opcode to do it.

If you have a spare registers, you make an indirect copy through that register,
    mov eax, lpMem   ; copy memory value into register.
    mov mVar, eax    ; copy register into memory value.

If you don't have a spare registers, it can be done another way but it is slightly slower,
    push lpMem       ; push memory value onto the stack.
    pop mVar         ; pop it back off as another memory value.


The Stack

The stack is conceptually a range of memory that can be used for temporary storage of data from either within a procedure or as the normal method of passing parameters to a procedure. The stack is normally accessed in code by the two mnemonics, PUSH and POP. The stack is accessed on a last on, first off basis which means that the last value pushed onto the stack is the first one to be popped back off the stack.

The next position that can be written on the stack is called the top of the stack. When a piece of data is pushed onto the stack, the processor decrements the stack pointer ESP then writes the data to the top of the stack, when a piece of data is popped back off the stack, the processor reads the data from the top of the stack then increments the stack pointer. The stack address decreases as more data is pushed onto it and the address increases as data is popped back off the stack

The schematic for the stack is as follows, each square represents 1 byte on the stack, the different colors are to demonstrate the different data being pushed and popped and the schematic assumes the top of the stack is the left side of each image.

Existing stack layout.

Pushes
Push a 32 bit value = push eax

Push a 16 bit value = push cx

Push another 16 bit value = push dx

Pops
Pop a 16 bit value = pop dx

Pop second 16 bit value = pop cx

Pop the 32 bit value = pop eax.

If you wrote the code,

    mov edx, 100
    mov ecx, 500

  ; ---------------------------------
  ; push the 2 values onto the stack
  ; ---------------------------------
    push edx; edx has the value 100
    push ecx; ecx has the value 500

  ; -------------------------------
  ; pop the 2 values off the stack
  ; -------------------------------
    pop eax; eax has the value 500
    pop ecx; ecx has the value 100

32 bit Windows has a convention of which registers must be preserved in a procedure, EAX, ECX and EDX can be modified freely within a procedure but the EBX, ESI and EDI registers are normally preserved if they are used. In most instances, EBP and ESP should be left alone as they are used at the entry and exit of procedures.

If you write a procedure that uses any of the 3 registers EBX, ESI and EDI, you must push them at the beginning of the procedure and at the end of the procedure before the RET instruction. The following code assumes that the procedure uses all 3 registers.

    push ebx
    push esi
    push edi
      ; write code here
    pop edi
    pop esi
    pop ebx

Balancing the stack
An important consideration when using the stack is to be symetrical in the byte count of what is pushed and what is popped. If the stack is not balanced on exit from a procedure, program execution begins at the wrong address which will almost exclusively crash the program. In most instances, if you push a given data size onto the stack, you must pop the same data size.

Tricks on the stack
The stack is very flexible in what can be pushed and popped. There are a few tricks that are very useful when using the stack, you can push a 32 bit value and then pop two 16 bit values.

  ; -----------------------------------
  ; push a 32 bit value onto the stack
  ; -----------------------------------
    push edx

  ; ------------------------------------
  ; pop two 16 bit values off the stack
  ; ------------------------------------
    pop ax
    pop cx

 Even though the pushed data size is different to the popped data size, four bytes have been pushed onto the stack and four bytes have been popped back off the stack so the stack is balanced.
The stack can be used for many different things, you can push a register and pop it later when you need it so that you do not need to allocate a memory variable to put it in. You can use the stack to move a piece of data between memory operands and registers.

    push ecx
    pop memVar
      or
    push memVar
    pop edx

 or between two memory variables
    push memVar1
    pop memVar2

 Instead of using a register,
    mov edx, memvar1
    mov memvar2, edx

A collection of small tricks of this type free up the number of registers that you can use in your procedures if they are managed carefully.


Addressing and Pointers

 An important distinction in assembler is the difference between the ADDRESS of a variable and the VALUE of a variable. The ADDRESS of a variable is WHERE it is located in memory, the VALUE of a variable is what is written AT that ADDRESS.

This is the ADDRESS of the variable in memory

This is the VALUE at that address

The method used in assembler to get the value at an address is a technique called "dereferencing".

    mov eax, lpvar    ; copy address into eax
    mov eax, [eax]    ; dereference it
    mov nuvar, eax    ; copy eax into new variable

 Using square brackets around EAX gives access to the information at the address in EAX. This is the case with any 32 bit register. A register enclosed in square brackets is effectively a memory operand. The size of the data accessed at the address is determined by the size of the register used to receive it. In the above example it is a 32 bit value as it uses a 32 bit register but it can be done with 16 and 8 bit values as well using the correct size register.

Pointers
Pointers are a useful high level language abstraction for passing addresses between procedures and performing other types of complex data manipulation.
In assembler, when you use an instruction like,
    lea eax, MyVar

 you have put the ADDRESS of a variable into the EAX register. When you take the next step and put that ADDRESS into a variable of its own and you have a POINTER to the address.
    mov lpMyVar, eax

 The mechanics of this process are worth understanding as it can generate errors that are hard to track down. You can pass a pointer to another procedure either by its value,
    mov eax, lpMyVar  ; copy the VALUE into eax
    push eax          ; push it as a parameter
    call MyProcedure  ; call the procedure

 or you can pass it by reference,
    lea eax, lpMyVar  ; load the ADDRESS into eax
    push eax          ; push it as a parameter
    call MyProcedure  ; call the procedure

 When you pass an address in this manner, you have added an extra level of indirection so at the procedure end, you have a reference to a reference to an address. To get the address in the procedure, you "dereference" the variable to get the original address.
    mov eax, lpMyVar
    mov eax, [eax]

 The original address is now in eax.


Libraries

Libraries are made from modules that are written in a very similar manner to normal code. There are many times when a common piece of code is needed and there is little point in re-inventing the wheel each time that type of code is needed.

This capacity can be performed by keeping large amounts of source code available and inserting the sections of source code into the body of the code that requires the capacity but libraries automate such forms of code in very useful and fast ways that are far less error prone than manually inserting the code.

Libraries make the development of complex objects possible because of the way they work. It is normal in code to call other procedures and this is called "dependency". Manually inserting sections of source code requires that the programmer has to work out the dependencies and find all of the additional code that is required to make the procedure work.

When you build a library of procedures and use them in a program, the program is linked after assembly and the linker resolves the dependencies so that all of the required code is in the final program. The linker will display an error if it cannot find all of the dependencies.

This is not only very convenient in coding terms but it is also very efficient in size terms as the linker only includes the code that is needed, it does not include any other library module if it is not called in the program.

To maximise the advantage of writing libraries, an important consideration needs to be kept in mind, to avoid any uncalled code in your program, you should never bundle a number of procedures together in a module if they are not always used together. If this happens, the module will be included complete with the unused procedures and this makes your code larger than it needs to be for no purpose.

This problem in libraries is called "granularity" and it can be avoided by writing each procedure in its own module unless other procedure are ALWAYS used with it and are not use by any other procedure.

Writing a module is relatively easy, the easiest way is to get a procedure going in normal code first to make sure it is reliable and correctly does what you require. When this is done, you convert the procedure into a module. A module is assembled into an OBJECT MODULE independently of any other code so you must use the INCLUDE directive for any other required files.

.386                   ; set processor type
.model flat, stdcall   ; memory model & calling convention
option casemap :none   ; case sensitive

  ; --------------------------------
  ; Include any needed INCLUDE files
  ; or procedure prototypes.
  ; --------------------------------
    include \masm32\include\windows.inc
    include \masm32\include\gdi32.inc
    include \masm32\include\user32.inc

  ; ---------------------------------------------------------
  ; Write the prototype for the procedure name below ensuring
  ; that the parameter count & size match and put it in your
  ; library include file.
  ; ---------------------------------------------------------
    YourModule PROTO :DWORD,:DWORD etc.....

.code

; -----------------------------------------------------
YourModule proc par1:DWORD,par2:DWORD etc.....

  ; your code

    ret

YourModule endp
; -----------------------------------------------------

 The easiest way to build a library from either a single module or multiple modules is to place the collection of source file that are going to be made into a library into a directory and write a batch file that does the work.

    @echo off
    \masm32\bin\ml /c /coff *.asm
    \masm32\bin\lib *.obj /out:yourlib.lib
    : The following line works as well
    : \masm32\bin\link -lib "*.obj" "/out:yourlib.lib"

 Once the library is built, you write an include file that has the prototypes for each module in the library. Using the library procedures in your code then requires that you use the INCLUDE directive for the include file and the INCLUDELIB directive for the library.

You can then call the procedure you have written directly from your code without having to find the source code and any dependencies.


Working With Strings

In 32 bit Windows, string data is almost exclusively zero terminated strings. There are other forms of string data used in 32 bit Windows, OLE string memory in either BYTE size characters or WORD size characters in UNICODE but most Windows API calls work with zero terminated strings. It is worth noting that string manipulation can be performed on any BYTE sequence, not just character data.

This technology of zero terminated strings is reasonably old but it is fundamentally simple in its structure, very economical in memory and in processing terms and it can be done in assembler both well and fast.

The form that strings are allocated in the .DATA section is as follows,
MyString db "This is a string",0

The normal data type for zero terminated strings is BYTE data and a zero terminated string can be addressed as a BYTE array in memory. There are many instances when processing string data where no terminator is used, working with binary data requires that you keep track of the length of the BYTE data and this is usually done in a seperate variable.

The older approach is to use the built in string instructions. In 32 bit code, the string instructions use the source index ESI, the destination index EDI and ECX as the loop counter. The string instructions in this prebuilt loop technique are used with the prefix instructions REP/REPE/REPNE which repeat the action of the string instruction until a condition is met.

A simple copy example shows how this is done, it is assumed that the dest buffer is large enough to receive the byte count in source.

source is the address of the of the source buffer to copy
dest is the address of the destination buffer
ln is the byte count to copy

    cld               ; set direction flag forward
    mov esi, source   ; put address into the source index
    mov edi, dest     ; put address into the destination index
    mov ecx, ln       ; put the number of bytes to copy in ecx
  ; --------------------------------------------------
  ; repeat copying bytes from ESI to EDI until ecx = 0
  ; --------------------------------------------------
    rep movsb
In this example, MOVSB copies each byte from ESI to EDI and decrements ECX. The exit condition for the REP prefix is when ECX is decremented to zero.
When you copy a zero terminated string, you can write an algorithm that copies until it finds an ascii zero.

    cld               ; clear direction flag to read forward
    mov esi, source   ; put address into the source index
    mov edi, dest     ; put address into the destination index
  label:
    lodsb             ; load byte from source into AL and inc ESI
    stosb             ; write AL to dest and inc EDI
    cmp al, 0         ; see if its an ascii zero
    jne label         ; read the next byte if its not

 A trick that will make this algorithm run faster is to directly move each byte from the source address to AL and then from AL the the destination address. On Pentium and later processors, it is faster to use MOV/INC than LODSB or STOSB. This is done by "dereferencing" both ESI and EDI so that they function as memory addresses.
It should be noted that the direction flag cld does not effect this method and you can use any 32 bit registers when you are not using the string instructions.

    mov esi, source   ; put address into the source index
    mov edi, dest     ; put address into the destination index
  label:
    mov al, [esi]     ; copy byte at address in esi to al
    inc esi           ; increment address in esi
    mov [edi], al     ; copy byte in al to address in edi
    inc edi           ; increment address in edi
    cmp al, 0         ; see if its an ascii zero
    jne label         ; jump back and read next byte if not

 This code is longer but faster on later processors with dual pipelines due to what is called pairing, when mnemonics can go through the two pipelines in pairs, the code runs nominally twice as fast. The choice of mnemonics in this simple algorithm are small instructions of the type that pair properly so it runs faster than the shorter algorithm using the older string instructions that do not pair.

Anonymous labels
There is a notation in MASM to address the need for always having to create unique label names, especially when a lot of code uses labels in close sequence where their position makes sense without needing to be named. It is called anonymous labels that have the form,

@@:
and they are addressed respectively with @F and @B.
jmp @F means to jump FORWARD to the next occurrence of @@:
jmp @B means to jump BACK to the last occurrence of @@:

Expanding the use of the algorithm
The previous algorithm is a good base for string manipulation that modifies bytes in the string, filters, upper and lower case conversions and other types of byte replacements.
If you want to filter a string so that it only has numbers in it, you test the range of ascii numbers in the string and disallow any others.

    ascii "0" is 48
    ascii "9" is 57

NumOnly proc source :DWORD, dest:DWORD

    mov ecx, source   ; put address into ecx
    mov edx, dest     ; put address into edx
  @@:
    mov al, [ecx]     ; copy byte at address in ecx to al
    inc ecx           ; increment address in ecx

; -----------------------------------------------------
; perform byte modification, replacement or omissions
; -----------------------------------------------------
    cmp al, 0 ; test for zero first
    je @F ; exit loop on ascii zero
    cmp al, "0" ; string literal
    jb @B ; if below 48 "0", jump back
    cmp al, "9" ; string literal
    ja @B ; if above 57 "9", jump back

; ------------------------------------------------------

    mov [edx], al ; copy byte in al to address in edx
    inc edx ; increment address in edx
    jmp @B
  @@:
    mov [edx], al ; copy ascii zero to address in EDI
    ret

NumOnly endp


Working With Macros

 Macro capacity is often referred to as a pre-processor as it allows the programmer to perform operations on the form of code BEFORE it is passed to the assembler. When written correctly, macros can declutter code, automate complex operations in convenient ways and make repetitious tasks simple.

You write a basic macro as follows,

  Do_This_Operation MACRO
    ; write your code here
  ENDM

 You write the name of the macro in your code.

    Do_This_Operation

 When the pre-processor in the assembler finds the macro, it expands the macro back up to the code that you wrote within the macro. A macro can be written to accept parameters which are inserted into the code you write in the correct places.

    RGB MACRO red, green, blue
      xor eax, eax
      mov al, blue ; blue
      rol eax, 8
      mov al, green ; green
      rol eax, 8
      mov al, red ; red
    ENDM

 In this simple macro, you can set the three BYTE values as either 3 immediate numerical operands, three memory operands or three registers.

    RGB 125, 175, 225
      or
    RGB Byte1, Byte2, Byte3
      or
    RGB cl, ch, dl

 When the macro is called in code, it expands the macro back up to the code you wrote with the parameters you passed to it in the correct places.

Macros differ from library modules n a number of important ways, each macro call directly inserts the macro code into the body of the code so if you call a macro ten times, you get the code ten times.

This is useful if you are writing repetitive code that loads an array prior to a function call and it is also faster than a procedure in that it does not have any stack overhead but the down side is that if the macro is larger in size and is not particularly speed critical, you code size will increase due to the repetition of the macro.

It is usually a programming decision to use either a macro or a procedure depending on which has the greatest advantage in the circumstances that code is used.

Macros can perform reasonably complex operations that have loop structures within them.

 ; --------------------------------------------------
 ; macro for making STDCALL procedure and API calls.
 ; --------------------------------------------------
   Scall MACRO name:REQ,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12, \
   p13,p14,p15,p16,p17,p18,p19,p20,p21,p22

   ;; ---------------------------------------
   ;; loop through arguments backwards, push
   ;; NON blank ones and call the function.
   ;; ---------------------------------------

      FOR arg,<p22,p21,p20,p19,p18,p17,p16,p15,p14,p13,\
      p12,p11,p10,p9,p8,p7,p6,p5,p4,p3,p2,p1>
        IFNB <arg>    ;; If not blank
          push arg    ;; push parameter
        ENDIF
      ENDM

      call name       ;; call the procedure

    ENDM
  ; ------------------------------------------------------------------

 This macro works by using a FOR loop that reads the parameter list backwards and if it each is not blank, it pushes the parameter onto the stack before calling the first parameter that is the procedure name.

Macros in part give the programmer the capacity to build their own language and this makes assembler a very flexible way to write fast and efficient code.

Local parameters in a macro
A problem arises if a MACRO has a label in it when the macro is called more than once, you get a duplicate label error. Fortunately there is a simple solution to the problem, MASM has a LOCAL

 This name LOCAL is ambiguous in MASM as MASM also uses the same term in a procedures to designate stack parameters. The two seperate usages should not be confused, a LOCAL in a MACRO has the following form,

MyMacro MACRO Parameter1, Parameter2 etc ...
    LOCAL MyLabel
    ; asm code
    jmp MyLabel
    ; asm code
  MyLabel:
    ; other asm code
ENDM

 MASM converts the LOCAL MyLabel to something like ?00001: and the next call to the macro will be ?00002 etc ... This ensures that there is no duplication error. LOCAL can be applied to variables as well.


Basic Loop Design

High speed loops are critical where performance matters and it is here where a lot of time can be wasted if the loop design is not written properly.

At there most basic, a loop is a label followed further down the instruction sequence by a jump back to it.

  label:
    ; assembler code
    jmp label

What has to be added to this loop is an exit condition so that it does not run infinitely. Simply adding the extra code will work,

      mov edx, 0

    label:
      ; assembler code
      inc edx
      cmp edx, 1000000
      je lblOut
      jmp label

    lblOut:

but it is suboptimal code because of the number of instructions it uses to test for the exit condition and to exit. What determines a faster loop design is what the loop will be used for.

If a loop does nothing more than repeat a set number of times, there is a well known optimisation trick that will make the loop run a lot faster.

      mov edx, 1000000

    label:
      ; assembler code here
      dec edx
      jnz label

This works because the DEC mnemonic sets the ZERO flag when the counter decrements to zero. The JNZ mnemonic will not jump to the label under the condition that the zero flag is set. It has a lower instruction count and it outperforms most other loop designs because of it.

When working with BYTE data, you usually need to increment the byte address each iteration of the loop so in terms of instruction count, using the address counter means that you don't have to add the code for a seperate counter.

      mov esi, src      ; put source address in esi
      mov edi, dst      ; put destination address in edi
      mov ecx, count    ; put count in ecx
      add ecx, esi      ; add address in esi to ecx
                        ; to have an exit condition to test

label:
      mov al, [esi]
      inc esi
        ; do something with the byte if needed
      mov [edi], al
      inc edi
      cmp ecx, esi      ; test for exit condition here
      jne label         ; if not equal, loop again

Unrolling a loop
There are times when a well optimised loop may still not be fast enough and that any increase in speed will justify the extra coding required to unroll the loop. Unrolling a loop means doing more in the loop each iteration so that the loop overhead is diminished.

To use a simple example, if you were copying data from one buffer to another at a DWORD at a time and you needed it to go faster again, you could try reading two DWORD reads and writes each iteration of the loop. Note that the examples do NOT handle any remainder after division.

Single DWORD copy.

      mov esi, src
      mov edi, dst
      mov ecx, count  ; count in ecx
      shr ecx, 2      ; divide by 4

    label:
      mov eax, [esi]
      add esi, 4

      mov [edi], eax
      add edi, 4
      dec ecx
      jnz label

Unrolled to perform 2 DWORD copies each iteration.

      mov esi, src
      mov edi, dst
      mov ecx, count      ; count in ecx
      shr ecx, 3          ; divide by 8

    label:
      mov eax, [esi]      ; read 1st DWORD
      mov ebx, [esi + 4]  ; read 2nd DWORD
      mov [edi], eax      ; write 1st DWORD
      mov [edi + 4], ebx  ; write 2nd DWORD
      add esi, 8          ; add 8 to esi

  add edi, 8          ; add 8 to edi
      dec ecx
      jnz label

This technique theoretically reduces the loop overhead by half. There are of course many other factors such as memory access speed but the final way of seeing if the rewritten algorithm is any faster is to benchmark it against the single DWORD copy version.

You can unroll this loop by a factor of four but the increase in speed reduces with the increase in the number of times the loop is unrolled so there may be no benchmarked gain in doing the extra coding, especially in a more complex loop.

Mnemonics to avoid
The Intel processors have a built in set of instructions for loops but they are very poorly optimised and run very slowly in comparison to CMP/JMP.

LOOP, LOOPE, LOOPZ, LOOPNZ, LOOPNE

These are leftover technology from the DOS era. In each instance you can write faster code by manually incrementing or decrementing the loop counter, comparing the result and jumping back to a label.

String instructions without the REP family of prefixes are suboptimal performers and should be replaced with manually code alternatives.

MOVS, LODS, CMPS, SCAS

These string instructions are normally used with the size specifier at the end, IE. MOVSD, LODSB etc ...
Manually code alternatives are a lot faster in loop code.

JCXZ should be replaced with,

    test ecx, ecx
    je StartLabel


Register Preservation Convention

A long time ago when MS-DOS was the main operating system in Intel based personal computers the main method of interacting with the operating system was done by interrupts and for each interrupt, the registers required to load data for the DOS function were specified with that interrupt.

At the compiler level different manufacturers applied whatever register usage suited their purpose and rarely were these usages ever compatible. In a non re-entrant operating system like MS-DOS this was of little consequence as only one program ran at a time and DOS did not have support for multitasking or external code reuse like a modern DLL, the closest was the old overlay system.
Microsoft introduced 32 bit Windows computing in the early 90s with Windows NT and along with it to match the difference in operating system architecture they also introduced a convention for the use of registers so that applications with different origins could predictably and reliably interact with the operating system.

Intel and compatible hardware from the i386 upwards came with eight (8) general purpose 32 bit registers and to be properly compatible with 32 bit Windows an application had to use the registers in a manner that was consistent with the operating system.

The eight general purpose 32 bit registers are,
eax ecx edx esp ebp ebx esi edi

 The registers ESP and EBP are usually used for constructing a stack frame which by its normal requirement preserves and restores these two registers and this leaves 6 general purpose registers which are split into two (2) seperate classes, those which the operating system expect to contain the same value when the application interacts with the operating system and those which can be freely modified without having to be restored.

The three registers that must remain the same for each interaction with the operating system are,
EBX ESI EDI

 The three registers that can be freely modified are,
EAX ECX EDX

 The convention is not without purpose as it provides a method where the least number of register preservations need to occur between procedures calling other procedures or systme function in the Windows APIs.

Without this efficiency you would see some of the very inefficient methods that are still occasionally used with sub-standard code where all of the registers are preserved and restored and a return value in the EAX register is loaded from a stack variable. This sub-standard method produces larger and slower code with no gain in reliability and only indicates inexperience with the author of such code.

The description above may sound complicated but in practice it is very simple to impliment.

myproc proc args etc .....

    push ebx
    push esi
    push edi

  ; write code that uses ANY of these registers here.

    pop edi
    pop esi
    pop ebx

    ret

myproc endp

This example procedure above uses the normal stack frame so ESP and EBP are already preserved and it also preserves and restores all 3 required registers. While this is safe code, not all procedures need to use any of the three registers so the registers only need to be preserved if the code within the procedure needs to use them which modifies them.

All of the Windows API functions are written this way and you can safely assume that any values you have in EBX ESI and EDI will be the same when the API function return to your calling code.
This means that if you need to have a counter within your procedure, if you preserve any one of these registers, you can use that register as the counter and it will work reliably after an API call or to a function that is written according to the Windows convention.

The reciprocal to this usage is that the 3 registers EAX ECX EDX can be freely modified not only in you own code but any procedure that you call that also uses the operating system convention. This means that if you must store values in any of the 3 mentioned registers and then call other procedures, you must preserve any of EAX ECX EDX before you call another procedure and restore them after it has returned.

In practice you can normally place value you want preserved between calls to other procedures in EBX ESI EDI and use EAX ECX EDX for transient values.

Because the convention allows EAX ECX EDX to be freely modified without having to be restored after, they can also be used to provide up to 3 seperate return values from a procedure. The normal return value is in EAX but you also return values in ECX and EDX.

A common mistake in procedure layout.
With 8 general purpose 32 bit registers where two are normally used for the stack frame, registers are a reasonably scarce resource and one of the common mistakes made when laying out a procedure is to treat registers like variables. In all but the most simple procedures this produces the problem that you run out of registers to hold all of the variables before you get the procedure written.

The solution is to use LOCAL variables to get the procedure running reliably then selectively replace them with any registers that may not be used in the procedure. With careful register reuse you can reduce the number of LOCAL variables by using registers and produce faster code if you get it right.


Working With Structures

When writing code in Windows, it is a common to handle data in blocks for some coding requirements. The normal method is to use a structure to group data in convenient ways so that it can be addressed as a single unit.

A structure is made up of members that have a specified data size. In a commonly used structure RECT, you have four DWORD size members.

    RECT STRUCT
      left    DWORD  ?
      top     DWORD  ?
      right   DWORD  ?
      bottom  DWORD  ?
    RECT ENDS

The notation for each member is membername, datasize, specifier. In most instances, the specifier is ? which means the member is not initialised to a value.

A structure is written in memory as a sequence of members so in the case of a RECT structure, it is written as four sequential DWORD size members in memory. The members of a structure can be filled in a number of different ways depending on how the structure was originally allocated.

If it is allocated in the .DATA section, it can be initialised to preset values but if it is allocated on the stack as a LOCAL value within a procedure, the values have to be coded into the structure.

    LOCAL Rct :RECT

    ; code

    mov Rct.left,   1
    mov Rct.top,    2
    mov Rct.right,  3
    mov Rct.bottom, 4

It should be noted that a structure member is a memory operand so you cannot directly move another memory operand into it, you must either use a register to copy it or the stack mnemonics, push / pop.

You can now refer to the filled structure as a single unit with ADDR Rct in an invoke directive procedure call. If an API call requires the address of a structure, you fill the structure with the values you require and call the API,

    invoke APIcall,parameter1,parameter2,ADDR Rct

If you write a procedure where you want the values in a structure passed to it, you can pass the structure by using the structures data type in the procedure.

MyProc proc par1:DWORD,par2:DWORD,MyRect:RECT

    mov eax, MyRect.left    ; copy first member into EAX

The individual members can then be accessed by their names in the procedure that receives the RECT as a parameter. You call the proc as follows,

    invoke MyProc,par1, par2, Rct

Nested structures
A method common to 32 bit Windows is the use of nested structures. MASM has a notation for dealing with this type of construction. If you needed a structure that had multiple structures in it,

    MyNestedStruct STRUCT
        item1 RECT  <>
        item2 POINT <>
    MyNestedStruct ENDS

This structure uses the above RECT struct and the following POINT struct.

    POINT STRUCT
      x  DWORD ?
      y  DWORD ?
    POINT ENDS

There are six members in this structure, four from the RECT structure and two from the POINT structure. Allocated on the stack it looks like this,

    LOCAL mns:MyNestedStruct

The six members are,

    mns.item1.left
    mns.item1.top
    mns.item1.right
    mns.item1.bottom
    mns.item2.x
    mns.item2.y

The notation for mns.item2.x means the allocated structure mns , its second item item2 and the first item in the POINT struct x.

Structures can be nested to multiple depths but they all use this basic notation and logic.

Advanced Structure Handling
Increasingly, there is a need to be able to handle structures that are passed as an address and this type of code is becoming more common in Windows code design. MASM has a specialised notation to make this process a lot easier to handle.

If for example you needed to pass the adress of a RECT structure to a procedure, you would normally make the call in the following manner,

    invoke MyFunction,ADDR Rct

At the procedure end of this function call you would normally have something like the following,

    MyFunction proc lpRect:DWORD

With a simple structure like RECT you can address the seperate parameters manually by putting the address into a register and write to the location of each member,

    mov eax, lpRct

    mov [eax],    DWORD PTR 10
    mov [eax+4],  DWORD PTR 12
    mov [eax+8],  DWORD PTR 14
    mov [eax+12], DWORD PTR 16

This works fine but with more complex structures this becomes much harder to work with and far more error prone.

The alternative is to use a method that MASM has to address the individual members by using the ASSUME directive.

   ASSUME eax:PTR RECT
    mov eax, lpRct
    mov [eax].left,   10
    mov [eax].top,    12
    mov [eax].right,  14
    mov [eax].bottom, 16
    ASSUME eax:nothing

This works by telling the assembler that the EAX register is to be treated like a RECT structure. The ASSUME eax:nothing tells the assembler that the register is no longer being used in this manner.

There is an alternative notation where you can individually "type cast" each member.

    mov eax, lpRct

    mov (RECT PTR [eax]).left,   10
    mov (RECT PTR [eax]).top,    12
    mov (RECT PTR [eax]).right,  14
    mov (RECT PTR [eax]).bottom, 16

The advantages of these techniques is that they use the convenience and reliability of a structure so that you do not have to calculate the offsets of each member and it also uses the normal member names. The downside of these techniques is that they use a register which is not always a desirable consequence. If the register usage is a problem, you will need to allocate LOCAL variables and copy the data from each required member to the variables.


High Level help Index

MASM32 Macro High Level Reference
Productivity Enhancement Techniques
Introduction
The Scope Of MASM32
Short History Of MASM
MASM and other assemblers

Unicode Support
Unicode support
Direct Unicode Macros
Using the TCHAR Keyword

Fundamental Architecture
Why is MASM different ?
Basic Architecture Of MASM32
High And Low Level Code

Basic Code Layout
Creating Procedures
Calling Procedures
Using Libraries

Control Flow Techniques
Using the .IF Syntax
Using switch Block Syntax
Using switch$ Syntax

Loop Code Methods
Using .WHILE Syntax
Using .REPEAT Syntax

Macro Categories
Code Calling Macros
Error Reporting
File IO Macros
Memory Allocation
Console Mode Macros
String Macros
Global Scope String Assignment
Dynamic String Arrays
File Dialogs
Path And Directory Macros
Text Toolbars
Performance Macros
Memory Line IO Macros
Environment
Macro Library
C Runtime Conversions
Specialised Prototypes
Pseudo Mnemonics


The Scope Of MASM32
The MASM32 Project is a multifaceted project that is directed at experienced programmers so they can learn or write 32 bit MASM code for the Windows Operating System and it addresses a wide range of capacities, some of which are peculiar to MASM.

Mnemonic Programming
At the lowest level there is direct mnemonic coding which is the core of assembler programming. This is followed by reusable procedures in application software that include both mnemonic coding and higher level API programming.

API Programming
Using the Windows API functions is a necessary part of programming 32 bit assembler for the Windows platform. The MASM32 project has been a leading advocate of writing high level code such as API functions like high level code so that code output is both reliable and time effective in development terms.

Library Design
Library design by converting procedures into seperate modules is an important component of MASM32 and it provides its own STATIC library both for its intrinsic use as well as being a model for library construction for custom software.

Language Design Using Macros
Macro design is the next step for assembler programmers using MASM as it involves a good understanding of all of the other capacities that MASM has. The macro system documented in this help file and generally in MASM32 is not only intrinsically useful in its own right but a viable example of how a programmer can shift from being a language user to a language designer and by doing so can become free of the assumptions of other languages and their limitations.


Short History Of MASM

MASM is a very well understood development tool that has been under constant development since 1981 and it is upgraded by Microsoft on a needs basis for hardware changes and operating system version differences. It became a radical tool in about 1990 with the introduction of MASM 6.00 in that it deviated from accepted assembler norms of that period by adding pseudo high level capacity for many common tasks and substantially increased the power and control of its macro capacity so that assembler programmers could construct complex higher level code in creative and original ways.

MASM was nearly lost to public usage in the middle 90s as programming fashion changed with the introduction of Windows 95 but Microsoft kept developing MASM for its own internal needs as a major operating system vendor where critical core components of the Windows operating systems were written in MASM. In this period a lot of folklore developed about what MASM was supposed to NOT be able to do which followed from other assemblers attempting to take over the market position that MASM had held for many years.

A couple of years later as the patches became available to change the last release version of MASM into a true 32 bit executable and MASM also became available through the device development kits for Windows 95 and 98. The licencing of the device development kits was flexible enough to allow MASM to be used for application development in Windows which in turn made the MASM32 Project possible.

A substantial number of people who had used MASM for years were not willing to abandon this type of capacity and actively contributed to the MASM32 Project so that the knowledge they had accumulated over years of commercial experience would be passed on to another generation who would learn and wield a tool of this power again.

MASM continues to be an esoteric tool owned and developed by a major operating system vendor for their own internal use in tuning performance critical areas of operating systems and other related commercial applications. It has never been a tool for the faint of heart and requires a lot of knowledge to use correctly but for those who make the effort and learn a tool of this power, they will have performance at their fingertips that few would understand or believe.

In more recent times as the interest in true low level programming has continued to rise, Microsoft have re-released MASM for their Visual C line of products so that programmers developing code for 32 bit Windows had the capacity to tune performance critical areas of their code.


MASM and other assemblers

MASM has been in constant development since 1981 and has been an important tool in the development of Microsoft operating systems from that period to current versions of 32 bit Windows.
Over a period of nearly 25 years there have been very good assemblers written and many of them have been written by highly skilled programmers or teams of programmers but MASM has simply outlasted them all as it is a necessary tool for operating system development by a major operating system vendor.

With a near 25 year development cycle and a matching corporate development budget MASM has accumulated a very powerful capacity that extends to its enormously powerful parsing capacity, object module compatibility with the major Microsoft development languages, a pre-processor that has never been fully exploited, built in debugging support and it has done all of this while preserving the historical Intel syntax in what is now a superset of the original Intel syntax.

With such a long development cycle, 16 bit code written 15 years ago can still be built using late versions of MASM as the format has remained compatible for longer than this time frame and this for among other reasons is why MASM has such good support as it is used and well understood by a very large number of experienced programmers.

While there is no doubt that there are a number of well written alternative assemblers that are capable of producing high quality binary code for the 32 bit Windows platform, the differences in capacity that follow from a 25 year long corporate budget and development cycle will not be bridged in the remaining life of the 32 bit versions of Windows.

The distinction is that basically the alternative assemblers are well suited for hobbyist programmers who are interested in the actual development of the assembler they are using while MASM is a tool for professional programmers who need to be able to deliver commercial quality code within a reasonable timeframe that is compatible with other code that they may be developing using the Microsoft C compiler.


Why is MASM different ?

As an assembler MASM differs from almost all compilers in that it does not have any built in runtime library at all. MASM comes with the capacity to assembler mnemonics to binary code, load and use external library modules and a number of built in macros for handling some higher level tasks but it will not produce any runtime code by itself at all.

This difference needs to be understood, especially by a programmer who is learning to write assembler for while programmers learning and writing high level languages can start using the built in runtime capacity to perform the basic tasks, there are no default runtime functions or capacities in MASM whatsoever.

When a programmer starts from scratch using an assembler as powerful as MASM, they are trying to do something that is very difficult as they are trying to learn a language by writing their own runtime library which is almost exclusively an advanced task for programmers who have extensive experience with that language.

It is by no means a disadvantage that MASM does not have a default runtime library as it has the capacity to dial up a runtime library that performs the basic tasks that are commonly associated with a programming language.

The MASM32 Project provides a viable and well tested runtime library that is a combination of both static library procedures and dedicated macros that provide much of the capacity of higher level languages yet without the assumptions of many high level languages.

When you use the MASM32 runtime library, you are using hand written assembler code and hand written macros that are designed to deliver very good performance in all but the most demanding tasks that are better suited for manual coding directly in assembler.

Apart from the intrinsic use of the MASM32 runtime library, the available capacity has another task in mind, by making a large number of functions and capacities available, the programmer learning assembler programming with MASM32 can get a reasonable amount of common tasks up and running reliably and easily enough so that they can start to learn direct assembler coding more quickly.

Rather than being bogged down with the complexities of writing a runtime library for a very powerful assembler like MASM just to perform basic functions, using the runtime library in MASM32 frees the programmer to get their code up and running so they can lay out and design their own pure assembler code for performance critical tasks.

Programmers who try and take on a bare assembler without a runtime library available have a very high failure rate and end up writing no assembler code where the programmer who uses the available capacity to get their code up and running more reliably and more quickly have a far higher success rate and learn to write the more complex direct assembler code within a reasonable time frame.

This situation is something like learning how to swim. If a non-swimmer is dumped out in the deep water, they have a very high chance of drowning before they ever learn how to swim where the non-swimmer who start off from the shore in shallower water will in most instances both survive and learn how to swim.

To enable the MASM32 runtime library, you add the following line at the very start of your application.

include \masm32\include\masm32rt.inc

It is recommended after you have gained enough experience that you learn how to dial up your own runtime library as it gives you more control and a lot more choices. The following section will show you how to more accurately dial up what you require for your application with basic startup code, include files and library files.

Basic Architecture Of MASM32


Basic Framework Of MASM32

Basic Architecture Of MASM32

The MASM32 Project has developed an integrated system over time to make direct assembler programming accessible in a fast and reliable manner where tasks within its target range can be developed within a reasonable time frame and yield very high performance where needed.

The basic MASM32 architecture is an integrated system of include files, import libraries, macros and a predefined framework to reliably build and share code. The assembler (ML.EXE) can be used to build files in many different ways but unless there is some form of minimum standardisation, no-one can build another persons code and this was the case years ago before comprehensive include files were made available with the MASM32 project.

The method used to build assembler files with the MASM32 Project makes no claim of being better or faster or any other attribute than any other technique, what it does claim is that it is reliable and very wide spread and this has facilitated a massive range of compatible and sharable code that is available to other MASM32 programmers. What follows is a general description of the layout of a MASM32 assembler source file and why it is done this way.

Leading Code For Any Application
.486                     ; create 32 bit code
.model flat, stdcall     ; 32 bit memory model
option casemap :none     ; case sensitive
This lead code establishes the minimum processor needed to run the application, the memory model required for 32 bit Windows applications, the calling convention for all of the default procedures and sets the assembler to work with case sensitive names as is required with 32 bit Windows.

Hard Coded paths
The MASM32 include files and libraries in the MASM32 project require a hard coded path that is relative to the root directory of the logical drive that MASM32 is installed on. While there are numerous methods of building assembler files that are different and work just as well, the MASM32 Project has used this method to avoid a common problem with programmers who have other programming environments set up on their development computer and that is ending up with the wrong version of LINK or calling the incorrect library or include files. Common problems are an assembler file that normally builds at 2k ending up at 16k because of different file alignment as default with the linker that is run. The hard coded paths solve problems of this type.

Matching Include And Library Files
MASM32 uses its own set of include files and libraries to handle the very large range of system based function that are normally called the Application Programmers Interface or API functions and it is done in a systematic manner. The leading include file in the WINDOWS.INC file that contains a very large number of constants and structures used by Windows functions. It should always be placed first before any other include file.

include \masm32\include\windows.inc

Libraries and include files in MASM32 are matched to the system DLLs that contain the API functions and are designed to be used in their matching "include" and "includelib" formats so that both the prototype and library function is available.
For each library you require, you also add the matching include file so you get the following code layout.

; include files
; ~~~~~~~~~~~~~
include \masm32\include\windows.inc
include \masm32\include\masm32.inc
include \masm32\include\gdi32.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
include \masm32\include\Comctl32.inc
include \masm32\include\comdlg32.inc
include \masm32\include\shell32.inc
include \masm32\include\oleaut32.inc
include \masm32\macros\macros.asm

; libraries
; ~~~~~~~~~
includelib \masm32\lib\masm32.lib
includelib \masm32\lib\gdi32.lib
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\Comctl32.lib
includelib \masm32\lib\comdlg32.lib
includelib \masm32\lib\shell32.lib
includelib \masm32\lib\oleaut32.lib

These include file and libraries handle a very large range of the Windows API functions but there are many other libraries and include files available if you need additional capacity build into the operating system.

The MASM32 Macro File
The above list includes a number of files that are not API function prototypes and libraries. The following line ensures that the dedicated MACRO file for MASM32 is loaded so that the extended functionality is available.

include \masm32\macros\macros.asm

There is also the MASM32 library that contains the runtime functions for both the macros that use library functions and it also makes all of the library available to the programmer using MASM32. The MASM32 library is what is called a STATIC library in that it has the actual code for each library model contained within it where the libraries that contain the API function calls are called IMPORT libraries which contain import data from system DLL files.

MASM can routinely handle STATIC and IMPORT libraries and the matching include files with the above syntax.

You would normally write your local procedure prototypes AFTER the system functions and libraries so that they have access to the API and STATIC library functions that you require for your own code.

Writing The DATA Section(s)
The initialised and uninitialised DATA sections should be added next, the order does not matter. Some people coming from different assembler have had problems with this but it is the normal layout for an assembler file written in MASM.

.data?                        ; uninitialised data section
  align 4
  blankhandle dd (?)
  txtbuffer1 db 128 dup (?)
  txtbuffer2 db 128 dup (?)

.data                         ; initialised data section
  align 4
  preset_number dd 128
  array dd txtbuffer1,txtbuffer2
  AppName db "My Application",0

Start And End Of Code
Following the data section(s) you must tell the assembler where the actual code for your application starts and finishes. This is done with a single label AFTER the data section(s) to indicate where the code starts and after the code is finished, you use a matching statement to tell the assembler that the code has ended. Convention has it that the label is usually named "start" but it can in fact be any label name that is unique within the application. The syntax is as follows.

start:
; All of your code goes between the two statements.
end start

This is in fact much easier to manage than it may look as MASM supports nested "include" statements so you can put all of the prototypes and libraries in a seperate include file and if it suits your design, you can include pieces of code in external files directly into the code that you are writing. This is a commonly used technique in MASM32 examples and it is done with the different code generators so that the code is a lot easier to read by reducing the amount of clutter to get to the code you are working on.


Unicode Support
The MASM32 include files now have system wide unicode support by the inclusion of the equate __UNICODE__ at the start of the source code BEFORE any include files. This factor is critical as the include files need to know which prototype system is being used .

The form of the equate is as follows,

__UNICODE__ equ 1

The Windows API prototypes in the include file occur in this form,

AddAtomA PROTO STDCALL :DWORD
IFNDEF __UNICODE__
  AddAtom equ <AddAtomA>
ENDIF

AddAtomW PROTO STDCALL :DWORD
IFDEF __UNICODE__
  AddAtom equ <AddAtomW>
ENDIF

If you define the equate __UNICODE__ the UNICODE form of the API is provided in source code, if the equate is not defined the ASCII form of the API is provided.

NOTE that all existing ASCII code written before unicode support work as they have always worked, the inclusion of the __UNICODE__ equate offers the additional option of coding directly in unicode without having to use the direct API name with the trailing "W".


High And Low Level Code

At its baseline as a bare tool, MASM (ML.EXE) is capable of converting assembler source code written with mnemonics (instructions) into opcodes that are stored in an object module. This is in fact the normal method used with Microsoft languages and it is why Microsoft C/C++ and MASM can be used together because they produce compatible object modules. MASM differs from compilers in that it has no intrinsic runtime library capacity built into it but the advantage of this is that it can use different runtime libraries without being restricted to only one.

Much of the difference between older 16 bit code and modern 32 bit code written in MASM is the sheer volume of high level code that is available through the architecture of the operating system. The availability of something like 12 thousand high level functions through the Windows API (Application Programmers Interface) added this enormous capacity to MASM at no effective cost apart from knowing how to call and use the functions. Without losing any of its low level capacity, the MASM programmer has direct access to the same functions that the operating system uses for most of its basic functionality.

The distinction in code types is still in fact there with assembler code written in MASM, on one hand you have the full range of processor instructions coupled with the operating system architecture of addressing, memory model and the like while on the other hand you have what is effectively a massive very high level library available to perform a very large range of different functions.

There is another factor that also changes the equation. Since about 1990 MASM has been able to do more than just crunch assembler mnemonics. From Verson 6.00 it made a radical departure from assemblers of that time and added the capacity to emulate a number of higher level language capacities with C style runtime comparisons, automated and type checked function calls and a number of loop control methods to make hack style code easier, faster and more reliable to write.

The type of code that such high level emulation produces is reasonably minimalist but contrary to popular opinion in some circles, it has passed the test of time and performs well on late model 32 bit hardware. We do hear from time to time about some new "gee whizz" features of the latest compiler on the block but where MASM has passed the test of time with its high level emulation, much of the current compiler design based on middle 90s RISC theory has not and it shows when you decompile the code.

The other factor rarely mentioned in such discussions is it is normal in MASM to code any speed critical algorithms directly in assembler code where high level users are stuck with high level code unless they can cobble together some inline assembler to get them out of trouble. MASM is in fact able to help in situations where high level code is not fast enough as it creates object modules that are compatible with Microsoft C compilers and it is one of the target tasks of MASM to replace compiler generated code where it is unable to produce the performance that is required.

Many have attempted to make MASM an appendage to another particular language yet MASM does not need any other language to make it work and as long as you have the rest of the tools required like a linker and resource compiler, it has an effective target range of applications where it is almost impossible to compete with in its own terms of size, speed and functionality.

As MASM programmers will from time to time get dragged into "holy war" arguments with supporters of other languages flogging their own set of assumptions about how others should write software in the same manner as they do, it is worth knowing at least a few of the assumptions. While you may end up tired of hearing some script kiddie regurgitating nonsense from a tutor who knew no better, it generally meant that their tutors learnt programming in the early to middle 90s and missed out on assembler programming with the results that they have passed on their ignorance to the next generation.

Assumption : Assembler is only useful for harware access.
Answer : This indicates how far out of date the assumption is, most hardware access like device drivers are written in C or C++. This assumption comes from the days when compilers had problems with accessing DOS 16 bit interrupts which necessitated cobbling together some assembler code to handle the system calls.

Assumption : Assembler is only useful for writing "inner loops".
Answer : It happens to write outer loops just as well and you can add to that nested loops, interdependent loops, crossfire loops, multiple entry and exit loops and many other freestyle variations that will give most compilers nightmares. With compilers that attempt some form of optimisation, it is bad technology to mix manual assembler code with high level code as the optimisers have enough problems of their own without adding to it. Effectively assembler code used with other high level languages should be built into a seperate module and linked into the project.

It is not by accident that much of the compiler literature over the last 10 to 15 years advises against freestyle loop code design that is common in assembler programming. It is generally related to the inability of the compilers to properly handle code of that complexity without making a mess of it. Structure loop coding is like a straight jacket in comparison to the freedom of design that assembler programmers have.

Assumption : Good (Basic/C/Pascal/Fortran/Cobol etc ..) is better than bad assembler.
Answer : Swap "assembler" with any other language mentioned in the list and the statement is still true.

Assumption : Development in assembler is too slow, you should use a low level compiler instead.
Answer 1 : Development with low level compilers is too slow, you should use a high level compiler instead.
Answer 2 : Development with high level compilers is too slow, you should use a scripting language instead.
Answer 3 : Development in a scripting language is too difficult for non-technical users, you should hire an expert like ME to write your code for you. For some outrageously large sum I can produce garbage for you that might do the job.
Answer 4 : etc .....

Assumption : Assembler is too hard to write.
Answer : For the person saying it, it is probably true. Advise them to limit themselves to something simpler like server side scripting.

Assembler has survived as a viable esoteric tool because of what it can do, not what inexperienced people think it cannot do or should not be able to do. Fashion has it moments but function endures because its serves more people over the long term in ways that are not served by the whims of fashion.


Creating Procedures

The syntax for creating procedure in MASM is reasonably simple and it is the basis for writing reliable code that is type checked by the assembler. It has a two part logic in that you tell the assembler what the procedure format is by writing a prototype.

item_name PROTO :DWORD,:DWORD

 Once you have the prototype written you write the procedure to match that argument count and sizes in the prototype.

item_name proc arg1:DWORD,arg2:DWORD

 The component parts of the above line are,

1. item_name The procedure name
2. proc      Tell the assembler that this is a procedure
3. arg1      The name used for the parameter
4. :DWORD   The size of the data passed as a parameter

The name of each parameter and its coresponding data size is what is usually referred to as the argument list. As long as it matches the prototype that you have written, you set the number of items in the argument list to suit the design of the procedure you require.

The following line tells the assembler where the end of the procedure is.

item_name endp

Between the two line that respectively contain the PROC keyword and the ENDP keyword is where the executable code for the procedure is written.

With this format of procedure MASM creates what is called a stack frame which is very similar to many high level languages and it allows the procedure to be used in much the same way as a high level language. You can safely write recursive code and similar techniques that directly use the stack as memory storage.

At a lower level MASM has a notation to create procedures that do not have a stack frame and this is usually when designing speed critical code where an extra register is required. There is also a minor speed gain in reduced stack overhead but this is only evident in very small procedures where it is viable to simply inline the code which is faster again.


Calling Procedures

The MASM32 Project has been a leading advocate of dealing with high level code in a high level manner and it is one of the factors in why assembler is enjoying new found popularity. MASM has its own built in "invoke" syntax that made emulating high level code far easier and in conjunction with the macro system that MASM supports, there are a range of different methods available to assembler programmers using the standard MASM32 macros.

Using a simple example of a system MessageBox() the progression is as follows.

invoke MessageBox,hWnd,ADDR Message,ADDR TitleTxt,MB_OK

With this standardised MASM technique, you have high level format complete with type checking and you obtain the return value by reading the EAX register.
MASM macros have the capacity to return a value so that they can be used with a similar notation to a function in a high level langauge in the EAX register. One of the standard MASM32 macros is rv() which is used as follows.

mov retval, rv(MessageBox,hWnd,ADDR Message,ADDR TitleTxt,MB_OK)

Effectively the complete function call can be treated as the EAX register and this allows the function call to be directly embedded into assembler notation.

cmp rv(MessageBox,hWnd,ADDR Message,ADDR TitleTxt,MB_OK), IDYES
je label

Here you have both high level convenience and reliability and low level compact notation and clarity.

It is common practice to be able to insert quoted text into function calls and MASM32 has a number of ways of doing this to acheive clean and compact notation. There are two forms available, one that is used in the STATEMENT position and the other that is used in ther FUNCTION position.

The STATEMENT position.
fn MessageBox,hWnd,"Hi, I am a Message Box","Greetings",MB_OK

The FUNCTION position.
mov retval, rv(MessageBox,hWnd,"Message Text for MessageBox","Title Text",MB_OK)

As before with the statement position macro, you obtain the return value in the EAX register where with the function position macro, you treat it as the EAX register and can directly use the function call in assembler notation.

Limitation
The macro parsing engine in MASM does not allow information enclosed in brackets (....) to be split across multiple lines so this will limit some uses of the function position macros. In these situations, you would use the statement position macro instead and manually obtain the return value in EAX. Note that when you write multiline macro code that you must use the line continuation indicator "\" for each split line so the assembler knows that the next line is part of the function call.

Code Efficiency
Each example using the simple MessageBox call all produce the same code. As manual assembler code, it is written as follows.

push MB_OK
push OFFSET TitleText
push OFFSET MessageText
push hWnd
call MessageBox
mov retval, eax


Using Libraries

A library procedure differs from a procedure you have written in your own code only in that it is already assembled into a working binary file and it is common to group many seperate procedures together in a single library. This type of library is usually called a STATIC library as it differs from a library that has EXPORT data for DLLs in that the code is actually contained in the library.

In most instances each static library has a matching include file that contains a prototype for each procedure in the library and all you need to do to be able to use any of the procedures in the library is to use the "include" directive to include the prototypes in the include file and use the "includelib" directive so that the linker can find the library.

include \masm32\include\masm32.inc
includelib \masm32\lib\masm32.lib

The standard library for the MASM32 project is an example of a static library that is made available by using these directives and it is a reasonable model for constructing custom libraries that are tuned to the individual programmers requirement.

MASM is of course able to create its own library modules that are then linked into static libraries and if they are written correctly, when you call a procedure from the static library, the only code added to your program is the code that is in the seperate module and any other code that the module depends on. The linker automatically calculates what is called "dependency" of modules and you only ever get the code your application requires.


Control Flow Techniques

MASM has a built in pseudo high level control flow technique that is very similar to use to many common high level languages. In conjunction with hand written macros this gives MASM a very useful capacity to write high level style control flow code the is efficient enough for all but the most speed critical pure mnemonic code.
Block .IF notation
The switch macro
The switch$ macro


Using the .IF Syntax

MASM has the capacity to handle both simple and complex block comparison operations in a clear and easy to use syntax that reasonably well emulates higher level code. The .IF block syntax can be safely nested in the normal high level manner and is subject to the normal rules of comparison using the CMP instruction.

Simple
.if variable == value
  ; do something here
.endif

This type of code can be extended in two directions, it can handle more complex comparisons on a single line and it can perform multiple comparisons sequentially as is common in high level languages.

Sequential Evaluation
.if variable == value
  ; do something
.elseif variable != another_value
  ; do someting else
.else
  ; otherwise
.endif

 You can repeatedly use the .elseif operator to perform additional sequential comparisons but you may only use one .else operator which must be the last option before the .endif operator.
Using the C comparison runtime operators below, more complex tasks can be performed and in a notation that will be familiar to many programmers.

Complex Evaluation
.if variable > 50 && variable < 100
  ; number is within range
.else
  ; number is out of range
.endif

The code created by the .IF technique is competitive in quality terms to code created by the better end of compilers but note that it is a specific technique that may not be flexible enough for low level code design within an algorithm where register choice and instruction order become critical to the algorithm's performance.

C comparison run-time operators
Operator Meaning

==             Equal
!=             Not equal
>              Greater than
>=             Greater than or equal to
<              Less than
<=             Less than or equal to
&              Bit test (format: expression & bitnumber)
!              Logical NOT
&&             Logical AND
||             Logical OR
CARRY?         Carry bit set
OVERFLOW?      Overflow bit set
PARITY?        Parity bit set
SIGN?          Sign bit set
ZERO?          Zero bit set


Using Switch Block Syntax

A common task in 32 bit Windows programming is comparing a single variable against a sequence of values and acting on a comparison match. A very common example is the operating system defined method of evaluating messages sent to a WndProc style procedure by the operating system.

This task can be done in a reliable manner using the .IF block syntax that MASM handles in a native manner but there is now a viable alternative written by Greg Falen that encapsulated the .IF block syntax in a very convenient manner to emulate a high level language switch block. This technique can be nested in the normal manner and has proven to be very reliable while making clear and easily readable code. The comparison rules are the same as the CMP instruction.

switch variable
  case value1 ; there must be at least one (1) case statement
    ; do something here
  case value2 ; optional extra case statement(s)
    ; do something else
  default ; optional default processing
    ; do any default processing
endsw

 Below is WndProc code copied directly from a working application.

switch uMsg
  case WM_INITDIALOG
    invoke SendMessage,hWin,WM_SETICON,1, FUNC(LoadIcon,NULL,IDI_ASTERISK)
    m2m hWnd, hWin
    return 1

  case WM_COMMAND
    switch wParam
      case IDOK
        fn MessageBox,hWnd,"You clicked OK","Hi",MB_OK or MB_ICONINFORMATION

      case IDCANCEL
        jmp quit_dialog
    endsw

  case WM_CLOSE
    quit_dialog:
    invoke EndDialog,hWin,0
endsw

Some will try and tell you that this form of code is not efficient but the disassembly below demonstrates otherwise. You can manually code sequential choices in a different manner that is slightly fast in some contexts but there is little to gain and you throw away coding speed, reliability and ease of code maintainance.

mov eax, [ebp+0Ch]
cmp eax, 110h
jnz lbl0
push 7F04h
push 0
call fn_00401256
push eax
push 1
push 80h
push DWORD PTR [ebp+8]
call fn_00401262
push DWORD PTR [ebp+8]
pop [403050h]
mov eax, 1
leave
ret 10h
jmp lbl4
  lbl0:
cmp eax, 111h
jnz lbl2
mov eax, [ebp+10h]
cmp eax, 1
jnz lbl1
push 40h
push 403042h
push 403033h
push DWORD PTR [403050h]
call fn_0040125C
jmp lbl4
  lbl1:
cmp eax, 2
jnz lbl4
jmp lbl3
jmp lbl4
lbl2:
cmp eax, 10h
jnz lbl4
  lbl3:
push 0
push DWORD PTR [ebp+8]
call fn_00401250
  lbl4:


Using switch$ Syntax

Some higher level languages have techniques for performing sequential comparison of string data and while it is not a built in mechanism in MASM, the macro system is powerful enough to develop this form of high level emulation in conjunction with a static library module and a number of existing macros contained in the MASM32 Project. These macros are __UNICODE__ aware.

Michael Webster has created a macro system that performs sequential comparison of quoted string data against a string address by using a simulated stack macro design by Greg Falen, components of the block .IF syntax, a static library module from the MASM32 library and a number of macros from the MASM32 Project.

Two versions are presented in the MASM32 macro system, the case SENSITIVE version that is documented below and a case INSENSITIVE version that differs only in that the notation has a trailing "i" before the "$" symbol. Note that you should not mix the set of evaluation operators with either macro as each is a seperate system. The syntax rules for each system work identically and the order of else$ and elsei$ must be the same if used.

Case SENSITIVE | Case INSENSITIVE
switch$ | switchi$
case$ | casei$
else$ | elsei$
endsw$ | endswi$

The case sensitive version uses a direct character match algorithm for word comparison where the case insensitive version uses a high speed table driven algorithm.

switch$ string_address
  case$ "quoted_text1" ; there must be at least 1 case$ statement
    ; perform action here
    ; if word maches

  case$ "quoted_text2" ; optional additional case$ statement
    ; perform action here
    ; if word maches

  else$ ; optional default processing
    ; perform default action

endsw$

 Note that the else$ statement if used must be the last option before the endsw$ statement.
Here is a simple working example.

switch$ lpstr
  case$ "word1"
    fn MessageBox,hWnd,"word1","Title",MB_OK

  case$ "word2"
    fn MessageBox,hWnd,"word2","Title",MB_OK

  case$ "word3"
    fn MessageBox,hWnd,"word3","Title",MB_OK

  case$ "word4"
    fn MessageBox,hWnd,"word4","Title",MB_OK

  else$
    fn MessageBox,hWnd,"default","Title",MB_OK

endsw$

 To demonstrate the actual efficiency of the macro code, this form was used to make the disassembly more readable.

switch$ lpstr
  case$ "word1"
    nop

  case$ "word2"
    nop

  case$ "word3"
    nop

  case$ "word4"
    nop

  else$
    nop

endsw$

Below is the disassembly which demonstrates that the generated code is hard to improve on with manual coding of a sequential comparison style of algorithm.

push 403096h
push DWORD PTR [ebp+8]
call fn_00401620
or eax, eax
jz lbl0
nop
jmp lbl4
  lbl0:
push 40309Ch
push DWORD PTR [ebp+8]
call fn_00401620
or eax, eax
jz lbl1
nop
jmp lbl4
  lbl1:
push 4030A2h
push DWORD PTR [ebp+8]
call fn_00401620
or eax, eax
jz lbl2
nop
jmp lbl4
  lbl2:
push 4030A8h
push DWORD PTR [ebp+8]
call fn_00401620
or eax, eax
jz lbl3
nop
jmp lbl4
  lbl3:
nop
  lbl4:


Loop Code Methods

MASM has two pseudo high level loop code methods available for clear coding of non-critical loop code.

The .WHILE loop technique.

The .REPEAT loop technique.


Using .WHILE Syntax

The .while syntax is a clear code method for less than highly critical loop code where readability and ease of maintainance are the main considerations.

.while eax > 0
  sub eax, 1
.endw

 The above .while loop produces the following code which shows the logic where the test is performed first by jumping to the end of the loop. This is the opposite of a .REPEAT / .UNTIL loop which is dealt with in the following topic. The code jumps to the end of the loop to performs the test and loops back and re-runs the loop if the exit condition is not met.

  jmp lbl1
lbl0:
  sub eax, 1
lbl1:
  cmp eax, 0
  ja lbl0

 A loop of this type is very easy to write manually but the .while syntax is capable of handling multiple test conditions using the C comparison runtime operators which give it the capacity to write very compact code that is complex in nature while being reasonably easy to modify and maintain.


Using .REPEAT Syntax

The .repeat syntax is a clear coding method for less than highly critical loop code where readability and ease of maintainance are the main considerations.

.repeat
  sub eax, 1
.until eax < 1

 The above .repeat loop produces the following code which shows the logic where the test is performed after the code in the loop has been run This is the opposite of a .WHILE loop which is dealt with in the preceding topic.

lbl0:
  sub eax, 1
  cmp eax, 1
  jnb lbl0

 A loop of this type is very easy to write manually but the .repeat syntax is capable of handling multiple test conditions using the C comparison runtime operators which give it the capacity to write very compact code that is complex in nature while being reasonably easy to modify and maintain.


Macro Categories

Part of MASM's great strength as an assembler is that it is a MACRO assembler with a very powerful if quirky pre-processor. The MASM32 Project has progressively developed a wide range of macros to put much of the ease of higher level code development into the hands of MASM programmers. The macros are both useful in themselves and as examples of how to write your own custom
macros as the complete code is available in the MASM32 project.
Code Calling Macros
Error Reporting
File IO Macros
Memory Allocation
Console Mode Macros
String Macros
Global Scope String Assignment
Dynamic String Arrays
File Dialogs
Path And Directory Macros
Text Toolbars
Performance Macros
Memory Line IO Macros
Environment
Macro Library
C Runtime Conversions
Specialised Prototypes
Pseudo Mnemonics


Code Calling Macros

You now have the choice of two systems that enhance the "invoke" capacity in MASM, the generic versions that have been rewritten to support both ASCII and UNICODE and a new enhanced system written by qWord which delivers additional capacity. Both systems respond to the __UNICODE__ equate and write the appropriate text data to the initialised data section.

The major advantage of these systems is direct quoted text support which makes code more intuitive to write and easier to maintain.

NOTE that there are limitations with the text that can be enclosed in double quotes, MASM control characters cannot be placed within the double quoted text. Where such characters are required you can use either a C based escapes macro or the chr$ macro that allows the character numbers to be placed in a normal DATA section style of comma delimited list.

fn MessageBox,hParent,"Text Message In Either ASCII or UNICODE","Title",MB_OK
  ; or
fnx MessageBox,hParent,"Text Message In Either ASCII or UNICODE","Title",MB_OK
  ; -------------

mov rval, rv(MessageBox,hParent,"Text Message In Either ASCII or UNICODE","Title",MB_OK)
  ; or
mov rval, rvx(MessageBox,hParent,"Text Message In Either ASCII or UNICODE","Title",MB_OK)

These two systems apply to any procedure or function call that is able to use quoted text as an argument.

fn SetWindowText,hWnd,"Title Text"
  ; or
fnx SetWindowText,hWnd,"Title Text"

Function calls with quoted string support
fn | High level style procedure call
rv | Get a return value from a procedure
fnc | High level style procedure call with C escape support
rvc | Get a return value from a procedure with C escape support

C style reference and indirection operators are supported.
&var  = Reference Operator. The address of the variable referenced.
*var  = Indirection Operator. The dereferenced content of the variable.

Extended Versions by qWord

fnx | High level style procedure call
rvx | Get a return value from a procedure
fncx | High level style procedure call with C escape support
rvcx | Get a return value from a procedure with C escape support

C style reference and indirection operators are supported.
&var  = Reference Operator. The address of the variable referenced.
*var  = Indirection Operator. The dereferenced content of the variable.

Legacy version
FUNC Get a return value from a procedure ASCII only.


Debug Macros

LastError$ Return the error string from GetLastError()


File IO Macros

Load and Save Complete File
Both macros are __UNICODE__ aware and have either ASCII or UNICODE versions which can be manually specified.
InputFile | Read entire file into a memory buffer.
OutputFile | Write a memory buffer to disk.
Note that the file lengths for these two macros are always specified in BYTES, to get the UNICODE character count you would divide the byte count by 2.

Low Level File Operations
These macros are specifically ASCII BYTE operations unless otherwise specified.

fcreate | Create a new file and return its handle
fcreateW | Same as above with UNICODE filename
fdelete | Delete a disk file
fdeleteW | Same as above with UNICODE filename
fopen | Open an existing file and return its handle
fopenW | Same as above with UNICODE filename
fclose | Close an open file handle
fread | Read data from an open file
fwrite | Write data to an open file
fprint | Write line of text to an open file
fprintc | Write text to open file with C style formatting
fseek | Set the current position in the open file
fseteof | Set the end of the open file to the current location
fsize | Return the size in bytes of the open file


Memory Allocation

 MASM32 preprocessor macros now support 3 seperate types of memory allocation, fixed memory using the GlobalAlloc() API function, OLE string memory for dedicated string work and Heap memory using the HeapAlloc() function. While there is a large degree of overlap with memory allocation functions, GlobalAlloc() appears to be faster on large single block allocations, HeapAlloc() shows some speed advantages in repeated small allocations and preallocated OLE string pool memory is tuned at the OS level for string manipulation.

Fixed Memory

alloc | Allocate a fixed block of memory
free | Free a fixed block of memory

String Memory

alloc$ | Allocate OLE string memory
free$ | Free OLE string memory

Heap Memory

halloc | Allocate Heap Memory
hsize | Return the size of allocate heap memory
hfree | Free Heap Memory

NOTE : There are other more specialised forms of memory allocation available using the Windows API functions.


Console Mode Macros
The console mode macros are designed to make console input and output fast and convenient. Some of them work in very similar way to historical DOS and BASIC commands.

cls | Clear the console screen
ccout | Display text at the console using C style formatting
GetConsoleCaption$ | Return the address of the console title bar
exit | Close application
getkey | Wait for key press and return it in EAX
inkey | Wait for user key input
input | Get text from console input
loc | Set the text cursor position
print | Print text to the console
printc | Display text at the console using C style formatting
printf | C runtime function to display text and other data at the console
SetConsoleCaption | Set the title bar text of the current console


String Macros

MASM32 already has a well tested library that has a reasonable number of procedures for manipulating string data. These can be used with similar code design to C style programming and the basic technology is the same, zero terminated strings that work from the string data address.

The macro system in MASM is powerful enough to reuse these C style procedures and present them in a format that has much of the speed and convenience of development that basic string functions have if the fundamental differences are understood. It is important to understand what the differences are so please read the overview of how these string macros work.

Most of the string macros now support both ASCII and UNICODE. If you define the equate __UNICODE__ at the beginning of your source file before any of the include files, then the UNICODE version of the macro will be used. The few that do not yet support UNICODE are marked as ASCII only.

String Macro Overview
Allocating String Buffers

Note that the string macros are used in the function position which means they can be assigned to variables or used within more complex macros if the differences are properly understood.

Normal string macros
add$ | Join two strings by appending the second onto the first
append$ | Append a zero terminated string and return next position
cat$ | Join multiple strings to a user defined buffer
chr$ | Return the address of combined quoted strings and bytes
cmp$ | Compare strings (case sensitive).
cmpi$ | Compare strings (case insensitive)
cfm$ | Format a quoted string with C style escapes
ptr$ | Cast a buffer to a pointer
len | Return the length of a zero terminated string
find$ | Find a substring in a source string
lcase$ | Convert string to lower case
ucase$ | Convert string to upper case
left$ | Read characters from left side of string
remove$ | Remove sub string from source string
right$ | Read characters from right side of string
ltrim$ | Trim the left side of a string of spaces
rtrim$ | Trim the right side of a string of spaces
trim$ | Trim both ends of a string of spaces
rev$ | Reverse a string
cmd$ | Get the address of a command line argument. ASCII only
ucCmd$ | Get the address of a command line argument. UNICODE only

Integer to string conversions

ustr$ | Convert unsigned 32 bit integer to a zero terminated string
sstr$ | Convert signed 32 bit integer to a zero terminated string
uhex$ | Convert unsigned 32 bit integer to a zero terminated hex string ASCII only.
hval | Convert hex string to 32 bit integer ASCII only.

String to integer conversions
sval | Convert signed string to 32 bit signed integer
uval | Convert unsigned string to 32 bit unsigned integer

The following Windows API wrapper macros allow them to be used in the function position. The arguments are exactly those of the original Windows API. These macros are __UNICODE__ aware.
    ; ----------------------------------
    ; API string functions from KERNEL32
    ; ----------------------------------
      lstrcat$ MACRO arg1,arg2
        invoke lstrcat,tstarg(arg1),reparg(arg2)
        EXITM <eax>
      ENDM

      lstrcmp$ MACRO arg1,arg2
        invoke lstrcmp,reparg(arg1),reparg(arg2)
        EXITM <eax>
      ENDM

      lstrcmpi$ MACRO arg1,arg2
        invoke lstrcmpi,reparg(arg1),reparg(arg2)
        EXITM <eax>
      ENDM

      lstrcpy$ MACRO arg1,arg2
        invoke lstrcpy,tstarg(arg1),reparg(arg2)
        EXITM <eax>
      ENDM

      lstrcpyn$ MACRO arg1,arg2,ccnt
        invoke lstrcpyn,tstarg(arg1),reparg(arg2),ccnt
        EXITM <eax>
      ENDM
    ; ----------------------------------

Also check the macros that use the C Runtime Library as they support a wider range of data types.


GLOBAL scope string assignment

Allocate a string in the .DATA section. These macros are __UNICODE__ aware.

STRING MACRO data_label,quoted_text:VARARG
This macro support both quoted text and character specified by number. The user assigned "data_label" is then addressed as an OFFSET.

STRADD MACRO data_label,args:VARARG
This macro support both quoted text and character specified by number. The user assigned "data_label" is then addressed as a POINTER to the string data.

Comments
These two macros differ only in how the data is addressed, The label for STRING is addressed as an OFFSET, the label for STRADD is addressed as a POINTER to the string data. Text data can be specified as both quoted text and by the character number. With UNICODE text if you have a method of identifying characters above the 256 character range available in an ASCII editor, you can specify them by number.

Example
STRING MyLabel,"My quoted text",13,10
mov eax, OFFSET MyLabel
  ; or
STRADD MyLabel,"My Quoted Text"
mov eax, MyLabel

NOTE that with GLOBAL scope in each module where it is used that each label name must be unique as is the case in the initialised data section.


Dynamic array macro functions
Read the overview of how this array system works
Allocate, reallocate and free a variable length dynamic array

arralloc$ | Create an empty dynamic array with a specified member count.
arrealloc$ | Reallocate an existing array to a larger or smaller member count.
arrfree$ | Deallocate an entire array and recover the memory used.
Write data to array members

arrset$ | Write/overwrite zero terminated data to array member.
arrbin$ | Write/overwrite any data of specified length to array member.
arrfile$ | Load text file into a new array.
arrtxt$ | Load zero terminated text into a new array.

Get data from an array member

arrget$ Get the start address of an array member.

Get block data from a string array

arr2disk$ | Write all text data from an array to a disk file.
arr2mem$ | Write all binary data from an array to a pre-allocated memory buffer.
arr2text$ | Write all text data from an array to a pre-allocated memory buffer.

Get information about the array and/or its members

arrlen$ | Get the stored length of an array member.
arrcnt$ | Get the count of array members.

Calculate memory storage size for complete array
arrtotal$ Calculate the total memory buffer size for the array as either binary or text data.

Manually change the array length

arrtrunc$ | Truncate an array to a smaller size.
arrextnd$ | Extend an array to a larger size.


 File Dialogs

OpenFileDlg | Display an Open File dialog and return the selected file name.
SaveFileDlg | Display an Save File dialog and return the selected file name.


Path And Directory Macros

Path macros
pth$ | Return path of current application
CurDir$ | Return the path of the current directory
SysDir$ | Return the path of the system directory
WinDir$ | Return the path of the Windows directory

Directory macros
chdir | Change Directory
mkdir | Make Directory
rmdir | Remove Directory
rndir | Rename Directory

Thes macros are __UNICODE__ aware.


Text Toolbars

Description

The text toolbar macros are designed to be used as a complete system for producing the minimalist interface demands of a flat toolbar with text only buttons. They are designed to be placed in a procedure by themselves with no other code as the macros handle both local variables and the return value code.
There are two variations of the toolbar code, one WITH and one WITHOUT a seperating line at the top.

TB_BEGIN hParent    ; without top seperator
TB_BEGIND hParent   ; with top seperator

 The hParent argument for both is the handle of the parent window to place the toolbar on. This is normally the parameter passed to the procedure that the toolbar macro code must be placed in.
There are two options to add items to the toolbar, a text item and a seperator between text items.

Text Item
TxtItem ItemID, ButtonID,Quoted_Text

Parameters
1. ItemID A zero based text item ID that must be sequential for each additional text item added to the toolbar. 0 1 2 3 4 5 6 etc ...
2. ButtonID The WM_COMMAND identifier for command processing.
3. Quoted_Text The text to display as the text toolbar item.

Text Item Seperator
TxtSeperator
The TxtSeperator macro has no parameters.

End Macro

TB_END
The TB_END macro has no parameters. It must be the last line in the procedure.

Example
text_bar proc hParent:DWORD
  TB_BEGIN hParent
  TxtItem 0, 50, "New"
  TxtItem 1, 51, "Open"
  TxtItem 2, 52, "Save"
  TxtSeperator
  TxtItem 3, 53, "Cut"
  TxtItem 4, 54, "Copy"
  TxtItem 5, 55, "Paste"
  TxtSeperator
  TxtItem 6, 56, "Exit"
  TB_END
text_bar endp

Comments
This macro system has been tested successfully on both Windows created with CreateWindowEx() and with dialog windows. To ensure that you have enabled the correct common control library, the following code is required in the application using the flat text toolbar.

LOCAL icce:INITCOMMONCONTROLSEX

mov icce.dwSize, SIZEOF INITCOMMONCONTROLSEX
mov icce.dwICC, ICC_BAR_CLASSES
invoke InitCommonControlsEx,ADDR icce


Performance Macros
The macros in this category

memalign | Align memory to a power of 2
chtype$ | High speed character recognition


Memory Line IO Macros
Macros for reading and writing lines of text directly to and from memory.

linein$ | Read line of text into a user defined buffer
lineout$ | Write line of text from a user defined buffer
tstline$ | Test if line of text is empty
Count Lines | A procedure to count the lines in a text file


Environment

Set or get an environment string. API based __UNICODE__ aware versions and legacy MSVCRT versions.

envset$ | Set an environment string __UNICODE__ aware
envget$ | Get an environment string __UNICODE__ aware
setenv | Set an environment string Legacy MSVCRT
env$ | Get an environment string Legacy MSVCRT


Macro Library

This category of macros are used as components in creating other more powerful macros.

reparg | Replace quoted strings with their DATA offsets.
tstarg | Test for quoted text and return an error if it is.
argcount | Return the count of arguments passed to a macro.
getarg | Return an argument from a list by its index.
op_type | Return a macro argument operand type.
cfm$ | Format a string using C style escapes


C Runtime Conversions

The following macros were developed by Greg Lyon using the functionality of the MSVCRT C runtime DLL. To use these macros you must use the include file and library for the msvcrt runtime DLL that is supplied with MASM32.

The following macros take a specified data size operand and return the address of a string that holds the results. The macro name prefixes indicate the data type that is converted. A leading "u" means an unsigned operand, a leading "s" means a signed operand. The leading "x" indicates a hexedecimal output format. The macros are used in the FUNCTION position to facilitate attributing return values or using direct mnemonics with the macro. Note that the string addresses are returned as an OFFSET in the data section.

Number to string macros.
-
ubyte$() | Unsigned BYTE input
sbyte$() | Signed BYTE input
xbyte$() | Hex notation output BYTE
uword$() | Unsigned WORD input
sword$() | Signed WORD input
xword$() | Hex notation output WORD
udword$() | Unsigned DWORD input
sdword$() | Signed DWORD input
xdword$() | Hex notation output DWORD
uqword$() | Unsigned QWORD input
sqword$() | Signed QWORD input
xqword$() | Hex notation output QWORD
real4$() | 32 bit FLOAT input
real8$() | 64 bit FLOAT input
real10$() | 80 bit FLOAT input

The following macros are the inverse of the above in that they convert ascii string format numeric characters to a range of different sized numeric data types. The prefixes are "a" for ascii and "h" for hex. The suffixes indicate whether the result is signed or unsigned for integer instructions. "u" for unsigned, "s" for signed and "r" with the three data sizes for floating point conversions. Note that the result is returned as an OFFSET in the data section.

String to number macros.
a2ub() | Ascii to unsigned BYTE
a2sb() | Asci to signed BYTE
h2ub() | Hex to unsigned BYTE
a2uw() | Ascii to unsigned WORD
a2sw() | Ascii to signed WORD
h2uw() | Hex to unsigned WORD
a2ud() | Ascii to unsigned DWORD
a2sd() | Ascii to signed DWORD
h2ud() | Hex to unsigned DWORD
a2uq() | Ascii to unsigned QWORD
a2sq() | Ascii to signed QWORD
h2uq() | Hex to unsigned QWORD
a2r4() | Ascii to 32 bit FLOAT
a2r8() | Ascii to 64 bit FLOAT
a2r10() | Ascii to 80 bit FLOAT


Specialised Prototypes

The following macros are for creating prototypes for procedures that have a known starting address and a known argument list. This can be from using the API call GetProcAddress() or from obtaining the start address of a procedure from a virtual table or an address passed to a callback procedure.

SPROTO | Create a STDCALL prototype
CPROTO | Create a C prototype


Pseudo Mnemonics
The following macros are designed to be used like assembler mnemonics but they contain higher level capacity.

m2m | Memory to memory copy of a variable
mrm | Memory to memory copy using EAX
sas | Assign a string to a LOCAL variable. __UNICODE__ aware.
cst | Copy one zero terminated string to another. __UNICODE__ aware.


(Untitled)

MASM32 Reference
Copyright The MASM32 Project 1998 - 2007

Using invoke
MASM High Level Syntax
Macro Reference
Full Listing
Register Summary
Ascii Characters
Calling Conventions
Processor Flags
Stack of 80-bit Data Registers
Conditional Assembly
Debugging in MASM32
Pentium Optimisation
Command Line Tools


Using invoke

Why use invoke ?
Popular legend has it that true low level assembler is written only at the mnemonic level and the rest is for people who do not properly understand what low level programming is about. The problem is for people who espouse this view is that they never produce anything much and when they do, it is usually of little consequence.

Few would understand that assembler is actually a high level language. At the hardware level, you only have opcodes and with the Intel x86 series of processors, the basic unit is a BYTE so when you use a mnemonic, you are using a high level simulation of a family of opodes that differ depending on the way the operands are arranged.

For people who are of such a robust disposition that they want to write in REAL low level code, the editor in MASM32 has the capacity to write hex directly as ascii text and save it to disk as a binary file. For the rest who want to write fast, reliable minimum size code and get it done in one lifetime, MASM has a pseudo high level syntax that has an exact correlation to code written the old hard way but without the errors, mysterious crashes and unresolvable bugs.

The traditional notation for calling procedures is the "push" parameter, "call" syntax. MASM has an alternative method of calling procedures which has many advantages in terms of both coding speed and reliability. A procedure called by INVOKE is type checked against a prototype of the same name for parameter size and number.

Traditional
push offset par4
push par3
push offset par2
push par1
call FunctionName
mov retval, eax

Invoke
invoke FunctionName,par1,ADDR par2,par3,ADDR par4
mov retval, eax

If there was an advantage in doing a function call the old way, you would bother but in this example, both assemble to the identical code but while the invoke syntax has reliable error checking against the prototype for the function that is called, the old way does not so if you put the wrong number of parameters or some other normal error, it will assemble but will crash when run.


MASM High Level Syntax

MASM has a number of built in operators that allow a programmer to use C style evaluation and loop code when writing high level Windows code that interfaces with the operating system.

More often than not, low level algorithms do not use any of the high level operators as it would produce suboptimal instruction sequences for maximum performance but much of the high level code inherant in Windows suffers from complexity rather than speed considerations and it is here where the C style high level emulation code provides its biggest advantage.

The .IF syntax allows conditional testing in a manner that makes high level Windows code far easier to both read and write. The alternative using "cmp reg, var", "jne label" produces nightmares in terms of tracking the number of jumps and labels needed and it does not perform any better or assemble any smaller.

.if uMsg == WM_COMMAND
  ;code
.elseif uMsg == WM_PAINT
  ;code
.elseif uMsg == WM_CLOSE
  etc ....

 MASM also has loop code techniques for emulating high level coding where it can be used to improve readability and maintainance.

The "condition" is evaluated using the Comparison run-time operators

Test condition at start of loop
.WHILE condition
  ; code that changes "condition"
.endw

Test condition at end of loop
.REPEAT
  ; code that changes "condition"
.until condition

 There are two methods of conditionally exiting the loops with the following operators with syntax variation depending on the task.
.BREAK
.BREAK .if condition
.CONTINUE
.CONTINUE .if condition

Example
    mov eax, 100

    .while eax > 0
      sub eax, 1
    .endw

  msgloop:
    invoke GetMessage, ADDR msg,NULL,0,0
    .break .if eax == 0
    invoke TranslateMessage, ADDR msg
    invoke DispatchMessage,ADDR msg
    jmp msgloop


MACRO Reference

One of MASM's great strengths is that it is a MACRO assembler which allows it to perform pre-processing of the text before the assembler reads the code and assembles the code. This allows the MASM programmer to wrote MACRO procedures that can expand or modify the text of the source code so that the source code can be written in convenient ways that improve the speed, reliability and throughput in the development cycle.

MACROS are the MASM programmers secret weapon in code production. Not only does the MASM programmer have the normal pseudo high level syntax to use for clear coding of complex decision making code, the "invoke" syntax for more reliable API calls and other function style procedures but they also have an almost unlimited method of expanding this capacity by writing MACROS that perform specific tasks in code manipulation.

MACROS can be used for many thing from simple text replacement, small inline conversions where the stack overhead of a procedure is bigger than the size of the expanded macro, complex looped expansion of repetitive code and in fact almost anything that will package code in more usable ways.

Basic Syntax
MACRO
ENDM
EXITM

Loop operators
FOR
FORC
GOTO
REPEAT
WHILE

Conditional testing
IF
ELSEIF
ELSE
ENDIF

Misc
Literal Text
MACRO LOCAL
PUSHCONTEXT
POPCONTEXT
 &parameter&
 Relational Operators
VARARG (Macro)
Nested Macros

Examples
Macro Function Reverse Ordering
Macro Function ArgI

Pre-defined operators for macros
CATSTR
INSTR
SIZESTR
SUBSTR


Full Listing

ALIGN ASSUME
.BREAK
.CODE
COMMENT
.CONST
.CONTINUE
.CREF
.NOCREF
.DATA
.DATA?
Data Types
ECHO
END
ENDM
EQU
TEXTEQU
.ERR
.ERRB
.ERRNB
.ERRDEF
.ERRNDEF
.ERRDIF
.ERRIDN
.ERRE
.ERRNZ
EXITM
EXTERNDEF
EXTERN
FOR
FORC
GOTO
IF
.IF
[ELSE]IF
[ELSE]IFE
[ELSE]IFB
[ELSE]IFNB
[ELSE]IFDEF
[ELSE]IFNDEF
[ELSE]IFDIF[I]
[ELSE]IFIDN[I]
INCLUDE
INCLUDELIB
INVOKE
LABEL
.LIST
.LISTALL
.LISTIF
.LISTMACRO
.LISTMACROALL
LOCAL
MACRO LOCAL
MACRO
.MODEL
.NOLIST
.NOLISTIF
.NOLISTMACRO
OPTION LJMP
OPTION NOLJMP
OPTION DOTNAME
OPTION NODOTNAME
OPTION READONLY
OPTION NOREADONLY
OPTION SCOPED
OPTION NOSCOPED
OPTION LANGUAGE
OPTION CASEMAP
OPTION EMULATOR
OPTION NOEMULATOR
OPTION OFFSET
OPTION PROLOGUE
OPTION EPILOGUE
OPTION NOKEYWORD
OPTION EXPR16
OPTION EXPR32
 OPTION SEGMENT OPTION NOSIGNEXTEND
OPTION PROC
ORG
PROC
PROTO
PUBLIC
PURGE
PUSHCONTEXT
POPCONTEXT
.RADIX
RECORD
REPEAT
.REPEAT
STRUCT
.TFCOND
TYPEDEF
TYPEDEF Directive
UNION
USES
WHILE
.WHILE
label:
Alternate Quotes
Literal Text
Character Negation
text comment
Macro text comment
Macro Expression
&parameter&
DUP
HIGH
LOW
HIGHWORD
LOWWORD
LENGTHOF
SIZEOF
LENGTH
SIZE
MASK
OFFSET
LROFFSET
PTR
SHORT
THIS
TYPE
OPATTR
WIDTH
CATSTR
INSTR
SIZESTR
SUBSTR
Local Code Labels
Line Continuation
Name Assignment
Location Counter $
Data Initialisation ?
Radix Specifiers
Logical Operators
Relational Operators
Macro Function ArgI
Macro Function Reverse Ordering
Register Summary
Processor Flags
Stack of 80-bit Data Registers
Comparison run-time operators
VARARG (Macro)
VARARG (Proc)
Calling Conventions
Memory model
.MODEL directive
Flat memory model
Nested Macros


register summary

Register Summary
The E register prefix refers to the full 32-bit register (386+)
Accumulator        [E]AX (AH/AL) Multiply, divide, I/O, fast arithmetic
Base               [E]BX (BH/BL) Pointer to base address (data segment)
Counter            [E]CX (CH/CL) Count for loops, repeats, and shifts
Data               [E]DX (DH/DL) Multiply, divide, and I/O

Source Index       [E]SI Source string and index pointer
Destination Index  [E]DI Destination string and index pointer
Base Pointer       [E]BP Pointer to stack base address
Stack Pointer      [E]SP Pointer to top of stack

Flags [E]<Flags> Processor flags
Instruction Pointer [E]IP Memory location of current instruction

Code Segment  CS Segment containing program code
Data Segment  DS Segment containing program data
Stack Segment SS Segment for stack operations
Extra Segment ES Extra program data segment
" FS Extra program data segment (386+)
" GS Extra program data segment (386+)

Control Registers CR(0-3) Paging, caching, and protection (386+)
Debug Registers DR(0-7) Data and instruction breakpoints (386+)
Test Registers TR(3-7) Testing the TLB and cache (386+)

Global Descriptor GDTR Address and limit of GDT (286+)
Local Descriptor LDTR Address, limit, and selector of LDT (286+)
Interrupt Descriptor IDTR Address and limit of IDT (286+)
Task Register TR Address, limit, selector, and attributes of current task


Ascii Characters

0  _ nul     16 _ dle ^P  32    48 0  64 @  80 P  96  `  112 p
1  _ soh ^A  17 _ dc1 ^Q  33 !  49 1  65 A  81 Q  97  a  113 q
2  _ stx ^B  18 _ dc2 ^R  34 "  50 2  66 B  82 R  98  b  114 r
3  _ etx ^C  19 _ dc3 ^S  35 #  51 3  67 C  83 S  99  c  115 s
4  _ eot ^D  20 ¶ dc4 ^T  36 $  52 4  68 D  84 T  100 d  116 t
5  _ enq ^E  21 § nak ^U  37 %  53 5  69 E  85 U  101 e  117 u
6  _ ack ^F  22 _ syn ^V  38 &  54 6  70 F  86 V  102 f  118 v
7  _ bel ^G  23 _ etb ^W  39 '  55 7  71 G  87 W  103 g  119 w
8  _ bs  ^H  24 _ can ^X  40 (  56 8  72 H  88 X  104 h  120 x
9  _ tab ^I  25 _ em  ^Y  41 )  57 9  73 I  89 Y  105 i  121 y
10 _ lf  ^J  26 _ eof ^Z  42 *  58 :  74 J  90 Z  106 j  122 z
11 _ vt  ^K  27 _ esc ^[  43 +  59 ;  75 K  91 [  107 k  123 {
12 _ np  ^L  28 _ fs  ^\  44 ,  60 <  76 L  92 \  108 l  124 |
13 _ cr  ^M  29 _ gs  ^]  45 -  61 =  77 M  93 ]  109 m  125 }
14 _ so  ^N  30 - rs  ^^  46 .  62 >  78 N  94 ^  110 n  126 ~
15 _ ¤ si ^O 31   us  ^_  47 /  63 ?  79 O  95 _  111 o  127 

The extended ascii characters generally do not display correctly with windows fonts.

128  Ç  144  É  160  á  176  _  192  +  208  -  224  _  240  _
129  ü  145  æ  161  í  177  _  193  -  209  -  225  ß  241  ±
130  é  146  Æ  162  ó  178  _  194  -  210  -  226  _  242  _
131  â  147  ô  163  ú  179  ¦  195  +  211  +  227  ¶  243  _
132  ä  148  ö  164  ñ  180  ¦  196  -  212  +  228  _  244  _
133  à  149  ò  165  Ñ  181  ¦  197  +  213  +  229  _  245  _
134  å  150  û  166  ª  182  ¦  198  ¦  214  +  230  µ  246  ÷
135  ç  151  ù  167  º  183  +  199  ¦  215  +  231  _  247  _
136  ê  152  ÿ  168  ¿  184  +  200  +  216  +  232  _  248  °
137  ë  153  Ö  169  _  185  ¦  201  +  217  +  233  _  249  •
138  è  154  Ü  170  ¬  186  ¦  202  -  218  +  234  _  250  ·
139  ï  155  ¢  171  ½  187  +  203  -  219  _  235  _  251  _
140  î  156  £  172  ¼  188  +  204  ¦  220  _  236  _  252  n
141  ì  157  ¥  173  ¡  189  +  205  -  221  ¦  237  _  253  ²
142  Ä  158  P  174  «  190  +  206  +  222  _  238  _  254  _
143  Å  159  ƒ  175  »  191  +  207  -  223  _  239  _  255


Calling Conventions

                              C    SYSCALL STDCALL  BASIC  FORTRAN  PASCAL
                          +-------+-------+-------+-------+-------+-------+
  Leading Underscore      |   X   |       |   X   |       |       |       |
                          |-------+-------+-------+-------+-------+-------|
  Capitalize All          |       |       |       |   X   |   X   |   X   |
                          |-------+-------+-------+-------+-------+-------|
  Arguments Left to Right |       |       |       |   X   |   X   |   X   |
                          |-------+-------+-------+-------+-------+-------|
  Arguments Right to Left |   X   |   X   |   X   |       |       |       |
                          |-------+-------+-------+-------+-------+-------|
  Caller Stack Cleanup    |   X   |       |   *   |       |       |       |
                          |-------+-------+-------+-------+-------+-------|
  BP Saved                |       |       |       |   X   |   X   |   X   |
                          |-------+-------+-------+-------+-------+-------|
  :VARARG Allowed         |   X   |   X   |   X   |       |       |       |
                          +-------+-------+-------+-------+-------+-------+

* The STDCALL language type uses caller stack cleanup if the :VARARG parameter is used. Otherwise, the called routine must clean up the stack.

The language type (langtype) determines the naming and calling conventions used by the assembler. This allows you to share code and data with modules written with other languages. Set the language type with the .MODEL or OPTION LANGTYPE: directives or with the /G<x> command-line option. Several directives allow you to specify a langtype parameter to temporarily override the language type.

You can use the /H command-line option to limit the length of names sent to the object file. Use this option to work with languages that limit the maximum length of identifiers.


Processor Flags

     1     1
     8     5               7             0
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    |A|V|R|0|N|IO-|O|D|I|T|S|Z|0|A|0|P|1|C| -- Layout of flags register
    |C|M|F| |F|PL |F|F|F|F|F|F| |F| |F| |F|
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

     Flag                  If set:

     CF    Carry           Carry or borrow to destination operand
     PF    Parity          Even parity in low-order byte of result
     AF    Aux. Carry      Carry or borrow to low four-order bits
     ZF    Zero            Result equal to 0
     SF    Sign            Result has negative sign
     TF    Trap            Switches to single-step mode
     IF    Interrupt       Enables interrupts (disables if cleared)
     DF    Direction       String operations process down rather than up
     OF    Overflow        Result too large or small for destination
     IOPL  I/O             I/O Privilege Level for IN, INS, OUT, OUTS, Priv CLI, STI (286+)
     NF    Nested Task     Instruction caused nested task switch (286+)
     RF    Resume          Debug faults disabled during instruction execution (386+)
     VM    Virtual 8086    Currently executing 8086 code on virtual processor (386+)
     AC    Alignment       Data aligned to four-byte boundary (486+) Check


Stack of 80-bit Data Registers

            79 78     63 62                                     0
            +-+---------+---------------------------------------+
     ST     +-+---------+---------------------------------------+
     ST(1)  +-+---------+---------------------------------------+
     ST(2)  +-+---------+---------------------------------------+
     ST(3)  +-+---------+---------------------------------------+
     ST(4)  +-+---------+---------------------------------------+
     ST(5)  +-+---------+---------------------------------------+
     ST(6)  +-+---------+---------------------------------------+
     ST(7)  +-+---------+---------------------------------------+
            | |         '- Mantissa
            | '- Exponent
             '- Sign

                         Tag Word Format

        15                     8  7                     0
        +--+--+--+--+--+--+--+--++--+--+--+--+--+--+--+--+
        |TAG7 |TAG6 |TAG5 |TAG4 ||TAG3 |TAG2 |TAG1 |TAG0 |

        +--+--+--+--+--+--+--+--++--+--+--+--+--+--+--+--+

      TAG--Tag values of Data Register Stack
         00 = Valid
         01 = Zero
         10 = Invalid, infinity, or denormalized
         11 = Empty

                        Control Registers

                           +----------+
     Control Word          +----------+   Each word is 16 or 32
     Status Word           +----------+   bits, depending on
     Tag Word              +----------+   segment mode. Total

     Instruction Pointer   +          +   size of state is 14
                           +----------+   bytes in 16-bit mode
     Operand Pointer       +          +   or 28 bytes in 32-bit
                           +----------+   mode.

     Total size of environment is 94 bytes in 16-bit mode or 108 bytes in 32-bit mode.

     When DOS loads an .EXE program, it sets registers as follows:

     Register     Points to

     ES           Segment of Program Segment Prefix (PSP)

     DS           Segment of PSP
     CS:IP        CS:IP address in EXE header
     SS:SP        SS:SP address in EXE header

     When DOS loads a COM program, it sets all segment registers to the beginning of the program, and IP to 100H.


Conditional Assembly


Debugging in MASM32

This essay was written by the following author and is reproduced here for your convenience. It is a technique for programmers who own a copy of SoftICE.

Setting up MASM for use with SoftICE
------------------------------------
by Lucifer
Mon January 25, 1999

Well, I have had a pain trying to get masm produced executables to debug
correctly with SoftICE.  After some kludging I've finally figured it out...

Its actually simple to do, but if you dont know what you're doing (or haven't
read your manual), its quite a pain. Set these options when you build your
project and you should have no problems debugging it.

Step 1 -  Setting up The Assembler:
-----------------------------------
        ML /COFF /Zi ...

Step 2 - Setting up The Linker:
-------------------------------
        Link /SUBSYSTEM:WINDOWS /DEBUG /DEBUGTYPE:CV ...

Step 3 - Seting up SoftICE:

---------------------------
This batch file will translate the symbol information and package the source
code.  This will allow you full symbolic and source level debugging.
It will then launch the debugger amd break on the module's entry point
(WinMain, DllMain, or DriverEntry). This batch file will completely replace
the use of Loader32.exe, giving quick and easy access to the debugger from
the command line.

rem DEBUG.BAT ----------------------
@echo off

nmsym /translate:source,package,always /source:. /load:execute,break %1

Now all you have to do is type "DEBUG MyProgram.exe" on the command line to
automatically load the source and symbols and begin debugging.

Step 4 - Setting up the Paths:
------------------------------
Now all you need to do is add your MASM bin directory to the PATH, as in:
SET PATH = %PATH%;C:\MASM\BIN

Step 5 - Using SoftICE to Debug:
--------------------------------

Once you have the program loaded into softice you can use the SRC command to toggle between source view, code view, and mixed mode...
You can also set breakpoints on your functions by typing BPX MyFunc.
BPM MyVar will break on access to a variable.
Of course, READ YOUR MANUAL so you really know what your doing...

NOTE: These settings haven't seemed to work for everybody... so if you have
problems, or know what I am doing wrong, please let me know.

-----------------------------------------------------------------------------

Copyright (C) 1999
lord-lucifer@usa.net


Pentium Optimisation

Pentium Optimization Cross-Reference by Instruction

---------------------------------------------------------------------------
                         replacement
instruction   CPU's      or action          description/notes
---------------------------------------------------------------------------

aad (imm8)      all        AL = AL+(AH*imm8)    If imm8 is blank uses 10.

                           AH = 0               AAD is almost always slower,

                                                but only 2 bytes long.

aam (imm8)      all        AH = AL/imm8         Same as AAD.

                           AL = AL MOD imm8

add             16-bit     lea reg, [reg+reg+disp]
                                                Use LEA to add
                                                base + index + displacement
                                                Also preserves flags;

                                                for example:

                                                  add bx, 4

                                                can be replaced by:

                                                  lea  bx, [bx+4]

                                                when the flags must not
                                                be changed.

add             32-bit     lea reg, [reg+reg*scale+disp]

                                                Use LEA to add
                                                base + scaled index + disp
                                                Also preserves flags.
                                                (See previous example).
                                                The 32-bit form of LEA
                                                is much more powerful
                                                than the 16-bit version

                                                because of the scaling
                                                and the fact that almost
                                                all of the 8 General purpose
                                                registers can be used
                                                as base and index registers.

and reg, reg    Pent       test reg, reg        Use TEST instead of AND

                                                on the Pentium because
                                                fewer register conflict
                                                will result in better pairing

bswap           Pent       ror eax, 16          Pairs in U pipe, BSWAP
                                                doesn't pair.
                                                disadvantage: modifies flags
                                                (Not a direct replacement)

call dest1      286+       push offset dest2    When CALL is followed by
jmp  dest2                 jmp  dest1           a JMP, change the return
                                                address to the JMP destination.

call dest1      all        jmp  dest1           When a CALL is followed by a
ret                                             RET, the CALL can be replaced

                                                by a JMP.

cbw             386+       mov ah, 0            When you know AL < 128
                                                use MOV AH, 0 for speed.
                                                But use CBW for smaller
                                                code size.

cdq             486+       xor edx, edx         When you know EAX is positive

                                                Faster, better pairing.
                                                disadvantage: modifies flags
                Pent       mov edx, eax         When EAX value could be
                           sar edx, 31          positive or negative
                                                because of better pairing

cmp mem, reg    286        cmp reg, mem         reg, mem is 1 cycle faster

cmp reg, mem    386        cmp mem, reg         mem, reg is 1 cycle faster

dec reg16                  lea reg16, [reg16 - 1]   Use to preserve flags
                                                    for BX, BP, DI, SI

dec reg32                  lea reg32, [reg32 - 1]   Use to preserve flags
                                                    for EAX, EBX, ECX, EDX
                                                        EDI, ESI, EBP

div <op>         8088       shr accum, 1         When <op>  resolves to 2, use
                                                shift for division.
                                                (use CL for 4, 8, etc.)

div <op>         186+       shr accum, n         When <op>  resolves to a power
                                                of 2 use shifts for division.

enter imm16, 0  286+       push bp              ENTER is always slower

                           mov  bp, sp          and 4 bytes in length
                           sub  sp, imm16       if imm16 = 0 then push/mov
                                                is smaller
                386+       push ebp
                32-bit     mov  ebp, esp
                           sub  esp, imm16

inc reg16                  lea reg16, [reg16 + 1]   Use to preserve flags
                                                    for BX, BP, DI, SI

inc reg32                  lea reg32, [reg32 + 1]   Use to preserve flags
                                                    for EAX, EBX, ECX, EDX
                                                        EDI, ESI, EBP

jcxz <dest>:    486+        test cx, cx          JCXZ is faster and
                           je   <dest>:          smaller on 8088-286.
                                                On the 386 it is the

                                                about the same speed
               486+        test ecx, ecx        Never use JCXZ on 486
                           je   <dest>:         or Pentium except for
                                                compactness

lea reg, mem   8088-286    mov reg, OFFSET mem  MOV reg, imm is faster
                                                on 8088 - 286. 386+
                                                they are the same.

        Note: There are many uses for LEA, see: add, inc, dec, mov, mul

leave           486+       mov sp, bp           LEAVE is only 1 byte
                           pop bp               long and is faster
                                                on the 186-386. The
                           mov esp, ebp         MOV/POP is much faster
                           pop ebp              on 486 and Pentium

lodsb           486+       mov al, [si]         LODS is only 1 byte long
                           inc si               and is faster on 8088-386,
                                                much slower on the 486.
                                                On the Pentium the MOV/INC
                                                or MOV/ADD instructions
                                                pair, taking only 1 cycle.

lodsw           486+       mov ax, [si]         see lodsb
                           add si, 2

lodsd           486+       mov eax, [esi]       see lodsb
                           add esi, 4

loop <dest>:     386+       dec cx               LOOP is faster and
                           jnz <dest>:           smaller on 8088-286.
                                                on 386+ DEC/JNZ is

loopd <dest>:               dec ecx              much faster. On the Pentium
                           jnz <dest>:           the DEC/JNZ instructions
                                                pair taking only 1 cycle.

loopXX <dest>:   486+       je  $+5              The 3 replacement
                                                 instructions
( XX = e,ne,z or nz)       dec cx               are much faster on the 486+.

                           jnz <dest>:           LOOPxx is smaller and
                                                faster on 8088-286

loopdXX <dest>:  486+       je  $+5              The speed is about the
                           dec ecx              same on the 386.
                           jnz <dest>:

mov reg2, reg1  286+       lea reg2, [reg1+n]   LEA is faster, smaller and
 followed by:                                   preserves flags. This is a

 inc/dec/add/sub reg2                           way to do a MOV and ADD/SUB
                                                of a constant, n.

mov acc, reg    all        xchg acc, reg        Use XCHG for smaller code
                                                when one of the registers
                                                final value can be ignored.
                                                Note that acc = AL, AX or EAX.

mov mem, 1      Pent       lea bx, mem          Displacement/immediate does
                           mov [bx], 1          not pair. LEA/MOV can be used
                                                if other code can be placed
                                                inbetween to prevent AGI's.
                           mov ax, 1            MOV/MOV may be easier to pair.
                           mov mem, ax

mov [bx+2], 1   Pent       mov ax, 1            Better pairing because
                           mov [bx+2], ax       displacement/immediate
                                                instructions do not pair.
                           lea bx, [bx+2]
                           mov [bx], 1

movsb           486+       mov al, [si]         MOVS is faster and
                           inc si               smaller to move a single

                           mov [di], al         byte, word or dword
                           inc di               on the 8088-386.
                                                On the 486+ the MOV/INC
                                                method is faster.
                                                NOTE: REP MOVS is always
                                                faster to move a large block.

movsw           486+       mov ax, [si]         see MOVSB

                           add si, 2
                           mov [di], ax
                           add di, 2

movsd           486+       mov eax, [esi]       see MOVSB
                           add esi, 4
                           mov [edi], eax
                           add edi, 4

movzx r16, rm8  486+       xor bx, bx           MOVZX is faster and
                           mov bl, al           smaller on the 386.

                                                On the 486+ XOR/MOV

movzx r32, rm8  486+       xor ebx, ebx         is faster. Possible
                           mov bl, al           pairing on the Pentium.
                                                (source can be reg or mem)

movzx r32, rm16 486+       xor ebx, ebx         disadvantage: modifies flags
                           mov bx, ax

mul n           8088+      shl ax, cl           Use shifts or ADDs instead of

                                                multiply when n is a power of
                                                2.

mul n           Pent       add ax, ax           ADD is better than single
                                                shift because it pairs better.

mul             32-bit     lea                  Use LEA to multiply by
                                                2, 3, 4, 5, 7, 8, 9

                           lea eax, [eax+eax*4] (ex: multiply EAX * 5)
                                                LEA is better than SHL on the
                                                Pentium because it pairs in
                                                both pipes, SHL pairs only in
                                                the U pipe.

or reg, reg     Pent       test reg, reg        Better pairing because

                                                OR writes to register.
                                                (This is for src = dest.)

pop mem         486+       pop reg              Faster on 486+
                           mov mem, reg         Better pairing on Pentium

push mem        486+       mov  reg, mem        Faster on 486
                           push reg             Better pairing on Pentium

pushf           486+       rcr reg, 1           To save only the carry flag
                                                use a rotate (RCR or RCL)
                              or                into a register. RCR and RCL
                                                are pairiable (U pipe only)

                           rcl reg, 1           and take 1 cycle. PUSHF is
                                                slow and not pairable.

popf            486+       rcl reg, 1           To restore only the carry
                                                flag.
                                                See PUSHF.
                              or
                           rcr reg, 1

rep scasb       Pent       loop1:               REP SCAS is faster and
                             mov al, [di]       smaller on 8088-486.
                             inc di             Expanded code is faster

                             cmp al, reg2       on Pentium due to pairing.
                             je  exit
                             dec cx
                             jnz loop1
                           exit:

shl reg, 1      Pent       add reg, reg         ADD pairs better. SHL
                                                only pairs in the U pipe.

stosb           486+       mov [di], al         STOS is faster and smaller

                           inc di               on the 8088-286, and the same
                                                speed on the 386. On the 486+

stosw           486+       mov [di], ax         the MOV/INC is slightly
                           add di, 2            faster.

stosd           486+       mov [edi], eax       REP STOS is faster on 8088-
                           add edi, 4           386.

                                                MOV/INC or MOV/ADD is faster
                                                on the 486+
                                                Note: use LEA SI, [SI+n]
                                                to advance LEA without
                                                changing the flags.

xchg            all                             Use xchg acc, reg to do a

                                                1 byte MOV when one register
                                                can be ignored.

xchg reg1, reg2 Pent       push reg1            pushes and pops are 1 cycle
                           push reg2            faster on Pentium due to
                           pop  reg1            pairing.
                           pop  reg2
                                                disadvantage: uses stack

                Pent       mov  reg3, reg1      Faster and better pairing
                           mov  reg1, reg2      if reg3 is available.
                           mov  reg2, reg3

xlatb           486+       mov bh, 0            XLAT is faster and smaller
                           mov bl, al           on 8088-386. MOV's are faster
                           mov al, [bx]         on 486+. Best to rearrange

                                                instructions to prevent AGI's

xlatb           486+       xor ebx, ebx         and get pairing on Pentium.
                           mov bl, al           Force high part of BX/EBX
                           mov al, [ebx]        to zero outside of loop.
                                                disadvantage: modifies flags


Command Line Tools

ML.EXE Options
LINK Options
LIB Options
EDITBIN Options
DUMPBIN Options


DUMPBIN Options

usage: DUMPBIN [options] [files]

Options
/ALL
/ARCH
/ARCHIVEMEMBERS
/DEPENDENTS
/DIRECTIVES
/DISASM
/EXPORTS
/FPO
/HEADERS
/IMPORTS
/LINENUMBERS
/LINKERMEMBER[:{1|2}]
/LOADCONFIG
/OUT:filename
/PDATA
/RAWDATA[:{NONE|BYTES|SHORTS|LONGS}[,#]]
/RELOCATIONS
/SECTION:name
/SUMMARY
/SYMBOLS
The DUMPBIN command line options are listed below. Some of the output each option provides is also listed.

/ALL Displays all available information except code disassembly. Use the /DISASM option to display disassembly. You can use /RAWDATA:NONE with the /ALL option to omit the raw binary details of the file.

Because the /ALL option is simply a combination of all the other options, an example is not needed.

/ARCHIVEMEMBERS Displays minimal information about member objects in a library.
The size of the output file depends on the number of object modules in the library. The following is part of the output from the Scrnsave.lib file:
Archive member name at 582: /0        ..\..\common\retail\scrnsave.obj
2FF359CC time/date Thu Jun 29 18:56:28 1995
         uid
         gid
  100666 mode
    214A size
correct header end

/DISASM Displays disassembly of code sections, using symbols if present in the file.
The following is part of the disassembly code from the Lib.exe file:
00401000: 8B 44 24 08        mov         eax,dword ptr [esp+8]
00401004: 68 00 20 40 00     push        402000h
00401009: 8B 4C 24 08        mov         ecx,dword ptr [esp+8]
0040100D: 50                 push        eax
0040100E: 51                 push        ecx
0040100F: E8 0C 00 00 00     call        00401020
00401014: 33 C0              xor         eax,eax
00401016: C3                 ret
00401017: CC                 int         3

/EXPORTS Displays all definitions exported from an executable file or DLL.
MFC40.DLL produces the following export information:

Section contains the following Exports for MFC40.DLL
          0 characteristics
   30733286 time date stamp Wed Oct 04 18:19:02 1995
       0.00 version
          1 ordinal base
       5782 number of functions
          4 number of names

ordinal hint   name

      2    0   DllCanUnloadNow  (00096182)
      1    1   DllGetClassObject  (0009611E)
      3    2   DllRegisterServer  (000961DB)
      4    3   DllUnregisterServer  (00096242)

/FPO Displays frame pointer optimization (FPO) records.
One of the MFC libraries, Nafxis.lib, provided us with some examples of frame pointer optimization records:
FPO Data (1)
                                       Use Has  Frame
 Address  Proc Size   Locals   Prolog  BP  SEH  Type   Params
00000000          9        0        0   N   N    fpo        0

FPO Data (1)
                                       Use Has  Frame
 Address  Proc Size   Locals   Prolog  BP  SEH  Type   Params
00000000         11        0        0   N   N    fpo        C

FPO Data (1)
                                       Use Has  Frame
 Address  Proc Size   Locals   Prolog  BP  SEH  Type   Params
00000000          3        0        0   N   N    fpo        0

/HEADERS Displays the file header and the header for each section. When used with a library, it displays the header for each member object.
This information was displayed from the Resource Compiler, Rc.exe:
FILE HEADER VALUES
     14C machine (i386)
       6 number of sections
306F7A22 time date stamp Sun Oct 01 22:35:30 1995
       0 file pointer to symbol table
     1D1 number of symbols
      E0 size of optional header
     302 characteristics
            Executable
            32 bit word machine
            Debug information stripped

OPTIONAL HEADER VALUES
     10B magic #
    2.60 linker version
    1E00 size of code
    1E00 size of initialized data
       0 size of uninitialized data
    1144 address of entry point
    1000 base of code
    3000 base of data
         ----- new -----
 2BB0000 image base
    1000 section alignment
     200 file alignment
       3 subsystem (Windows CUI)
    4.00 operating system version
    4.00 image version
    3.50 subsystem version
    8000 size of image
     400 size of headers
    62C8 checksum
  100000 size of stack reserve
    1000 size of stack commit
  100000 size of heap reserve
    1000 size of heap commit
       0 [       0] address [size] of Export Directory
    5000 [      3C] address [size] of Import Directory
    6000 [     394] address [size] of Resource Directory
       0 [       0] address [size] of Exception Directory
       0 [       0] address [size] of Security Directory
    7000 [     21C] address [size] of Base Relocation Directory
    3030 [      38] address [size] of Debug Directory
       0 [       0] address [size] of Description Directory
       0 [       0] address [size] of Special Directory
       0 [       0] address [size] of Thread Storage Directory
       0 [       0] address [size] of Load Configuration Directory
     268 [      44] address [size] of Bound Import Directory
    50A0 [      64] address [size] of Import Address Table Directory
       0 [       0] address [size] of Reserved Directory
       0 [       0] address [size] of Reserved Directory
       0 [       0] address [size] of Reserved Directory

SECTION HEADER #1
   .text name
    1D24 virtual size
    1000 virtual address
    1E00 size of raw data
     400 file pointer to raw data
       0 file pointer to relocation table
    3C20 file pointer to line numbers
       0 number of relocations
     37E number of line numbers
60000020 flags
         Code
         (no align specified)
         Execute Read

/IMPORTS Displays all definitions imported to an executable file or DLL.
The output displayed here is similar to the /EXPORTS output.

/LINENUMBERS Displays COFF line numbers. Line numbers exist in an object file if it was compiled with the Program Database (/Zi), C7 Compatible (/Z7), or Line Numbers Only (/Zd) switches. An executable file or DLL contains COFF line numbers if it was linked with the Generate Debug Info (/DEBUG) and COFF Format (/DEBUGTYPE:COFF) options.
An application generated using AppWizard displays line information data such as the following:
LINENUMBERS #1
   1E90   13     1ECD   13     1EF7   13     1F16   13     1F31   15
   1F46   15     1F61   24     1F9A   27     1FD0   2A     2001   2B

/LINKERMEMBER[:{1|2}] Displays public symbols defined in a library. Specify the 1 argument to display symbols in object order, along with their offsets. Specify the 2 argument to display offsets and index numbers of objects, and then list the symbols in alphabetical order, along with the object index for each. To get both outputs, specify /LINKERMEMBER without the number argument.
Winmmm.lib, the Windows Multimedia library, was used to get the following sample of DUMPBIN output.
Archive member name at 8: /
2FB537E1 time/date Sat May 13 15:51:13 1995
         uid
         gid
       0 mode
    2864 size
correct header end

    391 public symbols

     556C _CloseDriver@12
     58A0 _DefDriverProc@20
     5BDC _DriverCallback@28
     5F1C _DrvGetModuleHandle@4
     626A _GetDriverModuleHandle@4
     65C4 _NotifyCallbackData@20
     6914 _OpenDriver@12
     6C44 _PlaySound@12
     6F70 _PlaySoundA@12
     72A0 _PlaySoundW@12
/OUT:filename Specifies a filename for the output. By default, DUMPBIN displays the information to standard output.

/RAWDATA[:{BYTES|SHORTS|LONGS|NONE}[,number]] Displays the raw contents of each section in the file. The arguments control the format of the display, as shown below:
Argument    Result

BYTES      The default. Contents are displayed in hexadecimal bytes,
           and also as ASCII characters if they have a printed
           representation.
SHORTS     Contents are displayed as hexadecimal words.
LONGS      Contents are displayed as hexadecimal longwords.
NONE       Raw data is suppressed. This argument is useful to control
           the output of /ALL.
number     Displayed lines are set to a width that holds <number> values
           per line.
The information generated with this option is quite large, this is a small sample of output from an AppWizard application using the LONGS format:
RAW DATA #1
00000000  53EC8B55 00A15756 | E9004058 00000000      U[ASCII 239]_SVW[ASCII
237].|X@._...._
00000010  C95B5E5F EC8B55C3 | 5304EC83 4D895756      _^[++U[ASCII
239]_|[ASCII 226]_.SVW[ASCII 235]M_
00000020  3058B8FC 00E90040 | 5F000000 C3C95B5E      n+X0@._.|..._^[++_
/RELOCATIONS Displays any relocations in the object or image.
Below is a small portion of the relocation output obtained from an AppWizard application:
BASE RELOCATIONS #6

    1000 virtual address,       B0 SizeOfBlock
       7 HIGHLOW
      22 HIGHLOW
      36 HIGHLOW
      67 HIGHLOW
      89 HIGHLOW
/SECTION:section Restricts the output to information on the specified section.

/SUMMARY Displays minimal information about sections, including total size. This option is the default if no other option is specified.
Microsoft (R) COFF Binary File Dumper Version 3.00.5270
Copyright (C) Microsoft Corp 1992-1995. All rights reserved.

Dump of file tracer.exe

File Type: EXECUTABLE IMAGE

     Summary

        1000 .data
        1000 .idata
        1000 .rdata
        1000 .reloc
        1000 .rsrc
        1000 .text
/SYMBOLS Displays the COFF symbol table. Symbol tables exist in all object files. A COFF symbol table appears in an image file only if it is linked with the Generate Debug Info and COFF Format options under Debug Info on the Debug category for the linker (or the /DEBUG and /DEBUGTYPE:COFF options on the command line).
An AppWizard application was used to obtain the following example:
COFF SYMBOL TABLE
000 000065D0 SECT5  notype       Static       | .rsrc$02
001 00000011 DEBUG  notype       Filename     | .file
 C:\code\test\testView.cpp
004 000041A0 SECT3  notype       Static       | $SG23289
005 00004018 SECT3  notype       Static       | _$S189$S23301
006 00004168 SECT3  notype       Static       | _THIS_FILE$S23282
007 00001E90 SECT1  notype       Static       | .text
 Section length  2DE, #relocs   27, #linenums   22
009 00001EE2 SECT1  notype ()    Static       | _$E188
00A 00001EF7 SECT1  notype ()    Static       | _$E187
 tag index 0000002E size 0000001F lines 000012DF next function 00000033
00C 000042AC SECT3  notype       Static       | __init_CTestView$S23291
00D 00003998 SECT2  notype       Static       | $T23440
00E 00003978 SECT2  notype       Static       | $T23438
00F 000039C0 SECT2  notype       Static       | $T23447
010 000039A0 SECT2  notype       Static       | $T23446
011 00000021 DEBUG  notype       Filename     | .file


EDITBIN Options

usage: EDITBIN [options] [files]

Options
/BIND[:PATH=path]
/HEAP:reserve[,commit]
/LARGEADDRESSAWARE[:NO]
/NOLOGO
/REBASE[:[BASE=address][,BASEFILE][,DOWN]]
/RELEASE
/SECTION:name[=newname][,[[!]{cdeikomprsuw}][a{1248ptsx}]]
/STACK:reserve[,commit]
/SUBSYSTEM:{NATIVE|WINDOWS|CONSOLE|WINDOWSCE|POSIX}[,#[.##]]
/SWAPRUN:{[!]CD|[!]NET}
/VERSION:#[.#]
/WS:[!]AGGRESSIVE


LIB Options

usage: LIB [options] [files]

Options
/CONVERT
/DEBUGTYPE:CV
/DEF[:filename]
/EXPORT:symbol
/EXTRACT:membername
/INCLUDE:symbol
/LIBPATH:dir
/LIST[:filename]
/MACHINE:{ALPHA|ARM|IX86|MIPS|MIPS16|MIPSR41XX|PPC|SH3|SH4}
/NAME:filename
/NODEFAULTLIB[:library]
/NOLOGO
/OUT:filename
/REMOVE:membername
/SUBSYSTEM:{NATIVE|WINDOWS|CONSOLE|WINDOWSCE|POSIX}[,#[.##]]
/VERBOSE


LINK Options

usage: LINK [options] [files] [@commandfile]

Options
/ALIGN:#
/BASE:{address|@filename,key}
/COMMENT:comment
/DEBUG
/DEBUGTYPE:{CV|COFF}
/DEF:filename
/DEFAULTLIB:library
/DLL
/DRIVER[:{UPONLY|WDM}]
/ENTRY:symbol
/EXETYPE:DYNAMIC
/EXPORT:symbol
/FIXED[:NO]
/FORCE[:{MULTIPLE|UNRESOLVED}]
/GPSIZE:#
/HEAP:reserve[,commit]
/IMPLIB:filename
/INCLUDE:symbol
/INCREMENTAL:{YES|NO}
/LARGEADDRESSAWARE[:NO]
/LIBPATH:dir
/MACHINE:{ALPHA|ARM|IX86|MIPS|MIPS16|MIPSR41XX|PPC|SH3|SH4}
/MAP[:filename]
/MAPINFO:{EXPORTS|FIXUPS|LINES}
/MERGE:from=to
/NODEFAULTLIB[:library]
/NOENTRY
/NOLOGO
/OPT:{ICF[,iterations]|NOICF|NOREF|NOWIN98|REF|WIN98}
/ORDER:@filename
/OUT:filename
/PDB:{filename|NONE}
/PDBTYPE:{CON[SOLIDATE]|SEPT[YPES]}
/PROFILE
/RELEASE
/SECTION:name,[E][R][W][S][D][K][L][P][X]
/STACK:reserve[,commit]
/STUB:filename
/SUBSYSTEM:{NATIVE|WINDOWS|CONSOLE|WINDOWSCE|POSIX}[,#[.##]]
/SWAPRUN:{CD|NET}
/VERBOSE[:LIB]
/VERSION:#[.#]
/VXD
/WARN[:warninglevel]
/WINDOWSCE:{CONVERT|EMULATION}
/WS:AGGRESSIVE


ML.EXE Options

ML.EXE 6.14 Options

Options
ML [ /options ] filelist [ /link linkoptions ]
/AT Enable tiny model (.COM file)
/Bl<linker> Use alternate linker
/c Assemble without linking
/Cp Preserve case of user identifiers
/Cu Map all identifiers to upper case
/Cx Preserve case in publics, externs
/coff generate COFF format object file
/D<name>[=text] Define text macro
/EP Output preprocessed listing to stdout
/F <hex> Set stack size (bytes)
/Fe<file> Name executable
/Fl[file] Generate listing
/Fm[file] Generate map
/Fo<file> Name object file
/FPi Generate 80x87 emulator encoding
/Fr[file] Generate limited browser info
/FR[file] Generate full browser info
/G<c|d|z> Use Pascal, C, or Stdcall calls
/H<number> Set max external name length
/I<name> Add include path
/link <linker options and libraries>
/nologo Suppress copyright message
/Sa Maximize source listing
/Sc Generate timings in listing
/Sf Generate first pass listing
/Sl<width> Set line width
/Sn Suppress symbol-table listing
/Sp<length> Set page length
/Ss<string> Set subtitle
/St<string> Set title
/Sx List false conditionals
/Ta<file> Assemble non-.ASM file
/w Same as /W0 /WX
/WX Treat warnings as errors
/W<number> Set warning level
/X Ignore INCLUDE environment path
/Zd Add line number debug info
/Zf Make all symbols public
/Zi Add symbolic debug info
/Zm Enable MASM 5.10 compatibility
/Zp[n] Set structure alignment
/Zs Perform syntax check only


[ELSE]IF

Syntax: [ELSE]IF expression

[ELSE]IFE expression

Description
IF causes assembly of a block of statements if expression is true (nonzero). IFE causes assembly of a block of statements if expression is false (zero).

The <expression> must resolve to a constant and contain no forward references.


[ELSE]IFB

Syntax: [ELSE]IFB expression

[ELSE]IFNB expression

Description
IFB causes assembly of a block of statements if <expression> is blank. IFNB causes assembly of a block of statements if <expression> is not blank. The <expression> field is any name, number, or expression; typically, it is the name of a parameter of a macro.

Within a macro, a parameter name is replaced by an empty string if you call the macro without giving a corresponding argument. IFB and IFNB let you define default behavior when an argument is missing, but the :REQ and :=default MACRO parameters are preferred.


[ELSE]IFDEF

Syntax: [ELSE]IFDEF name

[ELSE]IFNDEF name

Description
IFDEF causes assembly of a block of statements if <name> is a previously defined symbol. IFNDEF causes assembly of a block of statements if name has not been defined.

You can define symbols on the command line or in the Macro Assembler Global Options dialog box.

Use of this feature with the IFDEF and IFNDEF directives lets you control which statements are assembled from the command line.


[ELSE]IFDIF[I]

Syntax: [ELSE]IFDIF[I] textitem1, textitem2

[ELSE]IFIDN[I] textitem1, textitem2

Description
Causes assembly of a block of statements depending on whether two textitems are different or identical. IFDIF assembles the block if <textitem1> and <textitem2> are different. IFIDN assembles the block if they are the same. IFDIFI and IFIDNI do the same actions but are not case sensitive.

The <textitem1> and <textitem2> parameters are text items.


MACRO

Syntax: name MACRO [parameter[:tag]] [,parameter[:tag]]...]
  [LOCAL varlist]
  statements
  [EXITM [textitem]]
ENDM

Description
Marks the beginning of a macro definition called <name> and takes optional parameters. The assembler generates the statements in the macro block each time the macro is called in source code. Macro procedures and macro functions can be nested up to 40 levels. Text macros may be nested up to 20 levels.

Macro procedures can be redefined at any time. The new definition affects any subsequent calls to this macro. Macro functions can only be redefined, if they have not been called yet.

Example
mymacro MACRO value:REQ, reg:=<AX>, options:VARARG
  LOCAL returnval
  -
  -
  -
  EXITM returnval
ENDM

Parameter Description
name A unique symbol name. It can appear later in source code, to call the macro.

parameter A valid symbol name. Each parameter can appear in the statements and is replaced by the corresponding item in the argument list whenever the macro is called.
:
tag Either :REQ, :=default, or :VARARG. :REQ causes an assembler error if the parameter is given a blank argument. :=default causes <parameter> to be assigned <default> if given a null argument. :VARARG allows a variable number of arguments to be passed as a comma-separated list to <parameter>. If :VARARG is used, it must be applied only to the last parameter of the MACRO directive.

statements Any valid assembler statements.

value Optional return value for macro function.


ENDM

Syntax: ENDM

Description
Terminates macro and iterative blocks.


EXITM

Syntax: EXITM [textitem]

Description
Terminates expansion of the current macro or repeat block and begins assembly of the next statement outside the block. If the EXITM directive is encountered in a nested macro block, the assembler returns to expanding the previous block level.

The <textitem> parameter is a text item that is returned to the calling statement. The <textitem> field is valid only with an EXITM directive at the end of a MACRO block.


FOR

Syntax: FOR parameter[:REQ|:=default], <argument [,argument]...>
  statements
ENDM

Description
Repeats <statements> once for each argument specified. The current argument replaces <parameter> in each iteration. IRP is a synonym for FOR and is included for compatibility with previous versions of the assembler.

Parameter Description
parameter A valid symbol name. If parameter appears in statements, it is replaced by a different argument in each iteration.

:REQ Optional tag for <parameter> causing an assembler error if <parameter> is given a blank argument.

:=default Optional tag for <parameter> causing <parameter> to be assigned <default> if given a blank argument.

argument Text, symbol, string, or numeric constant. Separate multiple iterations with commas. Angle brackets are required if a string <argument> includes spaces or commas. Leading spaces of string arguments are ignored.

statements Any valid assembler statements.


FORC

Syntax: FORC parameter, <string>
  statements
ENDM

Description
Repeats <statements> once for each character in the string. The character replaces <parameter> in each repetition. IRPC is a synonym for FORC and is included for compatibility with previous versions of the assembler.

Parameter Description
parameter A valid symbol name. If <parameter> appears in statements, then it is replaced by a different character each iteration.

string A literal string or a symbol defined with a string equate. All spaces are counted as characters. Angle brackets are required.

statements Any valid assembler statements.


GOTO

Syntax: GOTO macrolabel

Description
Causes assembler to skip to <macrolabel>. The GOTO directive is only allowed inside a MACRO, FOR, FORC, REPEAT, or WHILE block. The <macrolabel> is only visible within the block.

Example
MACRO Instruments
IFNDEF Cymbal
GOTO Crash
ENDIF
-
-
-
:Crash
.ERR <Undefined symbol.>
-
-
-
ENDM


REPEAT

Syntax: REPEAT expression
  statements
ENDM

Description
Assembles a block of statements <expression> times. REPT is a synonym for REPEAT and is included for compatibility with previous versions of the assembler.

The <expression> parameter must evaluate to a numeric constant. This constant is evaluated during the first pass. The <statements> are any valid assembler statements.


WHILE

Syntax: WHILE expression
statements
ENDM

Description
Marks a block of statements to be assembled repeatedly until <expression> is false (zero). The <expression> is a constant expression whose value is computed at assembly time.


IF

Syntax: IF cond expression
  ifstatements
[ELSEIF] cond expression
  elseifstatements
  -
  -
  -
[ELSE]
  elsestatements
ENDIF

Description
The IF block format can be used to create a source file that will generate a variety of programs, depending on constants or environment variables. For example, you can create a single source file that generates code for different memory models and operating environments. IF blocks can be nested up to 20 levels but cannot span include files or structure, union, or macro definitions.

The statements following the ELSE directive are assembled only if the preceding IF directive was found to be false (zero). Only one ELSE statement is allowed in each IF block, although there can be several ELSEIF statements.

IFcond is one of the conditional assembly directives beginning with "IF" (such as IF, IFE, and IFB). There is an optional ELSEIFcond corresponding to each IFcond.

The <ifstatements>, <elseifstatements>, and <elsestatements> are each a series of one or more assembly-code statements. The respective conditions determine which block is assembled, if any. The ELSE and ELSEIF blocks are optional.


Literal text

Syntax: <text>

Description
Treats <text> as a single literal string.

Angle brackets are often used in macro calls and with the FOR directive to ensure that values in a parameter list are treated as a single parameter. For example,

MyMacro <one, two, three> ;Passes one argument to  ; MyMacro
MyMacro one, two, three ;Passes three arguments to ; MyMacro

The assembler removes one set of angle brackets each time it inserts an argument into a macro expansion.

The <text> is any name, number, or expression. It can contain commas, spaces, tabs, or semicolons. The exclamation point (!) is an escape character that allows you to include special characters such as the semicolon, ampersand, and quotation marks.


Macro local

Syntax: LOCAL localname [,localname]...

Description
Declares a label or symbol for local use within a macro or iterative block. The assembler generates a different internal name for the symbol each time it expands the macro. The LOCAL directive allows you to call a macro that contains local jump statements and variable definitions without generating the same label each time the macro is expanded.

The <localname> parameter is the name of a label or symbol inside the macro. Inside the macro expansion, <localname> takes precedence over a global label or symbol with the same name.


PUSHCONTEXT

Syntax: PUSHCONTEXT context

POPCONTEXT context

Description
PUSHCONTEXT stores the context information indicated in <context>.
POPCONTEXT restores the context information indicated in <context>.
You can nest PUSHCONTEXT directives up to 10 levels.

You can use these directives to save and restore the state of the assembler in include files and procedures.

<context> Items Saved

ASSUMES   Register assumptions
RADIX     Current default radix
LISTING   Listing and cref flags
CPU       CPU and coprocessor directives
ALL       All of the above


&parameter&

The ampersand character "&"

Syntax: &parameter&

Description
Operator used within a macro or a repeat block; enables parameter substitution for <parameter>. Two parameters can be joined to form one symbol. You can join any number of parameters with the ampersand operator.

You can also use this operator to force parameter substitution in a quoted string. For this reason, if you want an ampersand to be included in a string, you must use the string escape character (!) before the &.

Use ampersands (&) only around macro parameters, in quoted strings, and inside angle brackets (<>). Each parameter to be substituted must have one ampersand on the left and right. If an ampersand is adjacent to white space, it can be omitted as long as one ampersand is next to each parameter to be substituted.

Example:
Guard MACRO Prisonernum:REQ, Prisonername:=Anonymous
ECHO <Number &Prisonernum has arrived at &@Time.>
EXITM Prisonernum&&Prisonername
ENDM

Badge Guard 2


Relational Operators

Syntax: expression1 EQ expression2

expression1 NE expression2

expression1 GT expression2

expression1 LT expression2

expression1 GE expression2

expression1 LE expression2

Description
The EQ, NE, GT, LT, GE, and LE relational operators determine if two constant expressions or data labels (in the same segment) are equal, not equal, greater than, less than, greater than or equal, or less than or equal to each other. The comparison returns true (-1) or false (0).

These operators work only with assembler symbols and constants; they cannot be used to evaluate registers or memory locations. Use comparison run-time operators with the .IF, .ELSEIF, .WHILE, and .UNTIL directives.


VARARG (Macro)

VARARG

VARARG (Macro)

The VARARG attribute allows you to pass a variable number of arguments to a macro. The macro parameter will be passed a comma-separated list of values (or a blank if no values are given) when called. You can apply the VARARG attribute only to the last parameter in a macro definition.

You can use the FOR directive to handle macro parameters with the VARARG attribute. The following macro function calculates the number of arguments in a VARARG parameter:

@ArgCount MACRO parmlist:VARARG
  LOCAL count
  count = 0
  FOR parm, <parmlist>
    count = count + 1 ; Count the parameters
  ENDM
  EXITM count
ENDM

This example button links to a macro that allows you to access an argument by its number.


Nested macros

You can separate macro arguments with white space or with commas. This is the same as using OPTION OLDMACROS.

The assembler uses the following rules to handle ampersands:

1. If a sequence of ampersands is found, the first ampersand is removed.

2. If a macro parameter is found, it is replaced by the actual parameter string.

3. Inside quoted strings and text literals, the string is scanned from left to right for ampersands. For each ampersand:

* If the ampersand is preceded or followed by a parameter, the parameter is substituted and the ampersand removed.

* If the ampersand is preceded by a previously substituted parameter, the ampersand is removed.

* In all other cases, the ampersand is ignored.

The assembler performs parameter substitution at each level of nesting. Therefore, you must add an extra ampersand before or after a macro parameter for each level of MACRO nesting or FOR/FORC/REPEAT/WHILE nesting.


Macro function reverse ordering

;* @ArgRev - Macro function returns a reversed order version of a
;* VARARG list.
;*
;* Shows: Operators - <> ! %
;* String directive - SUBSTR
;* Predefined function - @SizeStr
;*
;* Params: arglist - arguments to be reversed

@ArgRev MACRO arglist
  LOCAL txt, arg
  txt TEXTEQU <>
    % FOR arg, arglist
      txt CATSTR <arg>, <!,>, txt
    ENDM
  txt SUBSTR txt, 1, @SizeStr( %txt ) - 1
  txt CATSTR <!<>, txt, <!>>
  EXITM txt
ENDM


Macro Function ArgI

;* @ArgI - Macro function returns an argument specified by number
;* from a VARARG list.
;*
;* Shows: Directives - FOR LOCAL EXITM
;* TEXTEQU =
;* Operator - EQ
;*
;* Params: index - one-based number of the argument to be returned
;* arglist - argument list

@ArgI MACRO index:REQ, arglist:VARARG
  LOCAL count, retstr
  count = 0
    FOR arg, <arglist>
      count = count + 1
    IF count EQ index
  retstr TEXTEQU <arg>
  ENDIF
  ENDM
  EXITM retstr
ENDM


CATSTR

Syntax: @CatStr(string[, string...])

name CATSTR [textitem[, textitem...]]

Description
The @CatStr macro function concatenates one or more text items. The result can be used anywhere a text item is appropriate. The @CatStr function will not expand macros or expressions unless you use the expression operator (%).

The CATSTR directive concatenates strings and assigns the result to <name>. These two lines are equivalent:

language TEXTEQU @CatStr (<Quick>, <Pascal>)
language CATSTR <Quick>, <Pascal>

The <name> is a unique symbolic name, <string> is a text string, and <textitem> is a text item.


INSTR

Syntax: @InStr([position], string1, string2)

name INSTR [position,] textitem1, textitem2

Description
The @InStr macro function searches for the first occurrence of <string2> inside <string1> and returns the position of the first character of the match. The search begins at <position>, if you give that parameter. The @InStr function will not expand macros or expressions unless you use the expression operator (%).

The first character is indexed as 1. @InStr returns 0 if <string1> is not found.

The INSTR directive performs the same function as @InStr but assigns the result to <name>. These two lines are equivalent:

develop TEXTEQU @InStr (2, <MikeBobMichaelJim>, <Mi>)
develop INSTR 2, <MikeBobMichaelJim>, <Mi> ;develop is now 8

Parameter Description
name Name of the resulting constant.
position Starting character position of the search (default 1). Must be a positive integer.
string1 String being searched; any text.
string2 String to search for; any text.
textitem1 String being searched; any text item.
textitem2 String to search for; any text item.


SIZESTR

Syntax: @SizeStr(string)

name SIZESTR textitem

Description
The @SizeStr macro function returns the length of a text item in characters. The @SizeStr function will not expand macros or expressions unless you use the expression operator (%). A zero indicates a null (empty) string.

The SIZESTR directive performs the same function but assigns the result to <name>. These two lines are equivalent:

namelength TEXTEQU @SizeStr(<Denise>)
namelength SIZESTR <Denise>
;namelength is 6

The <name> is a unique symbolic name, <string> is a string, and <textitem> must be a text item.


SUBSTR

Syntax: @SubStr(string, start [,length])

name SUBSTR textitem, start [,length]

Description
The @SubStr macro function extracts specified characters from a text item. If <length> is not given, the function will return all characters to the right of (and including) the character pointed to by <start>. The @SubStr function will not expand macros or expressions unless you use the expression operator (%).

The SUBSTR directive performs the same function but assigns the result to <name>. These two lines are equivalent:

country TEXTEQU @SUBSTR (<AndorraMonacoLuxembourg>,8,6)
country SUBSTR <AndorraMonacoLuxembourg>,8,6
;country is <Monaco>

Parameter Description
name A unique symbolic name.
string A string to extract characters from.
textitem A text item to extract characters from.
start Starting position of substring; the first character is idexed as 1. Must be a positive integer constant.
length Number of characters to extract. Must be a positive integer constant.


.BREAK

Syntax: .BREAK [.IF condition]

Description

Terminates the nearest enclosing .WHILE or .REPEAT directive. If
the .IF condition is present, the loop is terminated only if the
value of <condition> is true.


.CODE

Syntax: .CODE [name]

Description

Starts a code segment (with segment name <name>, if given) and ends the previous segment, if any. Aligns the segment on a 2-byte boundary (.8086, .186, .286) or a 4-byte boundary (.386, .486). The .MODEL directive must precede this directive.

Segment name <name> is an optional parameter that overrides the default segment name. If <name> is not specified, the assembler generates a segment called _TEXT (tiny, small, compact, and flat models) or <modulename>_TEXT (medium, large, and huge models).


.CONST

Syntax: .CONST

Description

Starts a constant data segment (called CONST in DGROUP) and ends the previous segment, if any. For consistency with other languages, this segment should contain all strings, real numbers, and other constant data accessed by a high-level language. The CONST segment has the READONLY attribute.

The .MODEL directive must precede this directive.


.CONTINUE

Syntax: .CONTINUE [.IF condition]

Description

Skips to the code that evaluates the loop condition of the nearest enclosing loop. If the .IF condition clause is present, the skip will occur only if the value of <condition> is true.

This directive is valid only within a .REPEAT or .WHILE block.


.CREF

Syntax: .CREF

.NOCREF [name[, name]...]

Description
The .CREF directive enables collection of information for all symbols. These symbols will appear in the symbol table at the end of a listing file. If you generate a source-browser file with the /FR or /Fr command-line option, the browser will be able to access cross-reference information for these symbols. This directive is in effect by default.

The .NOCREF directive turns off cross-referencing for all symbols. Any references to symbols while .NOCREF is in effect are omitted from the cross-reference listing. If the <name> parameter is given with this directive, only the cross-reference information for the symbols specified by <name> is omitted.

.XCREF is a synonym for .NOCREF and is provided for compatibility with previous versions of the assembler.


.DATA

Syntax: .DATA

.DATA?

Description

The .DATA directive starts the initialized data segment (with segment name _DATA) and ends the previous segment, if any. The .DATA segment should contain all global data that have initial values.

The .DATA? directive starts the uninitialized data segment (with segment name _BSS) and ends the previous segment, if any. Place all uninitialized data in the .DATA? segment.

Although uninitialized data can be placed in the .DATA segment by declaring data with the ? operator, use the .DATA? directive to minimize the size of the .EXE file and to maximize compatibility with other languages.

The .MODEL directive must precede these directives. It generates a GROUP statement that places _DATA and _BSS in DGROUP.


.ERR

Syntax: .ERR [message]

Description
Generates an A2052 error message when assembled. Generally, this directive occurs in a conditional-assembly block and is used to indicate some error condition discovered at assembly time. This directive can be useful for verifying that the program assembled correctly and that user-defined bounds were not exceeded.

If <message> is given, it will be displayed with the standard assembler error messages. The <message> parameter is any text item


.ERRB

Syntax: .ERRB <textitem> [,message]

.ERRNB <textitem> [,message]

Description

The .ERRB directive generates an A2057 error if <textitem> is blank. The .ERRNB directive generates an A2058 error if <textitem> is not blank.

These directives are usually used within macro definitions; a macro parameter is replaced by an empty string if you call the macro and do not give a corresponding argument. These directives let you write macros that generate an assembly-time error if the wrong number of arguments is used in the macro call. However, the :REQ parameter attribute or the variable argument feature often provides the same functionality in a more straightforward way.

Parameter Description

textitem Item to be tested, any text item.

message Programmer-supplied error message, any text item.


.ERRDEF

Syntax: .ERRDEF name [,message]

.ERRNDEF name [,message]

Description
The .ERRDEF directive generates an A2056 error message if <name> is a previously defined symbol. The .ERRNDEF directive generates an A2055 error message if <name> has not been previously defined.

One of the most common uses of the .ERRNDEF directive is to ensure that a symbol has been defined before you attempt to use it. This situation can occur if the source code depends on the command-line /D option or the Macro Assembler Global Options dialog box to define a symbol.

If <message> is given, it will be displayed with the standard assembler error messages. The <message> parameter is any text item.


.ERRDIF

Syntax: .ERRDIF[I] <textitem1>, <textitem2> [,message]

.ERRIDN[I] <textitem1>, <textitem2> [,message]

Description
The .ERRDIF directive generates an A2060 error if <textitem1> and <textitem2> are different. .ERRIDN generates an A2059 error if the arguments are identical. These directives are commonly used inside macros to test for bad values passed as parameters. The .ERRDIFI and .ERRIDNI directives act the same as the .ERRDIF and .ERRIDN directives but perform case-insensitive comparisons.

The <textitem1> and <textitem2> parameters are text items.

If <message> is given, it will be displayed with the standard assembler error messages. The <message> parameter is any text item.


.ERRE

Syntax: .ERRE expression [,message]

.ERRNZ expression [,message]

Description
Tests value of <expression> and generates an error depending on the resulting value. The .ERRE directive generates an A2053 error if <expression> evaluates to false (zero). .ERRNZ generates an A2054 error if <expression> evaluates to true (nonzero). If <message> is given, it will be displayed with the standard assembler error message.

Parameter Description

expression Expression that evaluates to true, false, or a numeric constant. The expression cannot contain forward references.

message Programmer-supplied error message, any text item.


.IF

Syntax: .IF condition
  ifstatements
[.ELSEIF] condition
  elseifstatements
[.ELSE]
  elsestatements
.ENDIF

For "condition" see Comparison run-time operators

Description
Used for clear coding of common control-flow blocks. Generates comparison and conditional jump instructions so that if <condition> is true, the processor executes the instructions following .IF until the next .ELSEIF, .ELSE, or .ENDIF. .IF statements can be nested.

The .ELSEIF statement is used to create a code block that is executed if the preceding .IF and .ELSEIF conditions are false, and the current .ELSEIF condition is true. There can be several .ELSEIF blocks within a .IF block. The .ELSEIF statement performs the same function as a .IF inside a .ELSE but does not create another nesting level of .IFs.

.ELSE specifies an alternate code block if the matching .IF and previous .ELSEIF expressions are false.

.ENDIF closes the current .IF, .ELSEIF, or .ELSE code block. The assembler optimizes to get the best possible code. For example,

.IF ax==0
performs the comparison with:
or ax,ax
which is more efficient than:
cmp ax, 0


.LIST

Syntax: .LIST

Description
Enables listing of all source statements to the .LST file. The .LST file must first be enabled with a PWB MASM option or the /Fl command-line option. This directive is in effect by default.


.LISTALL

Syntax: .LISTALL

Description
Enables listing of all statements to the .LST file. The .LST file must first be enabled with a PWB MASM option or the /Fl command-line option. This directive is equivalent to the combination of the .LIST, .LISTIF, and .LISTMACROALL directives.


.LISTIF

Syntax: .LISTIF

Description
Enables listing of all statements in conditional blocks, even those in false blocks. This directive is in effect by default. The .LFCOND directive is a synonym of .LISTIF and is included for compatibility with previous versions of the assembler.


.LISTMACRO

Syntax: .LISTMACRO

Description
Enables an assembly listing file that includes macro expansion statements that generate code or data. Comments, equates, and segment definitions are not listed. This directive is in effect by default. The .LFCOND directive is a synonym of .LISTMACRO and is included for compatibility with previous versions of the assembler.


.LISTMACROALL

Syntax: .LISTMACROALL

Description
Enables listing of all source statements in a macro expansion, including normal comments but excluding macro comments. The .LALL directive is a synonym of .LISTMACROALL and is included for compatibility with previous versions of the assembler.


.MODEL

Syntax: .MODEL memorymodel [,langtype] [,ostype] [,stackoption]

Description
Initializes the program memory model. Must be placed at the beginning of the source file before any other simplified segment directive. Generates ASSUME and GROUP statements used by the specified memory model. Also creates the predefined equates for the various simplified segments. The .MODEL directive can occur only once in a program.

If you use the langtype argument with .MODEL, nested procedures are not allowed.

Parameter Description
Mmemory model TINY, SMALL, COMPACT, MEDIUM, LARGE, HUGE, or FLAT. If you are writing an assembler routine for a high-level language, this option should match the memory model used by the compiler or interpreter. FLAT is valid only in .386 or .486 mode. You must use the /AT command-line option or /TINY linker option to assemble tiny-model programs.

langtype Any language type. Instructs the assembler to follow the naming, calling, and return conventions for the indicated language. This affects the PUBLIC, EXTERN, PROC, PROTO, and INVOKE directives.

ostype OS_DOS is the only option currently supported and is the default.

stackoption NEARSTACK (if SS equals DS) or FARSTACK (if SS is not equal to DS). NEARSTACK is the default. The stack is not part of DGROUP with the FARSTACK option. This affects the code generated by the .STARTUP directive.


.MODEL directive

.MODEL directive

Description
If the .MODEL directive is preceded by the .386 or .486 directive (or their privileged counterparts), the assembler uses 32-bit segments. If the .386 or .486 directive follows the .MODEL directive, the default 16-bit segments are used. The flat memory model uses 32-bit segments and must be preceded by a .386 or .486 directive.

32-bit segments are available only on the 80386/486 processors.


.NOLIST

Syntax: .NOLIST

Description
Suppresses program listing. Use in conjunction with .LIST to prevent a particular section of a source file from being listed. The .XLIST directive is a synonym for .NOLIST and is included for compatibility with previous versions of the assembler.


.NOLISTIF

Syntax: .NOLISTIF

Description
Turns off the listing of the lines in subsequent conditional blocks whose condition is false. The .SFCOND directive is a synonym for .NOLISTIF and is included for compatibility with previous versions of the assembler.


.NOLISTMACRO

Syntax: .NOLISTMACRO

Description
Suppresses listing of macro expansions in a listing file. Macro calls are listed, but the source code generated by the call is not. The .SALL directive is a synonym for .NOLISTMACRO and is included for compatibility with previous versions of the assembler.


.RADIX

Syntax: .RADIX expression

Description
Sets the default radix (base) for integer constants to the value of <expression>. The default radix at the start of assembly is 10.

The .RADIX directive does not affect floating-point constants or numbers that have explicit radix overrride tags:

Tag Base
H hexadecimal
O or Q octal
T decimal
Y binary
R floating point

With a radix of 10 or below, you can use the characters B (b) and D (d) as the radix override characters for base 2 and base 10, respectively.

The <expression> must evaluate to a decimal number in the range 2 to 16 and cannot contain forward references.

If the current radix in your code is greater than 10 decimal, MASM 6.1 allows the radix specifiers B (binary) and D (decimal) only in compatibility mode. You must change B to Y for binary, and D to T for decimal, since both B and D are legitimate hexadecimal values, making numbers such as 12D ambiguous. If you want to keep B and D as radix specifiers when the current radix is greater than 10, you must specify OPTION M510.


.TFCOND

Syntax: .TFCOND

Description
Toggles the state of the assembler between .LISTIF and .NOLISTIF, determining whether or not false conditional blocks are included in assembler listings.


ALIGN

Syntax: ALIGN [number]

Description
ALIGN aligns the next variable or instruction on an offset address that is a multiple of [expression]. The [number] parameter must be a power of 2 [1,2,4,8,...] less than or equal to the alignment of the current segment. If [number] is omitted, the alignment is determined by the align field of the preceding SEGMENT directive.

In a segment containing no instructions, the assembler pads each skipped byte with nulls [00h]. In a code segment, the assembler inserts a no-operation sequence [not necessarily NOP instructions] to fill the gap.

This directive is useful for optimizing data and instruction fetches on processors with 16 or 32 bit data paths.

EVEN is a synonym for ALIGN 2.


ASSUME

Syntax: ASSUME segregister:seglocation [, segregister:seglocation]...

ASSUME dataregister:qualifiedtype
[, dataregister:qualifiedtype]...

ASSUME register:ERROR [, register:ERROR]...

ASSUME [register:]NOTHING [, register:NOTHING]...

Description
A general-purpose directive that allows the assembler to determine offsets, select the correct segment register, and verify certain register use assumptions at assembly.

The "ASSUME segregister:seglocation" syntax is used to inform the assembler of the current value of <segregister>. The assembler uses this information to calculate offsets correctly and to guard against segment selection errors. This directive does not generate code to change the value of <segregister>. The ASSUME directive is not necessary for the CS register, since CS is assumed to the current segment or group automatically. The <seglocation> can be any segment or group name, or an equivalent expression.

The "ASSUME dataregister:type" syntax informs the assembler that <dataregister> is subject to the constraints of <type>. If an assumed register is used incorrectly, the assembler generates an error. The <type> parameter must be the same size as <dataregister>.

ASSUME bx:WORD mov ax, [bx]            ; Error--cannot dereference non-pointer
ASSUME bx:PTR WORD mov [bx], 10h       ;
Assumes operand size is WORD mov [bx], al ;Error--cannot move byte into word memory
ASSUME al:WORD                         ; Error--al is only byte-sized
ASSUME bx:BYTE                         ; Error--bx is word-sized

The ASSUME directive can include ERROR, FLAT, or register:type. MASM 6.1 issues a warning when you specify ASSUME values for CS other than the current segment or group.

The "ASSUME register:ERROR" syntax causes the assembler to generate an error if <register> is later used explictly or implicitly. The OPATTR, .TYPE, and TYPE directives do not cause errors when referring to registers assumed to ERROR.

The "ASSUME register:NOTHING" syntax causes the assembler to remove all assumptions about <register>. ASSUME NOTHING removes all assumptions about all registers.

Use an ASSUME statement each time you load a known value into a segment register. Although not required, the ASSUME directive helps the assembler safeguard against segment selection errors and determine offsets. You may need to use instructions to initialize segment registers properly at run time.

If you use the ASSUME directive to set assumptions about a data register, it will override any assumptions for its subregisters. For example, ASSUME EDX:DGROUP will override assumptions for DL, DH, and DX.

Parameter Description
seg register CS, DS, ES, FS, GS, or SS. The assembler automatically maintains assumptions for the CS segment register.

seg location A segment address, another segment register, a group, or FLAT. You can find the segment address of a label by using the SEG operator. FLAT is the label of the single FLAT segment.

data register Any byte, word, or 32-bit register.

qualified type Any qualified type that will fit in <dataregister>.

register Any segment or data register.


COMMENT

Syntax:

COMMENT delimiter [text]
  [text]
[text] delimiter [text]

Description
Ignores all text between delimiters or on the same line as a delimiter. The two comment delimiters can be on the same or different physical lines.

In the following code segment, the text inside the asterisks and the MOV instruction are ignored:

COMMENT * This text is ignored
          by the assembler *  mov ax, 10h

Parameter Description
delimiter First nonblank character following the COMMENT directive
text All text up to and including the line containing the next occurrence of the delimiter.


Character_negation

Syntax: !character

Description
Treats <character> as a literal character rather than as an operator or a symbol. Used with special characters (<, >, ", ', %, ;, and comma) when the usual assembly language meaning of the character must be suppressed. A double exclamation point (!!) is treated as a single exclamation point. The escape character does not apply to strings in quotation marks or to backslashes at the end of a line.

For example:

<I!'m afraid I can!'t do that!!> = I'm afraid I can't do that!

<20!% !> 15!%> = 20% > 15%


Comparison run-time operators

Operator Meaning
== Equal
!= Not equal
>  Greater than
>= Greater than or equal to
<  Less than
<= Less than or equal to
&  Bit test (format: expression & bitnumber)
!  Logical NOT
&& Logical AND
|| Logical OR
CARRY? Carry bit set
OVERFLOW? Overflow bit set
PARITY? Parity bit set
SIGN? Sign bit set
ZERO? Zero bit set

The comparison run-time operators are used to make comparisons between variables, registers, and constants as the program is being executed. Use these operators to give conditions for conditional-control directives (.IF, .UNTIL, .WHILE). These operators can be combined with other run- time operators and parentheses to form complex conditions.

The conditional-control directives (.IF, .UNTIL, .WHILE) can also check the state of processor flags. The CARRY?, OVERFLOW?, PARITY?, SIGN?, and ZERO? flags can be used directly in a C-style expression.

For example:

.IF !PARITY? || ( AX == 0 )
  ;Execute body of block if parity
  ;flag is clear or if the AX
  ;register is zero
.ENDIF

Note: The expression is evaluated from left to right, so in this example, the state of the parity flag is checked before the AX comparison.


DUP

Syntax: count DUP (initialvalue [,initialvalue]...)

Description
Specifies <count> declarations of <initialvalue>. You can define arrays, buffers, and other data structures consisting of multiple data objects of the same size with the DUP operator. The <initialvalue> parameters must be inside parentheses. This operator can be used with data definition directives.

The <count> parameter is the number of declarations of <initialvalue>. This parameter cannot be negative or forward-referenced. The <initialvalue> parameter is either the undefined data symbol (?), a string, a constant expression, or another DUP operator. The value or values of <initialvalue> are evaluated once before duplication. Separate multiple initial values with commas.


Data types

  Syntax:   [name] [S]BYTE initializer  [, initializer]...

            [name] [S]WORD initializer  [, initializer]...

            [name] [S]DWORD initializer [, initializer]...

            [name] FWORD initializer    [, initializer]...

            [name] QWORD initializer    [, initializer]...

            [name] TBYTE initializer    [, initializer]...

            [name] REAL4 initializer    [, initializer]...

            [name] REAL8 initializer    [, initializer]...

            [name] REAL10 initializer   [, initializer]...

Description
                            Integer
    Type    Abbr  Size      Range        Types Allowed
  +-------+-----+---------+------------+----------------------------------+
  | BYTE  | DB  | 1 byte  | -128 to    | Character, String                |
  |       |     |         | +255       |                                  |
  +-------+-----+---------+------------+----------------------------------+
  | WORD  | DW  | 2 bytes | -32,768 to | 16-bit near ptr, 2 characters,   |
  |       |     |         | +65,535    | double-byte character            |
  +-------+-----+---------+------------+----------------------------------+
  | DWORD | DD  | 4 bytes | -2Gig to   | 16-bit far ptr, 32-bit near ptr, |
  |       |     |         | +4Gig-1    | 32-bit long word                 |
  +-------+-----+---------+------------+----------------------------------+
  | FWORD | DF  | 6 bytes |    --      | 32-bit far pointer               |
  +-------+-----+---------+------------+----------------------------------+
  | QWORD | DQ  | 8 bytes |    --      | 64-bit long word                 |
  +-------+-----+---------+------------+----------------------------------+
  | TBYTE | DT  |10 bytes |    --      | BCD, 10-byte binary numbers      |
  +-------+-----+---------+------------+----------------------------------+
  +-------+-----+---------+------------+----------------------------------+
  | REAL4 | DD  | 4 bytes |    --      | Single-precision floating point  |
  +-------+-----+---------+------------+----------------------------------+
  | REAL8 | DQ  | 8 bytes |    --      | Double-precision floating point  |
  +-------+-----+---------+------------+----------------------------------+
  | REAL10| DT  |10 bytes |    --      | 10-byte floating point           |
  +-------+-----+---------+------------+----------------------------------+

These directives allocate and optionally initialize one or more bytes of global data. The S prefix indicates signed data, but this information is used internally by the assembler for comparisons used by control-flow directives and argument passing in INVOKE statements. CodeView also uses this information to specify the data format.

The abbreviations (such as DB, DD) are limited forms of the data-declaration directives; they cannot be used as types. They are included for compatibility with previous versions of the assembler.

String initializers, available with the BYTE directive, allocate a byte for each character of the string. The characters are stored with the leftmost character in the lowest memory location so that BYTE "WASHINGTON would be assembled to

57 41 53 48 49 4E 47 54 4F 4E "WASHINGTON"

Character initializers, however, are stored with the leftmost character in the highest memory location. They are also limited to the current expression size so that under the default OPTION EXPR32

DWORD "WASH"

would be assembled to

48 53 41 57 "HSAW"

and under OPTION EXPR16

WORD "WA"

would be assembled to

41 57 "AW"

Use the REAL4, REAL8, and REAL10 data types for floating-point data. They inform CodeView that the data is in floating-point format and cause the assembler to perform more stringent type checking.

Parameter Description
name Symbol name assigned to the variable. If no name is assigned, the memory space is allocated, but the starting address of the variable has no symbolic name.
initializer A type shown in the table above, constant integer expression, ?, or DUP expression. Separate multiple values with commas or use the DUP operator.


ECHO

Syntax: ECHO message

Description
Displays message during assembly. The message is usually output to the screen, but you can redirect it to a file or another device. This directive can help show which statements were assembled. %OUT is a synonym for ECHO and is included for compatibility.

The <message> is any line of ASCII characters up to but not including any comment on the line. If angle brackets are used to enclose <message>, the angle brackets are displayed. To perform macro substitution, put the macro substitution operator (%) at the beginning of the line. Use a separate ECHO directive for each line.

To output the time and date of assembly, insert this line in your source code:

% ECHO Assembled on @Date at @Time


END

Syntax: END [address]

Description
Marks the end of a source file and optionally indicates the program load address. The optional <address> is a label or expression identifying where program execution begins. You can define <address> only once in a program, usually in the main module.

You cannot specify <address> if you have used the .STARTUP directive, which automatically sets a start address. If you are linking with a high-level language, the start address is typically set by that language's compiler.

END also closes the last segment in the source file.


ENDS

Syntax: name ENDS

Description
Marks the end of a segment or a structure definition previously started with SEGMENT, STRUCT, or UNION. To end a simplified segment (such as one started with .DATA), use the line

@CurSeg ENDS ;End current segment

A single .STACK statement opens and closes the stack segment, so you should not include an additional ENDS statement.


EQU

Syntax: EQU TEXTEQU

 Syntax: name EQU expression

name EQU <text>
name TEXTEQU textmacro
name TEXTEQU %expression

Description
The EQU directive assigns <expression> or <text> to <name>. Angle brackets indicate that <text> should not be evaluated as an expression.

EQU evaluates the numeric value of <expression> and assigns the resulting constant value to <name>. Unlike =, EQU does not allow numeric equates to be redefined. If <expression> cannot be evaluated, EQU treats <expression> as text.

The TEXTEQU directive acts like the EQU directive with text equates but performs macro substitution at assembly and does not require angle brackets. The TEXTEQU directive will also resolve the value of an expression preceded by a percent sign (%). The EQU directive does not perform macro substitution or expression evaluation for strings.

Text equates are limited to 255 characters. Text equates can be redefined to another value but not to a different type of symbol.

Parameter Description
name Symbolic name for <expression> or <text>

expression Variable or constant numeric expression (not a memory expression)

text String enclosed in angle brackets (<>)

textmacro A text macro (such as @Date) or a string enclosed in angle brackets (<>).

expression An expression preceded by a %.

Example
MASM EQU 5.1 + 0.9     ; Evaluates to 6.0
Msft EQU <Microsoft>   ; String equate
libpath TEXTEQU @Environ(<LIB>) ; Text Macro Equate
endstr TEXTEQU %(endadr-staradr); String equate to numeric value


EXTERNDEF

Syntax: EXTERNDEF [langtype] name:qualifiedtype
[, [langtype] name:qualifiedtype]...

EXTERN [langtype] name[(altID)]:qualifiedtype
[, [langtype] name[(altID)]:qualifiedtype]...

Description
The EXTERNDEF directive tells the assembler that one or more variables, symbols, data structures, or labels are defined in other modules. The behavior of the EXTERNDEF directive is determined by its context:

* If <name> is used in the current module but is not defined, <name> is made external. * If <name> is defined in the current module, it is made PUBLIC. * If <name> is neither used nor defined, the directive is ignored.

The EXTERNDEF directive allows you to put global data declarations in an include file without forcing the linker to pull in unneeded modules. Usually, you define <name> in one module and put the EXTERNDEF directive in a file that is included in all program modules. The PROTO directive automatically generates an EXTERNDEF for its related procedure.

EXTERN is a less flexible version of EXTERNDEF. It declares <name> as external whether or not it is used in the module. EXTRN is a synonym for EXTERN and is included for compatibility with previous versions of the assembler.

With the EXTERN directive, <name> can be followed by (altID), which allows the linker to select an alternate resolution for <name>. This is useful when creating library files.

Parameter Description
langtype A language type appropriate to <name>.

name A unique global symbolic name. Case mapping is overridden by OPTION CASEMAP.

qualifiedtype The qualified type to be given to <name>. Can also be ABS, which causes <name> to be imported as a constant. Does not have to match type given to <name> in original definition.

altID A unique global symbolic name to use as an alternate for <name>. Must be of the same type as <name>. The <altID> parameter cannot be declared as a <name> with an altID in an EXTERN statement in this or any other module.


Flat memory model

The flat memory model creates a program that contains one 32-bit segment for program data and program code. The code generated with the flat-model option will run only on 80386/486 processors. A .386 or .486 processor directive must precede the .MODEL directive that specifies the flat memory model.

This memory model causes the assembler to produce files with the .EXE extension.

All segment registers are automatically set to the same value with this memory model. The defaults in flat-model programs are NEAR code addressing and NEAR data addressing. The PROC distance is NEAR under the flat-model option. @CodeSize is 0, @DataSize is 0, and @Model is 7.

The FS and GS segment registers are not needed for flat-model programs. The .MODEL FLAT statement automatically generates this assumption:

ASSUME cs:FLAT, ds:FLAT, ss:FLAT, es:FLAT, fs:ERROR, gs:ERROR

When defining segments with the SEGMENT directive, you should use this ASSUME in your code.


HIGH

HIGH LOW

Syntax: HIGH expression
LOW expression

Description
The HIGH operator returns the high-order (most significant) byte of [expression] in two's-complement form. The LOW operator returns the low-order (least significant) byte of [expression] in two's- complement form. The [expression] must resolve to a constant or an OFFSET expression.


HIGHWORD

HIGHWORD LOWWORD

Syntax: HIGHWORD expression
LOWWORD expression

Description
The HIGHWORD operator returns the high-order (most significant) word of <expression> in two's-complement form. The LOWWORD operator returns the low-order (least significant) word of <expression> in two's- complement form. The <expression> must resolve to a constant or an OFFSET expression.


INCLUDE

Syntax: INCLUDE filename

INCLUDE <filename>

Description
Inserts source code from <filename> into the current source file during assembly. If <filename> does not include a fully-specified path, the assembler searches the directory of the current file, the /I command-line include path or the PWB include path, and then the INCLUDE environment variable. Nested INCLUDE directives are allowed.

The <filename> parameter is an existing file containing valid assembly-language statements and directives. No default file extension is assumed. Angle brackets are required if the filename or path includes a backslash, semicolon, greater-than, less-than, single quotation marks, or double quotation marks.


INCLUDELIB

Syntax: INCLUDELIB libraryname

INCLUDELIB <libraryname>

Description
Informs the linker that the current module should be linked with the <libraryname>. If <path> is not given, the linker searches the current working directory, directories given in the ML or LINK library field, and then the LIB environment variable from the TOOLS.INI file.

The <libraryname> parameter is an existing file containing code in LIB format. If no extension is specified, the default extension .LIB is assumed. Angle brackets are required if the libraryname or path includes a backslash, semicolon, greater-than, less-than, single quotation marks, or double quotation marks.


invoke

Syntax: INVOKE expression [,arguments]

Description
Automates the call interface to stack-based procedures. Handles all pushing of parameters onto the stack. Cleans up the stack when the procedure returns.

The <invokelist> is passed to the procedure according to the types given in that procedure's prototype. If necessary, the assembler will generate code to convert the elements of <invokelist> to the types specified in the prototype.

Parameter Description
expression Expression yielding address or label of procedure to be called. Must resolve to a valid address and cannot include any forward references.

arguments Sequential list of parameters passed. Can be register::register (for a register pair), expression, or ADDR label. ADDR label passes the address of <label> (segment and offset if DWORD, segment only if WORD) to the procedure.


LABEL

Syntax: name LABEL qualifiedtype

Description
Creates a new label of a given type at a specified location by assigning the current location-counter value and the given type to <name>. The <qualifiedtype> parameter determines the type of data or call distance for the label. This directive does not allocate data.

Parameter Description
name Symbol assigned to the label.
qualifiedtype Any qualified type.


LENGTHOF

Size operators

LENGTHOF variable

SIZEOF variable

SIZEOF type

LENGTH expression

SIZE expression

Description

The LENGTHOF operator returns the number of data items allocated for <variable>. The SIZEOF operator returns the total number of bytes allocated for <variable> or the size of <type> in bytes. For variables, SIZEOF is equal to the value of LENGTHOF times the number of bytes in each element.

The LENGTH and SIZE operators are allowed for compatibility with previous versions of the assembler. When applied to a data label, the LENGTH operator returns the number of elements created by the DUP operator; otherwise it returns 1. When applied to a data label, the SIZE operator returns the number of bytes allocated by the first initializer at the <variable> label.

The LENGTHOF and SIZEOF operators in MASM 6.1 handle arrays much more consistently. These operators return the number of data items and the number of bytes in an initializer.


LOCAL

Syntax: LOCAL name [[count]][:qualifiedtype] [, name [[count]] [:qualifiedtype]]...

Description
Generates code to create one or more stack (automatic) variables, which can be accessed only within the current procedure. The assembler uses the same method used by high-level languages to create local variables.

The <name> parameter is the name of the variable, and <count> is an optional expression (which must appear in square brackets) indicating the number of elements to allocate. The <qualifiedtype> parameter is any qualified type appropriate to <name>. The default <qualifiedtype> is WORD in a 16-bit segment and DWORD in a 32-bit segment.

Once declared in a LOCAL statement, local variables can be referred to by name. The assembler translates references to these variables into references to their actual location on the stack using the BP indirect addressing mode.

The assembler will generate an error if you have already defined <name> as a label.

Example
LOCAL array[20]:BYTE


LROFFSET

Syntax: LROFFSET expression

Description
Similar to OFFSET, but causes the offset to be resolved by the loader at run time. LROFFSET is usually applied to the offset of a function pointer. This run-time resolution allows Microsoft Windows to relocate code segments in real mode.

The <expression> is any label, variable, or other direct memory operand.

Example
INVOKE CreateRoutine, LROFFSET MyFunc, 0


Line continuation

Line Continuation
  Syntax: text \
text

Description
Enables an assembly-language statement to continue on the next line, ignoring the line break. You can join any number of physical lines with this method. A backslash occurring inside a comment or string is not considered to be a line-continuation character. Logical lines cannot exceed a total of 512 characters.

Comments can appear to the right of the \. A backslash is not required on a line ending with a comma.


Local code labels

Syntax: [instruction] @F
.
.
.
@@: [statement]
.
.
.
[instruction] @B

Description
The @@: label defines a local code label, which is in effect until the next instance of @@:. The @F and @B operands can be used in conditional and unconditional jump statements to jump to the next and previous @@: label respectively.

The @@: label is useful for defining a nearby jump point where a full label is not appropriate.

Example
cmp ax, 18h
jg @F
-            ; Less than or equal
-
-
@@:          ; Greater than

mov cx, 640  ; Set count

@@:
-            ; Loop statements
-
-
loop @B      ; Loop back


Location Counter $

Syntax: $

Description
Equates to the current value of the location counter (current offset address). Equivalent to THIS NEAR.

Example
title BYTE "Space Mutants II"
level WORD 0
hiscore BYTE 20 DUP (?)
tablelen EQU $-title ;tablelen = 38

In compatibility mode, the current address operator ($) applied to a structure returns the offset of the first byte of the structure. When OPTION M510 is not enabled, $ returns the offset of the current field in the structure.


Logical operators

Syntax: expression1 AND expression2

expression1 OR expression2

expression1 XOR expression2

NOT expression

expression SHL count

expression SHR count

Description
These operators perform logical manipulations of constant integer expressions. They return expressions of the size determined by the current expression size. Use the LOW and LOWWORD operators to return expressions of smaller sizes.

These operators should not be confused with their instruction counterparts. Operators cannot act on registers or memory.

Operand Description
expression Any constant integer expression in any valid radix.
count The number of bits to be shifted. Must be a constant positive integer. Bits shifted in are always 0.


MASK

Syntax: MASK record

MASK recordfieldname

Description
Returns a bit mask for the bit positions in a record or record field. A bit in the mask contains a 1 if that bit corresponds to a field bit. All other bits contain 0.

The <record> parameter is the name of any record. The <recordfieldname> parameter is the name of any field in a record.


Macro expression

Syntax: %expression

Description
Computes the value of <expression> and treats it as a text string. Use in macro calls when you need to pass the result of an expression rather than the actual expression to a macro. The <expression> can also be a text macro or a macro function.

When placed at the beginning of the line, % causes the calculation and substitution of all text macros on that line, including those inside angle brackets (<>). Macro function calls inside angle brackets (<>) are not expanded unless preceded by a %.


Memory model

Your choice of a memory model determines how memory is set up for program code and data. The following table shows attributes of the different memory models. Select a memory model for more information.

         Code      Data      Segment  Data and Code
              Distance  Distance  Width    Combined?
             +---------+---------+--------+-------------+
     Tiny    | NEAR    | NEAR    | 16-bit | Yes         |

             +---------+---------+--------+-------------+
     Small   | NEAR    | NEAR    | 16-bit | No          |
             +---------+---------+--------+-------------+
     Compact | NEAR    | FAR     | 16-bit | No          |
             +---------+---------+--------+-------------+
     Medium  | FAR     | NEAR    | 16-bit | No          |
             +---------+---------+--------+-------------+
     Large   | FAR     | FAR     | 16-bit | No          |
             +---------+---------+--------+-------------+

     Huge    | FAR     | FAR     | 16-bit | No          |
             +---------+---------+--------+-------------+
     Flat    | NEAR    | NEAR    | 32-bit | Yes         |
             +---------+---------+--------+-------------+

The OPTION SEGMENT and SEGMENT directives can override the default segment width.


Name Assignment

Syntax: name = expression

Description
Creates or redefines a constant symbol by assigning the numeric value of [expression] to [name]. This equate can be used in subsequent statements as a symbolic constant and can be redefined at any time.

The [name] field must be either a unique name or one previously defined with =. The [expression] fieldis any valid constant expression. Resolved at definition by the assembler.


OFFSET

Syntax: OFFSET expression

Description
Returns offset address of <expression> (usually a variable). The value returned by the OFFSET operator is an immediate operand. OFFSET can be applied to any immediate or memory expression except a register or segment.

The offset returned is relative to either the current group or segment. If there is both a current group and a current segment, the offset will have a group-relative default offset. This default can be changed with the M510 and OFFSET: options.

The OFFSET operator can accept an expression specifying a segment. In this case, the OFFSET operator returns the offset of the last byte of the given segment, relative to that segment's group. This value reflects the size of the given segment when the OFFSET operator is assembled.

The <expression> is any label, variable, segment, or other direct memory operand.


OPATTR

Syntax: OPATTR expression

.TYPE expression

Description
The OPATTR operator returns a one-word constant defining the mode and scope of expression. If <expression> is not valid or is forward- referenced, OPATTR returns a 0. If <expression> is valid, a nonrelocatable word is returned. The .TYPE operator returns only the low byte (bits 0-7) of the OPATTR operator and is included for compatibility with previous versions of the assembler.

Bit Set If
Position <expression>

0 References a code label
1 Is a memory expression or has a relocatable data
label
2 Is an immediate expression
3 Uses direct memory addressing
4 Is a register expression
5 References no undefined symbols and is without error
6 Is an SS-relative memory expression
7 References an external label
8-10 Language type:

Bits Language

000 No language type
001 C
010 SYSCALL
011 STDCALL
100 Pascal
101 FORTRAN
110 Basic

All other bits (11-15) are undefined and reserved for future expansion.


OPTION CASEMAP

Syntax: OPTION CASEMAP:maptype

Description
Controls the mapping of characters to uppercase. The <maptype> parameter can be ALL, NONE, or NOTPUBLIC, which correspond to the /Cu, /Cp, and /Cx command-line options. You can use this option only once per source file. The current language type, if any, will override <maptype>.

CASEMAP:NOTPUBLIC is the default. The CASEMAP option is set to ALL with the M510 option.


OPTION DOTNAME

Syntax: OPTION DOTNAME

OPTION NODOTNAME

Description
The DOTNAME option enables the use of the period (.) as the leading character in variable, label, macro, struct, union, and member names. NODOTNAME is the default. The DOTNAME option is enabled with the M510 option, since previous versions of the assembler recognized names with period prefixes.

The DOTNAME option does not have any effect on any of the reserved words. The use of the period in names is discouraged, as it can be confused with the field offset and structure operators.

If you don't want to use this directive in your source code, rename the identifiers whose names begin with a period.


OPTION EMULATOR

Syntax: OPTION EMULATOR
OPTION NOEMULATOR

Description
Controls how floating-point instructions are generated. NOEMULATOR, the default, generates the coprocessor instructions directly. EMULATOR generates instructions as well as special fixup records for the linker so that the floating-point emulator can be used. This option is definable only once per source file.

To use this option, you must link your assembly-language module with an emulator library from a Microsoft high-level language.

OPTION EMULATOR is equivalent to the /FPi command-line option.


OPTION EXPR16

Syntax: OPTION EXPR16

Description
The EXPR32 option selects 32-bit expressions and arithmetic. The EXPR16 option selects 16-bit expressions and arithmetic. The default is EXPR32. The expression word size cannot be changed once it has been explicitly set.

These options do not affect the processor type, segment size, or registers used.

Under OPTION M510, EXPR16 is the default unless the module contains a .386 or greater processor-selection directive.

MASM 5.1 treats expressions as 16-bit words if you do not specify .386 or .386P directives. MASM 6.1 by default treats expressions as 32-bit words regardless of the CPU type. You can force MASM 6.1 to use the smaller expression size with the OPTION EXPR16 statement.

Unless your MASM 5.1 code specifies .386 or .386P, OPTION M510 also sets 16-bit expression size. You can selectively disable this by following OPTION M510 with the OPTION EXPR32 directive, which sets the size back to 32 bits. You cannot have both OPTION EXPR32 and OPTION EXPR16 in your program.

It may not be easy to determine the effect of changing from 16-bit inter- nal expression size to 32-bit size. In most cases, the 32-bit word size does not affect the MASM 5.1 code. However, problems may arise because of differences in intermediate values during evaluation of expressions. You can compare the files for differences by generating listing files with the /Fl and /Sa command-line options with and without OPTION EXPR16


OPTION LANGUAGE

Syntax: OPTION LANGUAGE:langtype

Description
Specifies the default language type to be used with many directives. The most recent OPTION LANGUAGE: or .MODEL directive determines the current language type. The <langtype> parameter is any language type.


OPTION LJMP

Syntax: OPTION LJMP

OPTION NOLJMP

Description
The LJMP option enables automatic conditional-jump lengthening. LJMP is the default.

Enabling LJMP allows the assembler to generate code that emulates a conditional jump of greater than -128 to +127 bytes. If the jump is within this range, no special code is generated. It does not affect unconditional jumps or the control-flow directives.

The assembler will generate an A6003 warning for a lengthened jump so that you can identify it for later optimization.


OPTION NOKEYWORD

Syntax: OPTION NOKEYWORD:<keywordlist>

Description
Disables the recognition of the reserved words in <keywordlist> for the current module. The listed keywords can then be used as user-defined symbols. Keywords disabled with this directive cannot be reenabled. The <keywordlist> is a space-delimited list of reserved words; literal operands and predefined symbols are not allowed. The list of keywords must be enclosed in angle brackets (<>).

You can use this option to disable privileged instruction names or obsolete synonyms so they are free to be used as labels and variables. For example:

OPTION NOKEYWORD: <STR EXTRN IRPC>
STR BYTE 10 DUP (?)

MASM 6.1 has several new keywords that MASM 5.1 does not recognize as reserved. To resolve any conflicts, you can rename any offending symbols in your code, or selectively disable keywords with the OPTION NOKEYWORD directive.

The second option lets you retain the offending symbol names in your code by forcing MASM 6.1 to not recognize them as keywords. For example,

OPTION NOKEYWORD:<INVOKE STRUCT>

removes the keywords INVOKE and STRUCT from the assembler's list of reserved words. However, you cannot then use the keywords in their intended function, since the assembler will no longer recognize them.


OPTION NOSIGNEXTEND

Syntax: OPTION NOSIGNEXTEND

Description
The NOSIGNEXTEND option disables the generation of the sign- extended form (83h) of the AND, OR, and XOR instructions. The NEC V25 and V35 microprocessors do not support this opcode.


OPTION OFFSET

Syntax: OPTION OFFSET:offsettype

Description
Controls whether the OFFSET operator returns offsets relative to the current segment or group. OPTION OFFSET:GROUP causes OFFSET to return a group-relative offset if the label is in a segment that is part of a group. OPTION OFFSET:SEGMENT causes OFFSET to return a segment-relative offset. OPTION OFFSET:GROUP is the default.

The FLAT option causes fixups to be relative to the FLAT group.

OPTION M510 sets OPTION OFFSET:GROUP if a .MODEL directive has been used and OPTION OFFSET:SEGMENT otherwise. With previous versions of the assembler, the OFFSET type was SEGMENT with complete segment directives and GROUP with simplified segment directives.

The <offsettype> can be GROUP, SEGMENT, or FLAT.

When programming for the 80386 or 80486, the size of an OFFSET expression can be 2 bytes for a symbol in a USE16 segment, or 4 bytes for a symbol in a USE32 or FLAT segment. With OPTION M510, you can use a 32-bit OFFSET expression in a 16-bit context. Without OPTION M510, you must use the LOWWORD operator to convert the offset size.

With no .MODEL, MASM 5.1 computes offsets from the start of the segment, whereas MASM 6.1 computes offsets from the start of the group. (With .MODEL, MASM 5.1 also computes offsets from the start of the group.)

To force MASM 6.1 to emulate 5.1 behavior, specify either OFFSET:SEGMENT or OPTION M510. Both directives cause the assembler to compute offsets relative to the segment if you do not include .MODEL.

To selectively enable MASM 6.1 behavior, place the directive OPTION OFFSET:GROUP after OPTION M510. In this case, you should ensure each OFFSET statement has a segment override where appropriate.

When not in compatibility mode, the OPTION OFFSET directive determines whether the SEG operator returns a value relative to the group or segment. With OPTION M510, SEG is always segment-relative by default, regardless of the current value of OPTION OFFSET.


OPTION PROC

Syntax: OPTION PROC:visibility

Description
Sets the default procedure visibilty. The <visibility> parameter can be PRIVATE, PUBLIC, or EXPORT. If you do not use this option, the the default visibility will be PUBLIC.

With OPTION M510, the default <visibility> with no defined language type is PRIVATE. If you specify a language type in a .MODEL or OPTION LANGUAGE statement, the default <visibility> is PUBLIC.

Without a language type, MASM 5.1 makes procedures private to the module. By default, MASM 6.1 makes procedures public. You can explicitly change the default visibility to private with either OPTION M510, OPTION PROC:PRIVATE, or OPTION PROC:EXPORT.

To selectively enable MASM 6.1 behavior, place the directive OPTION PROC:PUBLIC after OPTION M510. You can override the default by adding the PUBLIC or PRIVATE keyword to selected procedures.


OPTION PROLOGUE

Syntax: OPTION PROLOGUE:macroname

OPTION EPILOGUE:macroname

Description
PROLOGUE registers <macroname> as the macro function to be called when a prologue needs to be generated. EPILOGUE registers <macroname> as the macro procedure to be called when a RET or IRET instruction is encountered.

You can revert to the default prologue or epilogue by specifying PrologueDef or EpilogueDef as <macroname>. EPILOGUE code is generated only if the RET or IRET instruction terminating the PROC block has no operand. The RETN, RETF, and IRETF instructions do not cause the assembler to generate epilogue code.

To suppress generation of the prologue or epilogue code, give NONE as the <macroname>.

The assembler expects a macro definition of this form:

macroname MACRO procname, flags, argbytes, localbytes, <reglist>, userparms:VARARG

Parameter Description
procname Macro name for the procedure or NONE.

flags Word-size bit flag: (1=On, 0=Off)

Bits Description
0-2 Language type:
000 Not specified
001 C
010 SYSCALL
011 STDCALL
100 Pascal
101 Fortran
110 Basic
111 Reserved
3 Reserved
4 Caller restores stack
5 FAR procedure
6 PRIVATE procedure
7 EXPORT procedure
8 Epilogue caused by IRET instruction

All other bits are reserved for future use.
argbytes The total number of bytes used by PROC arguments.

localbytes The total number of bytes used by variables defined with the LOCAL directive inside the PROC block.

reglist Comma-delimited list of registers from the PROC directive USE option. This list is reversed in in the EPILOGUE directive. Angle brackets are passed.

userparms Passed the optional macroarglist from the PROC directive.


OPTION READONLY

Syntax: OPTION READONLY

OPTION NOREADONLY

Description
The READONLY option sets the READONLY attribute for subsequent code segments. Enables checking for instructions that explicitly modify segments or groups containing code. Useful for detecting self- modifying code. NOREADONLY is the default.

This option replaces the command-line /P option from previous versions of the assembler. Segments can be also be made read- only with the READONLY parameter of the SEGMENT directive.


OPTION SCOPED

Syntax: OPTION SCOPED

OPTION NOSCOPED

Description
The SCOPED option causes a label (defined with the "label:" syntax) to be local to the procedure in which it is defined. Labels defined with the LABEL directive or the "label::" syntax are not affected by this option.

Using NOSCOPED will cause all labels to be global to the module. SCOPED is the default. The NOSCOPED option is enabled with the M510 option, if the .MODEL directive is used without a language type specification. Specifying .MODEL with a language type enables OPTION SCOPED.

Without a language type, MASM 5.1 assumes code labels in procedures have no scope--that is, the labels are not local to the procedure. When not in compatibility mode, MASM 6.1 always gives scope to code labels, even without a language type.

To force MASM 5.1 behavior, specify either OPTION M510 or OPTION NOSCOPED in your code. To selectively enable MASM 6.1 behavior, place the dir- ective OPTION SCOPED after OPTION M510.

To determine which labels require change, assemble the module without the OPTION NOSCOPED directive. For each reference to a label that is not local, the assembler generates error A2006.


OPTION SEGMENT

Syntax: OPTION SEGMENT:segmentsize

Description
The SEGMENT:USE16 option selects 16-bit segments. The SEGMENT:USE32 option selects 32-bit segments. The SEGMENT:FLAT option selects the 32-bit flat segment. This option overrides the segment size set optionally set by the SEGMENT and .MODEL directives.

The default segment size is selected by the following rules:

* A .386 or higher processor selection directive selects USE32.

* A .MODEL FLAT statement selects FLAT. All other memory models select USE16.

* The OPTION SEGMENT: directive will override any other defaults.

* In all other cases, the default is USE16.


ORG

Syntax: ORG expression

ORG $+expression

Description
Sets the location counter to a specific address, given by <expression>. The assembler implements this directive by adjusting the location counter.

ORG $+expression causes the assembler add <expression> bytes to the location counter. The <expression> must evaluate to a constant without forward references.

Inside a STRUCT block, the <expression> parameter is relative to the beginning of the structure. This can be used to create structure elements that refer to bytes lower in memory than the beginning of the structure.


PROC

Syntax: label PROC [distance] [langtype] [visibility]
[<prologuearg>]
[USES reglist] [,parameter [:tag]]...
[LOCAL varlist]
statements
label ENDP

Description
Defines a procedure called <label>. To use <parameter>, you must have previously specified a language type or used the <langtype> parameter. You should use a PROTO prototype before each procedure defined with the PROC directive. This ensures proper type checking and allows you to call the procedure with the INVOKE directive.

Procedures usually end with the RET instruction. You can remove data from the stack by specifying the number of bytes as a parameter of the RET instruction.

The assembler automatically generates PROLOGUE and EPILOGUE code to pass stack arguments properly to the procedure and clean up the stack after completion of the procedure. You can override the default prologue and epilogue code with user-defined macros by using the OPTION PROLOGUE: and OPTION EPILOGUE: directives. The RETF or IRETF instructions do not cause the assembler to generate epilogue code.

Procedures can be nested if they do not have parameters, local variables or the USES parameter and do not generate a new segment or group. You can avoid having to nest procedures by using the RETN and RETF instructions.

Local variables must be declared (using the LOCAL directive) before any instructions. There can be several LOCAL statements in a procedure.

Parameter Description

label Defines name for the procedure. Follows naming convention of <langtype>.

prologuearg Arguments to pass to the prologue procedure. With the default PROLOGUE and EPILOGUE, the FORCEFRAME argument generates a stack segment, even if one is not necessary. LOADDS causes the DS register to be saved in the PROLOGUE and restored in the EPILOGUE. Parameters must be separated by commas. Angle brackets are required but not passed.

distance NEAR, FAR, NEAR16, NEAR32, FAR16, or FAR32. Indicates the call distance of this procedure. If you choose NEAR or FAR, the assembler will select 16- or 32-bit NEAR or FAR depending on the current segment size. If you do not specify this option, the assembler determines the distance from the memory model and processor type. NEAR is the default if you do not use the .MODEL directive.

langtype Any valid language type. Determines naming style and calling convention.

visibility PRIVATE, PUBLIC, or EXPORT. Determines how the procedure is made available to other modules. PUBLIC is the standard default, but the default can be reset with the OPTION PROC directive. EXPORT implies PUBLIC and FAR and informs the linker that the procedure should be placed in the export entry table.

reglist List of registers that the prologue preserves on the stack and the epilogue restores on exit. Separate multiple registers with spaces.

parameter Procedure parameter. The assembler translates argument references into a direct reference to the stack location. Separate multiple arguments with commas.

tag Either a qualified type or VARARG. VARARG allows a variable number of arguments to be passed as a comma separated list to <argument>. If VARARG is used, it must be applied to the last parameter of the PROC directive. VARARG is only allowed with the C, SYSCALL, and STDCALL language types. If <tag> is omitted, the assembler defaults to WORD in a 16-bit segment or DWORD in a 32-bit segment.

statements Assembly-language statements and directives.


PROTO

Syntax: label PROTO [distance] [langtype] [, [parameter]:tag]...

Description
Defines a prototype for a subsequent procedure. Informs the assembler about how many and what kind of arguments should be expected in a procedure definition. This allows the assembler to perform type checking on arguments.

If you define a prototype for all stack-based procedures defined with the PROC directive, you can place procedure prototypes in a separate include file. This is recommended when using procedures in a library file.

Parameter Description
label Defines name for the procedure. Must exactly match <label> in PROC definition.

distance NEAR, FAR, NEAR16, NEAR32, FAR16, or FAR32. Indicates the call distance of this procedure. If you choose NEAR or FAR, the assembler will select 16- or 32-bit NEAR and FAR depending on the processor directive in effect. If you do not specify this option, the assembler determines the distance from the memory model and processor type. NEAR is the default if you do not use the .MODEL directive.

langtype Any valid language type. Determines naming style and calling convention.

parameter Procedure parameter. The assembler translates argument references into a direct reference to the stack location. Separate multiple arguments with commas.

tag Either a qualified type or VARARG. VARARG allows a variable number of arguments to be passed as a comma separated list to <argument>. If VARARG is used, it must be applied to the last parameter of the PROC directive. VARARG is only allowed with the C, SYSCALL, and STDCALL language types.


PTR

Syntax: qualifiedtype PTR expression
PTR qualifiedtype

Description
The first syntax treats <expression> as having the specified type. Type casting can be used with forward references or unlabeled addresses to specify a reference size, type, or distance.

The second syntax is used in defining qualified types.

The PTR keyword can also appear in qualified types to indicate that the type is a pointer variable.

The <qualifiedtype> can be any qualified type. The <expression> can be any valid expression. If <qualifiedtype> is a distance, <expression> cannot be a memory expresssion or a data label.

You can use a constant as the left operand to PTR in compatibility mode. Otherwise, you must use a type expression. With OPTION M510, a constant must have a value of 1 (BYTE), 2 (WORD), 4 (DWORD), 6 (FWORD), 8 (QWORD) or 10 (TBYTE). The assembler treats the constant as the parenthesized type. Note that the TYPE operator yields a type expression, but the SIZE operator yields a constant.

; With OPTION M510

    MyData  DW      0

    mov     WORD PTR [bx], 10           ; Legal
    mov     (TYPE MyData) PTR [bx], 10  ; Legal
    mov     (SIZE MyData) PTR [bx], 10  ; Legal
    mov     2 ptr [bx], 10              ; Legal

; Without OPTION M510

    MyData  WORD    0

    mov     WORD PTR [bx], 10           ; Legal
    mov     (TYPE MyData) PTR [bx], 10  ; Legal
;    mov     (SIZE MyData) PTR [bx], 10  ; Illegal
;    mov     2 PTR [bx], 10              ; Illegal
Example
mov        ax, (MyStruct PTR [bx]).Username
fld        TBYTE PTR MaxConvolution
INVOKE     MyRoutine, PTR TempValue

Under MASM 5.1, applying the PTR operator to a data initializer de- termines the size of the data displayed by CodeView. You can still use PTR in this manner in MASM 6.1, but it does not affect CodeView typing. Defining pointers with the TYPEDEF directive allows CodeView to generate correct information.


PUBLIC

Syntax: PUBLIC [langtype] name [,[langtype] name]...

Description
Makes one or more variables available to other modules in the program. PUBLIC names can be forward referenced.

The following can be made PUBLIC:

* NEAR and FAR code labels and procedures
* Data created with user-defined types, BYTE, WORD, and other types
* Data created with user-defined structures, unions, and records
* Labels created with the LABEL directive
* Symbolic constants created with EQU or =

The PUBLIC directive is normally used with the EXTERN directive. The EXTERNDEF and COMM directives allow more flexibility in global data declaration than the PUBLIC and EXTERN directives. One use is illustrated below.

                  +----------------------------------+
                  |                                  |
     +-USER.ASM---+-----------+        +-TOOLS.ASM---+----------+
     |                        |        |                        |
     | EXTERN global:WORD     |        |         PUBLIC  Global |
     |                        |        | Global  WORD    5      |
     +------------------------+        +------------------------+

Parameter Description

langtype Any language type. Used to control what format label names are sent to the linker.
name The name of a variable, label, or numeric equate defined within the current source file.


PURGE

Syntax: PURGE macroname [, macroname]...

Description
Deletes one or more currently defined macros from memory. Use this directive if your system does not have enough memory to keep all the macros needed for a source file in memory at the same time. The macro skeleton will remain, but it will not expand.

A macro can remove itself if PURGE is on the last line of the macro. Redefining a macro automatically purges the previous definition. Calling a purged macro is legal, but the macro will act like a blank macro.


RECORD

Syntax: recordname RECORD field [, field]...

Description
Declares a record template of one or more specified bit fields but does not allocate storage for the template. Separate multiple fields with a comma.

Records can be used as constants or expressions. They are treated as a BYTE or WORD with 16-bit expressions and as a BYTE, WORD, or DWORD with 32-bit expressions. The sum of the widths for all fields must not exceed the expression width.

Once a record template is declared, you can use it to define record variables or constants, in which each field not initialized assumes the default value. Records are defined with the following syntaxes:

[name1] recordname {[initializer1] [, initializer2]...}
[name1] recordname <[initializer1] [, initializer2]...>

Use of <recordname> is similar to the other variable definition directives (such as BYTE and WORD). Curly braces or angle brackets are required even if no initializers are given.

If a record constant appears as part of an expression in a control flow directive (such as .IF or .WHILE), you must use curly braces instead of angle brackets to enclose the fields.

The assembler will treat the name of a record field without the MASK or WIDTH operators as the bit number of the first bit of the record field.

Parameter Description

recordname A unique symbolic name.

field Each field is in the form

fieldname:width[= expression]

where <width> is a constant giving the width of the field (in bits) and <expression> optionally sets an initial or default value.


RADIX SPECIFIERS
Name          Base   Specifier  Digits

Binary           2   Y or B     0 1
Octal            8   Q or O     0 1 2 3 4 5 6 7
Decimal         10   T or D     0 1 2 3 4 5 6 7 8 9
Hexadecimal     16   H          0 1 2 3 4 5 6 7 8 9 A B C D E F
Floating- point 10   R          0 1 2 3 4 5 6 7 8 9 . E + -

To indicate the radix of a constant, place the specifier at the end of the number. Specifiers and hexadecimal digits can be uppercase or lowercase.

Hexadecimal numbers must always start with a decimal digit (0-9). If the first digit is one of the letters A to F, prefix the number with a leading 0 to distinguish it from a symbolic name.

If the current default radix, specified by the .RADIX directive, is 10 or less, B and D are treated as radix overrides. B and D are treated as hexadecimal digits if the default radix is above 11 or above 13, respectively.

Floating-point constants may be used as initializers only with the REAL4, REAL8, REAL10, DWORD, QWORD, and TBYTE directives. Floating- point constants can be represented with an optional exponent or a decimal point.

Example

INVOKE MyRoutine, 01001010Y, 43H, 75, 0AFH
mole REAL4 6.023E+23
pi REAL8 3.1415927
Xenon REAL10 54R


SHORT

Syntax: SHORT label

Description
Forces <label> type to SHORT. Normally, the assembler selects short jumps and branches when possible, but SHORT can be used to generate an error if a short jump to <label> is not possible. It disables any automatic conditional-jump lengthening (OPTION LJMP).

Short labels can be used in JMP instructions when the distance is less than 128 bytes from the start of the next instruction. This saves a byte of memory and reduces the number of clock cycles used.


STRUCT

Syntax: name STRUCT [alignment] [, NONUNIQUE]
  fielddeclarations
name ENDS

Description
Declares a structure as a new data type. STRUC is a synonym for STRUCT and is included for compatibility.

Once a structure name is declared, you can use it to define variables in which each field not initialized assumes the default value:

  [name] structname <[initializer [, initializer]...]>
    or
  [name] structname { \
  [initializer] \
  [, initializer]... \
  }
    or
  [name] structname constant DUP ({[initializer[, initializer]...]})

Curly braces or angle brackets are required even if no initializers are given. The DUP operator can be used to make duplicate initializations. Structures may be nested.

You must refer to structure members in the format structurename.membername or with a pointer to a structure followed by the .membername tag. You can use multiple sequential membernames to specify elements of nested structures.

The NONUNIQUE parameter requies elements of the structure to be accessed only by their fully specified names.

The ORG directive has a special meaning inside a STRUCT block.

Parameter Description
name A unique symbolic name for the structure.

alignment 1, 2, or 4. Byte boundary to align structure fields. The default is 1.

fielddeclarations Any valid data definitions (using BYTE, WORD, etc.) with initial values. Can also be another previously defined structure or a user-defined type. Field names do not need to be unique; you can reuse the same name in multiple structures. Some other directives are allowed in this field; see the BNF Appendix in the MASM Programmer's Guide.

initializer Data initializer for structure field.


THIS

Syntax: THIS qualifiedtype

Description
Returns an operand of <qualifiedtype> with offset and segment values equal to the current location-counter value. THIS can be used with EQU or = to create labels and variables. THIS NEAR is equivalent to $.

These two lines are equivalent:

tag1 EQU THIS BYTE
tag1 LABEL BYTE

The <qualifiedtype> can be any qualified type.


TYPE

Syntax: TYPE expression

Description
The TYPE operator returns a value and size and distance attributes appropriate to <expression>. You can use the constant returned by TYPE directly or use the attributes returned by TYPE. For example, you can use the returned attribute to specify a type for PTR.

<expression> Returns

Variable Number of bytes allocated for each element
Structure Total number of bytes in the structure
Constant 0
Code label Distance
Register Size of register in bytes


TYPEDEF

Syntax: name TYPEDEF qualifiedtype

name TYPEDEF PROTO prototypelist

Description
Defines a new type or creates a synonym for an already defined type. The TYPEDEF directive associates <name> with a type, and, once defined, the symbol can be used anywhere a type can be used or as a data declaration directive. The <qualifiedtype> parameter can specify a pointer to a qualified type. The TYPEDEF PROTO syntax defines a prototype type.

Once a type is defined, you can use it to define variables. Use is similar to the other variable definition directives (like BYTE and WORD).

Parameter Description
qualifiedtype Any qualified type. Can include a type previously defined by a TYPEDEF directive, but recursive definitions are not allowed.
prototypelist List of parameters for procedure prototype. Uses the same syntax as the PROTO directive.


TYPEDEF Directive

Description

Use TYPEDEF to

* Define types for procedure arguments in PROC, PROTO, and INVOKE statements.

* Define types used in high-level expressions such as .IF, WHILE, and .REPEAT.

* Define pointer types so that CodeView can give appropriate information about the pointer.

* Define the types for procedure arguments in procedure prototypes.

Typical TYPEDEFS

CHAR TYPEDEF BYTE                ; Rename an existing type
PCHAR TYPEDEF PTR CHAR           ; Create a pointer type
PWORD TYPEDEF PTR WORD           ; Create a pointer type
PPWORD TYPEDEF PTR PWORD         ; Create a complex pointer type
PMYSTRUCT TYPEDEF PTR MYSTRUCT   ; Create pointer type to structure or union
PPROTO TYPEDEF PROTO \
NEAR C arg1:byte arg2:word       ; Define proc prototype
PFUNCT TYPEDEF PTR PPROTO        ; Define pointer to proc
                                 ; prototype
Typical uses of TYPEDEFs:

user CHAR "Jill"                 ; Use new type as initializer
Puser PCHAR user                 ; Initialize a pointer
task PROC myvar:PMYSTRUCT        ; Pass pointer to structure
EXTERNDEF ppw:PPWORD             ; Define external with user type
proctbl PFUNC Up, Down, Home     ; Initialize procedure table
-
-
-
INVOKE proctbl[bx], pos          ; Call procedure from table


UNION

Syntax: name UNION [alignment] [, NONUNIQUE]
  fielddeclarations
[name] ENDS

Description
Declares a union as a new data type. Allows the same memory locations to be overlapped with different types. Identical to STRUCT except that each member has a 0 offset. The size of the union is the size of the largest member of the union.

Unions can be used to store one type of data in some circumstances and another type in a different situation. Unions also allow you to store data as one data type and then read it as another. Unions are initialized by using the union name as a data declaration directive. You only need to initialize a union for one data type.

You must refer to union members by their member names. The LABEL directive allows you to refer to the entire union as a unit.

The first-level definition of a union must include the <name> label preceding the ENDS. In nested unions, terminate the block with a ENDS statement without the <name> label.

The <alignment> field determines the byte alignment of any structures. This field can be 1, 2, or 4. The default is 1, unless overridden by the /Zp command-line option or the ALIGN or EVEN directives.

The NONUNIQUE parameter allows elements of the union to be accessed only by their fully specified names.

Some directives are allowed in the <fielddeclarations> field; see the BNF Appendix in the MASM Programmer's Guide.

Example
EXTENDCHAR UNION
  ascii BYTE ?           ; Define a union of byte and
  kanji WORD ?           ; word
EXTENDCHAR ENDS

 initial EXTENDCHAR <J>   ; Create a union variable
mov al, initial.ascii    ; Move byte-length data
mov bx, initial.kanji    ; Move word-length data


USES

Syntax: USES reglist

Description
An optional keyword used with PROC. Generates code to push the value of registers that should be preserved (and that will be altered by your procedure) on the stack and pop them off when the procedure returns.

The <reglist> parameter is a list of one or more registers. Separate multiple registers with spaces.


VARARG (Proc)

VARARG

VARARG (Proc)

The VARARG attribute allows you to pass a variable number of arguments to a procedure. The VARARG parameter receives a near pointer to an array of WORD elements (DWORD if a far address is passed). You can apply the VARARG attribute only to the last parameter in a procedure definition. You can only use VARARG in procedures when the C, SYSCALL, or STDCALL language types are in effect.

addup PROTO NEAR C, parmcount:WORD, parmvalues:VARARG

    invoke addup, 3, 5, 2, 4

    addup PROC NEAR C, parmcount:WORD, parmvalues:VARARG
    xor ax, ax
    xor bx, bx
    mov cx, parmcount

    .REPEAT
      add ax, parmvalues[bx]
      inc bx
      inc bx
    .UNTILCXZ

    ret

 addup ENDP


WIDTH

Syntax: WIDTH {recordfieldname|record}

Description
Returns width (in bits) allocated for a record or record field.

The <recordfieldname> is the name of any field defined in any record. The <record> is the name of any defined record.


;text

Normal and macro end of line comments

Syntax:

;  comment text
;; macro comment text

Description
The single semicolon treats <text> to the end of the line as a comment. The double semicolon treats <text> to the end of the line as a macro comment. In a listing file, macro comments appear with the macro definition, not with the macro expansion.

Comments must follow all other fields in a statement line.


Alternate Quotes

            "text"
            'text'

Description
Treats <text> as a string. You can use single or double quotation marks, but the quotation marks on both sides of <text> must be identical. A string can be up to 255 characters long and must be on a single physical line. You can use a quotation mark inside a string by repeating it twice in a row ("" or ''). The left-hand single quotation mark (`) is not allowed as a delimiter.

Example
quote1      BYTE     "This was called by 'int 23h'"
quote2      BYTE     'This was called by "int 23h"'
quote3      BYTE     "Use the ""ASSUME"" directive"
quote4      BYTE     'Use the ''ASSUME'' directive'


Data Initialisation

  Syntax:   ?

Description

Used as an initializer in data declarations; indicates a value that the assembler allocates but does not initialize. Can be used alone or with DUP, as in the following examples:

Extension  WORD     ?           ; Allocate 1 uninitialized word
Initials   BYTE     ?,?,?       ; Allocate 3 uninitialized bytes
Fullname   BYTE     20 DUP (?)  ; Allocate 20 uninitialized bytes

To minimize the size of executable files, use the .DATA? or .FARDATA? directives to define an undefined data segment. Put undefined data in these segments.

The assembler treats the ? initializer as either zero or as an unspecified value. In compatibility mode, however, the assembler always treats the ? initializer as zero unless it is used with the DUP operator. In this case the assembler allocates space, but does not initialize it with any value.


Sommaire

BONJOUR
Musique "Invention BWV784" J.S. BACH 1685-1750

Assembleur X86

MASM32

Nous veillons aux respects des droits d'auteur : si par erreur un contenu protégé est disponible sans indication sur ce site, merci de contacter l'administrateur, il sera retiré ou mis à jour dans les plus brefs délais.


List

The following list of mnemonics are the general purpose integer instructions including those introduced for the i486. In 32 bit code this list of instructions still perform the vast majority of the work done in 32 bit x86 Intel hardware and are the most backwards compatible instructions available for 32 bit operating systems using x86 hardware. Not listed below are the floating point instructions introduced in some models of the i486. The 486DX series had FP instructions, the 486SX series did not.

Later x86 processors have the multimedia extensions instructions (MMX) and the extended multimedia extensions (XMM) which work in larger data sizes than 32 bit and some are able to perform parallel processing of certain types of data, primarily data used for video and sound hence the "multimedia" association with their usage.

AAA | ASCII Adjust After Addition
AAD | ASCII Adjust AX Before Division
AAM | ASCII Adjust AX After Multiply
AAS | ASCII Adjust AL After Subtraction
ADC | Add With Carry
ADD | Arithmetic Addition
AND | Logical And
ARPL | Adjusted Requested Privilege Level of Selector
BOUND | Array Index Bound Check (80188+)
BSF | Bit Scan Forward (386+)
BSR | Bit Scan Reverse (386+)
BSWAP | Byte Swap (486+)
BT | Bit Test (386+)
BTC | Bit Test with Compliment (386+)
BTR | Bit Test with Reset (386+)
BTS | Bit Test and Set (386+)
CALL | Procedure Call
CBW | Convert Byte to Word
CDQ | Convert Double to Quad (386+)
CLC | Clear Carry
CLD | Clear Direction Flag
CLI | Clear Interrupt Flag (disable)
CLTS | Clear Task Switched Flag (286+ privileged)
CMC | Complement Carry Flag
CMP | Compare
CMPS | Compare String (Byte, Word or Doubleword)
CMPXCHG | Compare and Exchange
CWD | Convert Word to Doubleword
CWDE | Convert Word to Extended Doubleword (386+)
DAA | Decimal Adjust for Addition
DAS | Decimal Adjust for Subtraction
DEC | Decrement
DIV | Divide
ENTER | Make Stack Frame (80188+)
ESC | Escape
HLT | Halt CPU
IDIV | Signed Integer Division
IMUL | Signed Multiply
IN | Input Byte or Word From Port
INC | Increment
INS | Input String from Port (80188+)
INT | Interrupt
INTO | Interrupt on Overflow
INVD | Invalidate Cache (486+)
INVLPG | Invalidate Translation Look-Aside Buffer Entry (486+)
IRET_IRETD | Interrupt Return
Jxx | Jump Instructions Table
JCXZ_JECXZ | Jump if Register (E)CX is Zero
JMP | Unconditional Jump
LAHF | Load Register AH From Flags
LAR | Load Access Rights (286+ protected)
LDS | Load Pointer Using DS
LEA | Load Effective Address
LEAVE | Restore Stack for Procedure Exit (80188+)
LES | Load Pointer Using E
LFS | Load Pointer Using FS (386+)
LGDT | Load Global Descriptor Table (286+ privileged)
LIDT | Load Interrupt Descriptor Table (286+ privileged)
LGS | Load Pointer Using GS (386+)
LLDT | Load Local Descriptor Table (286+ privileged)
LMSW | Load Machine Status Word (286+ privileged)
LOCK | Lock Bus
LODS | Load String (Byte, Word or Double)
LOOP | Decrement CX and Loop if CX Not Zero
LOOPE_LOOPZ | Loop While Equal / Loop While Zero
LOOPNZ_LOOPNE | Loop While Not Zero / Loop While Not Equal
LSL | Load Segment Limit (286+ protected)
LSS | Load Pointer Using SS (386+)
LTR | Load Task Register (286+ privileged)
MOV | Move Byte, Word or Dword
MOVS | Move String (Byte or Word)
MOVSX | Move with Sign Extend (386+)
MOVZX | Move with Zero Extend (386+)
MUL | Unsigned Multiply
NEG | Two's Complement Negation
NOP | No Operation (90h)
NOT | One's Compliment Negation (Logical NOT)
OR | Inclusive Logical OR
OUT | Output Data to Port
OUTS | Output String to Port (80188+)
POP | Pop Word off Stack
POPA_POPAD | Pop All Registers onto Stack (80188+)
POPF_POPFD | Pop Flags off Stack
PUSH | Push Word onto Stack
PUSHA_PUSHAD | Push All Registers onto Stack (80188+)
PUSHF_PUSHFD | Push Flags onto Stack
RCL | Rotate Through Carry Left
RCR | Rotate Through Carry Right
REP | Repeat String Operation
REPE_REPZ | Repeat Equal / Repeat Zero
REPNE_REPNZ | Repeat Not Equal / Repeat Not Zero
RET_RETF | Return From Procedure
ROL | Rotate Left
ROR | Rotate Right
SAHF | Store AH Register into FLAGS
SAL_SHL | Shift Arithmetic Left / Shift Logical Left
SAR | Shift Arithmetic Right
SBB | Subtract with Borrow/Carry
SCAS | Scan String (Byte, Word or Doubleword)
SETAE_SETNB | Set if Above or Equal / Set if Not Below (386+)
SETB_SETNAE | Set if Below / Set if Not Above or Equal (386+)
SETBE_SETNA | Set if Below or Equal / Set if Not Above (386+)
SETE_SETZ | Set if Equal / Set if Zero (386+)
SETNE_SETNZ | Set if Not Equal / Set if Not Zero (386+)
SETL_SETNGE | Set if Less / Set if Not Greater or Equal (386+)
SETGE_SETNL | Set if Greater or Equal / Set if Not Less (386+)
SETLE_SETNG | Set if Less or Equal / Set if Not greater or Equal (386+)
SETG_SETNLE | Set if Greater / Set if Not Less or Equal (386+)
SETS | Set if Signed (386+)
SETNS | Set if Not Signed (386+)
SETC | Set if Carry (386+)
SETNC | Set if Not Carry (386+)
SETO | Set if Overflow (386+)
SETNO | Set if Not Overflow (386+)
SETP_SETPE | Set if Parity / Set if Parity Even (386+)
SETNP_SETPO | Set if No Parity / Set if Parity Odd (386+)
SGDT | Store Global Descriptor Table (286+ privileged)
SIDT | Store Interrupt Descriptor Table (286+ privileged)
SHL | Shift Logical Left
SHR | Shift Logical Right
SHLD_SHRD | Double Precision Shift (386+)
SLDT | Store Local Descriptor Table (286+ privileged)
SMSW | Store Machine Status Word (286+ privileged)
STC | Set Carry
STD | Set Direction Flag
STI | Set Interrupt Flag (Enable Interrupts)
STOS | Store String (Byte, Word or Doubleword)
STR | Store Task Register (286+ privileged)
SUB | Subtract
TEST | Test For Bit Pattern
VERR | Verify Read (286+ protected)
VERW | Verify Write (286+ protected)
WAIT_FWAIT | Event Wait
WBINVD | Write-Back and Invalidate Cache (486+)
XCHG | Exchange
XLAT_XLATB | Translate
XOR | Exclusive OR
Bare Opcodes List | Hex Opcodes And Mnemonics


Alternate Quotes.html

Alternate Quotes

"text"
'text'

Description

Treats <text> as a string. You can use single or double quotation marks, but the quotation marks on both sides of <text> must be identical. A string can be up to 255 characters long and must be on a single physical line. You can use a quotation mark inside a string by repeating it twice in a row ("" or ''). The left-hand single quotation mark (`) is not allowed as a delimiter.

Example

quote1 BYTE "This was called by 'int 23h'"
quote2 BYTE 'This was called by "int 23h"'
quote3 BYTE "Use the ""ASSUME"" directive"
quote4 BYTE 'Use the ''ASSUME'' directive'


Data Initialisation.html

Data Initialisation

Syntax: ?

Description

Used as an initializer in data declarations; indicates a value that the assembler allocates but does not initialize. Can be used alone or with DUP, as in the following examples:

Extension WORD ? ; Allocate 1 uninitialized word
Initials BYTE ?,?,? ; Allocate 3 uninitialized bytes
Fullname BYTE 20 DUP (?) ; Allocate 20 uninitialized bytes

To minimize the size of executable files, use the .DATA? or .FARDATA? directives to define an undefined data segment. Put undefined data in these segments.

The assembler treats the ? initializer as either zero or as an unspecified value. In compatibility mode, however, the assembler always treats the ? initializer as zero unless it is used with the DUP operator. In this case the assembler allocates space, but does not initialize it with any value.


index.htm

MASM32 Reference
Copyright The MASM32 Project 1998 - 2007

Using invoke
MASM High Level Syntax
Macro Reference
Full Listing
Register Summary
Ascii Characters
Calling Conventions
Processor Flags
Stack of 80-bit Data Registers
Conditional Assembly
Debugging in MASM32
Pentium Optimisation
Command Line Tools


a2wc
a2wc proc asc_txt:DWORD

Description
Convert zero terminated ANSI string to UNICODE string

Parameters
1. asc_txt Address of zero terminated string in ANSI format

Return Value
The address of a memory buffer that contains the UNICODE string.

Comments
When the string is no longer required, the return address should be deallocated with the OLE function,

invoke SysFreeString,strhandle
or the MASM32 macro
free$ strhandle


AboutBox

AboutBox proc Parent :DWORD,Instance :DWORD,Icon:DWORD,
              appname :DWORD,description:DWORD,
              copyright:DWORD

Description
AboutBox is a prebuilt dialog that is designed to be used as the about box in an application. Additional information is displayed in the lower half that is consistent with the function of an about box.

Parameters
1. Parent The handle of the windows that calls the dialog box.
2. Instance The instance handle for the application.
3. Icon The handle of the application's icon.
4. appname A zero terminated string that contains the name of the calling application.
5. description A zero terminated string that is used for additional description of the application named in the preceding parameter.
6. copyright A zero terminated string that can contain the copyright information for the application. This parameter can display up to 3 lines of text.

Return Value
The return value is always zero.

Comments
If the Icon handle parameter is zero, a default system icon will be displayed on the system menu. The three parameters that accept zero terminated strings are each displayed in a seperate static text control, the first two can only be displayed as a single line, the 3rd can display up to 3 lines of text to handle typical copyright text.


ArgByNumber

ArgByNumber proc src:DWORD,dst:DWORD,num:DWORD,npos:DWORD

Description
Return the contents of an argument from an argument list by its number.

Parameters
1. src The address of the zero terminated argument list.
2. dst The address of the destination buffer.
3. num The number of the argument to return.
4. npos The next read offset in the source address.

Return Value
The return value is the updated next read offset in the source if it is greater than zero.
The three possible return values are,
> 1 = The next read offset in the source
0 = The end of the argument list has been reached.
-1 = A non matching quotation error has occurred in the source.

Comments
This algorithm supports double quoted text and it is delimited by the space character, a tab or a comma or any combination of these three. It may be used in two seperate modes, single argument mode and streaming mode.

In seperate argument mode you specify the argument you wish to obtain with the "num" parameter and you set the "npos" parameter to zero.
In streaming mode you set a variable to zero and pass it as the 4th parameter "npos" and save the EAX return value back into this variable for the next call to the algorithm. The "num" parameter in streaming mode should be set to one "1".

mov eax, destbuffer      ; load destination buffer
cmp BYTE PTR [eax], 0    ; test its first BYTE
je no_arg                ; branch to no arg handler
print destbuffer,13,10   ; display the argument

Note
To support the notation of an empty pair of double quotes in an argument list, the parser in this algorithm return an empty destination buffer that has an ascii zero as it first character.


ArgCL

ArgCL - ArgCLC

ArgCl proc ArgNum:DWORD, ItemBuffer:DWORD ; GUI version
ArgClC proc ArgNum:DWORD, ItemBuffer:DWORD ; Console version

Description
Both procedures are designed to parse a command line and retreive the specified argument number from the command line if it exists. The GUI version has been superceded by the procedure GetCL which is more flexible across different version of the Windows operating system.

ArgClC is still a valid procedure for console mode applications. Both procedures support quoted text in quotation marks for arguments in the form "long file names" and will retreive arguments from one (1) to the number of arguments on the command line.

Parameters
1. ArgNum Argument number.
2. ItemBuffer Address of buffer to receive the argument if it exists.

Comments
The buffer for the returned argument should be set at 128 bytes in length which is the maximum allowable.

Return Values
0 = no command tail
1 = command tail processed normally
2 = processed but arg does not exist
3 = unmatched quotation marks
4 = empty quotation marks as arg [ "" ]


arr_add
arr_add proc arr:DWORD,cnt:DWORD,plus:DWORD

Description
Add an integer to every member of a DWORD array

Parameters
1. arr Starting address of DWORD array
2. cnt The number of members of the array
3. plus The intege to add to every array member

Return Value
There is no return value.


arr_mul
arr_mul proc arr:DWORD,cnt:DWORD,mult:DWORD

Description
Multiply every member of a DWORD array by an integer.

Parameters
1. arr Starting address of DWORD array
2. cnt The number of members of the array
3. mult The integer to multiply array members by.

Return Value
There is no return value.

Comments
The mult parameter is limited to 16 bit range (65536) because the algorith uses the IMUL mnemonic.


arr_sub

arr_sub proc arr:DWORD,cnt:DWORD,minus:DWORD

Description
Subtract an integer from every member of a DWORD array.

Parameters
1. arr Starting address of DWORD array
2. cnt The number of members of the array
3. minus The integer to subtract from array members.

Return Value
There is no return value.


AsciiDump

AsciiDump proc lpsrc:DWORD,lpbuf:DWORD,lnsrc:DWORD

Description
AsciiDump converts a binary file to assembler DB format.

Parameters
1. lpsrc The address of the byte data to be converted.
2. lpbuf The address of the buffer to receive the results.
3. lnsrc The length of the byte data to be converted.

Return Value
There is no return value.

Comments
This procedure is well suited for programmers who wish to write their own utility to convert binary data to assembler DB format for inclusion into assembler source code.
NOTE : The result is always larger than the source and the buffer must be large enough to receive the data. The buffer should be at least 4 times larger than the source.


atodw

atodw proc uses edi esi String:PTR BYTE

Description
atodw converts a decimal string to dword.
Note that the parameter String is an address of DWORD size.

Parameter
1. String The address of the decimal string to convert

Return Value
The DWORD value is returned in eax.

Example
invoke atodw,ADDR MyDecimalString


atodw_ex

atodw_ex proc lpstring:DWORD

Description
A high speed ascii decimal string to DWORD conversion for applications that require high speed streaming of conversion data.

Parameters
1.lpstring The address of the ascii decimal string.

Return Value
There is no return value.

Comments
This is an extended function aimed at applications where conversion speed is critical to their operation. For non speed critical string to number conversion the normal procedure should be used to save space.


atol

atol proc lpSrc:DWORD

Description
atol converts a zero terminated ascii string signed number into a 32 bit signed integer.

Parameter
1. lpSrc The address of the zero terminate string.

Return Value
The return value is the signed 32 bit integer. See comments

Comments
The algorithm will terminate on the first character less than 30h (The "0" character. The algorithm will strip any leading spaces but if it is used in an environment where leading tabs (ascii 9) are present, the tabs should be removed first.

The algorithm will accept the two sign specifiers "+" and "-" and will treat a numeric string with no sign specifier as a positive integer.

NOTE : The leading sign specifier should not be followed by a space or the procedure will fail.

EXAMPLE
1. - 12345678 will fail
2. -12345678 is correct


bin2byte_ex

bin2byte_ex proc lpword:DWORD

Description
bin2byte_ex is a high speed conversion from a binary notation value to a byte value.

Parameters
1.lpwordThe address of the binary notation string.

Return Value
The return value is the ascii number of the BYTE contained in the binary notation.

Comments
This procedure is suitable for application that must stream binary notation to byte data. It is a large procedure that is aimed at speed rather than minimum size.

NOTE that the input format is not tolerant, it must be 8 characters long and only comprised of the characters 0 and 1 as is normal for binary format data. If the data format you are converting has a trailing "b", it will need to be removed as the algorith only recognises exact 8 character binary notation.


bin2hex

bin2hex proc lpString:DWORD,lnString:DWORD,lpbuffer:DWORD

Description
A high speed binary to formatted HEX algorithm.

Parameters
1.lpString The binary data to be converted to formated HEX.
2.lnString The length of the binary data in BYTES.
3.lpbuffer The address of the destination buffer.

Return Value
The return value is the number of bytes written to the destination buffer.

Comments
The output data is approximately 3 times longer than the source data as it uses 2 characters plus a space for every byte in HEX format. The destination buffer should be at least 3 times the length of the source buffer to hold the result.


BinSearch

BinSearch proc StartPos:DWORD,lpString:DWORD,lnStrng:DWORD,
               lpSubStr:DWORD,lnSubSt:DWORD

Description
BinSearch searchs a source string for a sub string and if found, return the zero based offset of the sub string. This algorithm is ideally suited for binary search where zero terminated string functions are unsuitable.

Parameters
1. StartPos The zero based offset in the source string to start searching from.
2. lpString The address of the string to be searched.
3. lnStrng The length of the string to be searched.
4. lpSubStr The address of the sub string to search for.
5. lnSubSt The length of the sub string.

Return Value
Return value is the zero based offset of the first substring found in the source string or -1 if no substring is found.

Comments
Care should be taken to accurately set the length of both the source string and the sub string, this algorithm searches the full range of ascii characters so it can be used for searching binary files for BYTE sequences. Note that it does not depend on a zero terminator to determine the length of the source or sub strings so if the source or sub string lengths are incorrect, a general protection fault will occur after the end of the buffer has been read.

This algorithm has no error detection to keep its speed in relation to recursive searching so the parameters must be correct to avoid failure.


BitmapFromFile

BitmapFromFile proc pszFileName:DWORD

Description
BitmapFromFile returns a bitmap handle from an image file.
An image may be in either .bmp, .gif, .jpg, or .wmf format

Parameters
1. pszFileName pointer to the pathname of an image file

Return Value
The return value is a handle to a bitmap representation of the file compatible with the screen device context. If the function fails, the return value is NULL. To get extended error information, call GetLastError.

Comments
This function is provided as a convenience to the MASM32 community. It is not composed of highly optimized assembly code, so do not expect blinding speed.

This function uses certain aspects of the Windows API to do the actual conversion from the particular image format. Since the function contains no proprietary code, it may be used without any royalty payments. This may be especially important to those wishing to use .gif files.


BitmapFromMemory

BitmapFromMemory proc pHeap:DWORD, dwSize:DWORD

Description
BitmapFromMemory returns a bitmap handle from a program resource.
An image may be in either .bmp, .gif, .jpg, or .wmf format

Parameters
1. pHeap Address of a memory structure of an image structure.
2. dwSize Size of the memory structure in bytes.

Return Value
The return value is a handle to a bitmap representation of the file compatible with the screen device context. If the function fails, the return value is NULL. To get extended error information, call GetLastError.

Comments
This function is provided as a convenience to the MASM32 community. It is not composed of highly optimized assembly code, so do not expect blinding speed.
This function uses certain aspects of the Windows API to do the actual conversion from the particular image format. Since the function contains no proprietary code, it may be used without any royalty payments. This may be especially important to those wishing to use .gif files.


BitmapFromResource

BitmapFromResource proc hModule:DWORD, lpName:DWORD

Description
BitmapFromResource returns a bitmap handle from a program resource.
An image may be in either .bmp, .gif, .jpg, or .wmf format

Parameters
1. hModule Handle to the module whose executable file contains the resource. A value of NULL specifies the module handle associated with the image file that the operating system used to create the current process.

2. lpName If the high-order word of the lpName parameter is zero, the low-order word specifies the integer identifier of the name or type of the given resource. Otherwise, those parameters are long pointers to null-terminated strings. If the first character of the string is a pound sign (#), the remaining characters represent a decimal number that specifies the integer identifier of the resource's name or type. For example, the string "#258" represents the integer identifier 258.

An application should reduce the amount of memory required for the resources by referring to them by integer identifier instead of by name.

Resource file entries should use the identifier “IMAGE” for all image files to be loaded by this procedure. For backwards capability, bitmap files may have the identifier “BITMAP”

Return Value
The return value is a handle to a bitmap representation of the file compatible with the screen device context. If the function fails, the return value is NULL. To get extended error information, call GetLastError.

Comments
This function is provided as a convenience to the MASM32 community. It is not composed of highly optimized assembly code, so do not expect blinding speed.
This function uses certain aspects of the Windows API to do the actual conversion from the particular image format. Since the function contains no proprietary code, it may be used without any royalty payments. This may be especially important to those wishing to use .gif files.


BmpButton

BmpButton proc hParent:DWORD,topX:DWORD,topY:DWORD,
               rnum1:DWORD,rnum2:DWORD,ID:DWORD

Description
BmpButton is a custom control that uses 2 bitmaps for the UP and DOWN positions.

Parameters
1. hParent The handle of the window that thew control will be displayed on.
2. topX The top "x" co-ordinate for the control.
3. topY The top "y" co-ordinate for the control.
4. rnum1 The resource ID for the UP position bitmap.
5. rnum2 The resource ID for the DOWN position bitmap.
6. ID The identification number to attribute to the control.

Return Value
The return value is the handle of the control.

Comments
This function allows the programmer to exactly control the appearance of the bitmap button. When the button is clicked, it sends a WM_COMMAND message to the parent on release as is normal for buttons.

This control should be processed in the message handling proc like a normal button, trap the WM_COMMAND message in the parent of the control and process the wParam parameter to obtain the control ID.


Boyer Moore Algorithms

BMBinSearch proc startpos:DWORD,
                 lpSource:DWORD,srcLngth:DWORD,
                 lpSubStr:DWORD,subLngth:DWORD

BMHBinsearch proc startpos:DWORD,
                  lpSource:DWORD,srcLngth:DWORD,
                  lpSubStr:DWORD,subLngth:DWORD

SBMBinSearch proc startpos:DWORD,
                  lpSource:DWORD,srcLngth:DWORD,
                  lpSubStr:DWORD,subLngth:DWORD

Description
The three algorithms are variations of a Boyer Moore binary search design that is well suited for very high speed searching of binary or text data for a subpattern.

Parameters
1. startpos Zero based start address to nominate where to start searching.
2. lpSource The address of the data to be searched.
3. srcLngth The length of the search data.
4. lpSubStr The address of the pattern to search for.
5. subLngth The length of the pattern to search for.

Return Value
The functions return either the zero based offset of the pattern being searched for or -1 if the pattern does not occur within the data being searched.

Comments
The three algorithms are variations of a Boyer Moore design. The original design BMBinSearch is the most flexible across different search conditions. The two variations BMHBinsearch and SBMBinSearch are respectively a Horspool variation and a simplified variation which perform well depending on the hardware and the patterns being searched.

The minimum pattern length is 2 bytes but these algorithms are slower on very short paterns than a classic byte scanner. The algorithms have about a 300 character penalty at startup as they must construct a table so for either very short patterns or short data it is more efficient to use a byte scanner. BinSearch

Care should be taken to ensure the first parameter startpos is not past the end of the data being searched.


BrowseForFolder

BrowseForFolder proc hParent:DWORD, lpBuffer:DWORD, lpTitle:DWORD,lpString:DWORD

Description
BrowseForFolder is a system dialog from the shell32 library that is used to search for folders(directories).

Parameters
1. hParent The handle of the application calling the dialog.
2. lpBuffer 260 byte buffer that receives the path data if selection has been made.
3. lpTitle The address of the zero terminated title text for the dialog.
4. lpString The address of the zero terminated string for the secondary title.

Return Value
If a folder is selected, the full path is returned in the buffer supplied in the second parameter.

Comments
The application must include the shell32 and ole32 libraries and include files.


byt2bin_ex

byt2bin_ex proc var:BYTE,buffer:DWORD

Description
A high speed BYTE to binary format converter.

Parameters
1.varThe BYTE value to convert
2.bufferThe address of the buffer to receive the result.

Return Value
There is no return value.

Comments
The result will be 8 characters long plus the terminator so the destination buffer should be 12 bytes for alignment purposes.


byte_count

byte_count proc src:DWORD,cnt:DWORD,array:DWORD

Description
Count every character in a source file

Parameters
1. src Address of memory containing the characters to count
2. cnt Length of the data in BYTES
3. array Address of a 256 member DWORD array

Return Value
The count of every character is in its location in the 256 character array.

Comments
The array must be zero filled. Individual character counts can be retrieved with code such as the following.

mov eax, array             ; array address
xor edx, edx               ; clear EDX to avoid register stall
mov dl, ":"                ; copy required character into DL
mov ecx, [eax+edx*4]       ; get the count from the array for the character


circle

circle proc hndl:DWORD,colr:DWORD,tx:DWORD,ty:DWORD,lx:DWORD,ly:DWORD

Description
This function will display a circle or elipse within the rectangle bounded by the four parameters.

Parameters
1. hndl The window handle of the window where the circle is to be displayed.
2. colr The RGB COLORREF value for the colour of the circle.
3/4 tx, ty The top left co-ordinates for the bounding rectangle.
5/6 lx, ly The bottom right co-ordinates for the bounding rectangle.

Return Value
There is no return value.

Comments
You can make a COLORREF value in eax by using the following macro. Note that the three values are BYTE in size.

RGB MACRO red, green, blue
  xor eax, eax
  mov al, blue   ; blue
  rol eax, 8
  mov al, green  ; green
  rol eax, 8
  mov al, red    ; red
ENDM


ClearScreen

ClearScreen proc

Description
ClearScreen clears the console window and places the text cursor at position 0,0. It takes no parameters and does not return a value.
The following macro makes this procedure easier and faster to use.

cls MACRO
  invoke ClearScreen
ENDM


CloseMMF

CloseMMF proc lpMem:DWORD,hMMF:DWORD

Description
CloseMMF closes a memory mapped file opened by the CreateMMF procedure.

Parameters
1. lpMem The start address of the memory mapped file returned by the CreateMMF procedure.
2. hMMF The handle returned by the CreateMMF procedure.

Return Value
There is no return value.

Comments
When more than one application has opened the same named memory mapped file, the file is not closed until the last application that has opened it closes the file. It is safe to call this procedure even if the memory mapped file is still being used by another application as the operating system will leave it open until the last application using it closes it.


Cmpi

Cmpi proc src1:DWORD,src2:DWORD

Description
A table driven high speed case insensitive text comparison algo.

Parameters
1. src1 The address of the first zero terminated text.
2. src2 The address of the second zero terminated text.

Return Value
If the two text sources match as case insensitive, the return value is ZERO otherwise the return value is non zero.

Comments
This version differs from szCmpi in that it detects the zero terminator without the need for the length to be specified as an additional argument.


cmpmem
cmpmem proc buf1:DWORD,buf2:DWORD,bcnt:DWORD

Description
Compare two memory of the same known length.

Parameters
1.buf1 The first memory location to test
2.buf2 The second memory location to test against the first
3.bcnt The length of the buffers in BYTES.

Return Value
0 = different.
non 0 = byte identical.

Comments
The procedure is useful among other things for testing the contents of two files to see if they are the same.


ColorDialog

ColorDialog proc hWin:DWORD, instance:DWORD, Flags:DWORD

Description
ColorDialog is a system common dialog used for selecting colors.

Parameters
1. hWin The handle of the calling application.
2. instance The instance handle of the calling application.
3. Flags A set of values that can be combined to change the opening characteristics.

Return Value
The RGB value selected or zero.

Comments
The Flags value will accept either 0 for the default Color Dialog or the style CC_FULLOPEN to display the dialog with the custom color option displayed.


Comb Sort

CombSortA proc Arr:DWORD,aSize:DWORD
CombSortD proc Arr:DWORD,aSize:DWORD

Description
The algorithms differ only in that they sort in opposite directions, CombSortA sorts in Ascending order, CombSortD sorts in Descending order.

Parameters
1. Arr The starting address of the array
2. aSize The number of members in the array.

Return Value
There is no value returned from this procedure.

Comments
A comb sort is a design that collapses to a bubble sort when the predetermined GAP closes to zero. It is competitive with most traditional sorting methods and it has the advantage of simplicity and reasonably small code size. The comb sort is an "in place" sort that does not allocate additional memory so it can be used in places where memory usage must be kept under control.


create_array

create_array proc acnt:DWORD,asize:DWORD

Description
Create an array of pointers to a user defined array of user defined length and member count.

Parameters
1. acnt The number of members of the array
2. asize The size of each member in bytes

Return Value
The address of the array of pointers is returned in EAX
The address of the memory for the main array is returned in ECX

Comments
The asize parameter should always be set to a length that is divisible by 4 to maintain the alignment of the following array member otherwise there will be a serious performance penalty due to misaligned reads from memory. When the array is no longer required, both return values should be deallocate using either,

GlobalFree()
  or the MASM32 macro
free


CreateMMF

CreateMMF proc lpName:DWORD,bcnt:DWORD,lphndl:DWORD,lpMemFile:DWORD

Description
CreateMMF creates a memory mapped file from the system paging file that can be shared by other application in seperate processes.

Parameters
1. lpName The zero terminates string that names the file
2. bcnt The size of the required memory mapped file in BYTES.
3. lphndl The address of a DWORD variable to receive the address of the memory mapped file handle.
4. lpMemFile The address of a DWORD variable to receive the start address of the memory mapped file.

Return Values
The lphndl and lpMemFile have the file handle and start address written to them when the procedure returns. There is no return value in EAX.

Comments
A memory mapped file backed by the system paging file is effectively allocated memory but it has the attribute of being sharable between applications that call the same file name. This allows applications to share data by reading and writing to the memory mapped file.

NOTE that a memory mapped file allocate at a specified size cannot be reallocated to a different size. The file must be closed by all applications that access it and then reallocated to a different size. Use CloseMMF to close the memory mapped file.

Example
LOCAL hMMF :DWORD
LOCAL lpMMFile :DWORD

invoke CreateMMF,SADD("Memory_Mapped_File"),
                 1000000,ADDRhMMF,ADDR lpMMFile


decomment

decomment proc src:DWORD

Description
This procedure removes the comment from a single line of source code and trims any trailing spaces or tabs from the source.

Parameters
1. src The address of a zero terminated single line of source code.

Return Value
There are 3 possible return values.
1 = There is more code on the following line that is part of the same statement.
0 = Line of code is complete.
-1 = Quotation error, no closing quotation.

Comments
If the line of source code contains a comment, the result is written back to the same buffer. This algorithm supports both single and double quotations as alternate quotations. The line of code has trailing spaces and tabs removed. The comment character is the normal assembler ";" but the algorithm can be copied and this character can be changed to any other character.


DisplayBmp

DisplayBmp proc hParent:DWORD,bmpID:DWORD,x:DWORD,y:DWORD,ID:DWORD

Description
DisplayBmp encapsulates a static control set with the SS_BITMAP style to display a bitmap in the client area of a window.

Parameters
1. hParent Handle of window that the bitmap will be displayed on.
2. bmpID The resource ID number for the bitmap to be displayed.
3. x The top "x" co-ordinate to position the bitmap
4. y The top "y" co-ordinate to position the bitmap.
5. The ID number for the static control.

Return Value
The return value is the handle of the static control.

Comments
This procedure should be called from the WM_CREATE message in a window or a WM_INITDIALOG in a dialog box. It should NOT be placed in a WM_PAINT message.


DisplayIcon

DisplayIcon proc hParent:DWORD,iconID:DWORD,x:DWORD,y:DWORD,ID:DWORD

Description
DisplayIcon encapsulates a static control set with the SS_ICON style to display an icon in the client area of a window.

Parameters
1. hParent The handle of the window to display the icon on.
2. iconID The resource ID of the icon to display.
3. x The top "x" co-ordinate to position the icon.
4. y The top "y" co-ordinate to position the icon.
5. The ID number for the static control.

Return Value
The return value is the handle of the static control.

Comments
This procedure should be called from the WM_CREATE message in a window or a WM_INITDIALOG in a dialog box. It should NOT be placed in a WM_PAINT message.


dw2ah

dw2ah proc public dwValue:DWORD, lpBuffer:PTR BYTE

Description
dw2ah converts DWORD size data to a hexadecimal ascii string.
Note that the data type PTR BYTE is a DWORD address of BYTE data.

Parameters
1. dwValue is the value to be converted
2. lpBuffer is the address of the receiving buffer

Return Value
There is no return value

Comments
lpBuffer must be at least 10 bytes long


dw2bin_ex

dw2bin_ex proc var:DWORD,buffer:DWORD

Description
A high speed DWORD to binary conversion.

Parameters
1.var The DWORD to be converted.
2.buffer The destination address.

Return Value
There is no return value.

Comments
The resultinfg output is 32 characters in length so the destination buffer must be 32 plus a terminator. A buffer of 36 bytes is recommended for alignment reasons.


dw2hex

dw2hex proc source:DWORD, lpBuffer:DWORD

Description
dw2hex converts a DWORD value to an ascii hex string.

Parameters
1. source The DWORD value to convert
2. lpBuffer The address of the buffer to receive the ascii hex string

Return Value
There is no return value.

Comments
The buffer for the result needs to be 8 bytes long plus one byte for the terminator so for alignment, make the buffer 12 bytes long.


dw2hex_ex

dw2hex_ex proc src:DWORD,buf:DWORD

Description
A high speed DWORD to HEX conversion.

Parameters
1.srcThe source DWORD to convert.
2.bufThe address of the destination buffer for the result.

Return Value
There is no return value.

Comments
This algorithm is designed for applications that must stream such conversions at high speed. Non critical applications should use the normal procedure to save space.


dwtoa

dwtoa proc public uses esi edi dwValue:DWORD, lpBuffer:DWORD

Description
dwtoa convert a DWORD value to an ascii string.

Parameters
1. dwValue The DWORD value to convert.
2. lpBuffer The address of the buffer to put the converted DWORD into.

Return Value
There is no return value.

Comments
The buffer for the converted value should be large enough to hold the string including the terminating zero.


exist

exist proc lpszFileName:DWORD

Description
This function tests if a file exists at the path and file name in the zero terminated string.

Parameter
1. lpszFileName The zero terminated string that has the path & name of the file to test.

Return Value
If the return value in eax is zero, the file does not exist, if it is 1, then it exists.


filesize

filesize proc lpszFileName:DWORD

Description
This function returns the length of a file if it exists.

Parameter
1. lpszFileName The zero terminated string that has the path & name of the file.

Return Value
If the return value is minus one (-1) then the file does not exist, otherwise eax returns the size of the file in bytes.

Comments
This function will return the size of a file without opening it so it can be used to check the length of a running EXE file.


FloatToStr

FloatToStr  PROCstdcall public USES esi edi, fpin: QWORD, szDbl: PTR CHAR
FloatToStr2 PROCstdcall public USES esi edi, fpin: QWORD, szDbl: PTR CHAR

Note that szDbl is a DWORD size address of the buffer to receive the string data.

Description
FloatToStr converts a QWORD size floating point value to a string. FloatToStr2 differs only in that it outputs a larger number in normal notation before it starts to use engineering notation.

Parameters
1. fpin The QWORD value to convert.
2. szDbl The address of the buffer to place the result in.

Return Value
There is no return value.

Comments
The buffer for the string should be at least 19 bytes long as the procedure always write an 18 byte long string in szDbl. For alignment considerations, a 20 byte long buffer is recommended.


FontDialog

FontDialog proc hWin:DWORD, lf:DWORD, fStyle:DWORD

Description
FontDialog is a system common dialog for retreiving the name of a selected font.

Parameters
1. hWin The handle of the calling application's window.
2. lf The address of a LOGFONT structure.
3. fStyle Style(s) for the CHOOSEFONT structure.

Return Value
If eax returns zero, cancel was pressed. If selection is made, return in eax is non zero and LOGFONT structure is filled with font information.

Comments
The fStyle parameter is a set of styles that may be OR'd together to acheive the required effect. The reference for the styles are in the win32.hlp file for the CHOOSEFONT structure.


Frame3D

Frame3D proc hDC:DWORD,btn_hi:DWORD,btn_lo:DWORD,
             tx:DWORD, ty:DWORD, lx:DWORD, ly:DWORD,bdrWid:DWORD

Description
Frame3D will draw a 3D frame in the client area of a window at the co-ordinates provided.

Parameters
1. hDC You must provide a device context for this function.
2. btn_hi The nominal highlight colour.
3. btn_lo The nominal lowlight colour.
4 to 7. tx, ty, lx, ly The four co-ordinates for the rectangular area. The units are in pixels.
8. bdrWid The border width specified in pixels.

Return Value
There is no return value.

Comments
The rectangle drawn increases outwards as the border width increases.


FrameCtrl

FrameCtrl proc hCtrl:DWORD, step:DWORD, wdth:DWORD, direction:DWORD

Description
This procedure draws a frame around a control onto the client area of the window. It has the option of how many pixels to step outwards from the control and can draw either a raised or sunken frame.

Parameters
1. hCtrl The handle of the control to draw the frame around.
2. step The number of pixels to step outwards from the control.
3. wdth The width of the border in pixels.
4. direction Frame type, 0 for sunken frame, 1 for raised frame.

Comments
This procedure uses the Frame3D procedure to draw the frame onto the client area of the window. It is important to supply a control handle and not a control ID number. If you are using a control in a dialog box, you need to convert the ID number to a handle.


FrameGrp

FrameGrp proc hCtrl1:DWORD, hCtrl2:DWORD, step:DWORD, wdth:DWORD, direction:DWORD

Description
This proc draws a frame bounded by the top left co-ordinates of the first control handle and the bottom right co-ordinates of the second control handle. It is used to draw frames around groups of controls.

Parameters
1. hCtrl1 The control that has the top left corner position.
2. hCtrl2 The control that has the lower right corner position.
3. step The distance in pixels outwards from the controls to draw the frame.
4. wdth The width of the frame in pixels.
5. direction The direction of the frame. 0 = sunken frame, 1 = raised frame.

Comments
This procedure is designed to work on a group of controls, typically a group of same size buttons where the whole group is framed. It is important that both of the control handles are valid window handles and not ID numbers. If the group of controls to be framed are dialog box controls, the ID number of both controls must be converted to window handles.


FrameWindow

FrameWindow proc hndle:DWORD, step:DWORD, wid:DWORD, direction:DWORD

Description
This procedure is used for framing the client area of a window. It uses the co-ordinates of the window to determine the correct dimensions for the frame position.

Parameters
1. hndle The handle of the window.
2. step The number of pixels inside the window's client area to start the frame.
3. wid The width of the frame in pixels.
4. direction The direction of the frame, 0 = sunken, 1 = raised.

Comments
This procedure uses the Frame3D procedure to draw the frame onto the client area of the window. The handle must be a valid window handle. If you need to frame a dialog box, you must convert the dialog box ID number to a window handle first.


Free

Free proc public pv:DWORD

Description
Free frees a block of memory that was allocated by Malloc.

Parameter
1. pv Address returned by Malloc when memory was allocated.

Return Value
There is no return value.

Comments
Free frees a block of memory previously allocated through a call to Malloc. The number of bytes freed equals the number of bytes that were allocated. After the call, the memory block pointed to by pv is invalid and can no longer be used.

Note The pv parameter can be NULL. If so, this method has no effect.


get_ml

get_ml proc src:DWORD,dst:DWORD,rpos:DWORD

Description
get_ml is an algorithm to read the next statement from source code. The statement may be multiline with comments at the end of each line.

Parameters
1. src The address or the zero terminated source code.
2. dst The address of the destination buffer.
3. rpos The next read offset in the source code.

Return Value
There are 3 possible return values.
>0 = next read offset in source
0 = end of source data
-1 = quotation error, non matching quotes.

Comments
The algorithm supports both single and double quotations as alternate quotations and determines the quotation type by the first quote in the argument. It recognised two types of split line indicators, a trailing comma or a trailing "\" character for split lines on constants and similar. This algorithm uses the normal assembler comment character ";" but the complete algorithm can be copied and this can be changed to any other single character.

The output is the complete next statement in the source code with comments and CRLF pairs removed in the destination buffer. Note that no special formatting has been applied to the data as a normal tokeniser can normally handle unused spaces.

Example
This simple example scans through a complete source and displays each complete code statement at the console.

  mov rpos, 0
stlp:
  mov rpos, rv(get_ml,hMem,hBuf,rpos)
  print hBuf,13,10
  cmp rpos, 0
  jnz stlp


GetAppPath

GetAppPath proc lpPathBuffer:DWORD

Description
GetAppPath returns the address of the running application's path as a zero terminated string with the filename removed. The last character in the string is a trailing backslash "\" to facilitate parsing different filenames to the path.

Parameter
lpPathBuffer The address of the buffer that will receive the application path.

Return Value
There is no return value.

Comments
The buffer size should be 128 bytes long.


GetCL

GetCL proc ArgNum:DWORD, ItemBuffer:DWORD

Description
GetCl will retreive the argument specified in the procedure call and return the argument in the buffer specified. It differs slightly in its implementation in that it treats the path and name of the application making the call as arg 0.

Arguments are specified from arg 1 up to the number of command line arguments available. The procedure supports the retreival of arguments that are enclosed in quotation marks and will return the argument with the quotation marks removed.

Parameters
1. ArgNum Argument number.
2. ItemBuffer Address of buffer to receive the argument if it exists.

Return values
1 = successful operation
2 = no argument exists at specified arg number
3 = non matching quotation marks
4 = empty quotation marks

Comments
The buffer for the returned argument should be set at 128 bytes in length which is the maximum allowable.

Example
invoke GetCl, 1, ADDR ItemBuffer
If arg 1 exists, the procedure will place the argument in the buffer ItemBuffer.


getcl_ex

getcl_ex proc num:DWORD,pbuf:DWORD

Description
Extended version of GetCL.

Parameters
1. num The argument number to return from a command line.
2. pbuf The buffer to receive the selected argument.

Return Value
There are three (3) possible return values.
1 = successful operation
2 = no argument exists at specified arg number
3 = non matching quotation marks

Comments
This algorithm uses the ArgByNumber procedure to obtain the selected argument from a command line. It differs from the original version in that it will read a command line of any length and the arguments can be delimited by spaces, tabs, commas or any combination of the three.

It is also faster but as the ArgByNumber procedure is table driven, it is also larger.


GetClipboardText

Description
Read text from the clipboard if it is available and copy that text to a block of memory allocated with GlobalAlloc().

Parameters
The function takes no arguments. Use it as follows,
invoke GetClipboardText

Return Value
The return value is either zero (0) if no text is available on the clipboard or the return value is a GlobalAlloc() handle to memory that contains the clipboard text. Treat this handle as a direct memory pointer.

Comments
If the return value was NOT zero and a memory handle is returned, when the text is no longer required deallocate the memory with GlobalFree() or the macro "free". This does not neeed to be done if there was no text on the clipboard.


GetFile

GetFile proc Parent :DWORD,Instance :DWORD,Icon:DWORD,
             caption:DWORD,directory:DWORD,
             pattern:DWORD,buffer :DWORD

Description
The GetFile prebuilt dialog is designed to quickly get a file name from a predefined directory. It does not display directories or drives and uses a sorted list box to display the files for the chosen pattern.

Parameters
1. Parent The handle of the windows that calls the dialog box.
2. Instance The instance handle for the application.
3. Icon The handle of the application's icon.
4. caption A zero terminated string that is displayed on the title bar of the dialog.
5. directory A zero terminated string for the directory that the dialog is to display files in
6. pattern. A zero terminated string that has the file pattern required
7. buffer The address of a memory buffer that is large enough to hold the maximum length filename that can be displayed, this should be 260 bytes.

Return Value
The return value is always zero in EAX.

Comments
The buffer should be tested to see if the first BYTE is zero which indicates that the user cancelled the operation. If it is not zero, it will be the zero terminated string that contains the name of the selected file.


GetIP

GetIP proc Instance :DWORD,Parent:DWORD, Icon:DWORD,
           lpCaption:DWORD,lpText:DWORD,defIP:DWORD

Description
Dialog displays an IP control that can be optionally set with a default IP. It can be used to obtain an IP from a user or alternatively display a default IP with the user having the option to change it.

Parameters
1. Parent The handle of the windows that calls the dialog box.
2. Instance The instance handle for the application.
3. Icon The handle of the application's icon.
4. lpCaption A zero terminated string that has the caption required for the dialog box.
5. lpText A zero terminated string if text is required above the IP control for extra explanation to the user.
6. defIP The default IP address as a DWORD size variable.

Return Value
If the user cancels the operation, the return value in EAX is -1, else it is the IP as a single DWORD value. To convert the IP value to a string for display, use the IPtoString procedure. To make a single DWORD value IP address, use the macro MakeIP displayed below. It is contained in the include file MASM32.INC.

MakeIP MACRO val1,val2,val3,val4
  mov ah, val1
  mov al, val2
  rol eax, 16
  mov ah, val3
  mov al, val4
  EXITM <eax>
ENDM


GetPathOnly

GetPathOnly proc src:DWORD, dst:DWORD

Description
GetPathOnly reads the path of a complete file path and returns the path portion in the destination buffer.

Parameters
1. src Address of source zero terminated path.
2. dst Address of buffer to receive the path portion of a complete path.

Return Value
This procedure has no return value.

Comments
The destination buffer must be large enough to receive the path from the complete path.


GetPercent

GetPercent proc source:DWORD, percent:DWORD

Description
GetPercent calculates the percentage of the source specified in the second parameter.

Parameters
1. source Integer to obtain a percentage value from.
2. percent an integer between 1 and 100 to set the percentage required.

Return Value
The return value is the set percentage of the source in eax.

Comments
The return value is rounded down to the next integer value. This procedure was primarily designed to handle screen size percentages where integer return values are appropriate.


GetTextInput

GetTextInput proc hParent :DWORD,Instance :DWORD,
                  Icon :DWORD,caption :DWORD,
                  subcaption:DWORD,lpbuffer :DWORD

Description
The GetTextInput dialog is used to obtain text from the user. It has the option to display an additional text field above the edit control where the user enters the text.

Parameters
1. Parent The handle of the windows that calls the dialog box.
2. Instance The instance handle for the application.
3. Icon The handle of the application's icon.
4. caption A zero terminated string that contains the text to display on the title bar of the dialog.
5. subcaption A zero terminated string that contains the text to display in the addition field above the edit conrol.
6. lpbuffer The address of the buffer that will receive the text entered by the user. This buffer should be at least 128 bytes in length.

Return Value
The return value in EAX is always zero.

Comments
To test if the user has entered text, the first byte of the buffer should be tested for zero. If the value is not zero, the buffer contains the text typed by the user.


hex2bin

hex2bin proc src:DWORD,dst:DWORD

Description
A high speed algorithm that will convert formated hex from the same format as bin2hex procedure output back to binary.

Parameters
1.src The address of the formatted HEX data.
2.dst The address of the destination buffer.

Return Value
0 = no error
1 = invalid hex format, characters must be in pairs.
2 = illegal character in source.

Comments
This algorithm allow the user to write formatted HEX complete with side comments using ";" and convert the results to binary. The error conditions are to ensure that the HEX format saved as binary is valid. Notation for HEX must be in character pairs and characters that are not used in HEX notation will produce an error.


HexDump

HexDump proc lpString:DWORD,lnString:DWORD,lpbuffer:DWORD

Description
HexDump takes a byte sequence or string, text or binary and converts it to an ascii hex dump.

Parameters
1. lpString The address of the byte sequence or string to convert.
2. lnString The length of the byte sequence or string
3. lpbuffer The address of a buffer large enough to receive the results.

Return Value
There is no return value

Comments
The result is always larger than the source string or byte data so the buffer must be larger to receive it. In most circumstances, making the buffer 4 times the size of the source data is safe.


hexflip32

hexflip32 proc src:DWORD

Description
A special purpose algorithm for converting normal hex to memory order hex.

Parameters
1.src The address of the hex string to convert to memory order.

Return Value
The converted data is written back to the source buffer.

Comments
The algorithm accepts assembler format hex notation with the trailing "h" and optionally a leading "0" if required. Total string length must not exceed 10 bytes including the "h" and "0".
Output is a memory order hex string that is always 8 bytes long. If the input string is less than 8 bytes in length the output string is padded with trailing "0" s to make up the length.
The output is always written to the source string buffer and the buffer must be at least 9 bytes long. A buffer of 12 bytes satisfies alignment criterion.
01199AAFFh becomes "FFAA9911"


htodw

htodw proc uses ebx ecx edi edx esi String:DWORD

Description
htodw receives as its parameter, the address of a zero terminated string containing hex characters and returns the value as a DWORD in eax.

Parameter
1. String The address of the zero terminated string to be converted.

Return Value
The DWORD value is returned in eax.

Comments
It is the users responsibility to ensure that there are no non-hexadecimal characters in the string of numbers.


iFree

Free

Free proc public pv:DWORD

Description
Free frees a block of memory that was allocated by Malloc.

Parameter
1. pv Address returned by Malloc when memory was allocated.

Return Value
There is no return value.

Comments
Free frees a block of memory previously allocated through a call to Malloc. The number of bytes freed equals the number of bytes that were allocated. After the call, the memory block pointed to by pv is invalid and can no longer be used.

Note The pv parameter can be NULL. If so, this method has no effect.


iMalloc

Malloc

Malloc proc public cb:DWORD

Description
The Malloc method allocates a memory block in essentially the same way that the C Library malloc function does.

Parameter
1. cb The number of bytes to allocate.

Return Value
If cb is zero, Malloc allocates a zero-length item and returns a valid pointer to that item. If there is insufficient memory available, Malloc returns NULL.

Comments
The initial contents of the returned memory block are undefined and there is no guarantee that the block has been initialized, so you should initialize it in your code. The allocated block may be larger than cb bytes because of the space required for alignment and for maintenance information.

Note Applications should always check the return value from this method, even when requesting small amounts of memory, because there is no guarantee the memory will be allocated.


InString

InString proc StartPos:DWORD, lpszString:DWORD, lpszSubStr:DWORD

Description
InString searches for a substring in a larger string and if it is found, it returns its starting position in eax. It uses a one (1) based character index (1st character is 1, 2nd is 2 etc...) for both the "StartPos" parameter and the returned character position.

Parameters
1. StartPos Starting position to search for the substring.
2. lpszString Address of string to be searched.
3. lpszSubStr Address of substring to search for within the main string.

Return Values.
If the function succeeds, it returns the 1 based index of the start of the substring or 0 if no match is found.

Error Values
If the function fails, the following error values apply.
-1 = substring same length or longer than main string
-2 = "StartPos" parameter out of range (less than 1 or greater than main string length)

Example
invoke InString,1,ADDR szMainString,ADDR szSubString
mov txtPos, eax


IntDiv

IntDiv proc source:DWORD,divider:DWORD

Description
IntDiv divides the source by the divider.

Parameters
1. source DWORD size source integer
2. divider DWORD size divider

Return Value
The return value is the result of the integer division returned in eax.

Comments
The results are subject to integer resolution which will round down the result. This effect will be particularly noticable on small numbers.


IntMul

IntMul proc source:DWORD,multiplier:DWORD

Description
IntMul performs integer multiply on a DWORD size source by the multiplier.

Parameters
1. source DWORD size integer
2. multiplier DWORD size multiplier

Return Value
The return value is the result returned in eax.

Comments
The results are bound by DWORD size and no attempt is made to handle overflow so the size limit is about 4 gigabytes.


IntSqrt

IntSqrt proc source:DWORD

Description
IntSqrt produces the square root of the source integer and returns it in EAX.

Parameters
1. source is the 32 bit integer to get the square root from.

Return value
The return value in EAX is the square root of the source.

Comments
This is an integer function that rounds down to the next integer. Note that this rounding error on small numbers is substantial.


IPtoString

IPtoString proc IP:DWORD,lpBuffer:DWORD

Description
IPtoString is a procedure to convert a single DWORD IP value to a zero terminated string for display.

Parameters
1. IP The single DWORD value that contains the IP address.
2. lpBuffer A buffer that is large enough to hold the maximum length result of an IP

Return Value
The result is written to the buffer supplied in the second parameter. There is no return value in EAX.

Comments
The longest string that this procedure can return is 21 bytes plus the terminating zero. It is recommended that the buffer allocated for this result be 24 bytes for alignment purposes.


isalpha

isalpha proc char:BYTE

Description
A C style procedure to test if a character is alphabetic.

Parameters
1.char The character to test

Return Value
0 = character is non alphabetic
1 = character is upper case
2 = character is lower case

Comments
While this procedure is easy to use, if speed is critical, there is a macro chtype$() that is substantially faster in the MACROS.ASM file.


isalphanum

isalphanum proc char:BYTE

Description
A C style procedure to test if a character is alpha - numeric.

Parameters
1.charThe character to test.

Return Value
0 = Not alpha - numeric.
1 = Numeric character.
2 = Upper case character.
3 = Lower case character

Comments
While this procedure is easy to use, if speed is critical, there is a macro chtype$() that is substantially faster in the MACROS.ASM file.


islower

islower proc char:BYTE

Description
A C style procedure to test if a character is lower case.

Parameters
1.charThe character to test.

Return Value
0 = not lower case.
1 = lower case.

Comments
While this procedure is easy to use, if speed is critical, there is a macro chtype$() that is substantially faster in the MACROS.ASM file.


isnumber

isnumber proc char:BYTE

Description
A C style procedure to test if a character is a decimal number.

Parameters
1.char The character to test.

Return Value
0 = non numeric character.
1 = numeric character.

Comments
While this procedure is easy to use, if speed is critical, there is a macro chtype$() that is substantially faster in the MACROS.ASM file.


isupper

isupper proc char:BYTE

Description
A C style procedure to test if a character is upper case.

Parameters
1.charThe character to test.

Return Value
0 = not upper case
1 = upper case

Comments
While this procedure is easy to use, if speed is critical, there is a macro chtype$() that is substantially faster in the MACROS.ASM file.


lfcnt

lfcnt proc txt:DWORD

Description
Return the number of line feeds in a zero terminated text.

Parameters
1. txt The address of the text to count line feeds in

Return Value
The return value is the number of line feeds in the source.

Comments
The primary use for this procedure is to count the number of lines in a zero terminated text so it can be used as a counter for processing lines of text.


line

line proc hndl:DWORD,colr:DWORD,x1:DWORD,y1:DWORD,x2:DWORD,y2:DWORD

Description
line will display a line between the first X,Y co-ordinate and the second X,Y co-ordinate.

Parameters
1. hndl The handle of the window where the line will be displayed.
2. colr The RGB COLORREF value for the colour of the line.
3/4 x1, y1 The X, Y co-ordinates of the start of the line.
5/6 x2, y2 The X, Y co-ordinates of the end of the line.

Return Value
There is no return value.

Comments
You can make a COLORREF value in eax by using the following macro. Note that the three values are BYTE in size.

RGB MACRO red, green, blue
  xor eax, eax
  mov al, blue ; blue
  rol eax, 8
  mov al, green ; green
  rol eax, 8
  mov al, red ; red
ENDM


load_drives

load_drives proc list:DWORD

Description
Procedure to load the fixed drives and volume labels into a list box.

Parameters
1. list Handle to a list control.

Return Value
There is no return value.

Comments
The procedure can be modified to accept drives other than fixed drives and the string data can be changed in the list box display. If you need to use this procedure in a different form, copy it to your application using a different name to avoid conflicts with the MASM32 library and modify it to suit your requirements.


LoadList

 LoadList load the file names in the current directory into a list box. Long file names are supported.

Parameters
1. hWin The handle of the list box to receive the file names.
2. pattern The address of a zero terminated string that contains the required file pattern..

Return Value
There is no return value.

Comments
Set the current directory using the SetCurrentDirectory() API function call.


locate

locate proc x:DWORD,y:DWORD

Description
The locate function positions the text cursor in the console at whatever position is set in the two parameters.

Parameters
1. x The column number.
2. y The row number.

Return Value
There is no return value.

Comments
The locate function uses a zero based row & column numbering, top left corner is position 0,0.


ltoa

ltoa proc lValue:DWORD, lpBuffer:DWORD

Description
ltoa converts a 32 bit signed integer (LONG) and write the results to a buffer as a zero terminated string.

Parameters
1. lValue The 32 bit signed integer to convert.
2. lpBuffer A buffer of sufficient length to receive the zero terminated string.

Return Value
The number of characters written to the buffer or zero.

Comments
This procedure is a wrapper around the "wsprintfA" Windows API function. The buffer should be long enough to receive the maximum length result. 16 bytes is the recommended buffer size for size and alignment purposes.

Example
1. In the .DATA? section.
buffer db 16 dup (?)
2. As a LOCAL value in a procedure.
LOCAL buffer[16]:BYTE


ltok

ltok proc pTxt:DWORD,pArray:DWORD

Description
Tokenise lines of text "in place" and return an array of pointers to each token.

Parameters
1. pTxt The address of the source text to tokenise.
2. pArray The address of a DWORD variable that will be used for the handle of the array of pointers. Please refer to the comments section for further details.

Return Value
The return value in EAX is the number of tokens in the array of pointers.

Comments
When the address of the variable for the pointer array is passed to the procedure, the procedure in turn writes the address of the allocated memory back to that address so that within the scope of the procedure that allocated the variable and calls the tokeniser, the variable is then the direct pointer to the array of pointers. When the pointer array is no longer needed the variable should be deallocated using GlobalFree() within the same scope as the variable was allocated. The MASM32 macro "free" works correctly for this task.

Example
LOCAL MyVar :DWORD
Pass ADDR MyVar to the tokeniser.
Use MyVar as the address of the array of pointers after the tokeniser has returned.
free MyVar


MemCopy

MemCopy proc public uses esi edi Source:PTR BYTE,Dest:PTR BYTE,ln:DWORD

Note here that the source and destination parameters are DWORD size addresses of the respective source and destination buffers.

Parameters
1. Source Source buffer address.
2. Dest Destination buffer address.
3. ln The number of bytes to copy.

Return Value
There is no return value.

Comments
The destination buffer must be at least the same size as the source buffer otherwise the procedure will write past the end of the destination buffer and cause a write page fault.

Example
invoke MemCopy,ADDR MySource,ADDR MyDest,ln
MemCopy copies the byte count of memory from a source buffer to a destination buffer.


memfill

memfill proc lpmem:DWORD,ln:DWORD,fill:DWORD

Description
memfill is a fast memory filling procedure that works in DWORD unit sizes. It is usually good practice to allocate memory in intervals of four for alignment purposes and this procedure is designed to work with memory allocated this way.

Parameters
1. lpmem The address of the memory block to fill.
2. ln The buffer length to fill.
3. fill The fill character(s).

Return Value
There is no return value.

Comments
In most instances the fill character will be ascii zero but the DWORD value can be arranged in any manner convenient, it also can be loaded as a string which will be repeated at 4 byte intervals.
NOTE that the characters in the string will be reversed so that if you place "1234" in the DWORD variable, it will be written to the memory filled as "43214321" for the length of the filled memory. Also note that the procedure will round down the fill to the next interval of 4 if the buffer does not divide equally by four.


NameFromPath

NameFromPath proc lpPath:DWORD,lpBuffer:DWORD

Description
NameFromPath reads the filename from a complete path and returns it in the buffer specified in the parameter list.

Parameters
1. lpPath is the address of the full path that has the file name.
2. lpBuffer is the address of the buffer to receive the filename.

Return Value
The file name is returned in the buffer supplied in the second parameter.

Comments
The buffer to receive the filename must be large enough to acept the filename. For safety reasons if dealing with both long path and file name, the buffer can be made the same length as the source buffer.


Notes On Encryption

The algorithms in the library are components for constructing encryption systems. They use fundamentally simple low level encryption techniques in XOR, ROL and ROR. The strength of this system is not in the encryption method but in the capacity to use very large keys up to source length keys or longer.

Large keys of source length or longer present considerable problems for cracking encrypted data as it defeats many of the known techniques for of code breaking. There are no sequential repeats in the key, working on a small section of the encrypted data has no advantages and a dictionary attack fails when the key can be any type of data including binary files.

On modern computers, large files like bitmaps are very common so if you work for the KGB, having a badly scanned image of Richard Nixon would work as a key where if you worked for the CIA, a badly scanned image of Leonard Breznev would work as well.

Properly an encryption standard random pad is what should be used and each time the pad should be unique. reuse of the same pad progressively degrades the standard of encryption.

The methods in the library are secure in as much as they are published and therefore public encryption methods.
While the methods are primarily designed for block data encryption being read from and written to disk, there is no reason why they cannot be used for computer security related software and program protection.

XorData is encrypted on the first pass and decrypted on the next using the same key and source data. RolData and RorData are used in pairs where data encrypted with one is decrypted with the other using the same key.

The algorithms work by looping through the key until it finds the end then it repeats the loop so it will handle key data that is shorter than the source data but it is advantageous to use a key the size of the source or larger as there are no repeats in the sequence that can be used to crack the encryption.


nrandom

nrandom proc base:DWORD

Description
A Park Miller random algorithm written by Jaymeson Trudgen (NaN) and optimised by Rickey Bowers Jr. (bitRAKE).

Parameter
1.base Zero based range for random output.

Return Value
Random number within range set in "base" in EAX.

Comments
The seed for the random algorithm is set as a variable of GLOBAL scope in a seperate procedure atached to the library module. The variable is nrandom_seed and this variable should be set with a DWORD size number prior to the use of this algorithm.


OpenFileDialog

OpenFileDialog proc hParent:DWORD,Instance:DWORD,lpTitle:DWORD,lpFilter:DWORD

Description
OpenFileDialog displays a common dialog to obtain the name of a file.

Parameters
1. hParent The handle of the parent window.
2. Instance The application or DLL instance handle.
3. lpTitle The address of a zero terminated string with the dialog title.
4. lpFilter The file pattern(s) to display in the dialog.

Return Value
The return value in EAX is the offset of a dedicated 260 byte buffer for this procedure. If the user selects a file name it will be written to the buffer, if the user cancels the dialog, the first byte in the buffer is set to ascii zero.

Comments
If the pattern is too long to place in the macro, it can be placed in a seperate variable and used in the macro.You should test for the user cancelling the operation by testing the 1st byte in the buffer that is returned in EAX with code similar to the following.

  mov patn, CTXT("all files",0,"*.*",0,"txt files",0,"*.txt;*.ini",0)
  mov fname, OpenFileDlg(hWin,hInstance,SADD("Open File ..."),patn)
  cmp BYTE PTR [eax], 0
  jne @F
  ; code to respond to cancelling the dialog here
@@:


PageSetupDialog

PageSetupDialog proc hWin:DWORD, lppsd :DWORD, style:DWORD,
                     lMargin:DWORD, tMargin:DWORD,
                     rMargin:DWORD, bMargin:DWORD

Description
PageSetupDialog is a system common dialog for setting up parameters for a page to be printed.

Parameters
1. hWin Parent window handle.
2. lppsd Address of PAGESETUPDLG structure for return parameters
3. style Default is 0, else styles from PAGESETUPDLG reference.
4. lMargin 0 defaults to 500, inch = 1000
4. tMargin 0 defaults to 500, inch = 1000
4. rMargin 0 defaults to 500, inch = 1000
4. bMargin 0 defaults to 500, inch = 1000

Return Value
If OK is clicked, the return value is non-zero, if Cancel is clicked, zero is returned.

Comments
If OK is clicked, the PAGESETUPDLG structure is filled with the selection from the dialog.


parse_line

parse_line proc src:DWORD,array:DWORD

Description
Parse words in a line of text into an array of zero terminated strings.

Parameters
1.src The address of the zero terminated line of text.
2.array The array to write the words to.

Return Value
The return value is the number of words written to the array.
The words in the line of text are individually loaded into consecutive array locations.

Comments
The array address passed to the procedure must be an array of pointers to preallocated memory. The "create_array" procedure in the MASM32 library is ideally suited to this task as it allocates the memory and sets the array of pointers to the members of the array.

When you allocate the array of zero terminated strings, you must ensure that the individual buffer size is large enough and there are enough members to handle the maximum number of words on the line of text.

Words are determined by an allowable character table. The procedure was originally designed to parse lines of assembler code so it supports the following characters.

upper case ABCDEFGHIJKLMNOPQRSTUVWXYZ
lower case abcdefghijklmnopqrstuvwxyz
numbers 0123456789
quotation marks " "
square brackets [ ]
address calculation + - *
label identification :

The algorithm is flexible enough to do most normal line parsing requirements.


partial

partial proc startat:DWORD,psrc:DWORD,ppatn:DWORD

Description
Partial string matching algorithm with fixed "*" wildcard support.

Parameters
1. startat : zero based offset from start address.
2. psrc : address of zero terminated source to search.
3. ppatn : address of zero terminated pattern to find.

Return Value
-1 = NO match
0 and greater = zero based offset of match

Comments
Algorithm is a traditional linear scanner with a specialised matching loop to handle included wildcard characters.
Zero terminated string format for the pattern to find occurs in the following format.

For a range of similar words,
test
pest
best
text
The string "*e*t" will match all of them.

NOTE that the algorithm is not designed to handle variable length wildcard ranges, it is specifically designed for fixed character lengths.


PrintDialog

PrintDialog proc hWin:DWORD,lppd:DWORD,flags:DWORD

Description
PrintDialog is a system common dialog that is used to set printing options.

Parameters
1. hWin The handle of the calling application.
2. lppd The address of a PRINTDLG structure.
3. Flags Additional styles from the PRINTDLG reference material.

Return Value
If OK is clicked, the return value is non-zero, if Cancel is clicked, zero is returned.

Comments
The selection parameters are contained in the PRINTDLG structure if cancel was not pressed.


Quick Sort

nrQsortA proc Arr:DWORD,count:DWORD
nrQsortD proc Arr:DWORD,count:DWORD

Description
The algorithms differ only in that they sort in opposite directions, nrQsortA sorts in Ascending order, nrQsortD sorts in Descending order.

Parameters
1. Arr The starting address of the array
2. count The number of members in the array.

Return Value
There is no value returned from this procedure.

Comments
This algorithm type is generally faster than any of the traditional sorting algorithms but in some circumstances, data ordered in unusual ways may effect the speed of the sort. In most instances on random data, the algorithm type is very fast.

NOTE : The oleaut32 library and include file are needed because of the OLE string memory used by the procedure.


read_disk_file

read_disk_file proc lpfname:DWORD,lpMem:DWORD,lpLen:DWORD

Description
read_disk_file reads a disk file into memory and returns the address and length in two DWORD variables.

Parameters
1. lpfname The zero terminated file name.
2. lpMem The address of the DWORD variable that receives the starting address of the buffer.
3. lpLen The address of the DWORD variable that receives the number of bytes written to the memory buffer.

Return Value
The return value is non zero if the file is opened and zero if the procedure fails.

Comments
The lpMem value should be deallocated using GlobalFree() once the memory for the file content is no longer required.


Read_File_In

Read_File_In proc hEdit:DWORD,lpszFileName:DWORD

Description
Read_File_In reads the file specified in the second parameter and loads it into the edit control specified in the first parameter.

Parameters
1. hEdit is the handle of the rich edit control to be loaded.
2. lpszFileName is the address of a zero terminated filename.

Return Value
There is no return value.

Comments
This procedure uses the EM_STREAMIN method to load the file into the rich edit control.


readline

readline proc source:DWORD,buffer:DWORD,spos:DWORD

Description
A procedure to read a line of text directly from memory.

Parameters
1.source The address of the memory to read the text from.
2.buffer The destination buffer to write the line of text to.
3.spos The current location pointer.

Return Value
The updated "spos" value is returned in EAX.
The line length not including zero or 13 is returned in ECX.

Comments
Readline copies a line of text from the source to the buffer starting from the offset set in "spos", updates the "spos" variable to the start of the following line of text and returns that variable in EAX. EAX returns ZERO if the end of the source is on the current line.

The length of the line not including ascii 0 and 13 is returned in ECX. You should test the buffer if ZERO is returned in EAX as it may contain the last line of text that is zero terminated.

Normally the "spos" variable is allocated before the procedure is called and initialised to zero. It is then updated after each call to the procedure.

Conditions to test for.
1. End of source returns zero in EAX.
2. blank line has 1st byte in buffer set to zero
and a line length in ECX of ZERO.
3. Line length is returned in ECX.


RichEd1

RichEd1 proc a:DWORD,b:DWORD,wd:DWORD,ht:DWORD,
             hParent:DWORD,instance:DWORD,ID:DWORD,WRAP:DWORD

RichEd2 proc a:DWORD,b:DWORD,wd:DWORD,ht:DWORD,
             hParent:DWORD,instance:DWORD,ID:DWORD,WRAP:DWORD

Description
Both procedures differ only in that they use different versions of the rich edit control.

Parameters
1. a Top X co-ordinate for control
2. b Top Y co-ordinate for control
3. wd Width to create control.
4. ht Height to creat control
5. hParent Parent handle of control.
6. hInstance The instance handle of the application.
7. ID The identification number of the control.
8. WRAP Specify if wordwrap is required, 0 = none, 1 = wordwrap.

Return Value
The return value is the handle of the control.

Comments
Note that you must use LoadLibrary and the name of the version of richedit control that you intend to use. For richedit 1, the name is RICHED32.DLL, for richedit 2, the name is RICHED20.DLL.


SaveFileDialog

SaveFileDialog proc hParent:DWORD,Instance:DWORD,lpTitle:DWORD,lpFilter:DWORD

Description
SaveFileDialog displays a common dialog to obtain the name of a file.

Parameters
1. hParent The handle of the parent window.
2. Instance The application or DLL instance handle.
3. lpTitle The address of a zero terminated string with the dialog title.
4. lpFilter The file pattern(s) to display in the dialog.

Return Value
The return value in EAX is the offset of a dedicated 260 byte buffer for this procedure. If the user enters a file name it will be written to the buffer, if the user cancels the dialog, the first byte in the buffer is set to ascii zero.

Comments
If the pattern is too long to place in the macro, it can be placed in a seperate variable and used in the macro.You should test for the user cancelling the operation by testing the 1st byte in the buffer that is returned in EAX with code similar to the following.

  mov patn, CTXT("all files",0,"*.*",0,"txt files",0,"*.txt;*.ini",0)
  mov fname, SaveFileDlg(hWin,hInstance,SADD("Save File ..."),patn)
  cmp BYTE PTR [eax], 0
  jne @F
  ; code to respond to cancelling the dialog here
@@:


SetClipboardText

SetClipboardText proc ptxt:DWORD

Description
Write text to the clipboard.

Parameters
ptxt Address of text to write to the clipboard. This can be the adress of a normal zero terminated string or you can use on of the masm32 macros for a direct string literal.

Return Value
This procedure has no return value.

Examples
invoke SetClipboardText,ADDR MyText
fn SetClipboardText,"Hi I am text being written to the clipboard"


shell

shell proc lpfilename:DWORD

Description
shell runs another process synchronously. It is designed to run programs sequentially in much the same manner as DOS batch files.

Parameter
1. lpfilename is the zero terminated string that contains the file name and any command line parameters that are required to follow it.

Return Value
The function has no return value.

Comments
This function runs another process synchronously and the calling application is disabled for the duration of the time that the other process runs. Care should be taken with this function to ensure that the processes being run closes properly otherwise the calling application will remain disabled.

Notes
This function emulates a very old DOS era function that ran an external executable file in a non-re-entrant monotasking environment and it is designed to be fail safe even on obscure hardware that is not always compatible with modern operating systems and may have suffered viral or similar damage. It comes at the price that it does not deallocate two handles used in a structure by the CreateProcess Windows API. The two handles are released when the application closes.

The problem was reproducable on an AMD K6-2 3D NOW processor running at 550 megahertz. The particular processor required a patch from Microsoft for the win95b version as it crashed when starting. When the procedure deallocated the two handles, the operating system locks up.

If you can find a reason to loop an executable at high speed under synchronous conditions you can use the shell_ex procedure that is a more modern design complete with priority control of the app to be started. Note that shell_ex and an alternative procedure wshell will crash on the test computer mentioned. The failure when looping the shell procedure occurs at about 10 thousand iterations under test conditions which is well beyond the design range of the original shell procedure.


shell_ex

shell_ex proc lpfilename:DWORD,process_priority:DWORD

Description
An extended version of the original "shell" procedure that accepts a parameter to change the priority of the child process.

Parameters
1.lpfilename The name of the executable file to run.
2.process_priority One of the values from the SetPriorityClass() API function call.

Return Value
There is no return value.

Comments
There is a risk on some version of win9x that the two API calls to free two handles associated with the CreateProcess() API will cause the machine to reboot. This does not appear to be a problem with the NT/2K/XP series of Windows OS versions.


Sorting Overview

Two sort designs are presented, one is a non recursive Quick Sort, the other is a design published in BYTE magazine in the early nineties called a Comb Sort. Both type have ascending and descending versions and are designed to sort DWORD size integers.

The non recursive quick sort is the faster of the two but the comb sort is well suited for smaller sorts up to about 50,000 items. Over this the extra speed of the quick sort will start to show. The comb sort is smaller code and a simpler design which is also more memory efficient so it may suite simpler applications.


StdErr

StdErr proc lpszText:DWORD

Description
Output text to the screen by the standard error handle.

Parameters
1. lpszText Zero terminated string to display to standard error.

Return Value
The return value is the byte count written to standard error.

Comments
This is an alternate method to display text to the console that can be used when STDOUT has been redirected to a file.


StdIn

StdIn proc lpszBuffer:DWORD,bLen:DWORD

Description
StdIn receives text input from the console and places it in the buffer required as a parameter. The function terminates when Enter is pressed.

Parameters
1. lpszBuffer The buffer to receive the text input from the console.
2. bLen The length of the buffer.

Return Value
There is no return value.

Comments
The console determines the length of the maximum buffer size. 128 bytes should handle most console input needs. The position of the input on the console can be set with the locate function.


StdOut

StdOut proc lpszText:DWORD

Description
StdOut will display a zero terminated string at the current position in the console.

Parameter
1. lpszText A zero terminates string.

Return Value
There is no return value.

Comments
There is no effective length limit on the string displayed. The position of the displayed text on the console can be set with the locate function.
The following macro will allow quoted text to be displayed at the current position on the console with the following syntax,

print "This is a test !"

print MACRO Quoted_Text:VARARG
  LOCAL Txt
  .data
    Txt db Quoted_Text,0
  .code
  invoke StdOut,ADDR Txt
ENDM


StripLF

StripLF proc strng:DWORD

Description
StripLF is designed to remove the CRLF (ascii 13,10) by writing an ascii zero in the place of the first occurrence of ascii 13.

Parameters
1. strng is the address of the buffer that needs to be truncated.

Return Value
The procedure has no return value.

Comments
This procedure was designed primarily for console mode input where and ascii 13,10 is appended to the end of the result. This effects entering numerical values that are converted from string to DWORD. Removing the CRLF allows the entered numbers to be converted correctly.


StripRangeI

StripRangeI proc lpszSource:DWORD,lpszDest:DWORD,stByte:BYTE,enByte:BYTE

Description
The StriprangeI function removes a range of characters from a zero terminated string that start with the stByte parameter and finish with the enByte parameter and writes the result to the lpszDest buffer address.

Parameters
1. lpszSource The address of the source buffer.
2. lpszDest The address of the destination buffer.
3. stByte The starting byte for the range to remove.
4. enByte The end byte for the range to remove.

Return Value
There is no return value.

Comments
For safety purposes, the destination buffer should be the same size as the source buffer. This function is ideally suited for removing html tags and the angle brackets that enclose them.


StripRangeX

StripRangeX proc lpszSource:DWORD,lpszDest:DWORD,stByte:BYTE,enByte:BYTE

Description
This function will remove a range of characters from the zero terminated string in lpszSource and place the result in the buffer lpszDest. The range is determined by the starting byte parameter stByte and the end byte parameter enByte. It does not remove the starting and ending byte characters.

Parameters
1. lpszSource The address of the source buffer.
2. lpszDest The address of the destination buffer.
3. stByte The starting byte for the range to remove.
4. enByte The end byte for the range to remove.

Return Value
There is no return value.

Comments
For safety purposes, the destination buffer should be the same size as the source buffer. This function will remove characters from between the two byte parameters ands is well suited for example at removing text withing brackets. ThisText(Enclosed Text) becomes ThisText() when the starting and ending bytes are "(" and ")".


StrLen

StrLen proc item:DWORD

Description
This function has been adapted from an algorithm written by Agner Fog. It reads the length of a zero terminated string and places it in eax. It is an unusual function in that it will read up to 3 bytes past the end of a buffer as it uses DWORD size reads. It appears that the condition does not generate a GP fault in windows as memory is usually alocated in 4 byte blocks.

Parameter
1. item The address of the zero terminaed string.

Return value
The length of the zero terminated string is returned in eax.

Comments
This function is measurably faster than a classic byte scanner and has its place where linear read speed is required.


StrToFloat

StrToFloatPROCstdcall public, szIn: PTR BYTE, fpout: PTR QWORD

Note that both parameters are DWORD size addresses.

Description
StrToFloat converts a floating point string to a floating point number.

Parameters
1. szIn The address of the floating point string.
2. fpout The address of the QWORD buffer to hold the result.

Return Value
If the procedure encounters an illegal character that it cannot convert, it returns the address of the character in eax.

Comment
It is the user's responsibility to ensure that there are no illegal characters in the szIn input string.


szappend

szappend proc string:DWORD,buffer:DWORD,location:DWORD

Description
Append zero terminated string data to end of string buffer.

Parameters
1. string The main buffer to append extra data to.
2. buffer The data to append to main buffer.
3. location The offset to write the append data to.

Return Value
The location of the end of the buffer which can be used for the next call to szappend as the "Location" parameter.

Comments
This algorithm is designed to repeatedly append zero terminated string data to the end of a user defined buffer. It uses a location pointer to save repeatedly scanning the buffer for the end position. With a new buffer, the first byte should be set to ascii zero, with an existing zero terminated string in a buffer, you should supply the length and set the location parameter to that length.
The return value is the buffer end position which you pass back to the procedure for the next appended data.


szCatStr

szCatStr proc lpszSource:DWORD, lpszAdd:DWORD

Description
szCatStr appends the second zero terminated string (lpszAdd) to the end of the first zero tereminated string (lpszSource). The result is zero terminated.

Parameters
1. lpszSource The address of the source string to be appended to.
2. lpszAdd The address of the string to append to lpszSource.

Return Value
There is no return value.

Comments
It is the users responsibility to ensure that the buffer for the source string is large enough to accept the appended string. Failure to do this will end up with a write page fault.


szCmp

szCmp proc str1:DWORD,str2:DWORD

Description
szCmp compares two zero terminated strings for difference.

Parameters
1. str1 The first string to compare
2. str2 The second string to compare

Return Value
If the two strings match, the return value is the length of the string. If there is no match, the return value is zero.

Comments
The procedure can be used on strings that may be of uneven length as the terminator will produce the mismatch even if the rest of the charactes match.


szCmpi

szCmpi proc src:DWORD, dst:DWORD, ln:DWORD

Description
A table driven high speed case insensitive text comparison algo.

Parameters
1. src The address of the first string to compare.
2. dst The address of the second string to compare
3. ln The number of charactes to test for, usually the length of the first string.

Return Value
szCmpi returns zero if the two strings or byte sequences are identical or the character count where the two byte sequences mismatch.

Comments
This procedure uses a character table and a character count and it can be used on any BYTE sequence including string. If you need to emulate the characteristics of the case sensitive version, convert both strings to a single case and then do a case sensitive comparison.


szCopy

szCopy proc src:DWORD, dst:DWORD

Description
szCopy copies a zero terminated string from the source buffer to the destination buffer.

Parameters
1. src The address of the source string
2. dst The address of the destination buffer

Return Value
There is no return value

Comments
The destination buffer must be large enough to hold the source string otherwise a page write fault will occur.


szLeft

szLeft proc lpSource:DWORD, lpDest:DWORD, lnth:DWORD

Description
szleft reads a set number of characters from the start of a zero terminated string and writes them to the destination buffer.

Parameters
1. source Address of the source string.
2. dest Address of the destination buffer.
3. lnth The number of characters to read.

Return Value
There is no return value.


szLen

szLen proc lpString:DWORD

Description
szLen reads the length of a zero terminated string and returns its length in eax.

Parameter
1. lpString Address of zero terminated string.

Return Value
The length of the zero terminated string without the terminating zero byte in eax.


szLower

szLower and szUpper

szLower proc text:DWORD
szUpper proc text:DWORD

Description
szLower converts any uppercase characters in the supplied zero terminated string to lowercase.
szUpper converts any lowercase characters in the supplied zero terminated string to uppercase.

Parameter
1. text The address of the text to convert.

Return Value
There is no return value.

Comments
szLower and szUpper works on the original string and writes it back to the same address.


szLtrim

szLtrim proc source:DWORD,dest:DWORD

Description
szLtrim trims the leading spaces and tabs from a zero terminated string and places the results in the destination buffer provided..

Parameters
1. source The address of the source string.
2. dest The address of the destination buffer.

Return Value
The return value is the length of the trimmed string which can be zero.

Comments
If the string is trimmed to zero length if it has no other characters, the first byte of the destination adress will be ascii zero. Ensure the destination buffer is big enough to receive the substring, normally it is advisable to make the buffer the same size as the source string. If your design allows for overwriting the string, you can use the same string address for both source and destination.


szMid

szMid proc source:DWORD, substring:DWORD, stPos:DWORD, ln:DWORD

Description
szMid reads a set number of characters from a set starting position in the source string and writes them to the destination string.

Parameters
1. source Address of source string.
2. substring Address of buffer to receive the substring.
3. stPos Start position of first character.
4. ln The number of bytes to read.

Return Value
There is no return value.

Comments
It is the users responsibility to ensure that the length of the substring is fully contained within the source string. Failure to do so will result in either a read or write page fault.


szMonoSpace

szMonoSpace proc src:DWORD

Description
Format a string with single spaces only replacing any tabs with spaces and trimming tabs and spaces from either end of the string.

Parameters
1. src The address of the zero terminated string to format.

Return Value
The return value is the address of the source string passed to the procedure.

Comments
The algorithm removes any leading tabs and spaces then formats the string with single spaces replacing any tabs in the source with spaces. If there is a trailing space after formatting, the string is truncated to remove it.


szMultiCat

szMultiCat proc C pcount:DWORD,lpBuffer:DWORD,args:VARARG

Description
szMultiCat uses a buffer that can be appended with multiple zero terminated strings, this is more efficient when multiple strings need to be concantenated.

Parameters
1. pcount is the number of zero terminated strings to append.
2. lpBuffer is the address of the buffer to appends the strings to.
3. args is the comma seperated parameter list.

Return Value
This function does not return a value.

Comments
The allocated buffer must be large enough to accept all of the appended zero terminated strings. The parameter count must match the number of zero terminated strings.


szRemove

szRemove proc src:DWORD,dst:DWORD,remv:DWORD

Description
szRemove removes a substring from a source string and writes the result in the destination buffer.

Parameters
1. src The address of the source string
2. dst The address of the destination buffer
3. remv The address of the substring to remove

Return Value
The destination address is returned in the EAX register. This is mainly useful for writing a macro using this procedure.

Comments
The procedure supports using a single buffer for both the source and destination if the original string does not need to be preserved.


szRep

szRep proc src:DWORD,dst:DWORD,txt1:DWORD,txt2:DWORD

Description
Replace text in a zero terminated string.

Parameters
1. src The address of the source to replace text in.
2. dst The destination buffer for the results.
3. txt1 The text to replace.
4. txt2 The text to replace it with.

Return Value
The procedure has no return value.

Comments
While the text replacement technique is unproblematic, the memory strategy for the destination buffer needs to be properly thought out to get reliable operation. If the replacement is the same length as the text to replace or shorter, the destination buffer can safely be made the same length as the source buffer but if the replacement text is longer, a method to calculate the extra size of the destination buffer must be used.

The szWcnt procedure is one way of calculating the extra length required in the destination buffer. The technique is to calculate the additional length of the replacement word, subtract the original text length from it then multiply the result by the number of occurrences of the replacement text.

Example
Here is a working example of both replace methods.

@@:
  mov lwrd1, len(word1)
  mov lwrd2, len(word2)
  mov eax, lwrd2

.if lwrd1 >= eax
; --------------
; simple replace
; --------------
  add lsrc, 16384
  mov hsrc, alloc$(lsrc) ; allocate src and dst the same length
  mov hdst, alloc$(lsrc)
  invoke SendMessage,hEdit,EM_GETSELTEXT,0,hsrc ; get the selected text
  invoke szRep,hsrc,hdst,word1,word2 ; perform replacement on its contents
  invoke SendMessage,hEdit,EM_REPLACESEL,TRUE,hdst ; replace the selection in the editor
  free$ hdst
  free$ hsrc
  ret

.else
; ---------------
; complex replace
; ---------------
  add lsrc, 16384
  mov hsrc, alloc$(lsrc)
  invoke SendMessage,hEdit,EM_GETSELTEXT,0,hsrc ; get the selected text
  mov wcnt, rv(szWcnt,hsrc,word1) ; count the first word in source
  mov eax, lwrd2
  sub eax, lwrd1 ; calculate extra word2 length in eax
  invoke IntMul,wcnt,eax ; multiply word count by extra bytes
  add lsrc, eax ; add it to the source length
  mov hdst, alloc$(lsrc) ; allocate the larger size memory
  invoke SendMessage,hEdit,EM_GETSELTEXT,0,hsrc
  invoke szRep,hsrc,hdst,word1,word2
  invoke SendMessage,hEdit,EM_REPLACESEL,TRUE,hdst
  free$ hdst
  free$ hsrc

.endif


szRev

szRev proc lpszSource:DWORD,lpszDest:DWORD

Description
szRev reverses a zero terminated string in lpszSource and places it in lpszDest.

Parameters
1. lpszSource The address of the source string.
2. lpszDest The address of the destination buffer.

Return Value
There is no return value.

Comments
The destination buffer must be at least the size of the source buffer otherwise a read page fault will occur.


szRight

szRight proc source:DWORD, dest:DWORD, lnth:DWORD

Description
szRight reads a set number of characters from the end of a zero terminated string and writes them to the destination buffer.

Parameters
1. source Address of the source string.
2. dest Address of the destination buffer.
3. lnth The number of characters to read.

Return Value
There is no return value.


szRtrim

szRtrim proc source:DWORD,dest:DWORD

Description
szRtrim trims the trailing spaces and tabs from a zero terminated string and places the results in the destination buffer provided..

Parameters
1. source The address of the source string.
2. dest The address of the destination buffer.

Return Value
The return value is the length of the trimmed string which can be zero.

Comments
If the string is trimmed to zero length if it has no other characters, the first byte of the destination adress will be ascii zero. Ensure the destination buffer is big enough to receive the substring, normally it is advisable to make the buffer the same size as the source string. If your design allows for overwriting the string, you can use the same string address for both source and destination.


szTrim

szTrim proc src:DWORD

Description
szTrim trims leading and trailing tabs and spaces from a zero terminated string.

Parameter
1. src The address of the zero tereminated string.

Return Value
The return value is the length of the trimmed string which can be zero.

Comments
If the string is trimmed to zero length if it has no other characters, the first byte of the destination adress will be ascii zero. This procedure acts on the original source string and overwrites it with the result.


szWcnt

szWcnt proc src:DWORD,txt:DWORD

Description
Count the number of instances of a specified text in a zero terminated string.

Parameters
1. src The address of the zero terminated string.
2. txt The specified zero terminated text to count.

Return Value
The return value is the number of instances of the text to count.

Comments
This procedure among other things is used to calculate the extra length for an output buffer when replacing text with other text that is longer than the original text.


testreg

testreg proc

Description
testreg tests zero terminated string to see if they are registers.

Parameters
1. The string address is passed in the EAX register

Return Values
Not a register         0
Segment register       1   cs ds es ss fs gs
8 bit register         2   al ah bl bh cl ch dl dh
16 bit register        3   ax bx cx dx si di sp bp
32 bit register        4   eax ebx ecx edx esi edi esp ebp

Comments
This procedure is designed for very high speed word recognition of registers. It support both upper and lower case but not mixed case. It is used in applications that process assembler source code to test if an operand is a register or not.


tstline

tstline proc lpstr:DWORD

Description
This is a dedicated procedure to test the contents of a line of text loaded by the readline or writeline procedures or their matching macros linein$ or lineout$.

Parameters
1.lpstr The address of the string to test.

Return Value
If the return value is ZERO, the line of text has no useful content.
If the return value is not ZERO, it is the ascii number of the first character zero extended into EAX.

Comments
This procedure scans the string stripping leading spaces or tabs until it find either a character above ascii 32 (space) which it returns zero extended in EAX or alternatively if the first character after stripping any leading spaces or blanks is below ascii 32, it returns zero.

If the return value is non zero, it can be tested either as a DWORD against an immediate number or alternatively it can be tested as a BYTE in AL against another register or memory operand.


ucappend

ucappend proc buffer:DWORD,string:DWORD,cloc:DWORD

Description
ucappend appends the characters in "string" to the buffer "buffer" and returns the current location "cloc" so it can be used for the next append operation.

Parameters
  buffer = the buffer to append characters onto
  string = the characters to append to the buffer
  cloc   = the current append location POINTER

  NOTE that cloc POINTER is a BYTE counter. To get the UNICODE character count, divide "cloc" by 2.

Return Value
The return value is the current location pointer that is to be used for the next append operation.

Comments
This procedure is designed for high speed sequential append operations by avoiding the necessity of rescanning the string each iteration to find the end. The "cloc" argument allows the procedure to directly find the end of the existing characters so that it can write the next text data to the end of the buffer.

NOTE that the buffer to append the text data to must be large enough to hold all of the data being appended to it.

    LOCAL buffer[260]:TCHAR
    LOCAL bptr  :DWORD
    LOCAL str1  :DWORD
    LOCAL str2  :DWORD
    LOCAL str3  :DWORD
    LOCAL cloc  :DWORD

    mov bptr, ptr$(buffer)

    mov str1, chr$("one ")
    mov str2, chr$("two ")
    mov str3, chr$("three ")

    mov cloc, 0    ; start at the beginning of the buffer

    invoke ucappend,bptr,str1,cloc
    mov cloc, eax

    invoke ucappend,bptr,str2,cloc
    mov cloc, eax

    invoke ucappend,bptr,str3,cloc
    mov cloc, eax

This is a simple example, the procedure would normally be used in a loop where the variable "cloc" is updated each iteration of the loop.


ucArgByNum

ucArgByNum proc src:DWORD,dst:DWORD,num:DWORD

Description
ucArgByNum returns a user selected argument from a line of text if it exists.

Parameters
  src = string to get argument from
  dst = buffer to take selected argument
  num = 1 based number for argument, 1 = arg1, 2 = arg2 etc ...

Return Value
The return value is the user nominated argument number if the argument exists or ZERO if no argument is available.

Comments
Test EAX to determine if the nominated argument exists.

    test eax, eax
    jz no_arg_label


ucCatStr

ucCatStr proc wstr1:DWORD,wstr2:DWORD

Description
Append one unicode string to another.

Parameters
1.wstr1 The source string to append to.
2.wstr2 The string to append to it.

Return Value
There is no return value.

Comments
The source buffer must be large enough to accept the additional string appended to it.


ucCmdTail

ucCmdTail proc

Description
ucCmdTail returns the address of the command line tail if it exists..

Parameters
This procedure does not receive any arguments.

Return Value
The return value is the address of the command tail if it exists.

Comments
If you need to further modify the string returned by this procedure you should copy it to a buffer of its own so you do not alter the original command line string.

cst yourbuffer, cmdtail_return string_address
or
invoke ucCopy,cmdtail_return string_address,yourbuffer


ucCmp

ucCmp proc wst1:DWORD,wst2:DWORD

Description
Compare two unicode strings.

Parameters
1.wstr1 The first string to test
2.wstr2 The second string to test

Return Value
If the two strings do not match, the return value is ZERO otherwise the length of the two strings is returned.

Comments
NOTE: The returned string length on match is in CHARACTERS, not BYTES.


ucCopy

ucCopy proc wsrc:DWORD,wdst:DWORD

Description
Copy unicode string from one memory buffer to another.

Parameters
1.wsrc The address of the source string
2.wdst The address of the destination buffer

Return Value
There is no return value.

Comments
The destination buffer must be large enough to hold the source string.


ucFind

ucFind proc sPos:DWORD, wsrc:DWORD, wsub:DWORD

Description
Find a unicode substring in a unicode source string.

Parameters
1. sPos The required starting position in the source string.
2.wsrc The source string to be searched.
3. wsub The substring to find in the source string.

Return Value
If substring is not found, the return value is ZERO otherwise the starting position for the substring is returned.

Comments
The starting position and the return value if the substring is found are BOTH 1 (one) based indexes. The first character in the source buffer is at position ONE, not zero.


ucGetCL

ucGetCL proc obuf:DWORD,ccnt:DWORD,argnum:DWORD

Description
ucGetCL reads the length of a unicode string in characters.

Parameters
obuf   = user supplied output buffer
ccnt   = output buffer character count
argmun = the 1 based arg the user wants 1 = arg1, 2 = arg2 etc ....

Return Value
< 0 = buffer not large enough for selected arg
  0 = arg not found
> 0 = arg number read from command tail

Comments
This algorithm provides double buffer protection, it allocates memory based on the command tail length so the length cannot be overrun and it allocates the same length buffer for the user selected argument. When the argument is obtained from the "ucArgByNum" procedure, its length is checked against the length of the user supplied buffer and rejected if it is longer. The technique is designed to prevent deliberate command line exploits.

If you use an .IF block to evaluate EAX, ensure that you use SDWORD PTR before EAX as the return value can be nagative if the user supplied buffer is not large enough.

    .if SDWORD PTR eax < 0
      ; do something
    .else
      ; do default
    .endif


ucgetline

ucgetline proc src:DWORD,dst:DWORD,cloc:DWORD

Description
ucgetline reads the line of UNICODE text at the current location pointer. ( cloc )

Parameters
src  = text to get line from.
dst  = the buffer to receive the line if it exists.
cloc = the current location pointer.

Return Value
The return value is either the current location pointer for the next line "cloc" OR zero if no argument is available.

Comments
This procedure is used for tasks like reading a line of text at a time from a text file and placing it in a user defined buffer. NOTE that the text must be UNICODE text, it will not work on ASCII text.

    __UNICODE__ equ 1
    ...................

    LOCAL cloc  :DWORD
    LOCAL ptxt  :DWORD

    mov ptxt, chr$("line 1",13,10,"line 2",13,10,"line 3",13,10,"line 4",13,10)

    mov cloc, 0

  lbl:
    mov cloc, rv(ucgetline,ptxt,pbuf,cloc)
    cmp cloc, 0
    je @F
    print pbuf,13,10
    jmp lbl

  @@:


ucLeft

ucLeft proc wsrc:DWORD,wdst:DWORD,ccnt:DWORD

Description
ucLeft read a preset number of characters from the left side of the source string and write them to the destination buffer.

Parameters
1.wsrc The source string to read the characters from.
2.wdst The destination buffer.
3.ccnt The count of characters to copy to the destination buffer.

Return Value
There is no return value.

Comments
The destination buffer must be large enough to hold the number of characters read from the source buffer.


ucLen

ucLen proc lpwstr:DWORD

Description
ucLen reads the length of a unicode string in characters.

Parameters
1.lpwstr The address of the string to get the character count from.

Return Value
The return value is the character count.

Comments
The character count returned does NOT include the terminating zero.


ucLower

ucLower proc wsrc:DWORD

Description
ucLower converts a unicode string to lower case.

Parameters
1. wsrc The address of the string to convert.

Return Value
There is no return value.

Comments
This procedure is a wrapper for the API function CharLowerBuffW


ucLtrim

ucLtrim proc wsrc:DWORD,wdst:DWORD

Description
ucLtrim removes leading spaces from the left side of a unicode string.

Parameters
1. wsrc The source string to read the data from.
2. wdst The destination string to write the result to.

Return Value
There is no return value.

Comments
The destination buffer must be large enough to receive the results.


ucMid

ucMid proc wsrc:DWORD,wdst:DWORD,stPos:DWORD,ln:DWORD

Description
ucMid read a preset number of characters from a user defined starting point in a source string and writes the result to a destination buffer.

Parameters
1. wsrc The source string to read the data from.
2. wdst The destination buffer.
3. stPos The starting position to read from.
4. ln The number of characters to read.

Return Value
There is no return value.

Comments
The destination buffer must be large enough to receive the result.


ucMonoSpace

ucMonoSpace proc src:DWORD

Description
ucMonoSpace cleans up a string by trimming junk off each end and setting the spacing to single spaces..

Parameters
1.src = The address of the string to clean up.

Return Value
The return value is the address of the modified string passed to the procedure.

Comments
This procedure trims tabs and spaces from each end of "src" and replace any duplicate tabs and spaces with a single space. The result is written back to the source string address.


ucMultiCat

ucMultiCat proc C pcount:DWORD,lpBuffer:DWORD,args:VARARG

Description
ucMultiCat concantenates multiple unicode strings to a buffer that may contain other unicode string data.

Parameters
1. pcount The number of strings to append to the buffer.
2. lpBuffer The address of the destination buffer.
3. args A variable number of string addresses whose count has been set in "pcount".

Return Value
The procedure returns the address of the destination buffer so it can be used with a macro.

Comments
This procedure uses the C calling convention because it can handle a variable number of parameters. The destination buffer must be large enough to hold ALL of the strings being appended to it. If the buffer does not already have unicode string data, the first character position must be set to ZERO so that the data is written to the beginning of the buffer. Care should be taken to ensure that the "pcount" argument matches the number of string to be appended.


ucOpenFileDialog

ucOpenFileDialog proc hParent:DWORD,Instance:DWORD,lpTitle:DWORD,lpFilter:DWORD

Description
A File Open common dialog that takes and returns unicode string data.

Parameters
1.hParent The handle of the window that is calling the dialog.
2.Instance The application's hInstance member.
3.lpTitle A unicode string to use as the dialog's title.
4.lpFilter A unicode format control string for the file types to display.

Return Value
The return value is the address of the buffer that holds the file name. If no file name was selected, the first character in the buffer will be ZERO.

Comments
The buffer that is returned will be overwritten by the next call to the dialog so if the data is required it must be stored in another buffer before calling the procedure again.


ucRemove

ucRemove proc src:DWORD,dst:DWORD,remv:DWORD

Description
Remove every occurrence of a user defined string from a source string and write the result to the destination buffer.

Parameters
src  = the source string to remove text from.
dst  = the destination buffer for the result.
remv = the string  to remove from the "src" string.

Return Value
The destination address is the return value.

Comments
This algorithm produces a shorter string than the source if any text is removed so a destination buffer of the same length as the source can safely be used.


ucRep

ucRep proc src:DWORD,dst:DWORD,txt1:DWORD,txt2:DWORD

Description
Replace every occurrence of text in a source string and write its results to the destination string.

Parameters
src  = the source string to perform replacements in.
dst  = the destination buffer to write the results to.
txt1 = the text to replace.
txt2 = the text to replace it with.

Return Value
Return Value

Comments
NOTE : This algorithm does NOT perform any memory management on the destination buffer size. For simple replacements where the replacement text is the same length or shorter than the text it replaces you can safely use a buffer of the same length but if the replacement is longer than the text it replaces you need to make the destination buffer larger to handle the extra characters. With simple tasks you can just use a much larger destination buffer but for complex tasks you need to calculate the extra length required. The ucWcnt algorithm is designed to do this.

The technique is to do the simple arithmetic to get the extra character count for each replacement then multiply it by the number of occurrences of the string to replace. It is both useful and easy enough to perform to add a safety margin to the calculated buffer size.

In pseudo notation.
-----------------------------------------

slen1 = length(str1)
slen2 = length(str2)

If slen2 > slen1
  extra = slen2 - slen1                 ; calculate the length difference
  extra = extra * wordcount(srcstring)  ; multiply it by the word count in the source
  extra = extra + 1024                  ; add some padding
  bufferlen = sourcelen + extra         ; add the extra to the source length
Else
  bufferlen = sourcelen                 ; just allocate a buffer of the same size
EndIf

memory = memalloc(bufferlen)

-----------------------------------------


ucRev

ucRev proc wsrc:DWORD,wdst:DWORD

Description
Reverses a unicode string and write the result to a buffer.

Parameters
1.wsrc The string to reverse.
2.wdst The buffer to write the result to.

Return Value
There is no return value.

Comments
The destination buffer must be at least the size of the source buffer.


ucRight

ucRight proc wsrc:DWORD,wdst:DWORD,ccnt:DWORD

Description
Read a preset number of characters from the right side of the source string and write the data to a destination buffer.

Parameters
1.wsrc The address of the source string.
2.wdst The address of the destination buffer.
3.ccnt The number of characters to copy.

Return Value
There is no return value.

Comments
The destination buffer must be large enough to hold the results.


ucRtrim

ucRtrim proc wsrc:DWORD,wdst:DWORD

Description
Remove trailing spaces from a unicode string and write result to a destination buffer

Parameters
1.wsrc Source string to test.
2.wdst Destination buffer for result.

Return Value
There is no return value.

Comments
The destination buffer must be large enough to receive the result.


ucSaveFileDialog

ucSaveFileDialog proc hParent:DWORD,Instance:DWORD,lpTitle:DWORD,lpFilter:DWORD

Description
A Save File common dialog that returns unicode string data.

Parameters
1.hParent The handle of the window that is calling the dialog.
2.Instance The application's hInstance member.
3.lpTitle A unicode string to use as the dialog's title.
4.lpFilter A unicode format control string for the file types to display.

Return Value
The return value is the address of the buffer that holds the file name. If no file name was selected, the first character in the buffer will be ZERO.

Comments
The buffer that is returned will be overwritten by the next call to the dialog so if the data is required it must be stored in another buffer before calling the procedure again.


ucUpper

ucUpper proc wsrc:DWORD

Description
ucUpper converts a unicode string to uper case.

Parameters
1.wsrc The address of the source string to convert.

Return Value
There is no return value.

Comments
This procedure is a wrapper for the API CharUpperBuffW


ucWcnt

ucWcnt proc src:DWORD,txt:DWORD

Description
Count the number of occurrences of "txt" in "src".

Parameters
src = the source address to search.
txt = the text to search for.

Return Value
The return value is the number of occurrences of "txt" in "src".

Comments
This algorithm has various uses but one of its important uses is to count the number of occurrences of a string in the source when performing replacements that are longer than the text they replace.


udw2str

udw2str proc dwNumber:DWORD, pszString:DWORD

Description
udw2str converts an UNSIGNED DWORD to a string.

Parameters
1. dwNumber The unsigned DWORD to convert.
2. pszString The buffer to receive the result.

Return Value
There is no return value.

Comments
This algorithm is designed for unsigned DWORD input only.


ustr2dw

ustr2dw proc pszString:DWORD

Description
ustr2dw converts a zero terminated string to an UNSIGNED DWORD.

Parameter
1. pszString The address of the zero terminated string to convert.

Return Value
The unsigned DWORD is returned in EAX.

Comments
This procedure is designed for unsigned DWORD values only.


VerticalTile

VerticalTile proc hWin:DWORD,bmpID:DWORD,cnt:DWORD

Description
VerticalTile tiles a bitmap in the client area of a window from top down to the number of repeats set in the function call.

Parameters
1. hWin The handle of the window that has the tiled bitmap in its client area.
2. bmpID The resource ID number for the bitmap to be tiled.
3. cnt The number of repeats of the bitmap from top down.

Return Value
There is no return value

Comments
This procedure allows a small bitmap to be tiled vertically to cover the client area of a window, it is suitable for WEB style tiling and it allows image data to be displayed at a much smaller file size than a full client area size bitmap.


WordCount

WordCount proc startpos:DWORD,
               lpSource:DWORD,srcLngth:DWORD,
               lpSubStr:DWORD,subLngth:DWORD

Description
This algorithm is a Boyer Moore design that counts the number of occurrences of the substring in the source data. It can be used for both text and binary data.

Parameters
1. startpos The zero based starting position in the source data.
2. lpSource The address of the data to be searched.
3. srcLngth The length of the source data to be searched.
4. lpSubStr The address of the substring to be counted.
5. subLngth The length of the substring to be counted.

Return Value
Zero for no match or the number of occurrences in the source data of the substring.

Comments
The starting position should always be less than the length of the source minus the length of the pattern being counted.


wordreplace

wordreplace proc src:DWORD,dst:DWORD,wrd1:DWORD,wrd2:DWORD

Description
Globally replace whole words in the source text and write the result to the destination.

Parameters
1.src The source text to replace words in.
2.dst The destination buffer for the result.
3.wrd1 The word to replace.
4.wrd2 The words to replace it with.

Return Value
There is no return value.

Comments
This procedure is a table based linear text scanner based on the following allowable characters.

characters ! # $ % & ? @ _
numbers 0123456789
upper case ABCDEFGHIJKLMNOPQRSTUVWXYZ
lower case abcdefghijklmnopqrstuvwxyz

The procedure will recognise whole words made up of the above characters and will replace every instance of that word with the replacement text. It is suited for simple tasks like replacing whole words in text such as in a text editor but it is also fast enough to loop through a number of words and replace all of them in a macro built into a scripting language or similar application.
It is an interim technology for tasks smaller than those normally handled by a far more complex hash table.


wrd2bin_ex

wrd2bin_ex proc var:WORD,buffer:DWORD

Description
A high speed WORD to binary format converter.

Parameters
1.var The WORD size variable to convert.
2.buffer The address of the destination buffer.

Return Value
There is no return value.

Comments
This algorithm is suitable for streaming binary output as high speed.


write_disk_file

write_disk_file proc lpName:DWORD,lpData:DWORD,fl:DWORD

Description
write_disk_file writes the content of a memory buffer to a disk file

Parameters
1. lpName The address of a zero terminated string that contains the file name.
2. lpData The address of the buffer that contains the data to write.
3. fl The number of bytes to write to the file.

Return Value
The return value is the number of bytes written if the procedure succeeds or zero if it fails.

Comments
This procedure is designed to write a complete disk file each time it is called. It will overwrite an existing file of the same name.


Write_To_Disk

Write_To_Disk proc hEdit:DWORD,lpszFileName:DWORD

Description
Write_To_Disk writes the contents of a richedit control to a diskfile specified in the second parameter.

Parameters
1. hEdit The rich edit control to read from.
2. lpszFile Name The zero terminated disk file name.

Return Value
This procedure has no return value.

Comments
This procedure uses the EM_STREAMOUT method to write the contents of a rich edit control to a disk file.


writeline

writeline proc source:DWORD,buffer:DWORD,spos:DWORD,flag:DWORD

Description
An algorithm that writes a line of text to a memory buffer and updates the last write position.

Parameters
1.source The address of the text to write to the buffer.
2.buffer The buffer to write to.
3.spos The current write location pointer.
4.flag Select if a CRLF is appended to the text.
Zero = appended CRLF.
Non zero = no CRLF appended.

Return Value
EAX returns the updated "spos" location pointer.
ECX returns the number of BYTES written.

Comments
This algorithm is useful for writing text files directly to memory so the result can be written in one disk write. Normally the "spos" variable is allocated before the procedure is called, initialised to zero and updated each time the procedure returns with the new value.


wshell

wshell proc lpfilename:DWORD

Description
An alternative method of running an external executable file.

Parameters
1.lpfilename The name of the executable file to run.

Return Value
There is no return value.

Comments
This procedure has been included because a few people were very vocal in their demand for changes to the original reliable version of "shell". This version is neither recommended nor supported and it may cause early version of Windows to reboot on certain non standard hardware.

NOTE that the original version of "shell" is the recommended version, even though it has a minor memory leak by not closing the two handles associated with CreateProcess(). The memory is reclaimed when the application closes.

These considerations may no longer be applicable for OS versions from win2000 upwards.


wtok

wtok proc pText:DWORD,pArray:DWORD

Description
Tokenise words within text "in place" and return an array of pointers to each token. The algorithm supports MASM style alternate quotations.

Parameters
1. pTxt The address of the source text to tokenise.
2. pArray The address of a DWORD variable that will be used for the handle of the array of pointers. Please refer to the comments section for further details.

Return Value
The return value in EAX is the number of tokens in the array of pointers.

Comments
When the address of the variable for the pointer array is passed to the procedure, the procedure in turn writes the address of the allocated memory back to that address so that within the scope of the procedure that allocated the variable and calls the tokeniser, the variable is then the direct pointer to the array of pointers. When the pointer array is no longer needed the variable should be deallocated using GlobalFree() within the same scope as the variable was allocated. The MASM32 macro "free" works correctly for this task.

Example
LOCAL MyVar :DWORD
Pass ADDR MyVar to the tokeniser.
Use MyVar as the address of the array of pointers after the tokeniser has returned.
free MyVar

Note : This algorithm is designed to be modified by experienced programmers in terms of the character range in the table to control the contents of words to be tokenised. The single and double quotations should not be changed as the algorithm uses them internally. If you are familiar enough with an algorithm of this type, you can selectively remove either the single or double quotation support in specialised applications.


XorData

XorData RolData RorData

XorData proc lpSource:DWORD,ln:DWORD,lpKey:DWORD,lnKey:DWORD
RolData proc lpSource:DWORD,ln:DWORD,lpKey:DWORD,lnKey:DWORD
RorData proc lpSource:DWORD,ln:DWORD,lpKey:DWORD,lnKey:DWORD

Description
The three procedures are used in the identical manner, they differ only in the sequence to decrypt the encrypted data. XorData will decrypt data encrypted by itself using the same key. RolData and RorData are symetrical pairs where one will decrypt data encrypted by the other.

Parameters
1. lpSource The address of the source data to encrypt.
2. ln The length of the source data.
3. lpKey The address of the key data use to encrypt the source data.
4. lnKey The length of the key data.

Return Value
These procedures do not return a value.

Comments
The data for both the source and key are capable of having non printable characters including ascii zero which means the procedures must have the correct lengths in the parameters. Failure to set the correct lengths will result in general protection faults from either reading or writing past the end of the source or key.


(Untitled)

Introduction to 32 bit Assembler
Copyright The MASM32 Project 1998-2005

Flat memory Model
Protected Mode Memory
Instruction Operands
Opcodes and Mnemonics
Registers
Data Types In Registers
The Stack
Addressing and Pointers
Libraries
Working With Strings
Working With Macros
Basic Loop Design
Working With Structures
Register Preservation Convention


add$

mov pstr, add$(lpBuffer,lpString)

Description
Concantenate two strings.

Parameters
1. lpBuffer The address of the source string.
2. lpString The address of the string to append to the source.

Return Value
The return value is the address of the source string.

Comments
The buffer containing the source string must be large enough to hold the additional string data appened to it. This macro is __UNICODE__ aware.


alloc
mov hMem, alloc(byte_count)

Description
Allocate a block of fixed memory.

Parameters
1. byte_count The number of bytes of fixed memory to allocate.

Return Value
The starting address of the block of memory.

Comments
Memory allocate with the alloc macro should be freed with the free macro.

Example
mov hMem, alloc(16384)


alloc$
mov hString, alloc$(byte_count)

Description
Allocate a block of OLE string memory.

Parameters
1. byte_count The count in bytes of the size of the memory to allocate.

Return Value
The return value is the start address of the allocated memory. Properly it is a string handle.

Comments
Memory allocated with the alloc$ macro should be released using the free$ macro.


Allocating String Buffers

Some of the string macros require a buffer that is larger than the source string. In simple situations you can use memory allocated on the stack with the syntax,

LOCAL pstr :DWORD
LOCAL buffer[260]:BYTE
  or
LOCAL buffer[260]:TCHAR  ; data size defined by using __UNICODE__ or not. (Either BYTE for ASCII or WORD for UNICODE).

This method is easy to use and you do not have to deallocate the buffer as it is done on procedure exit. To make the buffer easier to use, it is useful to cast the address to a pointer variable which is done as follows.

mov pstr, ptr$(buffer)

When you need larger buffers it is viable to allocate dynamic memory which can be done with either of the following two memory allocation macros.

mov pstr, alloc(16384)
or
mov pstr, alloc$(16384)

The value returned by these memory allocation macro is already the pointer to the memory. Make sure that when you have finished using the allocated memory that you free the memory before you end the procedure.

If you have used alloc, free it with,
free pstr

If you have used alloc$, free it with,
free$ pstr

Where it is possible, load the source string directly into the buffer from the method that you obtain the string. If this is not possible, you can copy the data into the buffer or alternatively, set the start of the buffer to a zero byte and append the source you require to the zero length string in the buffer.

NOTE When you are allocating dynamic memory for UNICODE string data that you must have 2 bytes for each character so if you have a character count of 1024, you must allocate at least 2048 bytes of memory.


append$
mov location, append$(string,buffer,location)

Description
Append a string to another string and return the location of the next character after the appended string.

Parameters
1. string The address of the source string to append the following string to.
2. buffer The string to append to the source string.
3. location The address within the source string to write the second string to.

Return Value
The return value is the next character past the end of the appended string data so it can be used as the location parameter for a subsequent call to append$.

Comments
The source string must be placed in a buffer that is large enough to hold all of the string data appended to it. The advantage of this technique is that by returning the end location the following call does not need to rescan the length of the string to find the starting position to write to. This macro is __UNICODE__ aware.


argcount
argcount(arguments)

Description
Return the number of arguments in an argument list.

Parameters
1. arguments The list of arguments to count

Return Value
The return value is the number of arguments in the argument list.

Comments
The argument list is usually passed to a macro that uses this macro as a single name followed by VARARG.

YourMacro MACRO function:REQ,arglist:VARARG
;; macro statements
var = argcount(arglist)
;; macro statements
ENDM


arr2disk$
arr2disk$ MACRO arr,file_name

Description
Write text data from a complete array to a disk file.

Parameters
1. arr       The handle of an existing array.
2. file_name A zero terminated string containing the name of the file to write to disk. This can also be quoted text.

Comments
This macro function writes every line of text in an array to a disk file. It should not be used with binary data as it appends a CRLF to the end of each array member which would cause image errors in a binary file.


arr2mem$
arr2mem$ MACRO arr,pmem

Description
This function is designed to write a complete array to a pre-allocated memory buffer.

Parameters
1. arr  The handle of an existing array.
2. pmem The address of the preallocated memory buffer.

Comments
This function is designed so that the programmer can use whatever memory strategy they may choose to use but the memory buffer must be pre-allocated to the correct size. The macro function arrtotal$ is designed to calculate this memory buffer size. This macro function is primarily designed for writing binary data from the array to a single memory buffer and it does not append a CRLF to the end of each member so the arrtotal$ macro function should not calculate the extra 2 bytes for a CRLF delimited file.


arr2text$
arr2text$ MACRO arr,pmem

Description
This function is designed to write a complete array of text data to a pre-allocated memory buffer.

Parameters
1. arr  The handle of an existing array.
2. pmem The address of the preallocated memory buffer.

Comments
This function is designed so that the programmer can use whatever memory strategy they may choose to use but the memory buffer must be pre-allocated to the correct size. The arrtotal$ macro function is designed to calculate this memory buffer size. This macro function is designed for writing text data from the array to a single memory buffer and it appends a CRLF to the end of each member so the arrtotal$ macro function should calculate the extra 2 bytes for a CRLF delimited file.


arralloc$
arralloc$ MACRO member_count

Description
Create a dynamic variable length array with member_count of empty members.

Parameters
1. member_count The 1 based index number of members in the new array.

Comments
arralloc$ is a macro interface for the procedure create_string_array which allocates the pointer array for the number of members required and allocates an empty OLE string for every member of the array. the macro is to be used in the function position returning the handle to the array which is used by all of the array macros in this system. When the array is no longer required it should be deallocated with the macro arrfree$ which deallocates all of the array members and the main pointer array.

Example
LOCAL hArray  :DWORD
......
mov hArray, arralloc$(4096)


arrbin$
arrbin$ MACRO arr,indx,psrc,lsrc

Description
This macro function is designed to write binary data to an array member.

Parameters
1. arr  The handle of an existing array.
2. indx The 1 based index. of the array member to write the binary data to.
3. psrc The address of the binary data to write to an array member.
4. lsrc The length of the binary data to write to an array member.

Return values
1. The written binary data length.
2. 0 if length is zero.
3. -1 bounds error, below 1.
4. -2 bounds error, above index.

Comments
The OLE memory that is used for the array members stores the length at the beginning of the allocated memory 4 bytes below the start address. With the length specifier the memory can be used to write binary data with embedded ANSI zeros which make the array system suitable for building complex binary data. Although it is not of much use the function returns the written byte length of the binary data. In some circumstances when very large arrays are being use you can compare the return value to the lsrc parameter to ensure the correct length was allocated.


arrcnt$
arrcnt$ MACRO arr

Description
Get the member count for the array.

Parameters
1. arr  The handle of an existing array.

Comments
The array is designed to hold the array member count as its first member, index 0. The macro function arrcnt$ reads this data from the first array member and return the 1 based index count of array members.


arrealloc$
arrealloc$ MACRO arr,indx

Description
Reallocate an existing array to either a larger or smaller member count.

Parameters
1. arr  The handle of an existing array.
2. indx The number of members required for the new array size.

Comments
arrealloc$ is a macro interface to two seperate functions that either extend the array by appending empty members to the end of the array of truncating the trailing array members to a lower count. The data in the truncated members is lost with the reallocation. The choice of function is determined by the new count required and is automatically extended or truncated depending on if the new size is larger or smaller than the existing member count of the array.

Important note
The array handle returned by arrealloc$ may not be the same address as the handle passed to it, especially if the reallocation is to a larger size than the original array. Tis means that the earlier array address if it is stored in a register or another variable may now be an invalid address that will cause an unhandled exception (GP fault) if it is accessed as a valid memory handle. Always use the handle for the array as the array address reference and reload the register or other variable with the new handle so that it is a valid address.

Example
LOCAL hArray  :DWORD
......
mov hArray, arralloc$(2048)
......
mov hArray, arrealloc$(hArray,4096)


arrextnd$
arrextnd$ MACRO arr,indx

Description
manually increase the number of array members.

Parameters
1. arr  The handle of an existing array.
2. indx The new array index count to be extended to.

Comments
This function extends an existing array to a larger member count by appending new empty members to the end of the array. The arrealloc$ macro function calls the same procedure as this macro function when the reallocation is longer than the original array count.


arrfile$
arrfile$ MACRO file_name

Description
Load a CRLF delimited text file and write it directly to an array.

Parameters
1. file_name The zero terminated file name. Quoted text may also be used here.

Comments
An efficient and fast method of loading a complete text file into memory and writing each line to a seperate array member. The array is created by this function and the return value is the handle of the array. You may obtain the number of lines in the text file by using the array member count macro function arrcnt$. When the array is no longer required you use the arrfree$ macro function to deallocate all of the memory used by the array.


arrfree$
arrfree$ MACRO arr

Description
Deallocates all of the array members and the original pointer array.

Parameters
1. arr The array handle returned by arralloc$ or arrealloc$.

Comments
This macro function removes all of the array members and the pointer array freeing all memory allocate or reallocated in the array. It is important to ensure that the array handle is deallocated within the same scope as the original allocate or reallocation otherwise the memory cannot be released as the handle will be lost. If the array is wholy used within a procedure you would normally use a LOCAL variable for the handle and make sure you free the memory before the procedure ends. Alternately if you need the array in global scope you would create the handle in the .DATA? section so the array can be accessed at any point in the application using it.

Example
LOCAL retval  :DWORD
......
mov retval, arrfree$(hArray)


arrget$
arrget$ MACRO arr,indx

Description
Get the address of a specified array member.

Parameters
1. arr  The handle of an existing array.
2. indx The 1 based array index of the member required.

Return Values
1. The address of the array member requested.
2. -1 on lower bound error (< 1)
3. -2 on upper bound error (> index)

Comments
The arrget$ macro function returns the address of the array member nominated with the indx parameter. The function can be used directly with any normal addres based assembler procedure. With binary data you will need to use the arrlen$ macro function to get the binary data length for the array member it is stored in.

Example
mov ptxt, arrget$(hArray,64)
......
print arrget$(hArray,39)


arrlen$
arrlen$ MACRO arr,indx

Description
This function is designed to get the length of an array member.

Parameters
1. arr  The handle of an existing array.
2. indx The 1 based index of the array member.

Comments
This function reads the array member length from an address 4 bytes below the starting address of the array member memory. It is a standard OLE string memory capacity.


arrset$
arrset$ MACRO arr,indx,ptxt

Description
Write/overwrite zero terminated data to array member.

Parameters
1. arr  The handle of an existing array.
2. indx The 1 based index of the array member to write.
3. ptxt The address of the text to write to the array member, this may also be quoted text.

Return Values
1. The written text length.
2. 0 if text length or argument is zero.
3. -1 bounds error, below 1.
4. -2 bounds error, above index.
5. -3 out of memory error.

Comments
arrset$ writes a zero terminated string to an array member by dynamically allocating the memory for an array member then writing the data to that allocated memory. The written string length is returned by this macro function.


arrtotal$
arrtotal$ MACRO arr:REQ,xtra2:VARARG

Description
This function is designed to calculate the buffer size for either binary data of CRLF delimited text.

Parameters
1. arr   The handle of an existing array.
2. xtra2 The optional second argument to specify if an extra 2 bytes should be calculated for each line to hold a CRLF. If the argument is not used the function defaults to calculating an extra 2 to each line for a CRLF delimited text file.

0   =    no extra 2 bytes for each line.
non zero adds 2 bytes for every line.

Comments
This function is provided so that the programmer can use the memory allocation strategy of their own choice by passing a memory buffer allocated to the correct size to hold either binary data or CRLF delimited text data. It would normally be use with either the arr2mem$ macro function or the arr2text$ macro function.

Example
mov alen, arrtotal$(hArray)        ; default with 2 bytes added for each line.
mov alen, arrtotal$(hArray,0)      ; 2nd argument specifies no extra bytes.
mov alen, arrtotal$(hArray,1)      ; 2nd argument specified 2 extra bytes for each line.


arrtrunc$
arrtrunc$ MACRO arr,indx

Description
Truncate an existing array to a lower member count.

Parameters
1. arr  The handle of an existing array.
2. indx The last array member to include in the array.

Comments
This function is provided so that the programmer can manually change the size of the array. The data in truncated array members is lost when the member memory is deallocated and the main pointer array is shortened. The arrealloc$ macro function calls the same procedure as this macro function when the reallocation is shorter than the original array count.


arrtxt$
arrtxt$ MACRO ptxt

Description
Creates an array and writes multiline CRLF delimited text from a zero terminated buffer to the array members.

Parameters
1. ptxt The address of a zero terminated multiline buffer of text.

Comments
This macro function returns the handle of the array that stores the text data. The arrcnt$ macro function should be used to obtain the number of lines written to the array from the text buffer.


cat$

mov lpbuffer, cat$(lpBuffer,[variable number of strings])

Description
Concantenate multiple string into a single buffer.

Parameters
1. lpBuffer The address of the source buffer to append other strings to.
2. A variable number of string addresses to append to the source buffer.

Return Value
The return value is the address of the source buffer that can be assigned back to itself or to another pointer (string handle).

Comments
This is a very flexible and useful macro that can handle multiple strings in different formats. If the source buffer does not already have string data in it, the first character MUST be set to zero so it is seen as a zero length string. The "ptr$() macro performs this task correctly. The source string buffer must be large enough to receive all of the string data appended to it. This macro is __UNICODE__ aware.

Example
mov lpbuffer, cat$(lpbuffer,"The result is ",ustr$(count)," characters in length")


ccout
ccout "\tC style string formatting\n\tin MASM"

Description
Display text at the console with C style string formatting enabled.

Parameters
1. Quoted text which may contain escape sequences.

Return Value
There is no return value.

Comments
This macro uses the string formatting capacity of the cfm$ macro.


cfm$

Description
Format a quoted string using C style escape sequences.
Three versions are presented here.
1. acfm$() = ASCII only version
2. ucfm$() = UNICODE version
3.  cfm$() = Either ASCII or UNICODE depending on if the __UNICODE__ equate is present in the source file.

All three versions operate in the same manner and have the same capacity.

Parameters
A quoted string that can have escape sequences contained within it.

Return Value
The return value is the address of the formated string data as an offset in the .DATA section.

Comments
This macro is not designed to conform to the C "printf" string formatting specification, it is designed to give this form of formatting convenience to MASM programmers who may have a C background. It can be used either directly in a procedure call in normal code or be used in a dedicated macro that requires this style of formatting.
The direct formatting escapes are as follows, the numbers enclosed in brackets are the ASCII characters inserted into the quoted text.

\n = newline (13,10)
\t = tab (9)
\\ = "\" backslash (92)
\q = quote (34)
\0 = zero (0)

The following escapes are MASM specific to bypass the restrictions that MASM places on certain characters being contained within a quoted string.

\l = "<" left angle bracket. (60)
\r = ">" right angle bracket. (62)
\x = "!" exclaimation mark. (33)
\a = "(" left bracket. (40)
\b = ")" right bracket. (41)

The three versions allow the programmer to force either ASCII or UNICODE where required or automatically select the right version depending on if the __UNICODE__ equate is present in the source file.
Example
print cfm$("\tThis is a test\n\tof the \qcfm$\q macro\n")

Result
This is a test
of the "cfm$" macro


chdir
chdir lpstring

Description
Change from the current directory to another directory.

Parameters
1. lpstring The address of a zero terminated string containing the path of the directory to change to. This may also be a quoted text.

Return Value
This macro does not have a return value.

Comments
Use  LastError() if you have any errors with the macro call.


chr$

mov pstr, chr$("quoted text",13,10)

Description
Write mixed text and byte data to the .DATA section and return the starting address of that data.

Parameters
A variable number of items of quoted text and byte data.

Return Value
The return value is the starting address of the data written to the .DATA section.

Comments
This macro writes directly to the .DATA section and it can use either quoted text or byte data in the normal format for the .DATA section. It can be used in places where the internal MASM reserve characters interfere with quoted text or byte data being used. This macro is __UNICODE__ aware.

fn MessageBox,hWnd,chr$("one",13,10,"two",13,10"three",13,10),lpTitle,MB_OK


chtype$

Description
High speed alternative to procedures for character class recognition.

Parameters
1. character Either a BYTE register or the address of a BYTE as a memory operand.

Return Value
The return value is a 32 bit pointer to a byte in the character table that this macro uses.
It is returned in this form, BYTE PTR [eax+chtyptbl] and the contents of the BYTE will be one of the following character classes.

1 = numbers
2 = upper case characters
3 = lower case characters
4 = arithmetic operators
5 = punctuation & crlf
6 = space or tab

Comments
The application of a macro of this type is for a project that must evaluate characters in very large quantities where speed is a factor in the performance of the application.
When this macro is used, it adds a 256 byte character table to the executable so that characters can be determined in a single read from the character table. Typical uses for the macro are in the following examples.

movzx ecx, chtype$([ebp+4])
cmp chtype$([esp+4]), 2
cmp chtype$(ah), dl

The speed advantage of this technique is because it can determine the character class with a very low instruction count.

movzx eax, BYTE PTR character

The macro uses the following form to return a value that is placed in a normal assembler notation form.

EXITM <BYTE PTR [eax+chtyptbl]>


cls
cls

Description
This is a very simple macro that works the same way as the DOS command.


cmd$
mov pCmd, cmd$(argument_number)

Description
Return the address of the nominated command line argument.

Parameters
1. argument_number The nominated command line argument number.

Return Value
The return value is the address of the nominated command line argument.

Comments
The argument_number parameter is a 1 based index that specificed which command line argument to return. The following values are returned in the ECX register to indicate success or failure of the macro call.

1 = successful operation
2 = no argument exists at specified arg number
3 = non matching quotation marks
4 = empty quotation marks


cmp$ cmpi$

mov retval, cmp$(lpString1,lpString2)    ; case sensitive version
    or
mov retval, cmpi$(lpString1,lpString2)   ; case insensitive version

Description
Compare two strings. Two versions, case sensitive and case insensitive. Both macros are __UNICODE__ aware.

Parameters
lpString1 The address of the first zero terminated string to compare.
lpString2 The address of the second zero terminated string to compare.

Return Value
At its simplest the return value = zero if the strings match or NON zero if they do not match. If you need a simple YES or NO test the return value for ZERO.

Comments
The Windows API functions that provide this comparison capacity provide return values that are in the format used by string sort algorithms so that one string can be placed before another in a sorted list of strings. The following text is the Microsoft documentation for the return values.

"If the function succeeds and the string pointed to by lpString1 is less than the string pointed to by lpString2, the return value is negative; if the string pointed to by lpString1 is greater than the string pointed to by lpString2, it is positive. If the strings are equal, the return value is zero."


Count Lines

This is a procedure that may be added later to the MASM32 library. It counts the number of ascii 10 characters to determine the number of lines in a text file. As the last line of text may be zero terminated and would not add to the count of lines, it is advisable to add 1 to the final count so you can set up loop code with this result as a counter.
The procedure can be called with normal MASM syntax,

invoke lfcnt,lpText
mov lcnt, eax
add lcnt, 1
; or
mov lcnt, rv(lfcnt,lptext)
add lcnt, 1

 The procedure is prototyped in the normal manner,

lfcnt PROTO :DWORD

 The code below can be copied and pasted into the application.

; --------------------------------------------------------------

align 4

lfcnt proc txt:DWORD

; ---------------------------------------------
; get line count of text by counting line feeds
; ---------------------------------------------
    xor eax, eax ; set counter to zero
    mov ecx, txt
    sub ecx, 1
    jmp @F

  pre:
    add eax, 1              ; add 1 to return value if LF found
  @@:
    add ecx, 1
    cmp BYTE PTR [ecx], 0   ; test for zero terminator
    je @F
    cmp BYTE PTR [ecx], 10  ; test line feed
    je pre
    jmp @B
  @@:

    ret

lfcnt endp

; --------------------------------------------------------------


CPROTO
CPROTO MACRO func_addr:REQ,arglist:VARARG

Description
Create a C calling convention prototype for a procedure that has a known starting address and a known argument list.

Parameters
1. func_addr The name to be used for the address of the procedure that is being prototyped.
2. arglist A normal prototype list

Return Value
The return value is assigned to an equate of your own choice that must be a unique name within the application. See the example below for details on how to use it.

Comments
The following code shows how the two prototyping macros are used.

main proc
    LOCAL user :DWORD
    LOCAL msvc :DWORD
    LOCAL pbuf :DWORD
    LOCAL buffer[64]:BYTE
    mov pbuf, ptr$(buffer)

  ; ---------------------------
  ; prototype the two functions
  ; ---------------------------
 .const
    mbox SPROTO(adr1,:DWORD,:DWORD,:DWORD,:DWORD)
    _l2a CPROTO(adr2,:DWORD,:DWORD,:DWORD

.code
  ; -------------
  ; load the DLLs
  ; -------------
    mov user, rv(LoadLibrary,"user32.dll")
    mov msvc, rv(LoadLibrary,"msvcrt.dll")

  ; -----------------------------------
  ; load the procedure address into the
  ; variable specified in the prototype
  ; -----------------------------------
    mov adr1, rv(GetProcAddress,user,"MessageBoxA")
    mov adr2, rv(GetProcAddress,msvc,"_ltoa")

  ; -----------------------
  ; call the two procedures
  ; -----------------------
    invoke _l2a,1234,pbuf,10
    fn mbox,0,pbuf,"title",MB_OK

  ; -----------------
  ; free the two DLLs
  ; -----------------
    invoke FreeLibrary,user
    invoke FreeLibrary,msvc

    ret

main endp


cst
cst destination,source

Description
Copy a zero terminated string to a memory buffer.

Parameters
1. destination The destination memory buffer.
2. source A zero terminated string. This may also be quoted text.

Comments
The macro tests the first argument, the destination memory buffer and will halt and display an error message if it is a quoted text. This macro is __UNICODE__ aware.


CurDir$
mov cdir, CurDir$()

Description
Return the address of the current directory for the calling application.

Parameters
This macro has no parameters.

Return Value
The address of a 260 byte buffer that contains the address of the current directory.

Comments
The empty brackets are required by MASM's internal parser. This macro is __UNICODE__ aware.


Direct UNICODE macros

MASM does not natively support quoted unicode string data but its macro engine is capable of providing quoted UNICODE strings up to 240 characters long which is enough in most instances for quoted text in code.

These following macros can be used directly for creating UNICODE text or they can be called from other macros that provide unicode support.

Write UNICODE string data directly to the DATA section.
A2WDAT MACRO quoted@@text,dataname:VARARG

 ;;     ASCII literal string to UNICODE "dw" conversion.
 ;;     The macro has the ASCII character range 0 - 255
 ;;     and will convert 1 byte characters in the quoted
 ;;     string to 2 byte UNICODE characters written as "dw"
 ;;     in the initialised data section.
 ;;     The final string length is dictated by the MASM line
 ;;     length limit and is set at 240 characters.
 ;;
 ;;     This MACRO is primarily designed to be called by
 ;;     other macros, it does not create a .DATA section
 ;;     and it does not terminate the string data it writes.
 ;;
 ;;     This characteristic is so the macro can be called
 ;;     repeatedly by another macro. The calling macro
 ;;     then terminates the string when it has no more
 ;;     to write.
 ;;
 ;;     The optional dataname label is designed to be used
 ;;     on the first call and ommitted on subsequent calls
 ;;     when adding text to the original label address.
 ;;
 ;;     You can write a .DATA section entry in this manner.
 ;;
 ;;     .data
 ;;       A2WDAT "First block of text", mytext
 ;;       A2WDAT "Second block of text"
 ;;       A2WDAT "Third block of text"
 ;;       A2WDAT "Fourth block of text"
 ;;       dw 0
 ;;     .code
 ;;
 ;;     mov eax, OFFSET mytext

WSTR MACRO lblname,arglist:VARARG
Write a UNICODE string to the DATA section from the CODE section.

uni$ MACRO arglist:VARARG
uni$ is a function position macro that allows a UNICODE string to be directly inserted into a function call.

Both WSTR and uni$ macros support characters by number so embedded ("quoted",13,10) style notation can be used for characters that cannot be displayed within quotes. If you have a technique of identifying UNICODE characters by their WORD sized number, you can display UNICODE characters above the 256 character range capable within an ASCII editor.

Extended versions by qWord
UCSTR MACRO lbl,args:VARARG
;/*****************************************************************/
;/*             UCSTR - macro procedure                           */
;/* This macro creates a Unicode string in the current segment    */
;/* Parameters:                                                   */
;/*    lbl:    [optional] name of string                          */
;/*    args:   one ore more string literals, either enclosed by   */
;/*            single quotation marks or by double quotes.        */
;/*            Constants can also be used, blank arguments        */
;/*            force an error. The maximal number of characters   */
;/*            is something about 240.                            */
;/*                                                               */
;/* Remarks:   A termination zero must add by user!               */
;/*            Named strings can be used with the SIZEOF and      */
;/*            LENGTHOF operator. This macro wont work with       */
;/*            angle brackets and exclemation marks.              */
;/* Example:                                                      */
;/*          UCSTR myStr, "my string",13,10,'"quoted"',0          */
;/*                                                  qWord, 2011  */
;/*****************************************************************/

UCCSTR MACRO lbl,args:VARARG
;/*****************************************************************/
;/*             UCCSTR - macro procedure                          */
;/* This macro creates a Unicode string in the current segment    */
;/* This macro is identically to the UCSTR-macro, except, that it */
;/* adds support for some escape sequences:                       */
;/*     \\  ->  "\"                                               */
;/*     \t  ->  tab                                               */
;/*     \n  ->  new line (13,10)                                  */
;/*     \x  ->  "!"                                               */
;/*     \a  ->  "("                                               */
;/*     \b  ->  ")"                                               */
;/*     \l  ->  "<"                                               */
;/*     \r  ->  ">"                                               */
;/*     \p  ->  "%"                                               */
;/*     \A  ->  "&"                                               */
;/*     \q  ->  double quote '"'                                  */
;/*     \0  ->  zero-word                                         */
;/*                                                               */
;/* Example:                                                      */
;/*       UCCSTR myStr, "line 1\nline2\nI'm here\x",0             */
;/*                                                  qWord, 2011  */
;/*****************************************************************/

uc$ MACRO args:VARARG
;/***************************************************/
;/*               uc$ , macro function              */
;/* This macro is the function-version of UCSTR.    */
;/* In contrast to UCSTR, the created string is     */
;/* zero terminated. The macro assumes to be called */
;/* from the .code-section and places the string    */
;/* in the .data-section.                           */
;/* Example:                                        */
;/*      mov esi,uc$("my string",13,10,'xxyz')      */
;/*                                    qWord, 2011  */
;/***************************************************/

ucc$ MACRO args:VARARG
;/***************************************************/
;/*               ucc$ , macro function             */
;/* This macro is the function-version of UCCSTR.   */
;/* In contrast to UCCSTR, the created string is    */
;/* zero terminated. The macro assumes to be called */
;/* from the .code-section and places the string    */
;/* in the .data-section.                           */
;/*     mov esi,ucc$("\lHello World\r\n:-\b")       */
;/*                                    qWord, 2011  */
;/***************************************************/


env$
mov lpenv, env$(szString)

Description
Return the address of an environment string if it exists.

Parameters
1. Either a zero terminated string or quoted text

Return Value
If the string exists the address of the string is returned otherwise zero is returned.

Comments
The return value should be tested for zero to ensure that an environment string has been returned.

Example
mov penv, env$("link")
.if penv != 0
  print penv,13,10
.endif


exit
exit

Description
A simple macro to terminate a program. This macro is not exclusively a console macro and can be used to terminate any program.


fclose
fclose hFile

Description
Close an already open file handle.

Parameters
1. hFile The open file handle.

Return Value
Function has succeeded if the return value in EAX is not zero.

Comments
Errors should be tested with GetLastError().

Example
fclose hFile


fcreate
mov hFile, fcreate(filename)

Description
Create a new file with read / write access.

Parameters
1. filename A zero terminated string. This can be a quoted text.

Return Value
The return value is the handle of the new file.

Comments
The new file has read and write access. If there is an error, you should test the return value with GetLastError().

Example
mov hFile, fcreate("mynewfile.ext")


fdelete
cmp fdelete(lpString), 0

Description
Delete a disk file by its name.

Parameters
1. lpString A zero terminated string that contains the file name to delete from disk. This may also be a quoted literal string.

Return Value
The return vaue is non-zero if the function succeeds, zero if it fails.

Comments
This macro is a wrapper for the Windows API, DeleteFile(). It has been added for consistency with the names of the other file IO macros. It has been written in function format to facilitate testing the return value.

Example
cmp fdelete("tempfile.ext"), 0
jne @F
print "Hmmmmm, this operation failed",13,10
@@:


fn
fn SetWindowText,hWnd,"Main Window"

Description
Call any prototyped procedure with quoted string support.

Parameters
Any callable procedure with its argument list

Return Value
If the procedure has a return value, it will be in the EAX register.

Comments
This macro is generally used when a return value is not required. Because it does not use the EXITM operator, its arguments ae not enclosed in brackets so it can be split across multiple lines using the "\" line continuator.


fnc
fnc MessageBox,hWnd,"C style escape\nsequences\n","Example".MB_OK

Description
Call any prototyped procedure with the capacity to use quoted text with C style escape characters.

Parameters
Any prototyped procedure call and its associated argument list.

Return Value
If the procedure has a return value, it will be in the EAX register.

Comments
This macro differs from the "fn" macro only in that it supports additional formatting using C style escape sequences. The reference to this capacity the cfm$ macro. This macro is generally used when a return value is not required. Because it does not use the EXITM operator, its arguments ae not enclosed in brackets so it can be split across multiple lines using the "\" line continuator.


fncx macro

fncx
fncx MessageBox,hWnd,"C style escape\nsequences\n","Example".MB_OK

Description
Call any prototyped procedure with the capacity to use quoted text with C style escape characters.

Parameters
Any prototyped procedure call and its associated argument list.

Return Value
If the procedure has a return value, it will be in the EAX register.

Comments
This macro differs from the "fnx" macro only in that it supports additional formatting using C style escape sequences. This macro is generally used when a return value is not required. Because it does not use the EXITM operator, its arguments ae not enclosed in brackets so it can be split across multiple lines using the "\" line continuator.

qWord's original documentation

;/********************************************************************/
;/*                     fncx - macro procedure                       */
;/* This macro behave like the fnx-macros, except, that it adds      */
;/* support for escape sequences:                                    */
;/*     \\  ->  "\"                                                  */
;/*     \t  ->  tab                                                  */
;/*     \n  ->  new line (13,10)                                     */
;/*     \x  ->  "!"                                                  */
;/*     \a  ->  "("                                                  */
;/*     \b  ->  ")"                                                  */
;/*     \l  ->  "<"                                                  */
;/*     \r  ->  ">"                                                  */
;/*     \p  ->  "%"                                                  */
;/*     \A  ->  "&"                                                  */
;/*     \q  ->  double quote '"'                                     */
;/*     \0  ->  zero                                                 */
;/* Example:                                                         */
;/*     fncx MessageBox,0,"my string\n",&wsz[0],0                    */
;/*                                                     qWord, 2011  */
;/********************************************************************/


fnx Extended Function Call Macro

fnx
Extended function call macro.

fnx SetWindowText,hWnd,"Main Window"

Description
Call any prototyped procedure with quoted string support.

Parameters
Any callable procedure with its argument list.

Return Value
If the procedure has a return value, it will be in the EAX register.

Comments
qWord's original documentation for the "fnx" macro.

;/********************************************************************/
;/*                     fnx - macro procedure                        */
;/* This macro enhanced the INVOKE-directive:                        */
;/*   - It adds support for quoted ASCII or unicode strings.         */
;/*     The strings can be either enclosed by double quotes or by    */
;/*     single quotation marks.                                      */
;/*     The kind of created string (Unicode or ASCII) depends on the */
;/*     __UNICODE__ equate. If this equte is defined and has a       */
;/*     nonzero value, a unicode string is created. However, creation*/
;/*     of Unicode strings can be forced by using the 'L'-prefix:    */
;/*                 L"my string" or L'my string'                     */
;/*     ASCII strings can be forced by using the A-prefix:           */
;/*                 A"my string" or A'my string'                     */
;/*     MASM's reserved characters like exclamation marks, angel     */
;/*     brackets and single brackets [,...] can not be used.         */
;/*     (use fncx for escape sequences support)                      */
;/*   - ADDR-expressions can be shorten by using a ampersand '&':    */
;/*         fn MessageBoxW,0,&wsz[0],L'xyz',0                        */
;/*   - Pointers to DWORDs can be dereferenced, if they are leaded   */
;/*     by '*' (like dereferencing in c/c++):                        */
;/*                fnx MesageBox,0,*ppchar,...                       */
;/*   - a optional destination can be specified in front of the      */
;/*     function:                                                    */
;/*         fn dest=FncName,...                                      */
;/*                                                                  */
;/* Example:                                                         */
;/*     fnx MessageBoxW,0,L"my string",&wsz[0],0                     */
;/*     fnx hWnd = CreateWindowEx,...                                */
;/*                                                     qWord, 2011  */
;/********************************************************************/


fopen
mov hFile, fopen(filename)

Description
Open an existing file for read / write access.

Parameters
1. filename A zero terminated string. This can be a quoted text.

Return Value
The handle of the file.

Comments
If the function fails, you should test the return value with GetLastError().

Example
mov hFile, fopen("existingfile.ext")


fprint
fprint hFile,lptext

Description
Write a line of zero terminated text to a file.

Parameters
1. hFile The handle of the file to write to.
2. text The zero terminated text. This may be quoted text.

Return Value
There is no return value.

Comments
This macro always appends a CRLF pair to the end of the line. It is designed for operation that write lines of text sequentially.

Example
fprint hFile,"This is a line of text"


fprintc
fprintc hFile,"Hi Guys\n"

Description
Write zero terminated text with C style formatting to an open file.

Parameters
1. hFile The handle of the open file
2. lpText The address of a zero terminated string. This may also be quoted text that contains C style escape sequences as provided for in the cfm$ macro.

Return Value
This macro does not return a value.

Comments
This macro allows the programmer to write text to an open file using the text formatting capacity of the cfm$ macro which allows C style formatting of string data. It is useful where you need to sequentially append text to a file without necessarily placing it on a new line.


fread
mov bWritten, fread(hFile,lpMemory,bytecount)

Description
Read data from an open file.

Parameters
1. hFile The open file handle.
2. buffer The address of the buffer to write the data to.
3. bcnt The number of bytes to read.

Return Value
The return value is the number of bytes read from the file.

Comments
The buffer must be large enough to handle the number of bytes read into it. Normally the buffer will be allocated to at least that size or larger.

Example
mov bWritten, fread(hFile,lpMemory,bytecount)


free
free hMem

Description
Frees memory allocated with the alloc macro.

Parameters
1. hMem The handle or starting address of the memory allocated with alloc.

Return Value
There is no return value.

Comments
The macro uses the GlobalFree API function and can be used to free any memory allocated using GlobalAlloc().


free$
free$ hString

Description
Frees the memory allocate using the alloc$ macro.

Parameters
1. hString The handle of the string memory.

Return Value
The macro does not have a return value.

Comments
This macro can be used to free any string memory allocated using the OLE string library.


fseek
mov cloc, fseek(hFile,distance,location)

Description
Set the location of the file pointer.

Parameters
1. hFile The handle of the open file.
2. distance The number of bytes to move.
3. location The reference point to move from.

Return Value
The return value is the current location of the file pointer within the open file.

Comments
The distance argument can be specified as either a positive or a negative number which will be respectively added or subtracted from the position set in the location argument.

The location argument specifies what location in the file to use. There is a choice of 3 locations which are standard Windows equates.

FILE_BEGIN The beginning of the file.
FILE_CURRENT The current location of the file pointer.
FILE_END The end of the file

If for example you wished to set the file pointer at 100 bytes past the beginning of the file, you would use the equate FILE_BEGIN for the location argument and set the distance argument at 100.

Note that this macro will only work on files within the DWORD length. For files larger than 4 gigabytes use the SetFilePointer() API function.

Example

mov cloc, fseek(hFile,100,FILE_BEGIN)


fseteof
fseteof hFile

Description
Truncate a file at the current file pointer location.

Parameters
1. hFile The handle of the file to truncate.

Return Value
The macro has no return value.

Comments
The required location can either be set by read / write operations or it can be set using the fseek macro. It is normally used to truncate an existing file.

Example

fseteof hFile


fsize
mov flen, fsize(hFile)

Description
Returns the size in bytes of an open file.

Parameters
1. hFile The handle of the file.

Return Value
The length of the file in bytes.

Comments
The macro is limited to DWORD range. If you need to work on a file larger than 4 gigabytes, use the GetFileSize() API function.


FUNC
mov rval, FUNC(AnyProcedureCall,args ......)

Description
Call any procedure with a return value.

Parameters
Any procedure call complete with arguments that returns a value.

Return Value
The return value from a procedure call which is normally the EAX register.

Comments
This macro utilises the "invoke" syntax and the EXITM <eax> macro operator to return a value which can be either assigned to a variable with MOV or directly used in the same manner as the EAX register.

mov retval, FUNC(APIcall,arguments ...)
test FUNC(YourProc,arguments ...), eax
cmp FUNC(AnyProc,arguments ...), 1234
add edx, FUNC(APIcall,arguments ...)


fwrite
mov bwritten, fwrite(hFile,buffer,bcnt)

Description
Write data to an open file.

Parameters
1. hFile The open file handle.
2. buffer The address of the buffer to write the data to.
3. bcnt The number of bytes to read.

Return Value
The number of bytes written to the file or zero on failure.

Comments
Use GetLastError() if the operation fails.

Example
mov bwritten, fwrite(hFile,lpmemory,bytecount)


getarg
getarg(index,arguments)

Description
Return the content of an argument in an argument list specified by its index.

Parameters
1. index The argument number to return
2. arguments The argument list to return it from

Return Value
The return value is either the text of the argument or the text "-1" to indicate that the index number is larger than the argument count.

Comments
You can test the return value for the text "-1" with the IFIDN macro operator. This macro is among other things very useful for reading a list of arguments in reverse order to their position in the argument list.


GetConsoleCaption$
mov pTitle, GetConsoleCaption$()

Description
Return the address of the text from the title bar of the console.

Parameters
This macro has no parameters. It should use empty brackets () to satisfy the macro parser in MASM.

Return Value
The return value is the address of a 260 byte buffer that holds the zero terminated text from the title bar of the console.

Comments
The 260 byte buffer is reused with a subsequent call to the macro so if the string data needs to be preserved it should be copied to a memory buffer. This can be done with the "szCopy" procedure in the MASM32 library or the "cst" macro in the MASM32 macro file.

Example
mov pCaption, GetConsoleCaption$()
invoke szCopy,pCaption,pBuffer
or
cst pBuffer, pCaption


getkey
getkey

Description
Wait for a key press and return the value in EAX.

Parameters
There are no parameters for this macro.

Return Value
The return value is written in the low byte of the EAX register. EAX is zero extended so that it can be tested either as a DWORD or as a BYTE.

Comments
This macro can be used in the construction of simple menus which depend on which key a user presses. Create a "switch" block that tests the value of EAX or AL and branch to whatever code you require from that switch block.


Environment get and set macros

envset$
mov rval, envset$("lib","h:\masm32\lib\")
arg1 = variable to set
arg2 = string to set to variable

envget$
mov pvar, envget$("lib")
arg1 = variable to get

Example
    mov rval, envset$("lib","d:\masm32\lib\")    ; set environment variable
    mov pvar, envget$("lib")                     ; get environment variable
    print pvar,13,10

    mov rval, envset$("lib",NULL)                ; clear environment variable with NULL as string to set.
    print envget$("lib"),13,10

Comments
These macros are __UNICODE__ aware.


halloc
mov hMem, halloc(1024)

Description
Allocate heap memory.

Parameters
1. bytecount The count in bytes of memory to allocate.

Return Value
The return value is the address of the allocated memory. Use the LastError$ macro if you have memory allocation failures.

Comments
On recent Windows versions HeapAlloc() appears to be faster than other memory allocation techniques when used with repeated small allocations of memory. The return value should be stored in a variable and when the memory is no longer required, it should be deallocated using the hfree macro within the same scope as it was allocated under.


hfree
hfree hMem

Description
Free memory allocated by the halloc() macro.

Parameters
1. hMem The starting address returned by the halloc() macro.

Return Value
The macro does not set a return value but any errors can be tested using the LastError$ macro. A non zero result in EAX indicates an error.

Comments
When memory is allocated using a HeapAlloc() function, it is worth testing if the memory is properly deallocated otherwise it runs the risk in high allocation count situations of running out of memory if there is an error.


hsize
mov memsize, hsize(hMem)

Description
Return the size in bytes of the memory allocated using the halloc() macro.

Parameters
1. hMem The value returned by the halloc( ) macro.

Return Value
The size of the allocated memory block in BYTES or 0FFFFFFFFh if it fails.

Comments
The HeapSize() API used by this macro does not use the GetLastError() API.


hval
mov value, hval(lpString)

Description
Convert a hexadecimal string to a 32 bit integer.

Parameters
1. lpString The address of the hexadecimal format zero terminated string.

Return Value
The return value is the 32 bit integer value.

Comments
The hexadecimal string should be in correct HEX notation and should not have any leading or trailing notation.
0xED230AB7 should have the 0x stripped from it.
0ED230AB7h should have the trailing h stripped from it.


inkey
inkey
inkey NULL
inkey "Press a key to continue ..."

Description
Suspend a console application and wait until the user presses a key.

Parameters
Optional parameters.
1. No arg will display the default message at the current cursor location.
2. NULL displays the cursor with no text.
3. A user defined zero terminated string. This can be quoted text.

Return Value
The scancode for the key pressed is returned in EAX

Comments
The cursor is displayed at the current cursor position which is at the right end of any text that is used as a prompt. The macro will exit on any normal key but does not respond to control keys or F keys.

The default display text if no parameter is used is "Press any key to continue ..."
You can manually code this capacity with the following.

print "Press a key to perform the next action"
call wait_key
print chr$(13,10)


input
mov lpstring, input()
mov lpstring, input("Enter number here ",62," ")

Description
The input macro receives text input from the console and returns the address of that text. The text cursor or the prompt and text cursor is set at the current location on the console.

Parameters
1. Optional quoted text and character notation.

Return Value
The return value is the address of the text typed at the console.

Comments
By convention, STDIN appends a carriage return / line feed pair of characters to the end of the text typed at the console. The input macro calls a seperate function that removes the CRLF pair so that the input text can be directly converted to numeric data without any problems. The current version has a 128 character limit.


InputFile
mov hMem, InputFile(lpfile)     ; version that responds to the __UNICODE__ equate.
mov hMem, InputFileA(lpfile)    ; ASCII only version.
mov hMem, InputFileW(lpfile)    ; UNICODE only version.

Description
InputFile loads a complete disk file into a memory buffer and return the address of that buffer..

Parameters
lpfile A zero terminated string with the name of the file to open. It can also be quoted text.

Return Value
The return value is the address of the buffer that the file has been loaded into. The length of the disk file is returned in the ECX register.

Comments
You should test for the existence of the file before you try and open it. When you have finished with the data from the file, you should deallocate the memory for the file by using the macro free.

    ; If you specify either the ASCII or UNICODE version of the  *
    ; macro you must match the text type for the file name       *
    ; to the macro being called.                                 *
    ;                                                            *
    ; For ASCII use the "ascii()" macro.                         *
    ; for UNICODE use either the "uni$()" or the "uc$()" macro.  *
    ;                                                            *
    ; If you are providing an address instead of a literal       *
    ; string, the text must be in the matching format for either *
    ; ASCII or UNICODE.

Example
mov hMem, InputFile("myfile.ext")
mov flen, ecx
; your code
free hMem


istring

find$
mov pSubStr, find$(spos, source, sub_string)

Description
Search for a substring in a source string.

Parameters
1. spos The start position in the source string to search from.
2. source The source string to search.
3. sub_string The sub string to search for.

Return Value
The return value is the 1 based character index for the substring or ZERO if the substring is not found.

Comments
The spos parameter is a 1 based index so the initial search position should be set to 1 or higher.
The earlier macro name istring has been equated to the new name find$.
This macro is __UNICODE__ aware.


LastError$()

Description
The LastError$() macro is used to return the operating system defined error string associated with the last call to the GetLastError() API function.

Parameters
This macro has no parameters and should be used with empty brackets only.

Return Value
The return value is the address of the error string associated with the last call to the GetLastError() API function.

Comments
The return string can be used in either console mode with the "print" macro or in normal GUI mode in any context where a string can be displayed. The buffer used for the error string is overwritten with any subsequent calls to te macro. The buffer is 1024 bytes in length.


lcase$
mov lpString, lcase$(lpString)

Description
Convert a zero terminated string to lower case characters.

Parameters
1. lpString The address of the zero terminated string to convert.

Return Value
The return value is the address of the converted string.

Comments
The original string data is changed by this macro. This macro is __UNICODE__ aware.


left$
mov lpString, left$(lpString,slen)

Description
Read a set number of characters from the left side of a string and overwrite the original buffer with the results.

Parameters
1. lpString The address of the string to read from.
2. slen The number of charactes to read from the string.

Return Value
The return value is the address of the source string.

Comments
The original string data is overwritten by the result of this macro. This macro is __UNICODE__ aware.


len
mov flen, len(lpString)

Description
Scan the length of a zero terminated string and return its length.

Parameters
1. lpString The string address to get the length for.

Return Value
The return value is the length of the string not counting the zero terminator. This macro is __UNICODE__ aware.


linein$

mov spos, linein$(source,buffer,spos)

Description
linein$ reads a line of text from a source memory buffer to a user defined memory buffer and updates the spos variable to the next "read" position in the source.

Parameters
1. source The address of the memory to read the line of text from.
2. buffer The user defined buffer to write the line of text to.
3. spos A variable that contains the required "read" offset in the source.

Return Value
The return value is the next "read" location in the source memory. The line of text is written to the user defined memory buffer. The line length not including zero or 13 is returned in the ECX register.

Comments
In most instances the spos variable is set to zero before the read operation(s) begins so that the reading of lines of text begin at the beginning of the text. The source is typically a file loaded into memory but it can be any text source that is carriage return / line feed delimited.

Allocation of the user defined buffer must take into consideration the absolute longest line of text and ensure the allocated buffer is larger than the longest line. On 32 bit Windows using a buffer that is far larger than the expected longest line is viable because of the available memory to the system so allocating 4k or even 16k will not effect performance in most instances.

mov buffer, alloc$(16384)
; perform your text operation here
free$ buffer

Where you can safely ensure that the lines of text are limited to a normal length, it is easier to use the stack as a LOCAL buffer.

LOCAL buffer :DWORD
LOCAL txt[128]:BYTE
mov buffer, ptr$(txt)

This macro and the algorithm that it uses from the MASM32 library is not designed to handle binary data and the results of trying to read binary data are undefined. It should only be used on text data that is delimited by ascii 13,10 . A zero terminator for the source works OK as well.

The spos variable is properly an OFFSET indicator from the start of the source memory and the underlying algorithm automatically updates the variable so that the next read location does not have to be scanned to determine where to read from. The spos variable is always updated after the macro returns so by subtracting one (1) from the spos value you have the number of bytes read from the source

Example
LOCAL rpos:DWORD ; read position variable
LOCAL wpos:DWORD ; write position variable

mov rpos, 0 ; set variables to zero
mov wpos, 0
mov rpos, linein$(lpsource,lpbuffer,rpos)
cmp tstline$(lpbuffer), 0
je bypass
; process the line of text
; --------------------------------------------
; output the line of text with a CRLF appended
; --------------------------------------------
mov wpos, lineout$(lpbuffer,lpdest,wpos,0)
bypass:


lineout$

mov spos, lineout$(source,buffer,spos,op_crlf)

Description
Write a line of text from a user defined source to a memory buffer with the choice of appending a CRLF to the end of the line.

Parameters
1. source A user defined line of zero terminated text.
2. buffer The destination buffer to write the source to.
3. spos A variable that contains the required "write" offset in the destination.
4. op_crlf A variable that defined if a carriage return / line feed pair are appended to the end of the line.
Zero = appended CRLF.
Non zero = no CRLF appended.

Return Value
The return value is the next "write" location in the destination buffer. The line of text from the source is written to the destination buffer. The ECX register returns the number of bytes written to the destination buffer.

Comments
The destination buffer must be large enough to receive the sum total of text written to it. In circumstances where this is not possible, you can either develop a memory re-allocation strategy or open a file and write each line of text to the file until the data is finished. Check the File IO Macros to use this option if it suits your code design.

The spos variable is properly an OFFSET indicator from the start of the destination memory and the underlying algorithm automatically updates the variable so that the next write location does not have to be scanned to determine where to write to. The spos variable is always updated after the macro returns so by subtracting one (1) from the spos value you have the number of bytes written to the destination buffer.


loc
loc xc, yc

Description
The loc macro sets the location of the text cursor on the console.

Parameters
1. xc The X co-ordinate.
2. yc The Y co-ordinate.

Return Value
There is no return value.

Comments
The X and Y co-ordinates are both zero based.


ltrim$
mov lpString, ltrim$(lpString)

Description
Remove spaces and tabs from the left side of a string.

Parameters
1. lpString The address of the string to trim.

Return Value
The return value is the address of the source string.

Comments
The result overwrites the original string. This macro is __UNICODE__ aware.


m2m
m2m var2, var1

Description
Copy a DWORD sized memory operand to another DWORD sized memory operand.

Parameters
1. The destination operand.
2. The source operand.
Note the reverse ordering as is common with mnemonics.

Comments
X86 hardware does not support direct memory to memory copy and the capacity must be writen using existing mnemonics. This version uses the stack to push the source operand onto the stack and pop it back off the stack as the destination operand.


ME

HEY MAN,

I am a genuine Bona Fide certified ADA[tm] programmer with experience in VB2, Fortran 77 and direct experience programming Zilog Z80 series processors in HEX. Not only do I have this experience but I am a proven master at MIRC scripting. If I am not too tired after my shift at the local diner from midnight to dawn and have a bit of time before I start my day job pumping gas at the local gas station, I can finish this task for you in the next month or two and it won't cost you any extra above my quotation.


memalign
memalign reg, number

Description
Align memory to a user defined power of 2.

Parameters
1. reg Either a 32 bit register or a 32 bit memory operand that contains the current location in allocated memory.
2. number The user defined power of 2 alignment value.

Return Value
There is no return value.

Comments
The macro is normally used on allocated memory where alignment is required for performance or specification reasons. Alignment must be by a power of two (2).
2, 4, 8, 16, 32, 64 etc ....
This is the actual macro in the macros.asm file.

memalign MACRO reg, number
add reg, number - 1
and reg, -number
ENDM


mkdir
mkdir lpstring

Description
Create a new directory.

Parameters
1. lpstring The address of a zero terminated string that contains the name and path of the new directory. This may also be a quoted text.

Return Value
This macro does not have a return value.

Comments
Use LastError() if you have any errors with the macro call.


mrm
mrm mem2, mem1

Description
Copy one DWORD memory operand to another DWORD memory operand.

Parameters
1. The destination operand.
2. The source operand.
Note the reverse ordering as is common with mnemonics.

Comments
X86 hardware does not support direct memory to memory copy and the capacity must be writen using existing mnemonics. This version uses the EAX register which is faster than using te stack but it uses a register.


op_type

op_type(macro_argument)

Description
Determine what operand type has been passed to the macro.

Parameters
1. macro_argument The argument passed to the macro.

Return Value
0 = UNKNOWN operand type
1 = LOCAL or GLOBAL label
2 = GLOBAL variable
3 = LOCAL variable
4 = IMMEDIATE operand or CONSTANT
5 = REGISTER
6 = LOCAL procedure in module
7 = EXTERNAL procedure or API call

Comments
This macro is useful when you are designing code within a macro that can take various operand forms. By knowing the operand type, you can construct the code to work correctly with that operand type.


OpenFileDlg
mov fname, OpenFileDlg(hWin,hInstance,lpTitle,lpPattern)

Description
Display an Open File common dialog box.

Parameters
1. hWin The parent window handle.
2. hInstance The instance handle of the applciation.
3. lpTitle The address of a zero terminates string.
4. lpPattern The address of a zero terminated string that specifies the file pattern(s) to use.

Return Value
The return value is the address of a 260 byte buffer that holds the selected file name or if the 1st byte in the buffer is zero, the use cancelled the selection.

Comments
The format of the file pattern requires name and pattern pairs zero seperated and double zero terminated. To create the zero terminated string, you can set the information in the .DATA section as follows.

.data
  pattern db "Text Files",0,"*txt",0,"Ini Files",0,"*ini",0,0
.code

You can also use a pseudo mnemonic from the MASM32 macro file as follows.

sas pattern, "All files",0,"*.*",0

Example
mov fname, OpenFileDlg(hWnd,hInstance,"Open a New File",ADDR pattern)
cmp BYTE PTR [eax], 0 ; test if 1st byte is zero
jne @F ; jump forward if its not
; write cancel processing code here
@@:


OutputFile
mov rval, OutputFile(lpfile,lpmem,flen)     ; version that responds to the __UNICODE__ equate.
mov rval, OutputFileA(lpfile,lpmem,flen)    ; ASCII only version.
mov rval, OutputFileW(lpfile,lpmem,flen)    ; UNICODE only version.

Description
OutputFile writes the contents of a memory buffer to a disk file.

Parameters
1. lpfile The address of a zero terminated string that is the name of the file to write. This may also be a quoted text.
2. lpmem The address of the memory buffer to write to disk.
3. flen The number of bytes to write to disk.

Return Value
The return value is the number of bytes written to disk or zero if there is an error.

Comments
This macro will overwrite an existing file. As the return value is written to the EAX register, the complete macro can be written directly into assembler code as if it is EAX.

    ; If you specify either the ASCII or UNICODE version of the  *
    ; macro you must match the text type for the file name       *
    ; to the macro being called.                                 *
    ;                                                            *
    ; For ASCII use the "ascii()" macro.                         *
    ; for UNICODE use either the "uni$()" or the "uc$()" macro.  *
    ;                                                            *
    ; If you are providing an address instead of a literal       *
    ; string, the text must be in the matching format for either *
    ; ASCII or UNICODE.

Example
  test OutputFile("newfile.ext",pbuffer,flen), eax
  jnz @F
  ; set error message or condition here
@@:


Dynamic array overview
The dynamic array system is constructed by allocating an array of pointers in fixed memory (GlobalAlloc()) with the GMEM_FIXED flag set so that the pointer array is always contiguous in memory. The method of allocation for each member is an "allocate on demand" system that uses a default null string and null member length for an empty member and allocates a block of OLE memory for each member based on the required length of the data to be written to it. This logic make empty array creation much faster and does not waste the memory required to allocate an empty string. The price of using OLE string is that it is slightly slower than a couple of other Windows memory strategies because of its extra flexibility.

OLE string has been chosen for array members because it has some very useful characteristics, the most useful being the storage of the data length 4 bytes below the returned starting address of the array member which allows both binary and zero terminated data to be written to any member. OLE string memory is also 16 byte aligned which is useful with some of the late PIV / Core 2 Duo SSE instructions that require 16 byte alignment.

In pseudo high level notation a dynamic array using this system has the following logic. NOTE that the array system is always a 1 based index as the 0 member of the array is used as the storage for the array member count.

arr = alloc(member_count)

arr(0) = stored member count
arr(1) = pointer to a default null string
arr(2) = pointer to a default null string

When a member has data written to it it has this logic.

arr(3) = pointer to dynamically allocated OLE string memory
arr(4) = pointer to dynamically allocated OLE string memory
etc ....

The system is fully re-entrant so that multiple array can routinely be used with the only need for array identification being the array handle for each dynamically allocated array.

The MACRO interface.
The array system provides both a procedural interface and a macro interface to suit different coding styles. The macro interface has the advantage in that it allows return values on the same line and where appropriate embedded quoted text data. The macro interface is designed to be used in the function position to facilitate obtaining the return value in a clear and easy to read manner.

The PROCEDURE interface.
The procedure interface uses the identical names to the macros except for the trailing "$" notation.

mov hArray, arralloc$(member_count)

becomes

invoke arralloc,member_count
mov hArray, eax

It is important to understand the scope of the handle that the array uses as the memory allocated with this array system MUST BE DEALLOCATE within the same scope as it is allocated under. If you allocate a LOCAL handle for the array within a normal procedure and exit the procedure without deallocating the array, the memory for the array can no longer be identified to be deallocated elsewhere and the application then has a memory leak that could bring the application to a stop. If you need to be able to access an array across different procedures you would create the array handle in the .DATA? section so it is globally visible across the entire module.

You can of course pass the array handle to other procedures as the array system is designed so be able to access the array count, each member length and if needed to be able to calculate the entire memory required to store the whole array.


print

print printc
print lptext
print lptext,13,10
print "Quoted Text"
print "Quoted Text",13,10

Description
The print macro displays text at the current text cursor location on the console. The printc macro differs only in that it support C style excapes. These macros are __UNICODE__ aware.

Parameters
1. lptext The address of a zero terminated string. This can also be quoted text.
2. Optional extra quoted text and / or byte notation.

Return Value
There is no return value.

Comments
The print macro is very flexible in its capacity. It will display either a zero terminated string that is specified as an address as its 1st argument or it will display the contents of quoted text. The optional 2nd argument can contain any combination of quoted text and byte specifiers in the same manner as data specified in the initialised data section.

Example
mov DWORD PTR number, 1234
print "The result is ",62,32
print str$(number)," bytes",13,10
Console output => The result is > 1234 bytes


C runtime printf function

printf

printf("%d\t%d\t%Xh\n", 123, 456, 1024);

This macro is a near exact duplicate of the MSVCRT runtime function "printf" and used both the ASCII and UNICODE MSVCRT functions to provide this capacity. It has been added for C programmers who are familiar with using "printf" and prefer to use the notation for displaying a variety of data type based off the selected control escapes.

NOTE that this macro does not return a value, it is written specifically to use the normal brackets but not return a value. If you need the return value, it is in the EAX register. The trailing ";" is not required by the macro and functions in MASM as a comment character.

The original ASCII version of this macro was written by Michael Webster.

printf Type Field Characters (MSDN)

d | int | Signed decimal integer.
i | int | Signed decimal integer.
o | int | Unsigned octal integer.
u
         int Unsigned decimal integer.
x
 int Unsigned hexadecimal integer, using "abcdef."
X | int | Unsigned hexadecimal integer, using "ABCDEF."
e | double | Signed value having the form [-]d.dddd e [sign]ddd where d is a single decimal digit, dddd is one or more decimal digits, ddd is exactly three decimal digits, and sign is + or -.
E | double | Identical to the e format except that E rather than e introduces the exponent.
f | double | Signed value having the form [-]dddd.dddd, where dddd is one or more decimal digits. The number of digits before the decimal point depends on the magnitude of the number, and the number of digits after the decimal point depends on the requested precision.
g | double | Signed value printed in f or e format, whichever is more compact for the given value and precision. The e format is used only when the exponent of the value is less than –4 or greater than or equal to the precision argument. Trailing zeros are truncated, and the decimal point appears only if one or more digits follow it.
G | double | Identical to the g format, except that E, rather than e, introduces the exponent (where appropriate).

Example

main proc

    LOCAL sint  :DWORD
    LOCAL uint  :DWORD
    LOCAL hint  :DWORD

    mov sint, -1234             ; signed integer
    mov uint, 9876              ; unsigned integer
    mov hint, 1024              ; unsigned integer
    FLOAT8 fp64, 12345.67890    ; 64 bit FLOAT value

    printf("%d\t is a signed integer\n",sint);
    printf("%u\t is an unsigned integer\n",uint);
    printf("0%Xh\t is an unsigned integer in hex\n",hint);
    printf("%f\t is an unsigned float value\n",fp64);

    printf("\n%d is signed,%u is unsigned,0%Xh is in HEX and %f is a REAL8\n\n",sint,uint,hint,fp64)

    ret

main endp

Result
-1234    is a signed integer
9876     is an unsigned integer
0400h    is an unsigned integer in hex
12345.678900     is an unsigned float value

-1234 is signed,9876 is unsigned,0400h is in HEX and 12345.678900 is a REAL8


pth$
mov cpth, pth$()

Description
Return the address of the current application path.

Parameters
This macro has no parameters.

Return Value
The address of a 260 byte buffer that contains the address of the current application.

Comments
The empty brackets are required by MASM's internal parser. This macro is __UNICODE__ aware.


ptr$
mov lpstring, ptr$(buffer)

Description
Cast the address of a local variable to a pointer variable.

Parameters
1. buffer A buffer allocated on the stack.

Return Value
The address of the buffer.

Comments
This macro loads the address of a stack variable into a register and sets the first two (2) bytes to zero. It is suitable for both ASCII and UNICODE text. Assigning the return value to a variable makes the value into a pointer which is generally easier to use that repeatedly using LEA to obtain the address.


remove$
mov lpSource, remove$(lpSource,lpSubString)

Description
Remove any instance of a substring from a source string.

Parameters
1. lpSource The address of the source string.
2. lpSubString The address of the sub string.

Return Value
The return value is the address of the source string.

Comments
The result overwrites the original string. This macro is __UNICODE__ aware.


reparg
reparg(macro_variable)return offset as invoke ADDR.
repargv(macro_variable)return offset in a register.
repargof(macro_variable)return direct offset.

Description
Replace quoted text in a macro with a data section offset or return the original value if its is NOT quoted text.

Parameters
1. macro_variable An argument passed to a macro.

Return Value
reparg returns an INVOKE format ADDR variable.
repargv returns the offset in the EAX register.
repargof returns the direct offset.

Comments
This group of macros make it possible to use quoted text directly in a procedure call. If you were writing a simple macro that had a system MessageBox in it, you can use reparg as follows to handle quoted text.

YourMessageBox MACRO hndl,text1,text2,styl
  invoke MessageBox,hndl,reparg(text1),reparg(text2),styl
  EXITM <eax>
ENDM
You would call the macro this way.

mov hRetval, YourMessageBox(hWnd,"My Message","Msg Box Title",MB_OK)
The macro places the quoted text in the data section and substitutes the offset in the data section for the quoted text.


rev$
mov lpString, rev$(lpString)

Description
Reverse a zero terminated string.

Parameters
1. lpString The address of the string to reverse.

Return Value
The return value is the address of the reversed string.

Comments
The result overwrites the original string. This macro is __UNICODE__ aware.


right$
mov lpString, right$(lpString,slen)

Description
Read a set number of characters from the right side of a string and overwrite the original buffer with the results.

Parameters
1. lpString The address of the string to read from.
2. slen The number of charactes to read from the string.

Return Value
The return value is the address of the source string.

Comments
The original string data is overwritten by the result of this macro.


rmdir
rmdir lpstring

Description
Remove an existing directory.

Parameters
1. lpstring The address of a zero terminated string that contains the name and path of the directory to remove. This may also be a quoted text.

Return Value
This macro does not have a return value.

Comments
Use LastError$() if you have any errors with the macro call. This macro will fail if the directory has either files or subdirectories in it.


rndir
rndir oldname, newname

Description
Rename an existing directory.

Parameters
1. oldname The address of the old name.
2. newname The address of the new name.

Return Value
This macro does not have a return value.

Comments
Use LastError$() if you have any errors with the macro call.


rtrim$
mov lpString, rtrim$(lpString)

Description
Remove spaces and tabs from the right side of a string.

Parameters
1. lpString The address of the string to trim.

Return Value
The return value is the address of the source string.

Comments
The result overwrites the original string. This macro is __UNICODE__ aware.


rv
mov retval, rv(MessageBox,hWnd,"Message Text","Title",MB_YESNO)

Description
Call any prototyped procedure that has a return value.

Parameters
Any prototyped procedure complete with its argument list.

Return Value
The return value is in the EAX register.

Comments
When writing code with this macro, the complete macro call can be treated like the EAX register and it can be used directly in normal assembler statements as the EAX register.

test rv(Procedure,Arglist ...), eax
mov revval, rv(Procedure,Arglist ...)


rvc
test rvc(YourProc,"\tC Style\n\tEscape Sequences"), eax

Description
Call any prototyped procedure that has a return value.

Parameters
Any prototyped procedure complete with its argument list.

Return Value
The return value is in the EAX register.

Comments
This macro differs from the "rv" macro only in that it supports additional formatting using C style escape sequences. The reference to this capacity the cfm$ macro.


rvcx macro

rvcx
test rvcx(YourProc,"\tC Style\n\tEscape Sequences"), eax

Description
Call any prototyped procedure that has a return value.

Parameters
Any prototyped procedure complete with its argument list.

Return Value
The return value is in the EAX register.

Comments
This macro differs from the "rvx" macro only in that it supports additional formatting using C style escape sequences.

qWord's original documentation.

;/********************************************************************/
;/*                     rvcx - macro function                        */
;/* This macro behave like the rvx-macros, except, that it adds      */
;/* support for escape sequences:                                    */
;/*     \\  ->  "\"                                                  */
;/*     \t  ->  tab                                                  */
;/*     \n  ->  new line (13,10)                                     */
;/*     \x  ->  "!"                                                  */
;/*     \a  ->  "("                                                  */
;/*     \b  ->  ")"                                                  */
;/*     \l  ->  "<"                                                  */
;/*     \r  ->  ">"                                                  */
;/*     \p  ->  "%"                                                  */
;/*     \A  ->  "&"                                                  */
;/*     \q  ->  double quote '"'                                     */
;/*     \0  ->  zero                                                 */
;/* Example:                                                         */
;/*     mov edi,rv(myFunction,L"my string\x\n",&wsz[0],...)          */
;/*                                                     qWord, 2011  */
;/********************************************************************/


rvx Extended Return Value macro.

rvx
Extended function return value macro.

mov retval, rvx(MessageBox,hWnd,"Message Text","Title",MB_YESNO)

Description
Call any prototyped procedure that has a return value.

Parameters
Any prototyped procedure complete with its argument list.

Return Value
The return value is in the EAX register.

Comments
This is qWord's original documentation for the rvx macro.

;/********************************************************************/
;/*                     rvx - macro function                         */
;/* This macro is the function-version of the fnx-macro.             */
;/*                                                                  */
;/* Example:                                                         */
;/*      mov edi,rv(myFunction,L"my string",&wsz[0],...)             */
;/*      .break .if !rv(dest=myFunction,...)                         */
;/*                                                     qWord, 2011  */
;/********************************************************************/


sas
sas a$, "This is an assigned string"

Description
Assign a string to a local variable.

Parameters
1. A DWORD sized local variable.
2. The quoted text to assign to the local variable.

Comments
This is the same technique used in higher level languages to ensure a string only has LOCAL scope. String data is normally stored in the initialised data section of the executable file and by assigning it to a LOCAL variable, the string is only accessible within the procedure that it is allocated in. Once the string is assigned to the local variable it is used directly as the address of the string without using the ADDR or OFFSET operators. This macro is __UNICODE__ aware.

Example
LOCAL a$:DWORD ; allocate a LOCAL variable
........
sas a$,"My Quoted Text"
........
fn MessageBox,hWnd,a$,"Hi Guys",MB_OK


SaveFileDlg
mov fname, SaveFileDlg(hWin,hInstance,lpTitle,lpPattern)

Description
Display a Save File common dialog box.

Parameters
1. hWin The parent window handle.
2. hInstance The instance handle of the applciation.
3. lpTitle The address of a zero terminates string.
4. lpPattern The address of a zero terminated string that specifies the file pattern(s) to use.

Return Value
The return value is the address of a 260 byte buffer that holds the selected file name or if the 1st byte in the buffer is zero, the use cancelled the selection.

Comments
The format of the file pattern requires name and pattern pairs zero seperated and double zero terminated. To create the zero terminated string, you can set the information in the .DATA section as follows.

.data
  pattern db "Text Files",0,"*txt",0,"Ini Files",0,"*ini",0,0
.code

 You can also use a pseudo mnemonic from the MASM32 macro file as follows.
sas pattern, "All files",0,"*.*",0

Example
  mov fname, SaveFileDlg(hWnd,hInstance,"Save File As ....",ADDR pattern)
  cmp BYTE PTR [eax], 0 ; test if 1st byte is zero
  jne @F ; jump forward if its not
  ; write cancel processing code here
@@:


SetConsoleCaption
SetConsoleCaption MACRO title_text:VARARG

Description
Set the text on the title bar of the current console.

Parameters
1. title_text A zero terminated string containing the rquired txt to display. This may be quoted text.

Return Value
The macro does not return a value.

Comments
This macro can be used in conjunction with GetConsoleCaption$ to save and restore the previous title bar text


setenv
setenv szString

Description
Set a zero terminated string as an environment variable.

Parameters
1. szString Either a zero terminated string or quoted text.

Return Value
The macro does not return a value.

Comments
The zero terminated string needs to be in the form "var=string"
Example : setenv "link=\masm32\bin\"
Example : setenv lpString


SPROTO

SPROTO MACRO func_addr:REQ,arglist:VARARG

Description
Create a STDCALL prototype for a procedure that has a known starting address and a known argument list.

Parameters
1. func_addr The name to be used for the address of the procedure that is being prototyped.
2. arglist A normal prototype list

Return Value
The return value is assigned to an equate of your own choice that must be a unique name within the application. See the example below for details on how to use it.

Comments
The following code shows how the two prototyping macros are used.

main proc
    LOCAL user :DWORD
    LOCAL msvc :DWORD
    LOCAL pbuf :DWORD
    LOCAL buffer[64]:BYTE

    mov pbuf, ptr$(buffer)

; ---------------------------
; prototype the two functions
; ---------------------------
.const
    mbox SPROTO(adr1,:DWORD,:DWORD,:DWORD,:DWORD)
    _l2a CPROTO(adr2,:DWORD,:DWORD,:DWORD)

.code
; -------------
; load the DLLs
; -------------
    mov user, rv(LoadLibrary,"user32.dll")
    mov msvc, rv(LoadLibrary,"msvcrt.dll")

; -----------------------------------
; load the procedure address into the
; variable specified in the prototype
; -----------------------------------
    mov adr1, rv(GetProcAddress,user,"MessageBoxA")
    mov adr2, rv(GetProcAddress,msvc,"_ltoa")

; -----------------------
; call the two procedures
; -----------------------
    invoke _l2a,1234,pbuf,10
    fn mbox,0,pbuf,"title",MB_OK

; -----------------
; free the two DLLs
; -----------------
    invoke FreeLibrary,user
    invoke FreeLibrary,msvc

    ret

main endp


sstr$
mov lpResult, sstr$(Integer)

Description
Convert an signed 32 bit integer to a zero terminated string.

Parameters
1. Integer An unsigned 32 bit integer.

Return Value
The return value is the address of the zero terminated string that holds the result as an OFFSET.

Comments
Each macro call in the assembler source code provides a 20 byte long buffer in the data section to hold the results of the conversion. This macro is __UNICODE__ aware.


String Macro Overview
Basic as a language has one of the easiest techniques available for manipulating string data but it does so by adding a particular style of overhead where strings are repeatedly created and copied during the normal style of string operation. Effectively a basic program needs to have the code for a string engine in it and this is a different technology to the zero terminated string techniques used in both C and the MASM32 library procedures.

The string macros in MASM32 differ to this extent that they DO NOT create new strings but modify the existing ones so that when an operation is performed on a zero terminated string, the ORIGINAL data has been changed.

With basic, if you write a simple line of code,

b$ = LCASE$(a$)

You have created a new string b$ and the original a$ has not been modified.

With the following example in MASM code, variables like a$, b$ are simple DWORD variables declared on the stack with the LOCAL keyword.

LOCAL a$ :DWORD
LOCAL b$ :DWORD

With MASM32, if you write the line of code,

mov b$, lcase$(a$)

The string data at the address a$ is modified and the address is returned to the variable b$.
The capacity to nest function style macros is very useful and it allows code like,

mov a$, ucase$(ltrim$(a$))

This technique and similar more complex examples is possible because the return value from each macro is used as a parameter for the next lower macro. At a single sequence of nesting this technique works fine but problems can arise if there are multiple sequences of nesting as the second one may overwrite the value for the first if the value was returned in the EAX register. this can show in simple code that tried to use the same sequence of string functions twice.

invoke function,nested1(a$),nested2(b$),number

If there is a risk of this problem, it is easy enough to solved by assigning the two nested macros to a variable and then using the variable in the following procedure call.

mov var1, nested(a$)
mov var2, nested(b$)
invoke function,var1,var2,number

Managing String Buffers
String buffer size must be managed in the same manner as normal zero terminated strings. Where basic automatically allocates the buffer for each string, with zero terminated strings the programmer must ensure that the buffer size is large enough to receive the finished result. With multiple string operations, it is often viable to set two or more work buffers and keep reusing them. In some instances you need to reset the string length to zero by writing an ascii zero byte at the beginning of the string.

If for example you allocated a buffer of 1024 bytes and have data written to it so it needs to be cleared after it has been used so it can be classed as an empty string again which some macros require, all you do is cast the buffer back to a pointer again using the ptr$() macro and the buffer can be reused again.

LOCAL buffer[1024]:TCHAR ; allocate 1024 character on the stack (BYTE for ASCII, WORD for UNICODE).
mov lpstring, ptr$(buffer) ; cast the buffer to a pointer
; perform the required actions using lpstring.
mov lpstring, ptr$(buffer) ; clear the buffer again

CODE EFFICIENCY
By retaining the technology of zero terminated strings, this macro system deliver code quality that is hard to improve on manually yet it has much of the development speed and ease of writing basic code once you understand how it works.

mov pstr, right$(ucase$(left$(lcase$(pstr),9)),6)

 This nested set of macros disassembles to the following assembler code.

DISASSEMBLY
004014FC FFB514FFFFFF push dword ptr [ebp-0ECh]
00401502 E8C9030000 call fn_004018D0
00401507 6A09 push 9
00401509 50 push eax
0040150A 50 push eax
0040150B E840030000 call fn_00401850
00401510 50 push eax
00401511 E86A040000 call fn_00401980
00401516 6A06 push 6
00401518 50 push eax
00401519 50 push eax
0040151A E8E1030000 call fn_00401900
0040151F 898510FFFFFF mov [ebp-0F0h],eax


sval
mov value, sval(lpString)

Description
Convert a signed string value to a 32 bit integer.

Parameters
1. lpString The address of the signed numerical string value

Return Value
The return value is the 32 bit integer value.

Comments
The macro will recognise either leading sign notation for the negative values or no leading notation for a positive value. This macro is __UNICODE__ aware.


SysDir$
mov sdir, SysDir$()

Description
Return the address of the Windows system directory.

Parameters
This macro has no parameters.

Return Value
The address of a 260 byte buffer that contains the address of the Windows system directory.

Comments
The empty brackets are required by MASM's internal parser. This macro is __UNICODE__ aware.


TCHAR - Keyword

The TCHAR keyword is a conditional data size specifier that changes depending on whether the __UNICODE__ equate is defined. It allows data to be specified that is the correct size for the build type, either ASCII or UNICODE.

This is the TYPEDEF used in the WINDOWS.INC include file.

IFDEF __UNICODE__
    TCHAR                       typedef WORD
ELSE
    TCHAR                       typedef BYTE
ENDIF

It can be used in any context where BYTE or WORD is used in specific ASCII or UNICODE data declarations but has the advantage that you can write code that will build in either ASCII or UNICODE while maintaining the correct data size.

Typical examples are as follows.

As a LOCAL in a procedure.
LOCAL mybuffer[260]:TCHAR

In the DATA or DATA? section.
    itemname TCHAR 64 dup (0)     ; initialised data

    itembuffer TCHAR 128 dup (?)  ; uninitialised data

You can still write code using either BYTE or WORD or the abbreviated form "db" or "dw" and if the code you are writing is specific to either ASCII or UNICODE this may be the most viable option but if you choose to write code that can be built with either ASCII or UNICODE then the TCHAR keyword automates the data size for you.


trim$
mov lpString, trim$(lpString)

Description
Remove tabs and spaces from both ends of a string

Parameters
1. lpString The address of the source string.

Return Value
The return value is the address of the source string.

Comments
The result overwrites the original string.


tstarg

tstarg(macro_argument)

Description
Display an error and stop the assembler if a quoted text is passed to it.

Parameters
1. macro_argument The argument passed to the macro.

Return Value
If the argument is not quoted text, it returns the argument passed to it.

Comments
This macro is a form of error detection so that quoted text is not passed to another macro if it should not be used in that argument position. Typical applications are a macro that specifies the address of a buffer where quoted text will not work.


tstline$
tstline$ lpstr

Description
Test if a line of text has usable content.

Parameters
1. lpstr The address of the line of text to test.

Return Value
Return value is either the first usable text character zero extended to 32 bit or zero if the line has no useful content.

Comments
tstline$ scans the line of text specified in lpstr bypassing any leading spaces or tabs to obtain the first usable character. The macro is designed to test if a line of text is either empty or only contains spaces or tabs. Returning the first character in AL allows the testing of a comment or similar so that the line can be either included or avoided while reading the source. The return value of a usable character is zero extended to 32 bit to allow for 32 bit evaluation if required.

Example
test tstline$(lpstring), eax
jz no_useful_content

This direct assembler notation is possible because the macro returns a value in EAX and can be used anywhere where EAX can be used.


ucase$
mov lpString, ucase$(lpString)

Description
Convert a zero terminated string to upper case characters.

Parameters
1. lpString The address of the zero terminated string to convert.

Return Value
The return value is the address of the converted string.

Comments
The original string data is changed by this macro. This macro is __UNICODE__ aware.


ucCmd$ Macro

ucCmd$

mov retval, ucCmd$(argnumber)

Description
Get a user specified argument from the command line. This MACRO is UNICODE only.

Parameters
argnumber The 1 based argument number. 1 = arg1, 2 = arg2 etc ....

Return Value
The result is returned as an OFFSET to a buffer and can be assigned to a normal DWORD sized memory operand.

  Testing RETURN VALUES in EAX
  < 0 = buffer not large enough for selected arg
    0 = arg not found
  > 0 = arg number read from command tail

  NOTE that a negative return value indicates buffer
  over-run protection if and when a command line is
  longer than the MAX_PATH constant.

  if arg num > 0 result is written to user supplied buffer

Comments
Simple console example to loop through all available command line arguments.

    LOCAL pbuf  :DWORD           ; a normal memory operand

    push esi                     ; preserve ESI
    mov esi, 1                   ; start at arg 1

  @@:
    mov pbuf, ucCmd$(esi)
    test eax, eax                ; test EAX for no further arguments
    jle pastit                   ; exit on zero or less
    print ustr$(eax)," "         ; display the argument number
    print pbuf,13,10             ; display the argument
    add esi, 1
    jmp @B

  pastit:
    .if SDWORD PTR eax < 0       ; NOTE the SIGNED comparison using "SDWORD PTR"
      print "Larger buffer required for selected argument",13,10
    .elseif eax == 0
      print "no further arguments available",13,10
    .endif

    pop esi

    ret

NOTE that the procedure "ucGetCL" gives you more control over the buffer size if you need to use a size that is different to the constant MAX_PATH.
The buffer that is returned is used by each call to this macro, if you need to store different arguments from the command line, you should copy them to their own buffer using either the "cst" macro or the "ucCopy" procedure.


uhex$
mov lpHex, uhex$(integer)

Description
Convert an unsigned 32 bit integer to a hexadecimal zero terminated string.

Parameters
1. integer An unsigned 32 bit integer.

Return Value
The return value is the address of the zero terminated string that holds the result as an OFFSET.

Comments
Each macro call in the assembler source code provides a 20 byte long buffer in the data section to hold the results of the conversion.


ustr$
mov lpResult, ustr$(uInteger)

Description
Convert an unsigned 32 bit integer to a zero terminated string.

Parameters
1. uInteger An unsigned 32 bit integer.

Return Value
The return value is the address of the zero terminated string that holds the result as an OFFSET.

Comments
Each macro call in the assembler source code provides a 20 byte long buffer in the data section to hold the results of the conversion. This macro is __UNICODE__ aware.


uval
mov value, uval(lpString)

Description
Convert an unsigned decimal value to a 32 bit integer.

Parameters
1. lpString The address of the string to convert.

Return Value
The return value is the 32 bit integer value.

Comments
A signed value should not be passed to this macro as the results will be unreliable, use sval for signed values. This macro is __UNICODE__ aware.


WinDir$
mov wdir, WinDir$()

Description
Return the address of the Windows directory.

Parameters
This macro has no parameters.

Return Value
The address of a 260 byte buffer that contains the address of the Windows directory.

Comments
The empty brackets are required by MASM's internal parser. This macro is __UNICODE__ aware.