Quick question on C0 codetype

Started by hawkeye2777, December 20, 2009, 02:55:50 AM

Previous topic - Next topic

hawkeye2777

QuoteCST0 : Execute following ASM Code

C0000000 NNNNNNNN : execute ZZZZZZZZ
ZZZZZZZZ ZZZZZZZZ
ZZZZZZZZ ZZZZZZZZ
4E800020 00000000
It executes the NNNNNNNN lines of instruction placed under the code. The instructions MUST end with a blr (0x4E800020).

Along with the blr instruction, is 00000000 also required after it (like with the C2/D2 codetype)?

In case I didn't make sense, which of the following could be correct?:

C0000000 NNNNNNNN
ZZZZZZZZ ZZZZZZZZ
ZZZZZZZZ 4E800020

or
C0000000 NNNNNNNN
ZZZZZZZZ ZZZZZZZZ
ZZZZZZZZ 60000000
4E800020 00000000

or
C0000000 NNNNNNNN
ZZZZZZZZ ZZZZZZZZ
ZZZZZZZZ 4E800020
60000000 00000000


I haven't hacked in a while, so I don't remember everything about these codetypes. :/
Currently "retired" from hacking codes.

Almas

The first and second should both work.

dcx2

Sharkbyte - I think you want a C2 code, not C0.  C2 codes allow you to "inject" assembly into the game's execution at a specific address.

Hawkeye - hey, I need to thank you for a couple of codes you made that helped me find other totally unrelated codes.  Win!

Anyway, when exactly does a C0 code execute?  When the code handler encounters the C0 code during processing?  What are the safe registers to use?

dcx2

Yes, C2 will replace your target instruction with a branch to an address very low in memory.  When you inject asm with C2, you have many instructions (in your case, 2 - 3BA60080 E7B60010), but we can only replace one instruction in the assembly (the one at address 0x80099C8C).  So, we replace that one instruction with a branch to "somewhere else" - in your case, 0x800028f0.  At 0x800028f0, the code handler has written your injected ASM.

There are a few very important things with C2 code types and how they differ from C0 code types.  A C2 code is replacing an instruction in the game's assembly code.  You must remember to include that replaced instruction at the end of your C2 code.

In contrast, C0 codes don't replace anything.  However, the question I have is...when do the assembly instructions contained in a C0 code execute?  C2 codes execute when the instruction you replaced would be executed.  I imagine C0 codes execute during the code handler?

Also, when doing C2 codes, you need to carefully examine the surrounding assembly for "safe registers" - that is, registers that have no dependencies; that no subsequent instruction will read from that register without replacing its contents first.  If you use the wrong register you will freeze the game.

However, with a C0 code...what registers are safe?  Where is the assembly code to scan for dependencies?

dcx2

Quote from: Sharkbyte on March 17, 2010, 02:57:27 AM
=So when it writes to that address very low in memory, what is it actually there?  Were there old instructions in that address very low in memory that it replaced?

The code handler is located "very low in memory".  It has room specially allocated just for C2 code types.

QuoteHow do you find 'safe' registers?

Loads break dependencies.  Any time you see load immediate, load immediate shifted, load word, load halfword, or load byte, the value in the register is being wiped out - i.e. nothing depends on that register anymore.  It is "safe".

If anything reads from a register between your C2-code's address and the next load to that register, it has a dependency and is not safe.

BTW, r1 and r2 are never, ever safe.

Link

As dcx2 explained: the C2 code type is intended so that you can simply extend existing game code and modify it using your own addition. C0 basically executes custom code and its purpose is so that you can write assembly where codes simply aren't working. The code handler is basically an interpreter : it reads your codes and handles them according to the code definition. However, there can always be code intentions which you would like to do but the code handler is simply incapable of. In that case you can use C0 to write your own assembly code which gets executed whenever the code handler also gets executed.

C2 as mentioned modifies the game code.. C0 is more of a "design your own code type" thing.. one aspect: if you use a C0 code for a quite difficult pointer thing for example.. while a C0 code would be longer, it would be much faster! As explained.. whenever the code handler reads a line.. it needs to detect which code type it is.. and handle it accordingly. If you write your code in assembly.. the CPU would directly execute it and thus it would be faster.

As dcx2 also said: in most situations you will need to put the original instruction at the end of the the C2 injected assembly. Or at the beginning.. or well.. at least it should be executed (unless in rare cases you do something like:
IF blabla THEn
execute original instruction
ELSE
execute my code
- those cases exist!)

Other than that: as he said.. r1 and r2 are indeed never safe! Do not use them unless you have special reasons. r1 for example is the stack pointer. You can use it to put register values onto stack. Just to give you an example:

#STACK PUSH
stwu r1,-80(r1)      #reserve space in stack
stmw r14,8(r1)       #store registers beginning from r14 into stack

... your assembly here ...

#STACK POP
lmw r14,8(r1)        #read registers r14 to r31 from stack
addi r1,r1,80        #free stack memory 


First of all it lowers the stack pointer r1 by 80 (space for 20 4-byte values). And then it moves all registers beginning with r14 onto stack. They will keep their values so you can still read them but you can safely overwrite them - at the end of the code in the #STACK POP area they will be restored. Please note: the stack size is limited. This code requires 80 bytes in 99.9% of all cases you will get them! If you don't you need to lower the 80s and need to rase r14. So essentially that code snippet will give you the registers r14 to r31 for free use. That should be plenty!

dcx2

1) O_O!!  I have never seen stmw.  That's an *awesome* instruction.  That would make life so much easier if you need to push and pop more than 1 register...

2) Are there any restrictions on what values you use to make room on the stack?  I think I've only ever seen games allocate stack space 16 bytes at a time, but one would think that multiples of 4 are okay...80 is, conveniently, a multiple of 16.

3) So C0 runs during the code handler.  Does the code handler push any registers before letting the C0 execute?  Are there any interesting values (ba, po, etc) in the registers when a C0 code begins execution?

brkirch

Quote from: dcx2 on March 17, 2010, 11:40:28 AM
1) O_O!!  I have never seen stmw.  That's an *awesome* instruction.  That would make life so much easier if you need to push and pop more than 1 register...
The stmw instruction does help to size optimize code, but generally you will never see a compiler use it because the stmw instruction is supposedly much less time efficient than executing multiple stw instructions.

Quote from: dcx2 on March 17, 2010, 11:40:28 AM2) Are there any restrictions on what values you use to make room on the stack?  I think I've only ever seen games allocate stack space 16 bytes at a time, but one would think that multiples of 4 are okay...80 is, conveniently, a multiple of 16.
From http://www.ibm.com/chips/techlib/techlib.nsf/techdocs/852569B20050FF77852569970071B0D6/$file/eabi_app.pdf:
QuoteThe stack frame is always doubleword aligned (on 8 byte boundaries) by using padding, if necessary.
So stack frames can be created using multiples of 8, but not multiples of 4.

Quote from: dcx2 on March 17, 2010, 11:40:28 AM3) So C0 runs during the code handler.  Does the code handler push any registers before letting the C0 execute?  Are there any interesting values (ba, po, etc) in the registers when a C0 code begins execution?
No registers are pushed before the code is executed, so you can directly access the following:
r6 - ba
r15 - pointer to current position in code list (will have number of lines of C0 code * 4 added after the C0 code returns to the code handler)
r16 - pointer

However since no registers are saved, it is important that any registers changed are restored (unless it was one of the registers mentioned above which was intentionally changed).  Also some of the registers used by the code handler (like the register for po) were different in versions of Gecko OS before 1.07b, so keep in mind that if you make codes that modify code handler registers as they may not work correctly on those earlier versions.

dcx2

Thank you brkirch!  You're my hero.  I especially liked the IBM techdoc that you linked to...it was very yummy indeed and explained a lot of the idiosyncrasies surrounding the PPC assembly that I've been staring at.  It was also nice to learn about how r2 is really used.

Quote from: brkirch on March 19, 2010, 08:41:34 PM
From http://www.ibm.com/chips/techlib/techlib.nsf/techdocs/852569B20050FF77852569970071B0D6/$file/eabi_app.pdf:
QuoteThe stack frame is always doubleword aligned (on 8 byte boundaries) by using padding, if necessary.
So stack frames can be created using multiples of 8, but not multiples of 4.
But due to the stack frame header's Back Chain Word and LR Save Word, you can't actually use 8.  The smallest it will ever be is 16, then, but multiples of 8 that are greater than 16 are allowed.  Interesting...

QuoteHowever since no registers are saved, it is important that any registers changed are restored (unless it was one of the registers mentioned above which was intentionally changed).

According to the doc, by convention r3-r12 are volatile registers that can change across function calls.  If the code handler weren't using any of these registers, then we ought to be able to use them without pushing their values onto the stack, right?

Or should we not really trust that convention?  Considering the game wasn't compiled with the Gecko OS code handler in mind, when it hooks into the game's execution it's not exactly as if the game was expecting a function to be there...

brkirch

Quote from: dcx2 on March 19, 2010, 09:27:33 PM
But due to the stack frame header's Back Chain Word and LR Save Word, you can't actually use 8.  The smallest it will ever be is 16, then, but multiples of 8 that are greater than 16 are allowed.  Interesting...
The stack frame can be 8 bytes if you only need to save LR.

Quote from: dcx2 on March 19, 2010, 09:27:33 PMAccording to the doc, by convention r3-r12 are volatile registers that can change across function calls.  If the code handler weren't using any of these registers, then we ought to be able to use them without pushing their values onto the stack, right?

Or should we not really trust that convention?  Considering the game wasn't compiled with the Gecko OS code handler in mind, when it hooks into the game's execution it's not exactly as if the game was expecting a function to be there...
The code handler saves all GPRs to the stack (except r1 and r2) before executing anyway so yes you could use an unused register in the code handler for a C0 code.  Unfortunately though I can't guarantee that any unused registers will remain unused if any changes to the code handler are made in the future so I would recommend against it.

wiiztec

Quote from: dcx2 on March 17, 2010, 03:39:52 AM
The code handler is located "very low in memory".  It has room specially allocated just for C2 code types.

Not exactly, C2 codes actually branch to the actual C2 code stored in memory along with all other applied codes
If there's any code at all that you want to be button activated, or even able to toggle on & off, and I have the game, just PM me and I'll make it happen