Standard ASM code?

Started by Sharkbyte, May 28, 2010, 02:25:37 PM

Previous topic - Next topic

Romaap

From the looks of that dissassembly register 13 is in use, and it stores a pointer so when you load another value in it the game tries to load something from that value (it thinks it is an address).
And you set the register to 0xC5000000 which is not a proper address, thats why the game crashes.

So in order to let this work, you have to use another free register or store the register on the stack (this is a little bit more complex).

But another way to achieve the same result is to go back in the dissassembly, look up some instructions because the game had to load that value first and probably added a value to it.
So if you find the instruction that add a value to it, insert the C2 code there and just edit the register which has the value which is added.

dcx2

r13 is never safe.  It's a special register, I think.  r1 and r2 are never ever ever ever safe.  ever

When in doubt, r12 is almost always a safe register.  r0 is usually pretty safe, too, but there are some restrictions on using r0 with certain instructions.

Finding registers that hold 0 is not safe.  Safe registers are those whose value will not be read until they have been written to by something else first; this way, any value that you put into the register won't ever be read by the game.

When providing a disassembly, everything after the blr is useless (i.e. everything after the end of the current function).  It's also very important to include the disassembly *before* the breakpoint, so we know what has lead up to the current instruction.  If you can, you should include everything up to the previous blr (i.e. the end of the previous function); this way we can see the whole function, which helps when identifying input arguments and such.

It looks like the function that you're hitting (execute BP at 8001F0E0) runs multiple times per frame.  It might be adjusting *every* players' height (or even enemies!), instead of just player 1.  Notice how the r3 pointer is different between the two breakpoints.  You will probably have to follow the blr back to the caller and hook your C2 code somewhere there.

dcx2

Here is the whole function.

8001F0D4: C0440000 lfs  f2,0(r4)
8001F0D8: C0240004 lfs f1, 4 (r4)
8001F0DC: C0040008 lfs f0,8(r4)
8001F0E0: D0430000 stfs f2,0(r3)
8001F0E4:  D0230004   stfs   f1,4(r3)
8001F0E8:  D0030008   stfs   f0,8(r3)
8001F0EC:  4E800020   blr   

This function loads three floats from r4 and copies them over to r3.  It's definitely used by more than one caller.  You will have to follow the blr back to the caller after doing your write breakpoint.

dcx2

Yes, follow your first write breakpoint.  This will help you find when 8001F0E0 is processing the chunk of memory you're interested in; it processes many chunks of memory.

To follow the blr back to the caller, just step.  blr = Branch to Link Register.

You might want to read this tutorial, it describes this process in greater detail.

http://wiird.l0nk.org/forum/index.php/topic,5080

dcx2

I don't think you set the right Write breakpoint.  Look at the Link Register; that is telling us where our caller is.

In your original Write breakpoint, the LR was 8011C39C.  In your subsequent Execute breakpoint the LR was 80168F50.  This means there are *at least* two different callers.  If you repeatedly did Execute breakpoints and looked at the LR, you could probably find all the various callers...and I bet there would be a lot of 'em.

It is *paramount* that you make sure you find the caller who is handling the character you're interested in.  Lots of people call this function that lives between 8001F0D4 and 8001F0EC.  We're only interested in one specific phone call.

bl is like calling someone, blr is like hanging up.  Lots of other functions will bl 0x8001F0D4 but there's only one of those that we're interested in.