Excuse me if a topic has been made like this by someone else, but is it possible to add value to a float in an operation in ASM? I am wanting to gradually add value to a float and then decrease using ASM. Can someone tell me what instructions/checks I should do to make this possible? I do not want an li, because it writes the direct value to the register. I want to add value to the float, but i don't know what to do/how to go about this.
original instruction: D03E06F4 stfs f1,1780(r30)
I spent over three hours finding all the character offsets for the code I was working on and tried using the gecko register operations to add value gradually, and that worked. However, i was only able to execute the code for a few characters. (because the characters were sometimes different by the offsets)
Would I need to use the add operation or addi? I just want to add float value by a button activator.
I will provide additional information if needed to my posts.
You need to use lfs and fadds.
How much do you want to inc/dec by? The problem is that there is no way to load a float register directly, so your inc/dec value will have to be in memory somewhere. lfs the inc/dec value into an unused float register, then fadds the inc/dec with the original float, then stfs as normal.
http://wiird.l0nk.org/forum/index.php?action=post;quote=66230;topic=7858.15;num_replies=54;sesc=085b19cabb16a1b9e054ca23995a575d
I think this is what you're talking about.
Edit: http://wiird.l0nk.org/forum/index.php/topic,7858.15.html
Gecko Register code types are better at adding and subing floats than ASM. Otherwise, you need to use the bl trick.
I imagine he used f16...well...just 'cos he needed a register. He's not interested in the value that was in f16, because that's lost after lfs. It's just a scratch pad to do some work, so to speak.
lfs f16,252(r29) # load Z coordinate into f16
fadds f16,f16,f0 # add f0 to Z coordinate. f0 = 1.0 according to the register dump.
stfs f16,252(r29) # store f16 to Z coordinate
lfs f0,244(r29) # I imagine this is the original instruction that was hooked, and 244(r29) is the X, since 252(r29) is the Z.
He could probably have hooked a wide variety of addresses, so the offset in the original instruction isn't really important. The hook merely provides a convenient way to access the pointer of interest via r29.
Instead of using lfs to get a value from memory, he took advantage of a float register that consistently had a value he was interested in. This may not be stable, because if f0 ever changes, your moon jump speed will change too, because it will fadds a different f0 to f16.
Quoteyes, I think it is odd that the instructions are so far down in memory
Yes, it is odd, and I would watch that area with auto-update Memory Viewer while starting the game and loading a map, etc. You might find that this area of memory is being loaded dynamically with ASM, in which case you'll need the...uh...I think it's F4 code type, which is a C2 that only hooks when the right stuff is there.
If you want more help, you will need to do the following. Please use Gecko.NET, hit your breakpoint, go to disassembly tab, right click, Copy Function. Paste that into a spoiler since it can be large. Bold the breakpoint instruction please. Also double click the Call Stack listbox, copy and paste all the addresses here. And while you're at it, another copy of the registers...it's nice to compare different runs of the game through the same ASM.
---
Regarding the bl trick, Patedj tried to do something similar with another game. You can follow along here. http://wiird.l0nk.org/forum/index.php/topic,7858.msg66052.html#msg66052
However, that makes some assumptions based on having the whole function that he pasted in his first post. Other functions may require backing up LR. In his case, the hook he found wasn't quite right, and was affecting other avatars.
The only reason you prefer WiiRDGUI is because you're used to it. Gecko.NET is way, way more powerful. Once you are familiar with it, you won't go back to WiiRDGUI.
---
Yes, the ASM moves. I anticipated this. I had the same problem with Resident Evil 4; the ASM for the guns is loaded dynamically in the 81xxxxxx range, depending on the gun you have armed. That's why I wanted the Call Stack (which is something WiiRDGUI cannot give you). We can go down the call stack to find ASM that does *not* move, and then hook that.
Unfortunately, you used an Execute Breakpoint, so you might not have the right call stack. =( This ASM may be called multiple times per frame on different pointers. You can verify this by repeatedly setting an Execute Breakpoint on that instruction; if you have to press Set Breakpoint more than once to make the game advance one frame, it's being called many times and you will need to use data breakpoints to make sure that you breakpoint when it is interacting with the pointer you want. This way you know you have the right call stack.
We can continue with the current call stack, though, just to demonstrate. Look at the breakpoint instruction. The pointer of interest is in r30. If you work your way back up to the top of the function, you'll see 813ABBF4: 7C7E1B78 mr r30,r3. So the pointer was passed into this function via r3, and then it was cached in r30, and eventually used by your breakpoint.
Since r3 came from the caller, we will need the disassembly for the function below the current one in the call stack. Go to address 8137C1B8 and click Copy Function again. (you do not have to be at a breakpoint). Paste that into a spoiler.
8137C1B8 is also high up in memory, so it probably moves too. Therefore, you should *also* go to 80099114 and Copy Function that into a separate spoiler. This one is lower in memory, so it probably does not move.
Once you provide those disassemblies, I'll help you trace the path the pointer takes to get to your breakpoint function.
ahahahah how hilarious, he even guessed the game only from assembly behaviour XD
post half then try and modify/edit your post and add the other half if that doesnt work post half in one post and th other half in the next post.
I just need moderately sized chunks (say, estimate a hundred), from the beginning, around the bl that calls the next function, and the end. It helps to follow the input parameters along.
That said, my guess is that 80099060: 7C7E1B78 mr r30,r3 is probably where the pointer you want is cached into r30. 80099108: 7FC3F378 mr r3,r30 is where it gets ready to be passed to the bl. 80099198: 83C10008 lwz r30,8(r1) pops the old value of r30 that got over-written by the pointer passed into this function.
So, anywhere from 80099064 to 80099198 should be safe to hook, and r30 will have your pointer. Your offset comes from the breakpoint.
So I'm trying to teach you what you're supposed to look for when walking the stack. You need to remember: r3-r10 pass values into bl's, and that value is
lost. This is why we use r31-r14 to hold important values.
8137BD80: 396100A0 addi r11,r1,160 # this creates a temporary pointer to 160 bytes below the top of the stack in r11
8137BD84: 4AE2B9DD bl 0x801a7760 # this probably stw's a bunch of registers onto the stack
8137BD88: 880300FC lbz r0,252(r3)
8137BD8C: 3FE0813C lis r31,-32452 # first half of loading local variable r31 with a pointer
8137BD90: 7C7E1B78 mr r30,r3 # cache the input parameter r3 into the local variable r30
8137BD94: 2C000000 cmpwi r0,0
8137BD98: 3BFFA120 subi r31,r31,24288 # finish loading r31 pointer.
So we know where r30 came from. That helps when we get to the middle half, around your breakpoint.
137C1A8: 801E04AC lwz r0,1196(r30) # load a flag
8137C1AC: 54000253 rlwinm. r0,r0,0,9,9 # test flag; is bit 9 clear?
8137C1B0: 40820044 bne- 0x8137c1f4 # if set, take branch
8137C1B4: 7FC3F378 mr r3,r30 # load local variable r30 into r3 to pass into the bl
8137C1B8: 4802FA21 bl 0x813abbd88137C1BC: 7FC3F378 mr r3,r30 # load local variable r30 into r3 to pass into the bl
8137C1C0: 4802FC79 bl 0x813abe38
8137C1C4: 7FC3F378 mr r3,r30 # load local variable r30 into r3 to pass into the bl
8137C1C8: 48030C01 bl 0x813acdc8
...
So based on whatever is at 1196(r30), the game determines whether to execute this series of bl's on the pointer. One of these is the bl that lead to your breakpoint's function.
At the end, we have
8137CB84: E3E100A8 .word 0xe3e100a8 # ...what is this doing here?
8137CB88: 396100A0 addi r11,r1,160 # temp stack pointer
8137CB8C: CBE100A0 lfd f31,160(r1) # pop f1
8137CB90: 4AE2AC1D bl 0x801a77ac # pop the normal registers
8137CB94: 800100B4 lwz r0,180(r1) # get the pointer to the caller
8137CB98: 7C0803A6 mtlr r0 # load caller's pointer into LR
8137CB9C: 382100B0 addi r1,r1,176 # release the memory allocated on the stack
8137CBA0: 4E800020 blr # branch to the caller
Always look for this pattern at the end of functions, and the corresponding pattern at the beginning. One thing that's weird is the .word, there's no way that's actually a .word or the game would crash. It's actually an ASM instruction that vdappc didn't recognize. It also explains why we don't see the actual first few lines of the function; the .word confused Gecko.NET. The very beginning of a big function is almost always stwu r1 # allocate space on the stack, and mflr # store pointer to caller on the stack.
---
Now we can assemble a whole picture that follows the pointer along from one function to the next. This is proof that in the static function that starts at 8009904C has a pointer in r30 that eventually ends up used by your breakpoint instruction.
80099060: 7C7E1B78 mr r30,r3
80099108: 7FC3F378 mr r3,r30
8009910C: 818C0018 lwz r12,24(r12)
80099110: 7D8903A6 mtctr r12
80099114: 4E800421 bctrl
8137BD90: 7C7E1B78 mr r30,r3
8137C1B4: 7FC3F378 mr r3,r30
8137C1B8: 4802FA21 bl 0x813abbd8
813ABBF4: 7C7E1B78 mr r30,r3
813ABD64: D03E06F4 stfs f1,1780(r30)
---
And just in case you missed it last time...you have already had enough before this to attempt your C2 code.
Quote from: dcx2 on March 06, 2011, 10:57:11 PM
So, anywhere from 80099064 to 80099198 should be safe to hook, and r30 will have your pointer. Your offset comes from the breakpoint.
Functions do stuff. Functions like to have a single task. However, sometimes a single task is composed of multiple sub-tasks. So one function can use another function, which can use another function, which can use another function, and so on. When one function needs to use another, the first function is the caller, and the second function is the callee. The first function is said to call the second function. Input parameters are passed into the function at the beginning of a call, and sometimes return values are passed back to the caller at the end of a function.
bl calls functions. bl 0x80027780 is like picking up the phone and going "hey 80027780, I'm going to put something into r3, please do some work and return a result in r3". The caller is the function where the bl exists. The callee is given by the address of the bl. When the callee is done doing work for the caller, it can "hang up" using blr.
Why did we need to walk the stack in the first place? Your breakpoint instruction was 813ABD64: D03E06F4 stfs f1,1780(r30). Since we can't hook the function that your breakpoint is in, we need to find a different function. However, this different function might have the pointer of interest in a different register! That's why we need all the disassembly. We need to figure out where the value in r30 came from.
As it turns out, the value in r30 at your breakpoint came from the value in r30 in the caller's caller. But we need all the disassembly to prove it. It won't always work out like that.
When you see ".word" it doesn't mean "junk instruction". ".word" is not an instruction! It's data! ".word" is the disassembler (vdappc) telling you "Hey, this doesn't look like any known ASM instruction, so I'm just going to pretend it's data instead".
Regarding the .word in your disassembly, that's really weird and it makes me wonder if your vdappc is somehow corrupt and not recognizing the psq_ instructions. What you see there *should* be an instruction, and the Wii will execute it as an instruction, even if vdappc doesn't recognize it. I've never seen a real .word in ASM. The PowerPC CPU cannot execute a .word. If you try to execute a .word, the game will crash. Which is why I think something's wrong with your vdappc.
---
Regarding your float problem, please read the post I linked to earlier.
http://wiird.l0nk.org/forum/index.php/topic,7858.msg66052.html#msg66052
I know it can be hard and time consuming to learn all this, but it will make you a better hacker if you understand how all this works.
Your frustration comes from a lack of immediate results. You shouldn't look at this hack as a failure because you haven't got it to work (yet). You should look at this hack as a success based on everything you've learned.
---
When writing a C2 code, you should keep some notes on it. It also helps to have the pre-compiled ASM with notes. Here's what I think you put into the disassembler, and comments on what should be different.
bl SKIP_DATA
.float 2.0
SKIP_DATA:
mflr r12
lis r30,1780 # ???
lfs f6,0(r30) # should be (r12) instead of (r30)
lfs f1,1780(r30)
fadds f1,f1,f6
stfs f1,1780(r30)
also, your hook address was 80099078: 3863E274 subi r3,r3,7564, and yet I see no subi anywhere in your code. Anyway, you've gotten this close, so I'll tweak your code that little bit to make it work for you.
This turned out to be a little trickier. The head wants to "unspin" if you just add a value to it. In order to "undo the unspin", I needed to multiply by 1.111111. You should leave this value alone, but it's kinda fun to change it to really big values and watch the head spin like a propeller first. You can change the float addend to bigger or smaller values to make the head spin faster or slower. Note that you might want to make sure "Pause While Sending" is checked, or you might crash when uploading new C2 codes (that's a problem WiiRDGUI had, too); alternatively, go to Memory Viewer, address 80000000, Search groupbox (on the MemView tab!), change dropdown to "Hex", then search for d0c0de (do code), and it should bring you to your C2 code in memory. Now you can use the Memory Viewer poke box to modify the floats directly, without uploading new codes.
Hook
80099104: 819E0008 lwz r12,8(r30)
bl SKIP_DATA # branch over the data, and put a data pointer into LR
.float 0.1 # float addend to make head spin
.float 1.111111 # float multiplier to keep heads spinning
SKIP_DATA:
mflr r12 # put data pointer into r12
lfs f0,0(r12) # load f0 with the addend
lfs f2,4(r12) # load f2 with the multiplier
lfs f1,1784(r30) # load f1 with the head rotation
fmadds f1,f1,f2,f0 # f1 = f1 * f2 + f0
stfs f1,1784(r30) # store f1 to head rotation
lwz r12,8(r30) # original instruction
---
C2099104 00000006
4800000D 3DCCCCCD
3F8E38E3 7D8802A6
C00C0000 C04C0004
C03E06F8 EC2100BA
D03E06F8 819E0008
60000000 00000000
---
Here is what I mean about "you will see your code in memory viewer if you search for d0c0de". Notice how the red values exactly match the C2 code above.
800028B0 00000000 00000000 00D0C0DE 00D0C0DE
800028C0 *C2099104* 00000006 4800000D 3DCCCCCD
800028D0 3F8E38E5 7D8802A6 C00C0000 C04C0004
800028E0 C03E06F8 EC2100BA D03E06F8 819E0008
800028F0 60000000 48096814 FFFFFFFF FFFFFFFF
One last thing...your vdappc is broken. Instead of ".word 0xe3e100a8", I get "psq_l f31,168(r1),0,0".
80144BC4: E3E100A8 psq_l f31,168(r1),0,0
Make sure you have the vdappc from the official release build on googlecode.
Yes, the hardest part about ASM codes is finding a good hook. What registers are safe, what pointers are loaded, how many times per frame does this hook execute, etc. That is why walking the stack is so important...you open up so many more opportunities to find a good hook.
As far as offsets between zombies, no, I had no clue about the offsets. I didn't need to know, because the hook gives me access to all the pointers. This hook is executed once per character per frame; so if there are 8 characters, then this hook will run 8 times per frame.
Yes, this code controls all zombies. It controls any character whose pointer is passed into this function. It also affects the Merchant, but not Leon. I didn't try Ashley.
Regarding vdappc, download the official 0.63 build and unzip everything *except* the Gecko.NET exe (since you claim to have r115 you shouldn't overwrite it, 0.63 is actually r113 I think)
Any value for the addend and multiplier are safe. As I said, try making the multiplier something large like 3 or 4. You can watch an enemy's head spin like a propeller! It's kinda funny. EDIT: values less than 1.111111 will stop spinning eventually.
To make the heads spin faster, use a bigger addend (like 0.2). To make them spin slower, use a smaller addend (0.05). To make them spin the other way, use negative addends (-0.1).
You should refer to the floats by their float value instead of their hex value. You can even use Gecko.NET to search for floats (Data Type), you can display them as floats (View Mode), you can right-click a Value field and do "float to hex", and the assembler can understand ".float 1.0" means 0x3F800000.
I caution against making their heads rotate vertically. It makes it more difficult to get a head shot.