ASM & Register Safety
#1
ASM & Register Safety


Once you have reached beyond the realm of simple ASM codes (such as li, stw, nop type), you will eventually run into a situation where you will need to manipulate other registers than just the ones that are used at a code's default address.

Let's discuss Register Safety

A code creator simply cannot choose at will which registers to use as a temporary space to read/write/store data for specific codes. Doing so can cause unwanted effects on the game. Even if a code appears to be working, you are effecting 'hidden' functions of the game in a seriously detrimental manner.

Let's go over all the General Purpose Registers and explain which ones you are allowed to use...



Register 12 (99.9% Safe)

Register 12 is the almighty safest register. 99.9% of the time, you can use this register freely. Freely meaning you do not have to restore it's original contents at the conclusion/end of your assembly. I have yet to make one code where using r12 was ever an issue.



Register 11 (99% Safe)

Register 11 is what I call r12's little brother in regards to safety. 99% of the time, you can use this register freely. Only once ever in my 'ASM career' have I ever ran into a time where I couldn't use this register.



Register 0, and Registers 3 thru 10 (Semi Safe)

r0, and r3 thru r10 are what is known as volatile registers.

You can sometimes use these registers freely w/o restoring their original values. But this is not wise. If you must use these registers, please restore their original value(s).

Even with that being said, restoring the original value(s) is NOT a 100% guarantee for register safety.. Let's say you have a code, and you notice that r7 is usually the value of 0x0 whenever the code's default instruction is executed. So at the end of you code, you write li r7, 0x0. Good right? Maybe not. There could be a chance that r7 can be something other than 0x0. I'd advise testing a breakpoint multiple times (in varying circumstances of the game) to be sure a certain volatile register always holds a specific value.

Generally speaking with the volatile registers, the higher the number, the safer it is. So r10 would be the most 'safest' to use, with r3 being the least safe. r0 plus r3 and r4 are generally less safe than r5 thru r10.

If you must use one of these registers and want to save compiled code length by not restoring their original value(s), then stick with r10. I would give r10 a 95% 'safety rating' for use without restoring its value.

In conclusion, If you have to use the volatile registers, don't use r0, r3, and r4. Restore values for r5 thru r10. However, you don't have to restore r10 and will most likely be OK.



Registers 14 thru 31 (Not Safe)

r14 thru r31 are non-volatile registers. They are used for local variables. Their values must always be preserved. The values they contain will usually vary every time said address/function is executed by the game.

Here's a good example of what not to do with a non-volatile register:
Mdmwii, in his famous MAC Spoofer Code, dangerously used r19. When the MAC spoofer was finished, he ended the code with a li r19, 0x0. I decided to Breakpoint his code. At first it seemed r19 was always 0x0. But soon enough r19 would actually start to vary completely.

This issue obviously has been fixed for his MAC Spoofer code that is posted here on the forums (all new updated source code).



Registers 1, 2, & 13 (Dangerous)

Never, and I repeat NEVER use r1, r2, and r13!! Even if you backup their values and restore them, this is still dangerous. These registers are used by the CPU to access specific areas of memory related to constants, global variables, etc.  They will be read during interrupts which you will not see or know about.




At this point, you are probably wondering what is an efficient way to get more free registers. Before we dive into that, let's discuss a quick easy trick to get some free registers.

Looking Ahead Beyond your Code Address...

We know we can always use r11, and r12. Let's say the address after your code's address has this function - mulli r31, r8, 0x4

You can actually use r31 freely. This is because once your code is completely finished and the next address/function is executed by the game, r31 is going to be written to regardless. Obviously, this also shows that we cannot mess with r8 freely as r8 is being used as part of the mulli function to determine the result to write to r31.

Now you know that handy trick to get some more free registers, here's a rock solid method that allows you to use r14 thru r31.

This method is called the 'Push/Pop the Stack' method.



...Default ASM could reside here...

stwu r1,-84(r1) # make space for 18 registers
stmw r14,8(r1) # push r14-r31 onto the stack

...Your ASM contents...

lmw r14,8(r1) # pop r14-r31 off the stack
addi r1,r1,84 # release the space

...Default ASM could reside here...




The stwu, stmw instructions will make space on the stack frame for the registers, then the registers' values are stored onto the stack. The lmw, addi instructions will restore all the registers' values, then release the stack space. You may be wondering why those instructions are using r1 even though r1 is part of the dangerous category. The old r1 is correctly reserved in the stack frame and is retrieved back later. Thus the instructions are not violating any safety protocols.

You can now use r14 thru r31. If you include r11 and r12, you will have 20 free registers to use!

Question: Are there any cons to using the Push/Pop Stack method?

Generally, no. If you are nit picky about shortening the length of compiled code as much as possible, then try not to use it. As the method consists of four total ASM instructions (two lines of compiled code).

There is a very very rare chance that this can cause a crash. It has only happened to me once, at a specific address in the game (I still can't figure out why it happened...). So I would give it a 99.99% 'success' rate.



Quick info about Floating Point Registers:

f9 thru f13 (99% safe; same level of safety as r11/r12)

f2 thru f8 (Semi safe; same level of safety as r10 thru r4; the higher the number, the more safe)

f0 & f1 (Semi safe; same level of safety as r0, r3, r4)

f14 thru f31 (not safe; values must be preserved)

Beginner/Intermediate Coders will never need to 'push/pop' the stack for FPRs. So technical details of doing that will not be covered in this thread.



Conclusion:

Proper register safety is a must for any code. It is dependent on the responsibility of the coder to do his/her research and have their code(s) be safe for use in the game.

All Credits to:
dcx2
Y.S.
Reply


Forum Jump:


Users browsing this thread: 1 Guest(s)