16-Bit Write Help

Started by live2play, April 09, 2010, 04:11:46 AM

Previous topic - Next topic

dcx2

I think I saw brkirch write a sample template somewhere showing how to write to a float register.  But I can't remember where...if I find it again I'll link it here.

BTW, dunno if you saw my edit, but you can use F9 to take the two's comp in the Windows Calculator, just make sure you hit Enter after putting in the hex value.

Romaap

You dont have to convert it, you could just do:
li r0,0xFFFF

live2play

Thanks for all of the great information.  If you do find that floating point register write template, I would definitely be interested.

dcx2

This is the brkirch post I was talking about.  Read everything before the "To Create F6 Codes" part.  You'll see the templates I was talking about.  That is how you turn RAM-write-codes into ASM.  You only need the stack if there aren't any dependency-free registers.  Take for instance the first code, which was a lwz rD,d(rD).  Here is the template.


stwu r1,-16(r1) # make room on the stack
stw r11,8(r1) # push r11 onto the stack, so we don't lose it
lis r11,0xHHHH # load the upper 16 bits of r11 with our immediate, HHHH = 0000
ori r11,r11,0xLLLL # load the lower 16 bits of r11 with our immediate, LLLL = FFFF
stw r11,d(rD) # Write our immediate to the destination address
lwz r11,8(r1) # pop r11 off the stack
addi r1,r1,16 # clear the room we made on the stack
lwz rD,d(rD) # do the original load that we're replacing


Now, this is made inelegant by the stack stuff that deals with r1, all because we just aren't sure if r11 is important or not.  If you can tell for sure that a register isn't important (that no further instruction has a dependency on it), then you don't have to do this stack business.

In our case, we were pretty sure r0 was safe, because of the blr.  So we could remove the stack crap that preserves r11 and just blast whatever was in r0 since no further instructions will depend on it.

Quote
stwu r1,-16(r1)      # make room on the stack
stw r11,8(r1)      # push r11 onto the stack, so we don't lose it
lis r0,0xHHHH      # load the upper 16 bits of r11 with our immediate, HHHH = 0000
ori r0,r0,0xLLLL      # load the lower 16 bits of r11 with our immediate, LLLL = FFFF
stw r0,d(rD)      # Write our immediate to the destination address
lwz r11,8(r1)      # pop r11 off the stack
addi r1,r1,16      # clear the room we made on the stack
lwz rD,d(rD)      # do the original load that we're replacing

This can be further reduced, because your value has 0000 for HHHH, and li zeroes the upper 16 bits for free.

Quote
li r0,0xHHHH      # load the upper 16 bits of r11 with our immediate, HHHH = 0000
li r0,0xLLLL      # load r0 with LLLL = FFFF
stw r0,d(rD)      # Write our immediate to the destination address
lwz rD,d(rD)      # do the original load that we're replacing

For the example here, we don't need the stack, because we found a dependency-free register.  

Follow the pattern near the middle of brkirch's guide for the lfs.  For HHHHLLLL, use the hex representation of your float.

live2play

dcx2, thanks for the link and the explanation of the steps.  Probably one of the hardest things to do is determine if a register I want to use is being used by any other part of the code.  I guess always safer to do the stack stuff, right?  I'll look at the floating part of the turorial and hopefully I can get something to work.  My floating question is directly related to my post at http://wiird.l0nk.org/forum/index.php/topic,5425.0.html.  Do you have any ideas on that?  Seems like my only option is to hook the ASM that reads the "moving" MEM2 address so that I don't have to worry about trying to determine the address.  Do you know if there is a way to check the value of an address and only perform a write to the address if the value is present?  I was thinking that I could do that for the MEM2 value that is always in a different address by just making a code that checks all of the MEM2 addresses where the value may exist and only write the new value if the target value is found.  It seems like a lot of overhead, but seems that it would work.

live2play

I'm not able to access the link you provided (http://wiird.l0nk.org/forum/index.php/topic,2289.msg23710.html#msg23710) as it says that it is either incorrect or off limits to me.  Maybe noobs aren't welcome.  ;)

dcx2

As far as the link, I don't know why you can't see it.  It's posted in the Gecko 1.8 forum.  There might be a restriction on the ability to post, but it shouldn't restrict you from viewing...

In general, I prefer ASM hooks to pointer codes (actually, I probably prefer ASM everything, heh).  I don't think I've ever even used the pointer search function, it's just so much easier to breakpoint on the value and use the ASM that's already loaded with the right pointer.  The only caution is that some ASM is run on more than one thing (i.e. things that take away from your health might also take away from the enemies' health or environmental object "health", like in Resident Evil 4 when my damage divider made it harder to open boxes).

Scanning for dependencies isn't actually hard, it's just hard to explain.  It's like looking at the matrix.  I'll use one of your disassemblies as an example.

Quote
8013B88C:  4E800020   blr   
8013B890:  9421FFE0   stwu   r1,-32(r1)
8013B894:  7C0802A6   mflr   r0
8013B898:  90010024   stw   r0,36(r1)
8013B89C:  93E1001C   stw   r31,28(r1)
8013B8A0:  7C7F1B78   mr   r31,r3
8013B8A4:  80C30074   lwz   r6,116(r3)
8013B8A8:  7C043000   cmpw   r4,r6
8013B8AC:  418200AC   beq-   0x8013b958
8013B8B0:  3CA0000F   lis   r5,15
8013B8B4:  90830074   stw   r4,116(r3)
8013B8B8:  3805423F   addi   r0,r5,16959
8013B8BC:  7C040000   cmpw   r4,r0
8013B8C0:  7CA62050   sub   r5,r4,r6


Start with r5.  Notice that r5 is not used by any instruction until 8013B8B0, at which point it is used as a destination operand.  Since nothing used r5 up until the load, it is dependency-free.  You can do anything to r5 before 8013B8B0 and you're safe because the lis will always replace your "anything".

Once we've reached 8013B8B0, we can't touch r5 because the add at 8013B8B8 uses r5 as a source operand.  If we were to put something else there, the add would get messed up, because it depends on r5.

However, once we've reached 8013B8B8, r5 is free again.  This is because the next instruction that uses r5 is over-writing it (the sub at 8013B8C0) as a destination operand, so the value in r5 is dependency-free between 8013B8B8 and the sub.

In general, a register is dependency-free in the region between the last instruction that used the register as a source operand (8013B8B8) and the first instruction that uses it as a destination operand (8013B8C0).  If you don't see any instructions that use a register as a source operand, then the register is dependency free up until it is used as a destination operand for the first time (8013B8B0).