Guide For Calling Functions in ASM Codes - Printable Version +- Mario Kart Wii Gecko Codes, Cheats, & Hacks (https://mariokartwii.com) +-- Forum: Guides/Tutorials/How-To's (https://mariokartwii.com/forumdisplay.php?fid=45) +--- Forum: PowerPC Assembly (https://mariokartwii.com/forumdisplay.php?fid=50) +--- Thread: Guide For Calling Functions in ASM Codes (/showthread.php?tid=1052) |
Guide For Calling Functions in ASM Codes - Vega - 01-27-2019 Guide For Calling Functions in ASM Codes
Chapter 1: Intro / What is a Function?
This guide will teach your how to call (execute) functions for use in Gecko ASM Cheat Codes. This is a hefty tutorial, so please take your time and read thoroughly. What is a function? A function is a subroutine of code that accepts input(s), processes the inputs to preform a task(s), and returns back with output(s) depending on how the task(s) went. Of course, this is very general. Some functions don't take an input (task preformed is always the same), some functions don't give out an output(s), and some functions don't even return back at all. To execute a function, you "call" it. This means you have to setup the proper inputs, if necessary, beforehand. Once the inputs have been set, you can call the function. In general, functions are very large and contain complex tasks that should not be "handwritten". The C/C++ library has many built-in functions such as printf, memcpy, memmove, etc. Since every Wii game is mostly coded in C++, these functions will be present in memory. You can of course write your own functions for custom tasks, but when I speak of functions, it's for the very complex ones that should *not* be handwritten, and are already present in the Wii Game. Regarding Wii Games, they contain 3 different category of functions.
Video Game Developers use what is called a symbol map as a reference of where all the functions are located in memory. Most Wii games will have their symbol maps scrubbed before being released, meaning there is no file/information in the game that will tell us the names of the functions and where they are located at in memory. Luckily various devs/coders in the MKWii community have worked on a custom symbol map which you can find HERE Another symbol map that has is very detailed (but only has a small list of commonly used functions), can also be found HERE Chapter 2: Prologue, Epilogue, and understanding the Linking Mechanism
All functions reside in static memory (mem80 for MKWii). The majority of functions will start with a Prologue. A Prologue is simply a list of instructions that will create some stack space and backup some key registers onto that space. Template of a Prologue Code: stwu sp, -0xZZZZ (sp) Most prologues appear in this fashion. There are exceptions of course and some prologues may not look exactly like this. Also, some functions may not start with a prologue due to said functions being simple enough to not require backing up registers. Functions that do contain a prologue will always end in an Epilogue. Template of an Epilogue Code: lmw/lwz rX, 0xZZZZ (sp) Of course there are exceptions, not all epilogues look like this, but most do. Take note of the 'blr' instruction at the very end. All functions end with a 'blr' instruction. We won't go over all the instructions within the prologue and epilogue (some you should know already ofc) because calling/using functions within an ASM code is different than what you would find in a conventional PPC program/application. We do need to discuss the 'bl' and 'blr' instructions. Branch & Link bl label This is just like a normal branch instruction, except the address of the instruction that's directly below the branch-link instruction is placed in the Link Register. Example: Code: bl somewhere In the above example, once the bl instruction executes, the CPU will jump to the location of "somewhere", and then the Link Register will be written with the address of the location of the add instruction. Let's say the "bl somewhere" instruction resides in memory at address 0x804200F0. When it gets executed, the address value of 0x804200F4 (where the add instruction resides at) will be placed into the Link Register. This "linking mechanism" is important to understand because this is how functions can return back from where ever they were called from. As you saw earlier, the Epilogue always ends in the blr instruction Branch to Link Register: blr The blr instruction is just an unconditional branch, but it branches to the Memory Address in the Link Register. It's that simple. Chapter 3: How to Call a Function in your ASM Codes
Calling functions for use in ASM Codes differs a little bit than how a Wii game or a conventional PPC program does it. First, to call a function, you need to know its memory address (where does the function reside at in Memory). Once you have that address, you need a way to 'jump' to it. Let's go over a basic function that requires zero inputs and does **not** return back to us. This function is __OSShutdownToSBY. It does one job and that is to shut down the Wii. Now to call functions in your ASM Codes, there are two different methods. 1. Use the Link Register (LR) or.. 2. Use the Count Register (CTR) Calling a function via the LR: Let's look at a snippet of code that will call the __OSShutdownToSBY function. It's important to note that the location of a function within a Wii Game will differ per region (most of the time). The address of __OSShutdownToSBY for PAL MKWIi is 0x801AB960. By the way, this function is a Wii Library function and is present in all Wii Games, not just MKWii. Code: lis r12, 0x801A #Place address of _OSShutdownToSBY in r12 You should be aware of how the blr instruction operates from reading the previous chapter. Once the blr instruction has executed, you will be sent to address 0x801AB960 and start executing the following ASM instructions that are located there. The instructions within this function will perform all the necessary tasks that is required to force the Wii to shutdown. In real time, the shutdown is instant. Calling a function via the CTR: As mentioned earlier, 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. Code: lis r12, 0x801A #Place address of _OSShutdownToSBY in r12 The bctr instruction simply causes the execution of the CPU to jump to the address that's in the Count Register. Unlike __OSShutdownToSBY, most functions will return back to where they were called from. Therefore, when we call these types of functions, we need to supply the function the proper address to return back to. If not, your code will cause a crash or undefined behavior in the Game will occur. There are two instructions that you can choose from to make a function return back.,,
You can think of blrl as the combination of bl + blr. The blrl instruction will jump to whatever address is currently in the Link Register. Afterwards (this is IMPORTANT), the address of the instruction directly below blrl is placed into the Link Register. Example: Code: blrl Pretend that the address's of the blrl and add instructions is 0x80501CC0 and 0x80501CC4 respectively. When the blrl gets executed, the CPU will jump to the address that's currently in the LR. Afterwards, the CPU is executing some function, and the address (value) in the Link Register gets replaced with 0x80501CC4. That way when the function needs to return back, it knows how to come back to us. Example snippet of source (unfilled function address) using the LR and r12 Code: lis r12, 0xXXXX Example snippet of source (unfilled function address) using the CTR and r12 Code: lis r12, 0xXXXX Chapter 4: Arguments
You may be wondering at this point, why r12 is shown in the above snippet of sources in Chapter 3. This is because certain functions need 'arguments' (aka inputs) established before being called and certain specific registers must be used for these 'arguments'. If these arguments are not set in the correct registers and/or the registers are filled with invalid values, then the function will fail or cause your game to halt. Here's the structure of how arguments are set in the registers Code: r3 = 1st arg r0, sp (r1), rtoc (r2), and r11 thru r31 are never used for args. FPR's f0, and f9 thru f31 are also never used for float-value args. Most coders prefer to use r12 as the register to place the function's address in the LR/CTR before calling it. That is why r12 was used in the sources shown in Chapter 3. Let's take a look at the function NETCalcCRC (PAL address 0x801D1CA0). It's a function that is used to generate a 32-bit checksum on a desired block of data. NETCalcCRC requires two integer (non-float) args...
Here's an example of a snippet of source setting up the two args and then calling NETCalcCRC Code: lis r3, 0x8056 Chapter 5: Return Values
Referencing the above snippet of source from Chapter 4, NETCalcCRC will return to us with our 32-bit checksum value. Almost all functions (that are designed to be returned back from) will return a value in r3. A few functions will return values in both r3 and r4, and/or return a value in f1. Once NETCalcCRC has completed, r3 will now contain the 32-bit checksum value. NETCalcCRC returns 0 in r3 if a checksum could not be generated. Here's our source from Chapter 4, but it now has new instructions to verify what's in r3. Code: lis r3, 0x8056 Please note that while NetCalcCRC returns 0 for an error, most functions will return negative values (i.e. 0xFFFFFFFC) for errors. Chapter 6: Terminology, Caller vs Callee
Now would be a good time to go over some of the nicknames for various registers. You may have come across these names in some of my other tutorials before.
The Volatile Registers are the Caller-Saved Registers. This means that if there is data in them that needs to be preserved/saved, it must be done *before* you call a function. The Non-Volatile Registers are the Callee-Saved Registers. This means the Callee saves the data of these registers (not all, just the registers that will be utilized) during the Prologue of a function. The Caller can place data in these registers and know the data will be safe throughout a function call. Therefore, once the function call completes and return back, all the data is intact. THIS IS IMPORTANT. More on this in Chapter 8. Caller? Callee? What the heck does the even mean? Let's say you have a code and it calls a function. The portion of the code which sets the inputs, calls the function, and process the outputs, is known as the CALLER. The CALLEE is the instructions within the function itself, which ofc includes the prologue and epilogue. Keep in mind the Callee can become a new Caller. If a function contains a function within itself, this becomes the case. The function that calls the new function becomes the new Caller. The new function itself is the new Callee. The Caller is responsible for...
The Callee is responsible for...
An alternative name for Caller is Parent. And for Callee is Child. Chapter 7: Register Safety
Since we are calling functions within an ASM code, and not from a conventional program/application, we can use a modified version of the "Push/Pop the Stack" Method that will give us plenty of registers to freely use without over-complicating things. Here is the modified version~ Code: ##Default instruction could reside here## As you can see, this will backup registers r3 thru r31 for us, and then retrieve them once our code and function call(s) are complete. Therefore, you are 100% free to use these registers. Now depending on your ASM code, you may need to backup the following...
Which ones do I backup? This all depends on your code. At your Code's Address in Dolphin's Code View, take a look at some instructions that are further ahead, if you see any of the 3 registers being used, you will need to back them up. The Count Register rarely needs to be backed up. Here's a snippet of code to put before pushing the stack if you need to backup the LR and r0... Code: mr r11, r0 #Copy r0's value to r11 And a snippet of code to put after popping the stack... Code: mtlr r12 #Restore LR's value Chapter 8: Non-Volatile Registers
Back in Chapter 6, I've mention that the Non-Volatile registers are preserved throughout function calls. Trying to save data to a place like the Exception Vector Area before a function call, and then loading the data back from said Area after a function call may not be necessary. You can throw the data into the non-volatile registers instead. A good example use for the Non-Volatile Registers is for the ISFS based function calls. The ISFS family of function calls are responsible for reading and/or modifying of files on the Wii's NAND. To open a file you use the ISFS_Open function. It has arguments like most functions do, but what's important here is that ISFS_Open returns what is known as a File Descriptor (fd) as a byte value in r3. You need this File Descriptor value for all other ISFS based functions. All other ISFS based function calls require this fd as part of their arguments. So it would make sense to do something such as... Code: mr r31, r3 #Backup fd to a Non-Volatile Register At some point after calling ISFS_Open and before calling any other ISFS based function. Since r31 is a Non-Volatile, it's value will be safe throughout other function calls. Remember that since you are using the modified "Push/Pop the Stack" Method, you have r14 thru r31 at your disposal to backup data in. Even though the Push/Pop Stack Method backups r3 thru r13 as well, you *CANNOT* use these specific registers as a way to preserve data throughout a function call(s). Chapter 9: Stepping Thru Functions on Dolphin
Most functions simply have too many instructions for you to step thru when debugging. So to get around this problem you can use Instruction Breakpoints. When stepping through your code, right before your function gets called (via execution of blrl/bctrl), set an Instruction Breakpoint on the instruction that's immediately after the blrl/bctrl. You can set Instruction BPs very quickly by just left clicking on the address of the desired instruction in Code View. A grey dot will appear next to the address indicating an Instruction BP has been set. Like so... Once that Instruction BP has been set, simply press the play button or Dolphin (or use your Hotkey) to let the emulation play normally. After a split moment, you will then be on the instruction immediately after your blrl/bctrl. You can then take a look at r3 to verify your return value if desired. Also remember to check your arguments before the function was called. Happy coding! RE: Guide For Calling Functions (ASM) - lovops - 08-12-2020 Thanks RE: Guide For Calling Functions (ASM) - salmon01 - 08-12-2020 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. RE: Guide For Calling Functions (ASM) - JoshuaMK - 08-12-2020 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. RE: Guide For Calling Functions (ASM) - Seeky - 08-12-2020 http://wiki.tockdom.com/wiki/Compiler has good info for this kind of thing RE: Assembly Tutorial - coco - 11-22-2021 when i see https://mariokartwii.com/showthread.php?tid=922 and all other code why you can create a game or mod with the cheat code ? (for example your xyz swapper with this you can get all ia pos and make a minigame) RE: Guide For Calling Functions in ASM Codes - Vega - 11-22-2021 Not sure where to move your post to. But since it deals with function calls, I placed it here. |