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 r9 is usually the value of 0x0 whenever the code's default ASM is executed. So at the end of you code, you write li r9, 0x0. Good right? Maybe not. There could be a chance that r9 can be something other than 0x0. I'd advise testing a breakpoint 10 total 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 out of r3 thru 10. With r3 being the least safe. Both r3 and r4 are generally less safe than r5 thru r10. I won't get into the technical details, but in certain stages of a subroutine, r5 thru r10 can be used freely. However, r3 & r4 are always used as either inputs or outputs hence why they are less safe.

Note about r0: r0 is an odd ball type register. In certain ASM functions, it will be treated by the compiler as 0. For example:

addi r5, r0, 2

This will actually do addi r5, 0, 2 instead which is the same thing as li r5, 2.

In conclusion, If you have to use the volatile registers, don't use r0, r3, and r4.



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,-80(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,80 # release the space

...Default ASM could reside here...




The stwu, stmw functions will make space on the stack frame for the registers, then the registers' values are stored onto the stack. The lmw, addi functions will restore all the registers' values, then release the stack space.

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 functions (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)

How to push/pop the stack for FRPs (each FPR must be done as its own unique function)...



##Allow use of FPR's 20 thru 31##

...Default ASM could reside here...

stfs f20,88(r1)
stfs f21,92(r1)
stfs f22,96(r1)
stfs f23,100(r1)
stfs f24,104(r1)
stfs f25,108(r1)
stfs f26,112(r1)
stfs f27,116(r1)
stfs f28,120(r1)
stfs f29,124(r1)
stfs f30,128(r1)
stfs f31,132(r1)

...Your ASM contents...

lfs f20,88(r1)
lfs f21,92(r1)
lfs f22,96(r1)
lfs f23,100(r1)
lfs f24,104(r1)
lfs f25,108(r1)
lfs f26,112(r1)
lfs f27,116(r1)
lfs f28,120(r1)
lfs f29,124(r1)
lfs f30,128(r1)
lfs f31,132(r1)

...Default ASM could reside here...



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.

For a more technical approach of this info, plus more details.. visit this link - https://gamehacking.org/wiird/forum/inde...pic=6555.0

All Credits to:
dcx2
Y.S.
Reply
#2
Bump: Thread completely revised. Lots of good info added to help the beginners.
Reply


Forum Jump:


Users browsing this thread: 1 Guest(s)