In order to edit this wiki, you must register and verify your account.

Cemu patches: Difference between revisions

From Cemu Wiki
Jump to:navigation Jump to:search
(Initial version of Cemu patch format documentation)
 
No edit summary
Line 177: Line 177:
     # patch game code to jump to our code cave function
     # patch game code to jump to our code cave function
     0x21EFAA8 = bla _codeCaveFunction
     0x21EFAA8 = bla _codeCaveFunction
=See also=
[[Assembly Patching]]
[[Category:Cemu]] [[Category:List of tutorials]] [[Category:Graphic packs]]

Revision as of 02:08, 15 February 2020

Cemu game patches

Starting with version 1.17.0 Cemu supports patching gamecode via graphic packs. This has been previously been possible through Cemuhook. Patches are always applied via graphic packs.

There are currently two different formats for patches supported:

  • Cemuhook's patches.txt
  • Cemu's own patch format (.asm)

This page documents the new .asm format (referred to as 'Cemu patches'). For details on Cemuhook's format see example_patches.zip that is bundled with Cemuhook releases.

The file structure

When a graphic pack is applied according to rules.txt (see Graphic_packs_creation) Cemu will scan the graphic pack folder for any files matching the pattern patch_<anything>.asm For every match that is found, the file is parsed according to the rules laid out below.

Patch groups

Patches are divided into groups. Each group can apply to one or multiple modules based on a CRC match. The header of a group should always look like this:

   [group_name]
   moduleMatches = 0x11223344, 0xCFF30E4E

The group name is generally only used for debugging. Any generated error message will refer to the group name and line number.
moduleMatches is a list of CRCs that identify one or multiple RPX/RPL files. The patch group will be applied to any module that has a matching CRC. The CRC's of modules can be looked up in log.txt

Multiple patch groups can be in a single file. The instructions within a patch group can also reference labels or constants defined in any other patch group as long as they are activated for the same module (same CRC). Patch groups however cannot access anything outside of the current graphic pack.

Cemu patch format in detail

Patching individual instructions

The most basic use case for patches is to replace individual instructions within a target module.

To do this, first prepend a line with address = Cemu will then put the directive that follows at the specified location.

   0x0200E3A4 = li r3, 0
   0x0200E400 = nop

The write cursor

When replacing multiple instructions or when writing a larger function it can become tedious to manually keep track of the address for every line. For this Cemu offers a write cursor that automatically increments with output.

The current value of this pointer can be set with the .origin = directive. It is followed by a single parameter that specifies the unrelocated address. It also supports the keyword codecave, which will set the cursor to a location with unused space within the codecave region.

Example 1 - Assemble method in codecave
   .origin = codecave
   someLabel:
   li r3, 0
   blr
Example 2 - Replacing instructions in the game's text section
   .origin = 0x0200E3A4
   bla someLabel # written to 0x0200E3A4
   blr           # written to 0x0200E3A8

Note that the origin always has a lower priority than the per-line address. Using the address = prefix will also not increment the current write cursor.

Labels

Labels simplify branching and addressing of variables. To define a label write the name of the label followed by :

   OurLabel:

This will create a label at the current position of the write pointer. The label will automatically be relocated so that it always points to where the code is in memory. You can even put labels inside the code or data section of the module.

   0x0202034C = ExternalLabel:

This is useful if you want to reference an external variable or branch to a game function from your own code.

Constants and expressions

The format also has support for compile-time constants and expressions.

   myConst = $presetVariable + 5
   li r3, myConst    

Here myConst is assigned a value from a preset variable. Expressions are supported almost everywhere, you could also write:

   li r3, $presetVariable + 5    

Keep in mind that while constants act similar to variables, they don't allocate any space and cannot be used as a target for memory load/store instructions. For addressable variables see section #Data directives.

Data directives

In addition to PowerPC instructions the assembler also supports emitting several data types:

.int Signed 32bit integer
.uint Unsigned 32bit integer
.ptr Pointer; Alias for .uint
.float 32bit float
.double 64bit double
   SomeFloat:
   .float 123.45 # writes to the current write cursor position
   
   # load float from memory:
   lis r12, SomeFloat@ha
   lfs f0, SomeFloat@l(r12)   

Porting Cemuhook patches to Cemu's format

Be careful when porting patches to the new format. Both formats support the name = value syntax but the meaning is different.
For example:
name = 0x12345
Cemuhook treats this as a pointer to the address 0x12345, always applying relocation to it. Whereas Cemu treats it as a variable with the value 0x12345 with no further processing.
To get the same result in Cemu .asm patches write: name = reloc(0x12345) or 0x12345 = name:

A sample patch in both formats

Cemuhook

   [PatchName]
   moduleMatches = 0x12345678
   
   # code Cave
   codeCaveSize = 0x24
   
   # variable to hold preset parameter
   _ourVariable = 0x0000000
   0x0000000 = .int $gfxPackPresetVariable
   
   # assemble function in code cave
   _codeCaveFunction = 0x0000004
   0x0000004 = lis r11, _ourVariable@ha
   0x0000008 = lwz r11, _ourVariable@l(r11)
   0x000000C = cmpwi r11, 1
   0x0000010 = bne .+0x0C
   0x0000014 = li r3, 0
   0x0000018 = blr
   0x000001C = addi r3, r3, 1
   0x0000020 = blr
   
   # patch game code to jump to our code cave function
   0x21EFAA8 = bla _codeCaveFunction

Cemu

   [PatchName]
   moduleMatches = 0x12345678
   
   .origin = codecave # all follow-up instructions and variables will be written into the code cave
   
   # variable to hold preset parameter
   _ourVariable:
   .int $gfxPackPresetVariable
   
   # assemble function in code cave
   _codeCaveFunction:
   lis r11, _ourVariable@ha
   lwz r11, _ourVariable@l(r11)
   cmpwi r11, 1
   bne label_skip
   li r3, 0
   blr
   label_skip:
   addi r3, r3, 1
   blr
   
   # patch game code to jump to our code cave function
   0x21EFAA8 = bla _codeCaveFunction

See also

Assembly Patching