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
(It's a feature of the emulator.)
m (Correct file names in patches example)
 
(8 intermediate revisions by 5 users not shown)
Line 1: Line 1:
== Cemu game patches ==
Starting with version [[Release_1.17.0|1.17.0]], Cemu supports patching gamecode via graphic packs. In previous versions of Cemu, patching gamecode was done through [[Cemuhook]].
 
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:
There are currently two different formats for patches supported:
Line 7: Line 5:
* Cemu's own patch format (.asm)
* 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 [https://cemuhook.sshnuke.net Cemuhook] releases.
This article documents the new .asm format (referred to as ''Cemu patches''). For details on Cemuhook's format see example_patches.zip that is bundled with [https://cemuhook.sshnuke.net Cemuhook] releases.


== The file structure ==
== 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 <code>patch_<anything>.asm</code>
When a graphic pack is applied according to [[Graphic packs creation|rules.txt]], Cemu will scan the graphic pack folder for any files matching the pattern <span style="font-family: monospace; font-size: 95%">patch_<anything>.asm</span>. For every match that is found, the file is parsed according to the rules laid out below.  
For every match that is found, the file is parsed according to the rules laid out below.  
 
== Patch groups ==


=== Patch groups ===
Patches are divided into groups. Each group can apply to one or multiple modules based on a CRC match.  
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:
The header of a group should always look like this:


    [group_name]
<div style="background-color: #e4e8e9" class="box-caption"><span class="label" style="margin-right: .5em; background-color: #3498db">ASM</span> <strong>patch_<anything>.asm</strong></div>
    moduleMatches = 0x11223344, 0xCFF30E4E
</div><pre class="captioned">
[group_name]
moduleMatches = 0x11223344, 0xCFF30E4E
</pre>


The group name is generally only used for debugging. Any generated error message will refer to the group name and line number.<br />
The group name is generally only used for debugging. Any generated error message will refer to the group name and line number.<br />
Line 27: Line 26:
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.
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 ===
 
==== Patching individual instructions ====


The most basic use case for patches is to replace individual instructions within a target module.
The most basic use case for patches is to replace individual instructions within a target module.
Line 35: Line 32:
To do this, first prepend a line with <code>address = </code> Cemu will then put the directive that follows at the specified location.
To do this, first prepend a line with <code>address = </code> Cemu will then put the directive that follows at the specified location.


    0x0200E3A4 = li r3, 0
<div style="background-color: #e4e8e9" class="box-caption"><span class="label" style="margin-right: .5em; background-color: #3498db">ASM</span> <strong>patch_<anything>.asm</strong></div>
    0x0200E400 = nop
</div><pre class="captioned">
0x0200E3A4 = li r3, 0
0x0200E400 = nop
</pre>


==== The write cursor ====
=== 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.
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.
For this Cemu offers a write cursor that automatically increments with output.


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


===== Example 1 - Assemble method in codecave =====
==== Assemble method in codecave ====


    .origin = codecave
<div style="background-color: #e4e8e9" class="box-caption"><span class="label" style="margin-right: .5em; background-color: #3498db">ASM</span> <strong>patch_<anything>.asm</strong></div>
    someLabel:
</div><pre class="captioned">
    li r3, 0
.origin = codecave
    blr
someLabel:
li r3, 0
blr
</pre>


===== Example 2 - Replacing instructions in the game's text section =====
==== Replacing instructions in the game's text section ====


    .origin = 0x0200E3A4
<div style="background-color: #e4e8e9" class="box-caption"><span class="label" style="margin-right: .5em; background-color: #3498db">ASM</span> <strong>patch_<anything>.asm</strong></div>
    bla someLabel # written to 0x0200E3A4
</div><pre class="captioned">
    blr          # written to 0x0200E3A8
.origin = 0x0200E3A4
bla someLabel # written to 0x0200E3A4
blr          # written to 0x0200E3A8
</pre>


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


==== Labels ====
=== Labels ===


Labels simplify branching and addressing of variables. To define a label write the name of the label followed by :<br />
Labels simplify branching and addressing of variables. To define a label write the name of the label followed by :<br />
    OurLabel:
 
<div style="background-color: #e4e8e9" class="box-caption"><span class="label" style="margin-right: .5em; background-color: #3498db">ASM</span> <strong>patch_<anything>.asm</strong></div>
</div><pre class="captioned">
OurLabel:
</pre>
 
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.
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.
You can even put labels inside the code or data section of the module.


    0x0202034C = ExternalLabel:
<div style="background-color: #e4e8e9" class="box-caption"><span class="label" style="margin-right: .5em; background-color: #3498db">ASM</span> <strong>patch_<anything>.asm</strong></div>
</div><pre class="captioned">
0x0202034C = ExternalLabel:
</pre>


This is useful if you want to reference an external variable or branch to a game function from your own code.
This is useful if you want to reference an external variable or branch to a game function from your own code.
Line 75: Line 88:
The format also has support for compile-time constants and expressions.  
The format also has support for compile-time constants and expressions.  


    myConst = $presetVariable + 5
<div style="background-color: #e4e8e9" class="box-caption"><span class="label" style="margin-right: .5em; background-color: #3498db">ASM</span> <strong>patch_<anything>.asm</strong></div>
    li r3, myConst     
</div><pre class="captioned">
myConst = $presetVariable + 5
li r3, myConst     
</pre>


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


    li r3, $presetVariable + 5  
<div style="background-color: #e4e8e9" class="box-caption"><span class="label" style="margin-right: .5em; background-color: #3498db">ASM</span> <strong>patch_<anything>.asm</strong></div>
</div><pre class="captioned">
li r3, $presetVariable + 5
</pre>


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]].
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]].
Line 90: Line 109:


{| class="wikitable"
{| class="wikitable"
|-
|.byte
|8bit integer (a byte)
|-
|.short
|16bit integer
|-
|-
|.int
|.int
|Signed 32bit integer
|32bit integer
|-
|.uint
|Unsigned 32bit integer
|-
|-
|.ptr
|.ptr
|Pointer; Alias for .uint
|Pointer; Alias for .int
|-
|-
|.float
|.float
Line 105: Line 127:
|.double
|.double
|64bit double
|64bit double
|-
|.string
|String of arbitrary length
|}
|}


    SomeFloat:
<div style="background-color: #e4e8e9" class="box-caption"><span class="label" style="margin-right: .5em; background-color: #3498db">ASM</span> <strong>patch_<anything>.asm</strong></div>
    .float 123.45 # writes to the current write cursor position
</div><pre class="captioned">
SomeFloat:
.float 123.45 # writes to the current write cursor position
      
      
    # load float from memory:
# load float from memory:
    lis r12, SomeFloat@ha
lis r12, SomeFloat@ha
    lfs f0, SomeFloat@l(r12)  
lfs f0, SomeFloat@l(r12)
</pre>


== Porting Cemuhook patches to Cemu's format ==
== Porting Cemuhook patches to Cemu's format ==
Line 128: Line 156:
'''Cemuhook'''
'''Cemuhook'''


    [PatchName]
<div style="background-color: #e4e8e9" class="box-caption"><span class="label" style="margin-right: .5em; background-color: #3498db">TXT</span> <strong>patches.txt</div>
    moduleMatches = 0x12345678
</div><pre class="captioned">
[PatchName]
moduleMatches = 0x12345678
      
      
    # code Cave
# code Cave
    codeCaveSize = 0x24
codeCaveSize = 0x24
      
      
    # variable to hold preset parameter
# variable to hold preset parameter
    _ourVariable = 0x0000000
_ourVariable = 0x0000000
    0x0000000 = .int $gfxPackPresetVariable
0x0000000 = .int $gfxPackPresetVariable
      
      
    # assemble function in code cave
# assemble function in code cave
    _codeCaveFunction = 0x0000004
_codeCaveFunction = 0x0000004
    0x0000004 = lis r11, _ourVariable@ha
0x0000004 = lis r11, _ourVariable@ha
    0x0000008 = lwz r11, _ourVariable@l(r11)
0x0000008 = lwz r11, _ourVariable@l(r11)
    0x000000C = cmpwi r11, 1
0x000000C = cmpwi r11, 1
    0x0000010 = bne .+0x0C
0x0000010 = bne .+0x0C
    0x0000014 = li r3, 0
0x0000014 = li r3, 0
    0x0000018 = blr
0x0000018 = blr
    0x000001C = addi r3, r3, 1
0x000001C = addi r3, r3, 1
    0x0000020 = blr
0x0000020 = blr
      
      
    # 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
</pre>


'''Cemu'''
'''Cemu'''


    [PatchName]
<div style="background-color: #e4e8e9" class="box-caption"><span class="label" style="margin-right: .5em; background-color: #3498db">ASM</span> <strong>patch_<anything>.asm</strong></strong></div>
    moduleMatches = 0x12345678
</div><pre class="captioned">
[PatchName]
moduleMatches = 0x12345678
      
      
    .origin = codecave # all follow-up instructions and variables will be written into the code cave
.origin = codecave # all follow-up instructions and variables will be written into the code cave
      
      
    # variable to hold preset parameter
# variable to hold preset parameter
    _ourVariable:
_ourVariable:
    .int $gfxPackPresetVariable
.int $gfxPackPresetVariable
      
      
    # assemble function in code cave
# assemble function in code cave
    _codeCaveFunction:
_codeCaveFunction:
    lis r11, _ourVariable@ha
lis r11, _ourVariable@ha
    lwz r11, _ourVariable@l(r11)
lwz r11, _ourVariable@l(r11)
    cmpwi r11, 1
cmpwi r11, 1
    bne label_skip
bne label_skip
    li r3, 0
li r3, 0
    blr
blr
    label_skip:
label_skip:
    addi r3, r3, 1
addi r3, r3, 1
    blr
blr
      
      
    # 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
</pre>


=See also=
=See also=
[[Assembly Patching]]
* [[Assembly Patching]]


[[Category:Feature]] [[Category:List of tutorials]] [[Category:Graphic packs]]
[[Category:Features]] [[Category:List of tutorials]] [[Category:Graphic packs]]

Latest revision as of 16:31, 19 September 2022

Starting with version 1.17.0, Cemu supports patching gamecode via graphic packs. In previous versions of Cemu, patching gamecode was done through Cemuhook.

There are currently two different formats for patches supported:

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

This article 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.

File structure

When a graphic pack is applied according to rules.txt, 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:

ASM patch_<anything>.asm
[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.

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.

ASM patch_<anything>.asm
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.

Assemble method in codecave

ASM patch_<anything>.asm
.origin = codecave
someLabel:
li r3, 0
blr

Replacing instructions in the game's text section

ASM patch_<anything>.asm
.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 :

ASM patch_<anything>.asm
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.

ASM patch_<anything>.asm
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.

ASM patch_<anything>.asm
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:

ASM patch_<anything>.asm
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:

.byte 8bit integer (a byte)
.short 16bit integer
.int 32bit integer
.ptr Pointer; Alias for .int
.float 32bit float
.double 64bit double
.string String of arbitrary length
ASM patch_<anything>.asm
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

TXT patches.txt
[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

ASM patch_<anything>.asm
[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