Guide For Calling Functions (ASM)
Guide For Calling Functions (ASM)

Chapter 1: Intro

Mario Kart Wii was written in C++. Thus, it contains many generic C++ type functions (such as memcpy, memset, printf, sqrt, etc) in memory. Obviously, the game has its own unique functions as well such as DWC_Auth, DWC_Login, etc.

You can create a cheat code by including the calling of one of these functions, or just calling the function by itself. The majority of the time, these functions will start off with stwu type ASM instruction.

During a subroutine, certain instructions will occur, then a 'branch then link' (bl) instruction will follow. After the 'bl' instruction, you will be at the beginning of some sort of function call. The end of a function call results in a Branch to Link Register (blr).

I won't get into all the endless technical details of subroutines in Power PC ASM, this guide will simply demo how to call some very basic functions.

A list of many functions for MKW can be found HERE (PAL); some Wii & MKW specific functions are also included. Credits to Megazig for the original list. Credits to Star for finding the list and posting the thread plus additional new functions. Credits to RiiDefi for also the addition of new functions.

Also, here's a way smaller list (more detailed for arguments, return values, etc) for functions most commonly found in MKW codes -

Chapter 2: Manipulating the Link Register to Call a Function

You should already know what the Link Register is since you know some ASM. An easy way to call a function, is to have the address of that function in the Link Register, then branch to the Link Register. The function called OSRestart (responsible for restarting the game/disc) starts at address 0x801A8688 (PAL). Let's look at a set of ASM instructions below to see how we would call that function:

lis r12, 0x801A #Set 1st half address of PAL OS Restart
ori r12, r12, 0x8688 #Set 2nd half address
mtlr r12 #Copy value of r12 (0x801A8688) to the Link Register
blr #Branch to Link Register (Call/Start the function)

Once the blr instruction is executed, you will be sent to address 0x801A8688 and start executing the following ASM instructions that are there in memory. If one were to make a cheat code out of the above list of ASM instructions, this will cause the game/disc to reboot whenever that cheat code is used/activated.

Instead of using the Link Register, you also have the option to use the Count Register. Here's that same source from above but using the Count Register instead of the Link Register.

lis r12, 0x801A #Set 1st half address of PAL OS Restart
ori r12, r12, 0x8688 #Set 2nd half address
mtctr r12 #Copy value of r12 (0x801A8688) to the Count Register
bctr #Branch to Count Register (Call/Start the function)

A completed activate-able code of the first source listed above is located HERE

Chapter 3: Arguments

Certain functions need 'arguments' established before being called or else the calling of said function will cause the game to freeze or black-screen. Usually the game prefers starting off with r3 as the first argument. Then proceeding to r4, then r5 etc etc for any other added arguments if required. The register values can be integer values, memory pointers (such as pointing to a file path, in ASCII), etc.

If a certain function you are calling is not working or you need to figure out what the arguments are, it is best the take the address of said function and set an instruction breakpoint on Dolphin. Do whatever is necessary in the game to make the game call the function. Then the game will 'break'. Take a look at r3, r4, r5, etc. by the way, r11 and above are never used as arguments for function calls.

MarioKart Wii has a game specific function called NETCalcCRC, it's used for check-summing the data save whenever the data save is loaded or updated. NETCalcCRC has two arguments. The 1st argument (r3) is a memory pointer that is the address in memory to where the beginning of the data will be. The 2nd argument (r4) is the size of that data to be used for the checksum.

Chapter 4: Re-Linking

If we were to make a code to call the NETCalcCRC32 function by utilizing a mtlr/blr method. The game will freeze. Most functions need a 're-link'. This re-link allows you to call the function and return back from where you started.

If using the Link Register to call a function, the instruction blrl (Branch to LR and Link) is what you need. If using the Count Register to call a function, the instruction bctrl (Branch to CTR and Link) will work.

Obviously, function calls that are responsible for actions such as shutting down the Wii do not need a re-link. Anyway, let's look at a snippet of source (PAL) that would call the NETCalcCRC32 with a re-link. Random values for the arguments are used.

lis r3, 0x8042 #Set 1st Arg for NETCalc
ori r3, r3, 0xCC00
li r4, 0x0200 #Set 2nd Arg
mtlr r12
blrl #Call the function and re-link

This will tell the NETCalcCRC32 function to checksum 0x200 bytes of data starting at memory address 0x8042CC00.

Chapter 5: Return Values

Some functions will return values after being called (with a re-link ofc). It can be important to know these return values, as they usually indicate whether or not an error has occurred. For almost all functions, r3 is the only register used for return values. Some rare functions may be use both r3 and r4.

For NETCalcCRC32, a 32 bit checksum value is returned in r3.

Chapter 6: Backing up Registers; Register Safety

Due to r3 thru r10 being used for arguments, it's pretty important that you will need to backup these registers somehow beforehand. Especially r3, r4, and r5. A good way to do this is called pushing/popping the stack. Normally, coders push the stack for the use of the Global Variable registers (r14 thru r31), but with function calls, this method of pushing/popping the stack will be slightly different. For pushing/popping the stack using the follow snippet of code...

##Default instruction could reside here##

stwu r1,-0x80(r1) #Push stack, make space for 29 registers
stmw r3,8(r1)

##Contents of your ASM code will reside here##

lmw r3,8(r1)
addi r1,r1,0x80 #Pop stack

##Default instruction could also reside here##

Now depending on your ASM code, you may also need to backup the following...
Link Register
Count Register

Which ones do I backup?
Once again, this all depends on your code. If you code address is coming up to a BL instruction, you obviously don't need to backup the Link Register as its value is about to replaced anyway. If r0 is getting a value loaded into it before your code address and there is some sort of compare instruction using r0 after your code address, you obviously need to backup r0. Just set a breakpoint on your code address, and take a good look at the instructions before and after your code address. The Count Register rarely needs to be backed up.

Here's a snippet of code to put before pushing the stack...

mr r11, r0 #Copy r0's value to r11
mflr r12 #Copy LR's value to r12

And a snippet of code to put after popping the stack...

mtlr r12 #Restore LR's value
mr r0, r11 #Restore r0's value

You should already be familiar with the fact that r11 and r12 is safe to use 99% of the time without backing up their values. For a refresher on generic register safety view this thread -

Chapter 7: Non-Volatile Registers

When calling functions with a re-link, you don't have to store values to some place in memory such as the Exception Vector Area for later use for another function. The values in r14 thru r31 are for global variables, thus their values are saved (returned) after the re-link is done on a function call. Knowing this can help chop down on a codes length. Need to store some values throughout a function call? Throw them in r31 then going downward as necessary.

Chapter 8: Conclusion

As you can see, functions can make complex codes a bit easier to write. As long as you have the arguments correct, you shouldn't have much trouble.
Since this thread was bumped, I thought I’d share some tips I’ve found useful.

It probably goes without saying, but in my opinion the best hook addresses for function calls are those right after a ‘bl.’ Picking such an address makes things easier because there’s no backing up of registers to worry about (except possibly r3 or f1).

Also, in dealing with functions used by an actual game, most of these will be methods belonging to a particular class. This implies there will be an inherent “this” pointer as the argument in r3, with the actual arguments beginning in r4. Just something I realized which is helpful to know, especially for reverse engineering.
I've known the r3 thing for a while, the idea of using the address right after a bl is something I haven't really thought about. It's a smart idea, although it's good practice that r3 and f1 should always be considered unsafe since they are going to potentially be used as return values of the said function.
Super Mario Eclipse, what Super Mario Sunshine could've been.
#5 has good info for this kind of thing

Forum Jump:

Users browsing this thread: 1 Guest(s)