This section takes a takes a brief moment to describe the assembly program and makefile that comprise the package. We'll compile and run our program at the end.
Let's take another look at that assembly program and dissect it a bit. I'll leave the real discussion of assembly to finer folks than I and your text books. But I will give a quick rundown.
1 ; This is a very simple 32 bit assembly program 2 ; that uses the Win32 API to display hello world on the 3 ; console. 4 5 TITLE Hello World in Win32 ASM (helloworld.asm) 6 7 .386 8 .MODEL flat, stdcall 9 .STACK 4096 10 11 ; ---------------------------------------------------------------------------- 12 ; These are prototypes for functions that we use 13 ; from the Microsoft library Kernel32.lib. 14 ; ---------------------------------------------------------------------------- 15 16 ; Win32 Console handle 17 STD_OUTPUT_HANDLE EQU -11 ; predefined Win API constant (magic) 18 19 GetStdHandle PROTO, ; get standard handle 20 nStdHandle:DWORD ; type of console handle 21 22 WriteConsole EQU <WriteConsoleA> ; alias 23 24 WriteConsole PROTO, ; write a buffer to the console 25 handle:DWORD, ; output handle 26 lpBuffer:PTR BYTE, ; pointer to buffer 27 nNumberOfBytesToWrite:DWORD, ; size of buffer 28 lpNumberOfBytesWritten:PTR DWORD, ; num bytes written 29 lpReserved:DWORD ; (not used) 30 31 ExitProcess PROTO, ; exit program 32 dwExitCode:DWORD ; return code 33 34 ; ---------------------------------------------------------------------------- 35 36 37 38 39 ; ---------------------------------------------------------------------------- 40 ; global data 41 ; ---------------------------------------------------------------------------- 42 43 .data 44 consoleOutHandle dd ? ; DWORD: handle to standard output device 45 bytesWritten dd ? ; DWORD: number of bytes written 46 message db "Hello World",13,10,0 ; BYTE: string, with \r, \n, \0 at the end 47 48 ; ---------------------------------------------------------------------------- 49 50 51 52 53 .code 54 55 ; ---------------------------------------------------------------------------- 56 procStrLength PROC USES edi, 57 ptrString:PTR BYTE ; pointer to string 58 ; 59 ; walk the null terminated string at ptrString 60 ; incrementing eax. The value in eax is the string length 61 ; 62 ; parameters: ptrString - a string pointer 63 ; returns: EAX = length of string prtString 64 ; ---------------------------------------------------------------------------- 65 mov edi,ptrString 66 mov eax,0 ; character count 67 L1: ; loop 68 cmp byte ptr [edi],0 ; found the null end of string? 69 je L2 ; yes: jump to L2 and return 70 inc edi ; no: increment to next byte 71 inc eax ; increment counter 72 jmp L1 ; next iteration of loop 73 L2: ret ; jump here to return 74 procStrLength ENDP 75 ; ---------------------------------------------------------------------------- 76 77 78 79 80 ; ---------------------------------------------------------------------------- 81 procWriteString proc 82 ; 83 ; Writes a null-terminated string pointed to by EDX to standard 84 ; output using windows calls. 85 ; ---------------------------------------------------------------------------- 86 pushad 87 88 INVOKE procStrLength,edx ; return length of string in EAX 89 cld ; clear the direction flag 90 ; must do this before WriteConsole 91 92 INVOKE WriteConsole, 93 consoleOutHandle, ; console output handle 94 edx, ; points to string 95 eax, ; string length 96 offset bytesWritten, ; returns number of bytes written 97 0 98 99 popad 100 ret 101 procWriteString endp 102 ; ---------------------------------------------------------------------------- 103 104 105 106 107 ; ---------------------------------------------------------------------------- 108 main PROC 109 ; 110 ; Main procedure. Just initializes stdout, dumps the string, and exits. 111 ; ---------------------------------------------------------------------------- 112 INVOKE GetStdHandle, STD_OUTPUT_HANDLE ; use Win32 to put 113 ; stdout handle in EAX 114 115 mov [consoleOutHandle],eax ; Put the address of the handle in 116 ; our variable 117 118 mov edx,offset message ; load the address of the message 119 ; into edx for procWriteString 120 121 INVOKE procWriteString ; invoke our write string method. 122 ; It'll check EDX 123 124 INVOKE ExitProcess,0 ; Windows method to quit 125 126 main ENDP 127 ; ---------------------------------------------------------------------------- 128 129 END main |
break down by line
1-3 are comments. Note that comments begin with a ';' character
5-32 are header data including directives, function prototypes, and constants.
44-46 are global variables
56-101 are procedures to calculate a string length and write a string to the console
108-126 are the main procedure that starts the program. We'll break it down further
112, 115 uses the windows api to get an address to write to standard out. Then we store it in a global variable.
118, 121 calls our procWriteString procedure to display the global string "Hello World".
124 calls Windows' ExitProcess to quit the program gracefully.
80 indicates the end of the program and file.
Now that we can see the basic form of an assembly program it should be easy to reference it's constructs in manuals and build on the at basic shell. Now, let's have a second look at the helloworld.mak makefile.
1 # A very simple make file for a windows 32 bit assembly console program 2 # it assembles and links 3 4 # nmake help is online at: 5 # http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vcug98/html/_asug_macros_and_nmake.asp 6 7 # Assemble the code into coff format producing map and listing files, 8 # including symbolic debugging info. Try "ml /?" for more options 9 # and descriptions 10 11 # 32 bit link our .obj file with the kernel32.lib file and create an exe file 12 13 all: helloworld.exe 14 15 helloworld.exe: helloworld.asm 16 ml /nologo /coff /c /Zi /Fl /Fm $? 17 link32 /nologo /DEBUG /incremental:no /subsystem:console /entry:main /out:debug\helloworld.exe helloworld.obj kernel32.lib |
If you've ever worked with source distributions this format should look vaguely familiar. But let's detail it.
1-1 are comments. Comments begin with the '#' character Comments are goooodddddd!
13 defines the default target 'all' and says that it depends on a sub-target helloworld.exe.
15 defines the target 'helloworld.exe' and specifies that it depends on the helloworld.asm file. That means nmake will be smart enough to know to recompile if you change the ASM file.
16 is the first command run for the 'helloworld.exe' target. It runs the assembler on helloworld.asm to create a coff object file.
17 is the second command run for the 'helloworld.exe' target. It runs the 32bit linker to link helloworld.obj with kernel32.lib to make a real program, helloworld.exe!!
Now that we have a better idea how the assembly file is formed and how the makefile helps compile it let's move on the glory moment, compilation and execution. If everything is setup correctly you should be able to click Build icon on the toolbar to compile the program (see figure 10).
The build panel should look like figure 11.
Finally, the climax. Run your compiled program by clicking the execute button (!) (see figure 12).
If all goes well you'll see a DOS/CMD box like in the following picture. (see figure 13).
Excellent! Now we know our framework is capable of compiling and running an assembly program and we have a working example of code and a make file. We're ready to move on to debugging the program and examining its guts.