Appendix A
Differences
Between
MASM 6.1 and 5.1
For the many users who come to version 6.1 of the Microsoft Macro Assembler directly from the popular MASM 5.1, this appendix describes the differences between the two versions. Version 6.1 contains significant changes, including:
u An integrated development environment called Programmer’s WorkBench (PWB) from which you can write, edit, debug, and execute code.
u Expanded functionality for structures, unions, and type definitions.
u New directives for generating loops and decision statements, and for declaring and calling procedures.
u Simplified methods for applying public attributes to variables and routines in multiple-module programs.
u Enhancements for writing and using macros.
u Flat-model support for Windows NT and new instructions for the 80486 processor.
The OPTION M510 directive (or the /Zm command-line switch) assures nearly complete compatibility between MASM 6.1 and MASM 5.1. However, to take full advantage of the enhancements in MASM 6.1, you will need to rewrite some code written for MASM 5.1.
The first section of this appendix describes the new or enhanced features in MASM 6.1. The second section, "Compatibility Between MASM 5.1 and 6.1," explains how to:
u Minimize the number of required changes with the OPTION directive.
u Rewrite your existing assembly code, if necessary, to take advantage of the assembler’s enhancements.
New Features of Version 6.1
This section gives an overview of the new features of MASM 6.1 and provides references to more detailed information elsewhere in the documentation. For full explanations and coding examples, see the documentation listed in the cross-references.
The Assembler, Environment, and Utilities
Most of the executable files provided with MASM 6.1 are new or revised. For a complete list of these files, read the PACKING.TXT file on the distribution disk. The book Getting Started also provides information about setting up the environment, assembler, and Help system.
The Assembler
The macro assembler, named ML.EXE, can assemble and link in one step. Its new 32-bit operation gives ML.EXE the ability to handle much larger source files than MASM 5.1. The command-line options are new. For example, the /Fl and /Sc options generate instruction timings in the listing file. Command-line options are case-sensitive and must be separated by spaces.
For backward compatibility with MASM 5.1 makefiles, MASM 6.1 includes the MASM.EXE utility. MASM.EXE translates MASM 5.1 command-line options to the new MASM 6.1 command-line options and calls ML.EXE. See the Reference book for details.
H2INC
H2INC converts C include files to MASM include files. It translates data structures and declarations but does not translate executable code. For more information, see Chapter 20 of Environment and Tools.
NMAKE
NMAKE replaces the MAKE utility. NMAKE provides new functions for evaluating target files and more flexibility with macros and command-line options. For more information, see Environment and Tools.
Integrated Environment
PWB is an integrated development environment for writing, developing, and debugging programs. For information on PWB and the CodeView debugging application, see Environment and Tools.
Online Help
MASM 6.1 incorporates the Microsoft Advisor Help system. Help provides a vast database of online help about all aspects of MASM, including the syntax and timings for processor and coprocessor instructions, directives, command-line options, and support programs such as LINK and PWB.
For information on how to set up the help system, see Getting Started. You can invoke the help system from within PWB or from the QuickHelp program (QH).
HELPMAKE
You can use the HELPMAKE utility to create additional help files from ASCII text files, allowing you to customize the online help system. For more information, see Environment and Tools.
Other Programs
MASM 6.1 contains the most recent versions of LINK, LIB, BIND, CodeView, and the mouse driver. The CREF program is not included in MASM 6.1. The Source Browser provides the information that CREF provided under MASM 5.1. For more information on the Source Browser, see Chapter 5 of Environment and Tools or Help.
Segment Management
This section lists the changes and additions to memory-model support and directives that relate to memory model.
Predefined Symbols
The following predefined symbols (also called predefined equates) provide information about simplified segments:
Predefined Symbol Value
hidden text@stack DGROUP for near stacks, STACK for far stacks
hidden text@Interface Information about language parameters
hidden text@Model Information about the current memory model
hiddentext@Line The source line in the current file
hiddentext@Date The current date
hiddentext@FileCur The current file
hiddentext@Time The current time
hiddentext@Environ The current environment variables
For more information about predefined symbols, see "Predefined Symbols" in Chapter 1.
Enhancements to the ASSUME Directive
MASM automatically generates ASSUME values for the code segment register (CS). It is no longer necessary to include lines such as
ASSUME
CS:MyCodeSegment
in your programs. In addition, 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.
For more information, see "Setting the ASSUME Directive for Segment Registers" in Chapter 2 and "Defining Register Types with ASSUME" in Chapter 3.
Relocatable Offsets
For compatibility with applications for Windows, the LROFFSET operator can calculate a relocatable offset, which is resolved by the loader at run time. See Help for details.
Flat Model
MASM 6.1 supports the flat-memory model of Windows NT, which allows segments as large as 4 gigabytes. All other memory models limit segment size to 64K for MS-DOS and Windows. For more information about memory models, see "Defining Basic Attributes with .MODEL" in Chapter 2.
Data Types
MASM 6.1 supports an improved data typing. This section summarizes the improved forms of data declarations in MASM 6.1.
Defining Typed Variables
You can now use the type names as directives to define variables. Initializers are unsigned by default. The following example lines are equivalent:
var1 DB 25
var1 BYTE 25
Signed Types
You can use the SBYTE, SWORD, and SDWORD directives to declare signed data. For more information about these directives, see "Allocating Memory for Integer Variables" in Chapter 4.
Floating-Point Types
MASM 6.1 provides the REAL4, REAL8, and REAL10 directives for declaring floating-point variables. For information on these type directives, see "Declaring Floating-Point Variables and Constants" in Chapter 6 .
Qualified Types
Type definitions can now include distance and language type attributes. Procedures, procedure prototypes, and external declarations let you specify the type as a qualified type. A complete description of qualified types is provided in the section "Data Types" in Chapter 1.
Structures
Changes to structures since MASM 5.1 include:
u Structures can be nested.
u The names of structure fields need not be unique. As a result, you must qualify references to field names.
u Initialization of structure variables can continue over multiple lines provided the last character in the line before the comment field is a comma.
u Curly braces and angle brackets are equivalent.
For example, this code works in MASM 6.1:
SCORE
STRUCT
team1 BYTE 10 DUP (?)
score1 BYTE ?
team2 BYTE 10 DUP (?)
score2 BYTE ?
SCORE ENDS
first SCORE {"BEARS", 20, ; This comment is allowed.
"CUBS", 10 }
mov al, [bx].score.team1 ; Field name must be qualified
; with structure name.
You can use OPTION OLDSTRUCTS or OPTION M510 to enable MASM 5.1 behavior for structures. See "Compatibility between MASM 5.1 and 6.1," later in this appendix. For more information on structures and unions, see "Structures and Unions" in Chapter 5.
Unions
MASM 6.1 allows the definition of unions with the UNION directive. Unions differ from structures in that all fields within a union occupy the same data space. For more information, see "Structures and Unions" in Chapter 5.
Types Defined with TYPEDEF
The TYPEDEF directive defines a type for use later in the program. It is most useful for defining pointer types. For more information on defining types, see "Data Types" in Chapter 1, and "Defining Pointer Types with TYPEDEF" in Chapter 3.
Names of Identifiers
MASM 6.1 accepts identifier names up to 247 characters long. All characters are significant, whereas under MASM 5.1, names are significant to 31 characters only. For more information on identifiers, see "Identifiers" in Chapter 1.
Multiple-Line Initializers
In MASM 6.1, a comma at the end of a line (except in the comment field) implies that the line continues. For example, the following code is legal in MASM 6.1:
longstring BYTE
"This string ",
"continues over two lines."
bitmasks BYTE 80h, 40h, 20h, 10h,
08h, 04h, 02h, 01h
For more information, see "Statements" in Chapter 1.
Comments in Extended Lines
MASM 5.1 allows a backslash ( \ ) as the line-continuation character if it is the last nonspace character in the line. MASM 6.1 permits a comment to follow the backslash.
Determining Size and Length of Data Labels
The LENGTHOF operator returns the number of data items allocated for a data label. MASM 6.1 also provides the SIZEOF operator. When applied to a type, SIZEOF returns the size attribute of the type expression. When applied to a data label, SIZEOF returns the number of bytes used by the initializer in the label’s definition. In this case, SIZEOF for a variable equals the number of bytes in the type multiplied by LENGTHOF for the variable.
MASM 6.1 recognizes the LENGTH and SIZE operators for backward compatibility. For a description of the behavior of SIZE under OPTION M510, see "Length and Size of Labels with OPTION M510," later in this appendix. For obsolete behavior with the LENGTH operator, see also "LENGTH Operator Applied to Record Types," page 356.
For information on LENGTHOF and
SIZEOF, see the following sections in
chapter 5: "Declaring and Referencing Arrays," "Declaring and
Initializing Strings," "Declaring Structure and Union
Variables," and "Defining Record Variables."
HIGHWORD and LOWWORD Operators
These operators return the high and low words for a given 32-bit operand. They are similar to the HIGH and LOW operators of MASM 5.1 except that HIGHWORD and LOWWORD can take only constants as operands, not relocatables (labels).
PTR and CodeView
Under MASM 5.1, applying the PTR operator to a data initializer determines 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. See "Defining Pointer Types with TYPEDEF" in Chapter 3.
Procedures, Loops, and Jumps
With its significant improvements for procedure and jump handling, MASM 6.1 closely resembles high-level - language implementations of procedure calls. MASM 6.1 generates the code to correctly handle argument passing, check type compatibility between parameters and arguments, and process a variable number of arguments. MASM 6.1 can also automatically recast jump instructions to correct for insufficient jump distance.
Function Prototypes and Calls
The PROTO directive lets you prototype procedures in the same way as high-level languages. PROTO enables type-checking and type conversion of arguments when calling the procedure with INVOKE. For more information, see "Declaring Procedure Prototypes" in Chapter 7.
The INVOKE directive sets up code to
call a procedure and correctly pass arguments according to the
prototype. MASM 6.1 also provides the VARARG keyword to
pass a variable number of arguments to a procedure with
INVOKE. For more information about INVOKE and
VARARG, see "Calling Procedures with INVOKE" and "Declaring
Parameters with the PROC Directive" in
Chapter 7.
The ADDR keyword is new since MASM 5.1. When used with INVOKE, it provides the address of a variable, in the same way as the address-of operator (&) in C. This lets you conveniently pass an argument by reference rather than value. See "Calling Procedures with INVOKE" in Chapter 7.
High-Level Flow-Control Constructions
MASM 6.1 contains several directives that generate code for loops and decisions depending on the status of a conditional statement. The conditions are tested at run time rather than at assembly time.
Directives new since MASM 5.1 include
.IF, .ELSE, .ELSEIF, .REPEAT,
.UNTIL, .UNTILCXZ, .WHILE, and .ENDW.
MASM 6.1 also provides the associated .BREAK and
.CONTINUE directives for loops and IF
statements.
For more information, see "Loops" in Chapter 7 and "Decision
Directives" on
page 171.
Automatic Optimization for Unconditional Jumps
MASM 6.1 automatically determines the smallest encoding for direct unconditional jumps. See "Unconditional Jumps" in Chapter 7.
Automatic Lengthening for Conditional Jumps
If a conditional jump cannot reach its target destination, MASM automatically recasts the code to use an unconditional jump to the target. See "Jump Extending," page 169.
User-Defined Stack Frame Setup and Cleanup
The prologue code generated immediately after a PROC statement sets up the stack for parameters and local variables. The epilogue code handles stack cleanup. MASM 6.1 allows user-defined prologues and epilogues, as described in "Generating Prologue and Epilogue Code" in Chapter 7.
Simplifying Multiple-Module Projects
MASM 6.1 simplifies the sharing of code and data among modules and makes the use of include files more efficient.
EXTERNDEF in Include Files
MASM 5.1 requires that you declare public and external all data and routines used in more than one module. With MASM 6.1, a single EXTERNDEF directive accomplishes the same task. EXTERNDEF lets you put global data declarations within an include file, making the data visible to all source files that include the file. For more information, see "Using EXTERNDEF" in Chapter 8.
Search Order for Include Files
MASM 6.1 searches for include files in the directory of the main source file rather than in the current directory. Similarly, it searches for nested include files in the directory of the include file. You can specify additional paths to search with the /I command-line option. For more information on include files, see "Organizing Modules" in Chapter 8.
Enforcing Case Sensitivity
In MASM 5.1, sensitivity to case is influenced only by command-line options such as /MX, not the language type given with the .MODEL directive. In MASM 6.1, the language type takes precedence over the command-line options in specifying case sensitivity.
Alternate Names for Externals
The syntax for EXTERN allows you to specify an alternate symbol name, which the linker can use to resolve an external reference to an unused symbol. This prevents linkage with unneeded library code, as explained in "Using EXTERN with Library Routines," Chapter 8.
Expanded State Control
Several directives in MASM 6.1 enable or disable various aspects of the assembler control. These include 80486 coprocessor instructions and use of compatibility options.
The OPTION Directive
The new OPTION directive allows you to selectively define the assembler’s behavior, including its compatibility with MASM 5.1. See "Using the OPTION Directive" in Chapter 1 and "Compatibility between MASM 5.1 and 6.1," later in this appendix.
The .NO87 Directive
The .NO87 directive disables all coprocessor instructions. For more information, see Help.
The .486 and .486P Directives
MASM 6.1 can assemble instructions specific to the 80486, enabled with the .486 directive. The .486P directive enables 80486 instructions at the highest privilege level (recommended for systems-level programs only). For more information, see Help.
The PUSHCONTEXT and POPCONTEXT Directives
The directive PUSHCONTEXT saves the assembly environment, and POPCONTEXT restores it. The environment includes the segment register assumes, the radix, the listing and CREF flags, and the current processor and coprocessor. Note that .NOCREF (the MASM 6.1 equivalent to .XCREF) still determines whether information for a given symbol will be added to Browser information and to the symbol table in the listing file. For more information on listing files, see Appendix C or Help.
New Processor Instructions
MASM 6.1 supports these instructions for the 80486 processor:
80486 Instruction Description
BSWAP Byte swap
CMPXCHG Compare and exchange
INVD Invalidate data cache
INVLPG Invalidate Translation Lookaside Buffer entry
WBINVD Write back and invalidate data cache
XADD Exchange and add
For full descriptions of these instructions, see the Reference or Help.
Renamed Directives
Although MASM 6.1 still supports the old names in MASM 5.1, the following directives have been renamed for language consistency:
MASM 6.1 MASM 5.1
.DOSSEG DOSSEG
.LISTIF .LFCOND
.LISTMACRO .XALL
.LISTMACROALL .LALL
.NOCREF .XCREF
.NOLIST .XLIST
.NOLISTIF .SFCOND
.NOLISTMACRO .SALL
ECHO %OUT
EXTERN EXTRN
FOR IRP
FORC IRPC
REPEAT REPT
STRUCT STRUC
SUBTITLE SUBTTL
Specifying 16-Bit and 32-Bit Instructions
MASM 6.1 supports all instructions that work with the extended 32-bit registers of the 80386/486. For certain instructions, you can override the default operand size with the W (word) and the D (doubleword) suffixes. For details, see the Reference or Help.
Macro Enhancements
There are significant enhancements to macro functions in MASM 6.1. Directives provide for a variable number of arguments, loop constructions, definitions of text equates, and macro functions.
Variable Arguments
MASM 5.1 ignores extra arguments passed to macros. In MASM 6.1, you can pass a variable number of arguments to a macro by appending the VARARG keyword to the last macro parameter in the macro definition. The macro can then reference additional arguments relative to the last declared parameter. This procedure is explained in "Returning Values with Macro Functions" in Chapter 9.
Required and Default Macro Arguments
With MASM 6.1, you can use REQ or the
:= operator to specify required or default arguments. See
"Specifying Required and Default Parameters" in
Chapter 9.
New Directives for Macro Loops
Within a macro definition, WHILE repeats assembly as long as a condition remains true. Other macro loop directives, IRP, IRPC, and REPT, have been renamed FOR, FORC, and REPEAT. For more information, see "Defining Repeat Blocks with Loop Directives" in Chapter 9.
Text Macros
The EQU directive retains its old functionality, but MASM 6.1 also incorporates a TEXTEQU directive for defining text macros. TEXTEQU allows greater flexibility than EQU. For example, TEXTEQU can assign to a label the value calculated by a macro function. For more information, see "Text Macros" in Chapter 9.
The GOTO Directive for Macros
Within a macro definition, GOTO transfers assembly to a line labeled with a leading colon(:). For more information on GOTO, see Help.
Macro Functions
At assembly time, macro functions can determine and return a text value using EXITM. Predefined macro string functions concatenate strings, return the size of a string, and return the position of a substring within a string. For information on writing your own macro functions, see "Returning Values with Macro Functions" in Chapter 9.
Predefined Macro Functions
MASM 6.1 provides the following predefined text macro functions:
Symbol Value Returned
hiddentext@CatStr A concatenated string
hiddentext@InStr The position of one string within another
hiddentext@SizeStr The size of a string
hiddentext@SubStr A substring
For more information on predefined macros, see "String Directives and Predefined Functions" in Chapter 9.
MASM 6.1 Programming Practices
MASM 6.1 provides many features that make it easier for you to write assembly code. If you are familiar with MASM 5.1 programming, you may find it helpful to adopt the following list of new programming practices for programming with MASM 6.1. The list summarizes many of the changes covered in the following section, "Compatibility Between MASM 5.1 and 6.1."
u Select identifier names that do not begin with the dot operator (.).
u Use the dot operator (.) only to reference structure fields, and the plus operator (+) when not referencing structures.
u Different structures can have the same field names. However, the assembler does not allow ambiguous references. You must include the structure type when referring to field names common to two or more structures.
u Separate macro arguments with commas, not spaces.
u Avoid adding extra ampersands in macros. For a list of the new rules about using ampersands in macros, see "Substitution Operator" in Chapter 9 and "OPTION OLDMACROS," page 372.
u By default, code labels defined with a colon are local. Place two colons after code labels if you want to reference the label outside the procedure.
Compatibility Between MASM 5.1 and 6.1
MASM 6.1 provides a "compatibility mode," making it easy for you to transfer existing MASM 5.1 code to the new version. You invoke the compatibility mode through the OPTION M510 directive or the /Zm command-line switch. This section explains the changes you may need to make to get your MASM 5.1 code to run under MASM 6.1 in compatibility mode.
Rewriting Code for Compatibility
In some cases, MASM 6.1 with OPTION M510 does not support MASM 5.1 behavior. In several cases, this is because bugs in MASM 5.1 were corrected. To update your code to MASM 6.1, use the instructions in this section. This usually requires only minor changes.
Many of the topics listed here will not apply to your code. This section discusses topics in order of likelihood, beginning with the most common. In addition, you may have conflicts between identifier names and new reserved words. OPTION NOKEYWORD resolves errors generated from the use of reserved words as identifiers. See "OPTION NOKEYWORD," page 376, for more information.
Bug Fixes Since MASM 5.1
This section lists the differences between MASM 5.1 and MASM 6.1 due to bug corrections since MASM 5.1.
Invalid Use of LOCK, REPNE, and REPNZ
Except in compatibility mode, MASM 6.1 flags illegal uses of the instruction prefixes LOCK, REPNE, and REPNZ. The error generated for invalid uses of the LOCK, REPNE, and REPNZ prefixes is error A2068:
instruction
prefix not allowed
Table A.1 summarizes the correct use of the instruction prefixes. It lists each string instruction with the type of repeat prefix it uses, and indicates whether the instruction works on a source, a destination, or both.
Table A.1 Requirements for String Instructions
Instruction Repeat Prefix Source/Destination Register Pair
MOVS REP Both DS:SI, ES:DI
SCAS REPE/REPNE Destination ES:DI
CMPS REPE/REPNE Both DS:SI, ES:DI
LODS -- Source DS:SI
STOS REP Destination ES:DI
INS REP Destination ES:DI
OUTS REP Source DS:SI
No Closing Quotation Marks in Macro Arguments
In MASM 5.1, you can use both single and double quotation marks (' and ") to begin strings in macro arguments. The assembler does not generate an error or warning if the string does not end with quotation marks on a macro call. Instead, MASM 5.1 considers the remainder of the line to be part of the macro argument containing the opening quote, as if there were a closing quotation mark at the end of the line.
By default, MASM 6.1 now generates error A2046:
missing single
or double quotation mark in string
so all single and double quotation marks in macro arguments must be matched.
To correct such errors in MASM 6.1, either end the string with a closing quotation mark as shown in the following example, or use the macro escape character (!) to treat the quotation mark literally.
; MASM 5.1
code
MyMacro "all this in one argument
; Default MASM 6.1 code
MyMacro "all this in one argument"
Making a Scoped Label Public
MASM 5.1 considers code labels defined with a single colon inside a procedure to be local to that procedure if the module contains a .MODEL directive with a language type. Although the label is local, MASM 5.1 does not generate an error if it is also declared PUBLIC. MASM 6.1 generates error A2203:
cannot declare
scoped code label as PUBLIC
If you want to make a label PUBLIC, it must not be local. You can use the double colon operator to define a non-scoped label, as shown in this example:
PUBLIC
publicLabel
publicLabel:: ; Non-scoped label MASM 6.1
Byte Form of BT, BTS, BTC, and BTR Instructions
MASM 5.1 allows a byte argument for the 80386 bit-test instructions, but encodes it as a word argument. The byte form is not supported by the processor.
MASM 6.1 does not support this behavior and generates error A2024:
invalid operand
size for instruction
Rewrite your code to use a word-sized argument.
Default Values for Record Fields
In MASM 5.1, default values for record fields can range down to -2n, where n is the number of bits in the field. This results in the loss of the sign bit.
MASM 6.1 allows a range of -2n-1 to 2n-1 for default values. Illegal initializers generate error A2071:
initializer too
large for specified size
Design Change Issues
MASM 6.1 includes design changes that make the language more consistent. These changes are not affected by the OPTION directive, discussed later in this appendix. Therefore, the changes require revisions in your code. In most cases, the necessary revisions are minor and the circumstances requiring changes are rare.
Operands of Different Size
MASM 5.1 does not require operands to agree in size, as the following code illustrates:
.DATA?
var1 DB ?
var2 DB ?
.CODE
.
.
.
mov var1, ax ; Copy AX to word at var1
The operands for the MOV instruction do not match in size, yet the instruction assembles correctly. It places the contents of AL into var1 and AH into var2, moving a word of data in one step. If the code defined var1 as a word value, the instruction
mov var1,
al
would also assemble correctly, copying AL into the low byte of var1 while leaving the high byte unaffected. Except at warning level 0, MASM 5.1 issues a warning to inform you of the size mismatch, but both scenarios are legal.
MASM 6.1 does not accept instructions with operands that do not agree in size. You must specifically "coerce" the size of the memory operand, like this:
mov BYTE PTR
var1, al
Conflicting Structure Declarations
MASM 5.1 allows you to declare two or more structures with the same name. Each declaration replaces the previous declaration. However, the field names from previous declarations still remain in the assembler’s list of declared values.
MASM 6.1 does not allow conflicting declarations of a structure. It generates errors A2160 through A2165 for each conflicting declaration. The errors note a specific conflict, such as conflicting number of fields, conflicting names of fields, or conflicting initializers.
Forward References to Text Macros Outside of Expressions
MASM 5.1 allows forward references to text macros in specialized cases. MASM 6.1 with OPTION M510 also permits forward references, but only when the text macro is referenced in an expression. To revise your code, place all macro definitions at the beginning of the file.
HIGH and LOW Applied to Relocatable Operands
In some cases, MASM 5.1 accepts HIGH and LOW applied to relocatable memory expressions. For example, MASM 5.1 allows this code sequence:
; MASM 5.1
code
EXTRN var1:WORD
var2 DW 0
mov al, LOW var1 ; These two instructions yield the
mov ah, HIGH var1 ; same as mov ax, OFFSET var1
u
u
u
u
u
u
u
u
u
u
u
u
u
u
file: /Techref/language/masm/masmAPA.htm, 106KB, , updated: 2005/10/13 11:51, local time: 2024/11/9 17:24,
44.210.149.218:LOG IN ©2024 PLEASE DON'T RIP! THIS SITE CLOSES OCT 28, 2024 SO LONG AND THANKS FOR ALL THE FISH!
|
©2024 These pages are served without commercial sponsorship. (No popup ads, etc...).Bandwidth abuse increases hosting cost forcing sponsorship or shutdown. This server aggressively defends against automated copying for any reason including offline viewing, duplication, etc... Please respect this requirement and DO NOT RIP THIS SITE. Questions? <A HREF="http://massmind.org/techref/language/masm/masmAPA.htm"> APPENDIX A</A> |
Did you find what you needed? |
Welcome to massmind.org! |
Welcome to massmind.org! |
.