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. The second part goes back to making modular programs. 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, Saying that mov cx, 9 means 'cx = 9' is not a good comment. If you think you can get by without it, you are better than I. Or you are a fool. Let yourself decide. Assemblers cannot live without comments. ALSO COMMENT the sections of code: * * * This section takes the command line and copies it to a buffer, It expects: CX = number of characters in the command line * * *
Maybe i need to lay off the caffeine... ;) - - - - - - - - - - - - - - - - Modularity: You could write a program straight from beginning to end with no modularity to it. 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. 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. 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 hereI 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 |