Designing Functions
Extending the capabilities of ASM

Powers (Exponents) POWER A,B = Takes register A to the power of register B, which is written as AB. Stores result to A. POWER is a great instruction. Now we know how to add, subtract, multiply, divide, and take powers in ASM. Guess what? The instruction POWER does not exist. I made it up. *mua ha ha ha ha* All right, all right. I will say that ADD, SUB, IMUL, IDIV, LEA, and all those other ones I've mentioned before are real. But POWER is not. So, if we want to use exponents, we can't do it at all? Wrong. We can totally use powers, but we have to calculate them in terms of IMUL. A power or exponent is just multiplying a number by itself a bunch of times. So by using IMUL a bunch of times, we can do the same thing as POWER would if it were a real instruction. In this case, we want to create our own function that takes in some PUSHes and calculates the result of a power operation. The Simple Power Function Here's a simple function that will calculate power operations for us. It will take EAX to the power of ECX, which is written as EAXECX. The result will be stored to EAX.
    Address   Instruction    Comments
    00493A20  CMP ECX,0      ;Is the power 0?
    00493A23  JE 493A32      ;If yes, then jump to MOV EAX,1.
    00493A25  MOV EDX,EAX    ;Otherwise, save the original value of EAX.
    00493A27  DEC ECX        ;Beginning of the cycle. Decrease ECX by 1.
    00493A28  CMP ECX,0      ;Now is ECX less than or equal to 0?
    00493A2B  JLE 493A37     ;If yes, then break the cycle by jumping to RETN.
    00493A2D  IMUL EAX,EDX   ;Otherwise, multiply EAX by its original value.
    00493A30  JMP 493A27     ;Repeat the cycle.
    00493A32  MOV EAX,1      ;EAX to the power of 0 must be 1.
    00493A37  RETN           ;Return to the address after the CALL.
Now we can take powers.
    MOV EAX,9
    MOV ECX,5
    CALL 493A20
The above code will calculate 95 = 59049, which is E6A9 in hex. So E6A9 is stored to EAX. Also notice that ECX and EDX are used when calculating the power. If we want to save the values of ECX and EDX, we just do this:
    MOV EAX,9
    MOV ECX,5
    PUSH ECX
    PUSH EDX
    CALL 493A20
    POP EDX
    POP ECX
The Complex Power Function The simple power function is quite useful, but it has limitations. You're forced into using EAX and ECX. You can't take EDX to the power of EAX unless you MOV the values of the registers around a lot. This is our new goal:
    The Better Power Function:
    PUSH (registerA ID number)
    PUSH (registerB ID number)
    CALL 493A40                 ;Calculates registerA to the power of registerB. Stores result to registerA.
    ADD ESP,8
This new power function should let us choose which registers we want to use instead of telling us that we have to use EAX and ECX. To make this function, we have to invent identification numbers for each register: EAX has ID number 1. ECX has ID number 2. EDX has ID number 3.
    Address    Instruction
    00493A40   PUSH EBP              ;--- These two lines of
    00493A41   MOV EBP,ESP           ;--- code start the function.
    00493A43   CMP DWORD [EBP+C],1   ;Does registerA have ID number = 1?
    00493A47   JNE 493A4C            ;If not, go check for ID number = 2.
    00493A49   PUSH EAX              ;If yes, then EAX is the 1st register we want.
    00493A4A   JMP 493A56            ;Go check for registerB.
    00493A4C   CMP DWORD [EBP+C],2   ;Does registerA have ID number = 2?
    00493A50   JNE 493A55            ;If not, the ID must be 3.
    00493A52   PUSH ECX              ;If yes, then ECX is the 1st register we want.
    00493A53   JMP 493A56            ;Go check for registerB.
    00493A55   PUSH EDX              ;We know the ID is 3, so EDX is the 1st register we want.
    00493A56   CMP DWORD [EBP+8],1   ;Does registerB have ID number = 1?
    00493A5A   JNE 493A5F            ;If not, check for ID number = 2.
    00493A5C   PUSH EAX              ;If yes, then EAX is the 2nd register we want.
    00493A5D   JMP 493A69            ;Go POP the previously PUSHed values into the right registers.
    00493A5F   CMP DWORD [EBP+8],2   ;Does registerB have ID number = 2?
    00493A63   JNE 493A68            ;If not, the second ID number must be 3.
    00493A65   PUSH ECX              ;If yes, then ECX is the 2nd register we want.
    00493A66   JMP 493A69            ;Go POP the previously PUSHed values into the right registers.
    00493A68   PUSH EDX              ;We know the second ID is 3, so EDX is the 2nd register we want.
    00493A69   POP ECX
    00493A6A   POP EAX
    00493A6B   CALL 493A20           ;Call the simple power function and calculate EAX to the power of ECX.
    00493A70   CMP DWORD [EBP+C],1
    00493A74   JE 493A82             ;If the first ID number = 1, exit the function since EAX already holds the answer.
    00493A76   CMP DWORD [EBP+C],2
    00493A7A   JNE 493A80
    00493A7C   MOV ECX,EAX           ;If the first ID number = 2, store answer into ECX.
    00493A7E   JMP 493A82
    00493A80   MOV EDX,EAX           ;If the first ID number = 3, store answer into EDX.
    00493A82   MOV ESP,EBP           ;--- These three lines of
    00493A84   POP EBP               ;--- code will exit the
    00493A85   RETN                  ;--- function.
Now, the above block of code is quite complex and long. At the very least, it's one of the longest pieces of handwritten ASM code we have seen so far. One thing that you should notice is that we accessed the arguments that were PUSHed right before the CALL to the function. In this case, the last argument PUSHed before the CALL is registerB, so registerB's ID number will be inside DWORD [EBP+8]. registerA is the second to last argument PUSHed, so registerA's ID number will be inside DWORD [EBP+C]. To make the job of understanding this function easier, I'll translate the ASM to psuedocode:
    begin the "Complex Power Function"
    if (register A has ID number of 1)
    then PUSH EAX
    otherwise
        if (register A has ID number of 2)
        then PUSH ECX
        otherwise PUSH EDX
    afterwards
    if (register B has ID number of 1)
    then PUSH EAX
    otherwise
        if (register B has ID number of 2)
        then PUSH ECX
        otherwise PUSH EDX
    afterwards
    POP ECX                       ;The value of register B now goes into ECX.
    POP EAX                       ;The value of register A now goes into EAX.
    CALL (simple power function)  ;Simple power function will calculate EAX to the power of ECX.
    if (register A has ID number of 1)
    then
        exit this function
    otherwise
        if (register A has ID number of 2)
        then
            store EAX to ECX
            exit this function
        otherwise
            store EAX to EDX
            exit this function
Now, if you look at the complex power function, you'll realize that it doesn't do the "calculating" part by itself. In fact, the complex power function just shuffles around the registers until the value of register A gets stored into EAX, and the value of register B gets stored into ECX. Then it shuffles around the registers some more until the final answer gets stored to register A, whatever register that may be. In order to do the job of calculating, the complex power function will CALL the simple power function! This is one of the key points of function design: a function is allowed to CALL other functions. We put the simple power function at 493A20, and we put the complex power function at 493A40. The two functions are far enough from each other that they don't overlap. Here's a quote from a famous writer:
"So nat'ralists observe, a flea Hath smaller fleas that on him prey, And these have smaller fleas that bite 'em, And so proceed ad infinitum." --Jonathan Swift
Jonathan Swift is thinking about the possibility that a big flea may have smaller fleas that feed upon that big flea, and those small fleas have even smaller fleas, and so on until we encounter fleas that are almost impossibly small.[1] Even though big fleas don't really have miniature fleas that live on them, we can easily apply a similar idea to Cave Story assembly hacking:
"So ASM hackers observe, a single assembly function has other functions that it will CALL, and these other functions CALL other functions too, and so on..."[2]
Now we put this function to work.
    Instructions
    PUSH 2        ;ECX has ID = 2.
    PUSH 3        ;EDX has ID = 3.
    CALL 493A40   ;Calculates ECX to the power of EDX, stores to ECX.
    ADD ESP,8
    Instructions
    PUSH EAX
    PUSH ECX      ;Save the values of EAX and ECX.
    PUSH 3
    PUSH 3
    CALL 493A40   ;Calculates EDX to the power of itself, stores to EDX.
    ADD ESP,8
    POP ECX
    POP EAX       ;Load the values of EAX and ECX.
Notice that the first function call is equivalent to the fake command POWER ECX,EDX. The second function call is the same as the fake command POWER EDX,EDX, and it doesn't mess up the values of EAX and ECX because we remembered to preserve them. Navigation Previous Lesson: Structure of Functions Next Lesson: Object Oriented Programming Table of Contents [1]Actually, Mr. Swift was mocking mathematicians and he knew it was ridiculous for big fleas to contain small fleas. Go figure. [2]I cannot say "ad infinitum" at the end, because your computer does not have an infinite amount of memory and therefore an infinite number of function CALLs don't actually happen while Cave Story is running. There are a lot of CALLs that occur, just not an infinite number of them. Also, a function doesn't necessarily need to call other functions... it just might call other functions.