Assembly and Cracking From the Ground Up
An Introduction by Greythorne the Technomancer

Modularity and Procedures



Developing Applications the Cool Way



Recently I was asked a few things about how to create large programs.
There are a few tricks to doing this.

The second part goes back to making modular programs.
The first part goes to

Recently I have been asked questions from a few people on why program form is important.

IMPORTANT BEYOND REASON: COMMENT AS MUCH AS YOU CAN,
I mean put a comment on most lines on what they do in relation to the part of the code you have written

Saying that mov cx, 9 means 'cx = 9' is not a good comment.
Commenting that 'cx = loop 9 times' is INVALUABLE to being able to debug your code, or go back and finish
If you have never written larger programs, DO NOT QUESTION, DO IT!
Especially when you want someone to help you debug your code.
They will not help without this information, it is just impossible.

If you think you can get by without it, you are better than I.
Go and just disassemble a listing with IDA and crack everything.
There is no need for you to learn more.
You are a God. You need no text to help you. You understand all forms of math and code just by looking at the instructions.
Go apply to mensa and await your nobel peace prize. It will come tomorrow.

Or you are a fool. Let yourself decide.

Assemblers cannot live without comments.

ALSO COMMENT the sections of code:
example:

* * *

This section takes the command line and copies it to a buffer,
then parses the command line and stores importand switches as flags in memory

It expects:

CX = number of characters in the command line

* * *


This is also invaluable.

Maybe i need to lay off the caffeine...

;)

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

Modularity:

You could write a program straight from beginning to end with no modularity to it.
You could also stick yourself with never being able to write code over 64k.
Your code could be so intermingled that if you need to change so much as one small detail, you need to rewrite the whole thing.

Or you could write in sections that can be easily altered at a moment's notice and called by several parts of the code, thus reducing typing and the possibility of bugs.

Sounds better when I put it like that doesn't it?

There is also something else involved here.
In many prgram compilers, the compiler has to compile the program in sections.
If your section is larger than the compiler's memory buffer, you cannot compile your program.

When you modularize your files, compilers are able to compile each section separately, thus causing no memory overloads.

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

Okay then, now you ask HOW do I do this efficently?

Procs.

All decent languages have the ability to make subroutines that can be used from anywhere within your program.
In Assembly they are called procs (short for procedures for those pascal people out there)

C calls them functions (though every language handles them slightly differently)

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

In standard tasm, when you load it with no special mode in mind, a proc can look like this:

     PrintLine	proc	near

	mov	ah, 9	; DOS print function ah=09h
	int	21h	;

     	ret		; return from proc

     endp	PrintLine

and to use it you can do this:

     mov dx, offset MyMessage
     call    PrintLine

This is really handy!!!

It has its drawbacks though, which become apparent when you write several of them
     ;----------------------	

      CompareByte proc	near

	Loop:
		inc ah
		cmp ah, 092h
		jne	Loop

		ret

      endp	CompareByte

     ;----------------------	

      CompareWord proc	near

	Loop:
		inc ax
		cmp ax, 02942h
		jne	Loop

		ret

      endp	CompareWord

     ;----------------------	

When you compile this, even though CompareWord and CompareByte are 2 separate routines, the label 'Loop' is duplicated. The compiler has no idea which one you are referring to in either case, so the compiler returns an error.

So you would normally have to make differences in the names like so:
     ;----------------------	

      CompareByte proc	near

	CmpByteLoop1:
		inc ah
		cmp ah, 092h
		jne	CmpByteLoop1

		ret

      endp	CompareByte

     ;----------------------	

      CompareWord proc	near

	CompareWordLoop1:
		inc ax
		cmp ax, 02942h
		jne	CompareWordLoop1

		ret

      endp	CompareWord

     ;----------------------	

If you had a particularly long program, you would get SICK of trying to find ways to differentiate the things.

There is an easy solution.

Use IDEAL MODE.

In the top of the EXE or COM file template header, add the word IDEAL to let TASM know that we are using the ideal mode.
Here is an altered version of my com file header you already know:
     ;----------------------	

	COM_PROG  segment byte public

	        ideal

	        assume  cs:COM_PROG

	        org     100h

	start:

     ;----------------------	

this makes our basic way to write a proc a little simpler as well...

     proc	PrintLine

	mov	ah, 9	; DOS print function ah=09h
	int	21h	;

     	ret		; return from proc

     endp	PrintLine

proc and endp line up for ease of reading as a bonus.

The real bonus comes in the form of a pair of 'at' signs (@@)
Take a look at the following code changes to our CompareByte example.

     ;----------------------	

      proc	CompareByte 

	@@Loop:
		inc ah
		cmp ah, 092h
		jne	@@Loop

		ret

      endp	CompareByte

     ;----------------------	

      proc	CompareWord 

	@@Loop:
		inc ax
		cmp ax, 02942h
		jne	@@Loop

		ret

      endp	CompareWord

     ;----------------------	

The @@ symbols refer to locality.
That means that anything inside the proc with @@ in front of it is local to the proc, and no other code sees it.

When something is not local, it is called GLOBAL, which means it is available to all sections of code.

Global parts of code are very handy, but only for a few things.
In a game program it is very nice to have the running total of your score global, for example.

Locality makes it possible to make larger programs without having dangerous effects on other sections of code.

Looking back at our program to get 'y' or 'n'...

I will rewrite it here as an example of proceduralizing (gret word eh?) the code.
I will overdo it a bit on purpose. In computer science classes, the end goal is to make the main section of code have as few lines as possible, and only to make a few calls and then exit. A simplistic vew of 'main' would include:

	; your code here

	call input
	call process
	call output
	
	; end program here

I won't require that kind of pressure on you, but the more you have your program built in sub-parts rather than one big block of code, the easier your coding job will be in the long run.

[ -------------------------  CUT HERE -------------------------- ]

            ;**********************************************
            ;
            ; KEYPRESS.ASM
            ; Our First Interactive Program
	    ; (With a little proceduralizing)
            ;
            ; Compile with:
            ;
            ;      TASM KEYPRESS.ASM
            ;      TLINK /t KEYPRESS.OBJ
            ;
            ; +gthorne'97
            ;
            ;**********************************************

                   .model small
                   .code
                   .386

                    ideal

                    org     100h

            start:  jmp     MAIN_PROGRAM

            ;----------------------
            ; Your Data Here
            ;----------------------

            CopyMsg     db      'Copyright (c)1997 By Me!',0Dh,0Ah,'$'

            PressEnter  db      0Dh,0Ah,'$'

            ;----------------------
            ; Your Procedures Here
            ;----------------------

            proc PrintString            ; Print a string in DX

            mov ah, 09h                 ; DOS command 9 = print string
            int 21h                     ; tell DOS to issue command

            ret                         ; return from call
            endp PrintString            ;

            ;----------------------

            proc PrintChar              ; Print a character in DL

            mov     ah,6           ; DOS function 06h, print a character
            int     21h           ; tell DOS to do the command
                                     ;(which will make a BEEP)    

            ret                         ; return from call
            endp PrintChar              ;
        
            ;----------------------
                                        
            proc CopyRight              ; Display Copyright Message

            mov dx, offset CopyMsg      ; tell DOS where string is
            call PrintString

            ; Press ENTER for the heck of it

            mov dx, offset PressEnter   ; tell DOS where string is
            call PrintString

            ret                         ; return from call
            endp CopyRight              ;

            ;----------------------

            proc GetInput               ; Check for valid input

            @@Loop:

            ; GET A KEY FROM THE USER INTO AL (DOES NOT ECHO)

            mov     ah,8                ; DOS function 08h, get a key from user 
            int     21h                 ; tell DOS to do the command

            mov      bl, al	; store key for later in BL register
                                    ;so we don't lose it
		; because AL gets clobbered
                                    ; when a CMP is issued

            cmp       bl, 'Y'		; see if user pressed a 'Y'
            je        @@Done

            cmp       bl, 'N'		; see if user pressed a 'N'
            je        @@Done

            cmp       bl, 'y'		; see if user pressed a 'y'
            je        @@Done

            cmp       bl, 'n'		; see if user pressed a 'n'
            je        @@Done

            ; WE GO BEEP IF ANY OTHER KEY WAS PRESSED

            mov      dl, 07h           ; copy the BEEP code into DL
            call     PrintChar

            jmp @@Loop

            @@Done:

            ; ECHO (SHOW) WHAT KEY THE USER PRESSED

             mov      dl, bl         ; copy the user keypress from BL into DL
             call     PrintChar

             ret                        ; return from call
             endp GetInput              ;


            ;----------------------

            MAIN_PROGRAM:

            ;---------------
            ; Your Code Here
            ;---------------

            call CopyRight    ; Display Copyright Message
            call GetInput      ; Get User Input

            ;---------------
         
            mov al, bl        ; put keypress into AL to be the
                                   ;exit code from this program

            mov ah,4ch       ; quit to DOS
            int 21h

            end     start


[ -------------------------  CUT HERE -------------------------- ]

Take Care!



+gthorne'97