what type of argument must be passed to the exitprocess procedure

  • Download source code - iv.8 KB

Introduction

A macro is a symbolic name that y'all give to a serial of characters called a text macro or give to one or more than statements, chosen a macro procedure or function. As the assembler evaluates each line of your programs, it scans the source lawmaking for the proper noun of an early on defined macro, so substitutes the macro definitions for the macro name. A macro procedure is a named cake of associates language statements. Once defined, it can exist invoked (chosen) many times, fifty-fifty receiving dissimilar arguments passed. Then you can avoid repeatedly writing the same code in places.

In this commodity, nosotros'll talk about some usages that are not thoroughly discussed or not conspicuously documented. We'll bear witness and analyze examples in the Microsoft Visual Studio IDE. The topics will be related miscellaneously to the Repeat directive, checking the parameter type and size in a macro procedure, and generating memory in repetitions with the current location counter $.

All the materials presented here came from my teaching [ii] for years. Thus, to read this article, a general agreement of Intel x86-64 assembly language is assumed, and being familiar with Visual Studio 2010 or above is required. Preferred, having read a textbook typically like [3]; or the MASM Programmer's Guide [5] that was originated in 1992 by Microsoft merely still so valuable in today's MASM learning. If you lot are taking an Assembly Linguistic communication Programming class, this could be a supplemental reading or study reference.

Using Echo to the Output Window

According to MSDN, the Repeat directive displays a message to the standard output device. In Visual Studio, you are able to use ECHO to transport a string to the IDE's Output pane to evidence assembling/compiling messages, such as warning or error, similar to what MSBuild does.

A simplified snippet to examination Repeat would exist like this:

.386          .model flat,stdcall ExitProcess proto,dwExitCode:DWORD  mTestEcho MACRO    ECHO **          Examination          Echo with Zero **   ENDM  .code main PROC    mTestEcho    invoke ExitProcess,0          main ENDP END master

This code was working fine in VS 2008. Unfortunately, since VS 2010, the Echo directive does not event in writing to the output window in Visual Studio. As seen in [4], information technology doesn't, unless you configure it to generate verbose output to assembly your code. To do this, you should go:

Tools->Options->Projects and Solutions->Build and Run

And from the "MSBuild projection build output verbosity" dropdown box, cull the "Detailed" option (observe that default is "Minimal"):

Image 1

To test the macro, you only need to compile an individual .ASM file, instead of building the whole projection. Only right click on your file and choose Compile:

Image 2

To verify, you have to sentry the display in the VS Output pane. The Echo directive is really working, nonetheless, the message you interested "** Test Echo with Nothing **" is buried somewhere in hundreds of lines that MSBuild generated. You must search tediously to find:

Image 3

In learning MASM Assembly programming, this is definitely not a preferred mode to practice. What I suggested is to use text "Mistake:" or "Warning:" with ECHO, while still leaving MSBuild default output setting "Minimal" unchanged.

1. Output as Error

Simply add together "Mistake:" in the Echo statement in the macro and proper name it as mTestEchoError:

mTestEchoError MACRO    Repeat Mistake: **          Test          Echo with Error ** ENDM

Now let'southward call mTestEchoError in main PROC. Compiling the code, you can see the minimal output and so concise as below. Notice that because of Error here, reasonably the consequence said failed.

Image 4

ii. Output as Warning

Only add "Warning:" in the Echo statement and proper name it as mTestEchoWarning:

mShowEchoWarning MACRO     Repeat Alarm: **          Exam          Echo with Alarm **   ENDM

And so calling mTestEchoWarning in chief PROC and compiling it, y'all can see the minimal output much simpler equally beneath. Since but Warning designated, the compiling succeeded.

Image 5

Equally yous are enlightened, this mode, the Echo directive generates curtailed and clear letters without you searching for the outputs. The sample is in TestEcho.asm for download.

Checking Parameter Type and Size

When you laissez passer an argument to a macro procedure, the procedure receives it from the parameter although just a text substitution. Ordinarily, you will check some weather from the parameter to do something accordingly. Since this happens at assembling time, it means that the assembler would choose some instructions if a condition is satisfied, else provide other instructions for unsatisfied if needed. Definitely, you can check the constant statement values, either in cord or number. Notwithstanding another useful bank check perhaps, is based on the parameter type or size for registers and variables. For example, one macro procedure only accepts unsigned integers and featherbed signed ones, while the second macro may deal with 16 and 32-chip without for eight and 64-bit arguments.

ane. Argument as a Retentiveness Variable

Let'southward define three variables here:

.information    swVal SWORD          i          wVal          Discussion          2          sdVal SDWORD          3        

When applying the TYPE and <lawmaking>SIZEOF operators to these variables, we merely have:

          mov          eax, TYPE swVal               mov          eax, SIZEOF swVal             mov          eax, Type wVal                mov          eax, SIZEOF wVal              mov          eax, Blazon sdVal               mov          eax, SIZEOF sdVal           

Equally seen above, at that place is no numeric difference either between Blazon and SIZEOF, or between WORD and SWORD. The start four instructions all are moving the byte count 2 to EAX. However, Blazon can do more than than just returning byte counts. Let'southward try to check SWORD blazon and size with the parameter par:

mParameterTYPE MACRO par    IF TYPE par EQ Blazon SWORD        Repeat warning: ** Blazon par is Type SWORD    ELSE        ECHO warning: ** TYPE par is          Non          Blazon SWORD       ENDIF ENDM      mParameterSIZEOF MACRO par    IF SIZEOF par EQ SIZEOF SWORD       Repeat warning: ** SIZEOF par is SIZEOF SWORD    ELSE        ECHO alarm: ** SIZEOF par is          Not          SIZEOF SWORD        ENDIF    ENDM

And then calling two macros by passing the above defined variables

Repeat alert: --- Checking TYPE          and          SIZEOF for wVal --- mParameterTYPE wVal mParameterSIZEOF wVal  ECHO warning: --- Checking TYPE          and          SIZEOF for swVal --- mParameterTYPE swVal mParameterSIZEOF swVal  Echo warning: --- Checking TYPE          and          SIZEOF for sdVal --- mParameterTYPE sdVal mParameterSIZEOF sdVal        

Run into the following results in Output:

Image 6

Obviously, the TYPE operator tin can be used to differentiate the signed or unsigned arguments passed, as SWORD and Give-and-take are different types. While SIZEOF is simply a comparison of byte counts, equally SWORD and WORD are both two bytes. The last 2 checks means the type of SDWORD is not SWORD and the size of SDWORD is 4 bytes not 2.

Furthermore, let'due south make directly checks, since two operators also can apply to data type names hither:

mCheckTYPE MACRO     IF Blazon SWORD EQ TYPE          Word          ECHO warning: ** TYPE SWORD EQ TYPE          Give-and-take          ELSE          ECHO alarm: ** TYPE SWORD          Non          EQ TYPE          WORD          ENDIF ENDM   mCheckSIZEOF MACRO     IF SIZEOF SWORD EQ SIZEOF          Word          Echo warning: ** SIZEOF SWORD EQ SIZEOF          Discussion          ELSE          Echo warning: ** SIZEOF SWORD          Non          EQ SIZEOF          Give-and-take          ENDIF ENDM

The following result is intuitive and straightforward:

Image 7

two. Argument as a Register

Since an argument can be a annals, let's call ii previous macros to check its TYPE and SIZEOF:

mParameterTYPE          AL          mParameterSIZEOF          AL          mParameterTYPE          AX          mParameterSIZEOF          AX        

We receive such messages:

Image 8

As we see hither, for blazon check, neither AL nor AX (even xvi-bit) is signed WORD. Really, you cannot employ SIZEOF to a annals that causes assembling error A2009. You lot can verify it direct:

          mov          ebx, SIZEOF          al                    mov          ebx, TYPE          al        

Only which type is for registers? The reply is all registers are unsigned by default. Simply make this:

mParameterTYPE2 MACRO par    IF Blazon par EQ          WORD          Echo warning: ** Type par is          WORD          ELSE        Echo warning: ** Type par is          Non          Discussion          ENDIF ENDM        

And phone call:

mParameterTYPE2          AL           mParameterTYPE2          AX        

Also notice that I direct utilise the information type name Discussion here equivalent to using Blazon Discussion.

3. An Case in Practice

Now let's take a look at a concrete example that requires moving an statement of a 8, 16, or 32-bit singed integer into EAX. To create such a macro, we take to utilise either the instruction mov or the sign-extension movsx based on the parameter size. The following is i possible solution to compare the parameter's type with the required sizes. The %OUT is the same equally ECHO equally an culling.

mParToEAX MACRO intVal    IF TYPE intVal LE SIZEOF          Discussion                    movsx          eax, intVal    ELSEIF Type intVal EQ SIZEOF          DWORD                    mov          eax,intVal    ELSE      %OUT Mistake: ***************************************************************      %OUT Fault: Argument intVal passed to mParToEAX must be          viii,          16,          or          32          bits.          %OUT Mistake:****************************************************************    ENDIF ENDM

Test it with different sizes and types for variables and registers:

            mParToEAX bVal           mParToEAX swVal          mParToEAX wVal           mParToEAX sdVal          mParToEAX qVal             mParToEAX          AH              mParToEAX          BX              mParToEAX          EDX              mParToEAX          RDX        

Every bit expected, the Output shows the following messages to reject qVal reasonably. Besides fine is an error reported for RDX, as our 32-bit projection doesn't recognize a 64-fleck annals.

Image 9

You lot can try the downloadable lawmaking in ParToEAX.asm. Furthermore, allow's generate its listing file to run across what instructions the assembler has created to substitute macro calls. As expected, bVal, swVal, wVal, and sdVal are good just without qVal; while AH, BX, and EDX good merely without RDX:

          00000000          .data          00000000          03          bVal          BYTE          3          00000001          FFFC          swVal SWORD   -4          00000003          0005          wVal          Give-and-take          5          00000005          FFFFFFFA      sdVal SDWORD   -6          00000009          qVal          QWORD          seven          0000000000000007          00000000          .code          00000000          main_pe PROC                              mParToEAX bVal                 00000000          0F BE          05          one          movsx          eax, bVal          00000000          R                mParToEAX swVal                00000007          0F BF          05          1          movsx          eax, swVal          00000001          R                mParToEAX wVal         0000000E  0F BF          05          one          movsx          eax, wVal          00000003          R                mParToEAX sdVal                00000015          A1          00000005          R          1          mov          eax,sdVal                mParToEAX qVal                                     mParToEAX          AH            0000001A  0F Be C4          1          movsx          eax,          AH          mParToEAX          BX            0000001D  0F BF C3          i          movsx          eax,          BX          mParToEAX          EDX                    00000020          8B C2          1          mov          eax,EDX          mParToEAX          RDX                    1          IF TYPE          RDX          LE SIZEOF          WORD          AsmCode\ParToEAX.asm(45) : error A2006:undefined symbol :          RDX          mParToEAX(1): Macro Called From   AsmCode\ParToEAX.asm(45): Main Line Lawmaking          1          ELSE AsmCode\ParToEAX.asm(45) : error A2006:undefined symbol :          RDX          mParToEAX(3): Macro Called From   AsmCode\ParToEAX.asm(45): Master Line Code                 invoke ExitProcess,0          00000029          main_pe ENDP             END        

Generating Data in Repetitions

In this section, we'll talk almost using macros to generate a retentiveness block, an assortment of integers in the information segment, rather than calling macros in lawmaking. We'll prove three ways to create the same linked list: using an unchanged location counter $, retrieving changed values from the counter $, and calling a macro in data segment.

1. Using an Unchanged Locate Counter $

I simply borrowed the LinkedList snippet from the textbook [3] to modify it with eight nodes as:

LinkedList ->11h ->12h ->13h ->14h ->15h ->16h ->17h ->18h ->00h

I added six extra DWORDs of 01111111h at the cease for padding, although unnecessary while easy to format in the Memory window to watch:

ListNode STRUCT   NodeData          DWORD          ?   NextPtr          DWORD          ? ListNode ENDS  TotalNodeCount =          eight          .data       Counter =          0          LinkedList LABEL          PTR          ListNode    REPT TotalNodeCount       Counter = Counter +          1          ListNode <Counter+10h, ($ + Counter * SIZEOF ListNode)>    ENDM    ListNode <0,0>             DWORD          01111111h,          01111111h,          01111111h,          01111111h,          01111111h,          01111111h        

The memory is created. The list header is the characterization LinkedList, an alias that points to 0x00404010:

Image 10

Each node contains iv-byte DWORD for NodeData and another DWORD for NextPtr. As Intel IA-32 using piddling endian, the first integer in retentiveness 11 00 00 00, is 00000011 in hexadecimal; and its next pointer xviii forty xl 00, is 0x00404018. So the 2 rows encompass all eight listing nodes. In the tertiary row, the first node with two zero DWORDs acts as a tail (although a waste node). Immediately followed is padding of 6 01111111.

Now let's encounter what happens to the current location counter $. As mentioned in [iii]:

The expression ($ + Counter * SIZEOF ListNode) tells the assembler to multiply the counter past the ListNode size and add their production to the current location counter. The value is inserted into the NextPtr field in the structure. [It'south interesting to notation that the location counter'due south value ($) remains fixed at the first node of the listing.]

This is really true that the value of $ always remains 0x00404010 without changing in each iteration in the REPT block. The NextPtr address calculated past ($ + Counter * SIZEOF ListNode) makes node by node to link together to generate LinkedList eventually. However, you might enquire if we could become the actual electric current memory address to use in iteration? Yes. Hither information technology comes.

ii. Retrieving Changed Values From the Location Counter $

.data      Counter =          0          LinkedList2 Label          PTR          ListNode    REPT TotalNodeCount       Counter = Counter +          one          ThisPointer = $       ListNode <Counter+20h, (ThisPointer + SIZEOF ListNode)>    ENDM    ListNode <0,0>             DWORD          02222222h,          02222222h,          02222222h,          02222222h,          02222222h,          02222222h          len = ($ - LinkedList)/Blazon          DWORD        

Hey, almost nothing changed simply to proper noun a new symbolic constant ThisPointer = $ that just assigns the $'south electric current memory address to ThisPointer. Now nosotros can utilise ThisPointer in the similar calculations to initialize the NextPtr field of ListNode object by a simpler expression (ThisPointer + SIZEOF ListNode). This also makes node by node to link one another to generate LinkedList2 this time. You can cheque LinkedList2's retention, 0x00404070:

Image 11

To differentiate the first LinkedList, I let Counter+20h to make it as:

LinkedList2 ->21h ->22h ->23h ->24h ->25h ->26h ->27h ->28h ->00h

By comparing ii retentivity blocks, both perform exactly the same functionality. Notice that at final, I purposely calculate the len to meet how many DWORDs generated until now.

len = ($ - LinkedList)/TYPE          DWORD        

Equally an interesting exercise, please think of the value of len in your listen. In code, move len to a register to verify.

3. Calling a Macro in Information Segment

By making the 3rd linked list, nosotros can understand that not but can yous call a macro in code, but you lot can also call ane in the data segment. For this purpose, I ascertain a macro named mListNode with a parameter called starting time, where a ListNode object is simply initialized. To differentiate the previous two, I make Counter+30h for NodeData and assign NodePtr equally (starting time + Counter * SIZEOF ListNode).

.information       mListNode MACRO start        Counter = Counter +          i          ListNode <Counter+30h, (start + Counter * SIZEOF ListNode)>    ENDM      LinkedList3 = $         Counter =          0          REPT TotalNodeCount       mListNode LinkedList3       ENDM    ListNode <0,0>             DWORD          03333333h,          03333333h,          03333333h,          03333333h,          03333333h,          03333333h        

The third list looks like:

LinkedList3 ->31h ->32h ->33h ->34h->35h ->36h->37h ->38h->00h

Nosotros now accept the lesson from LinkedList2 by having LinkedList3 = $ get-go at the beginning. Find I simply use symbolic constant LinkedList3 as the third list header, instead of the Label directive. Now I set up the REPT repetition with only i macro call by passing the header accost LinkedList3 to mListNode. That'south information technology! Run into retention at 0x004040D0:

Image 12

Imagine what if you lot pass $ every bit an argument to mListNode, without LinkedList3 = $?

4. Checking an Address and Traversing a Linked List

Finally, let us put all generations of 3 lists together and run LinkedList.asm (available for download). In the code segment, I first remember iii list headers' addresses as below:

          mov          edx,Start LinkedList          mov          ebx,OFFSET LinkedList2          mov          esi,OFFSET LinkedList3            mov          eax, len        

Equally expected EDX, 00404010 is for LinkedList; EBX, 00404070 for LinkedList2; and ESI, 004040D0 for LinkedList3. The whole memory of three lists is neighboring each other as shown:

Image 13

Notice because of LinkedList3 as a symbolic 1, nosotros don't even accept to employ the Kickoff operator hither. Let'due south go out ESI for the LinkedList3 and traverse this list to meet every NodeData values with a loop like this:

            NextNode:              mov          eax, (ListNode          PTR          [esi]).NextPtr          cmp          eax,          0          je          quit                mov          eax, (ListNode          PTR          [esi]).NodeData                    mov          esi, (ListNode          PTR          [esi]).NextPtr          jmp          NextNode  quit:

Unfortunately, we oasis't involved whatsoever implementation of an output procedure to call here to show EAX that NodeData moved. But in your debugging, but setting a break indicate in that location to watch EAX should exist enough to verify from 31h, 32h, …, to 38h.

Summary

By scrutinizing the above examples, we exposed something that you may not know about the macro in MASM assembly programming. An assembly language programme can be executed with Intel or AMD specified instructions at runtime. While on the other side, MASM provides many directives, operators, and symbols to command and organize the instructions and retentiveness variables during the assembling fourth dimension, similar to preprocessing in other programming languages. In fact, with all the features, the MASM macro itself could be considered every bit a sub or mini programming language with iii control mechanisms of sequential, provisional, and repetition.

However, some usages of MASM macro accept non been discussed in detail. In the article, we beginning introduced a better fashion to output your error or alert text making it so piece of cake to trace macro behaviors. Then with if-else structures, we presented how to cheque the type and size for a macro's parameter that is a usual practice either for memory or register arguments. Finally, nosotros discussed the macro repetitions with 3 examples to generate the aforementioned linked list, as well equally a ameliorate understanding to apply the current address locator $ symbol. The downloadable zip file contains all samples in .asm files. The projection file MacroTest.vcxproj has been created in VS 2010, while it tin exist opened and upgraded in any recent VS version.

This article does non involve hot technologies like .NET or C#. Assembly Linguistic communication is comparatively traditional without much sensation. But please refer to TIOBE Programming Customs Alphabetize, the ranking of Assembly Linguistic communication is on the rise recently, which means unlike types of assembly languages play an important role in new device development. Academically, Assembly Linguistic communication Programming is considered equally a enervating form in Information science. Therefore, I hope this commodity could serve as trouble-solving examples for students and perchance, developers as well.

References

  • Microsoft Macro Assembler Reference
  • CSCI 241, Assembly Language Programming class site
  • Kip Irvine, Associates Language for x86 Processors, 7th edition
  • MASM Echo directive does not result in writing to the output window
  • MASM 6.1 Documentation

History

  • Feb 26, 2016 -- Original version posted

vogelequirt.blogspot.com

Source: https://www.codeproject.com/Articles/1080585/Something-You-May-Not-Know-About-the-Macro-in-MASM

0 Response to "what type of argument must be passed to the exitprocess procedure"

Post a Comment

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel