5. Compiling your project

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

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.

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).

Click the build icon

Figure 10

The build panel should look like figure 11.

A successful build.

Figure 11

Finally, the climax. Run your compiled program by clicking the execute button (!) (see figure 12).

Click execute.

Figure 12

If all goes well you'll see a DOS/CMD box like in the following picture. (see figure 13).

A successful execution

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.