Custom Code/Introduction to ASM Hacks: Difference between revisions

From Zenith
Jump to navigation Jump to search
Content added Content deleted
m (→‎Requirements: Fix link + title)
mNo edit summary
 
(15 intermediate revisions by 4 users not shown)
Line 1: Line 1:
{{DISPLAYTITLE:Introduction to ASM Hacks}}
{{DISPLAYTITLE:Introduction to ASM Hacks}}{{Warning|msg=<big><big><strong>The information in this page is outdated and may be incorrect.<strong><big><big>}}


In order to do very low-level modifications to the game, C++ cannot just be used by itself. For these purposes we need '''assembly''', or "ASM" hacks to patch or alter functions in the code. The game uses 32-bit PowerPC assembly code, so that is what all patches will need to be written in. To introduce you to the basic ASM build system, we will be making a small patch to disable the music speedup after 100 seconds.
wip


== Requirements ==
== Requirements ==
* Setup a custom code environment
* [[NSMBU-Haxx/Setup|NSMBU-Haxx/Setup NSMBU-Haxx]]
* asmsetup.S (dead link)
* [https://cdn.discordapp.com/attachments/814594642595151902/819005128429404201/asmsetup.S asmsetup.S]


== Guide ==
== Steps ==
All assembly hacks contain a YAML file, which contains hooks that will patch areas of the code to have branch instructions to our custom functions. These hooks can also do some basic tasks by themselves, but for more complex tasks, a .S file is also necessary, which contains pure assembly.
(blah blah introduction) To introduce you to the basic ASM build system, we will be making a small patch to disable the music speedup after 100 seconds.


===Preparation===
===Preparation===
Before we start creating our patch, first we need to include the <code>asmsetup.S</code> file in our project. Simply download the file from [https://cdn.discordapp.com/attachments/814594642595151902/819005128429404201/asmsetup.S here], and place it in your /include/ directory in the <nowiki>[[NSMBU-Haxx]]</nowiki> project files.
Before we start creating our patch, first we need to include the <code>asmsetup.S</code> file in our project. Simply download the file from ''here'' (Dead link), and place it in your /include/ directory in the project files.


===Finding our target function===
===Finding our target function===
To find our target function, we can refer to the <nowiki>[[Symbol Map]]</nowiki> to see the address for the specific function. In our case, the symbol is <code>shouldHurryUp__11MusicPlayerFv</code> which corresponds to <code>0xF5783D8</code>. Let's make a hook to disable it!
To find our target function, we can refer to the [[Symbol Map]] to see the address for the specific function. In our case, the symbol is <code>shouldHurryUp__11MusicPlayerFv</code> which corresponds to <code>0xF5783D8</code>. Let's make a hook to disable it!

===Patching the function===
===Patching the function===
To try and disable the function, we can try and insert a <code>nop</code> function that does nothing. To do this first we create a YAML file called <code>nohurryup.yaml</code>. Inside it, we can insert the following lines of code:
To try and disable the function, we can try and insert a <code>nop</code> function that does nothing. To do this first we create a YAML file called <code>nohurryup.yaml</code>. Inside it, we can insert the following lines:<syntaxhighlight lang="yaml" line="1">
---

Files: []
<code>---</code>
Hooks:

- type: nop
<code>Files: []</code>
addr: F5783D8

<code>Hooks:</code>
</syntaxhighlight>What this does is replace the instruction at address <code>F5783D8</code> with a <code>nop</code> instruction which does nothing. This should work right? Well, let's test it out.

<code>- type: nop</code>

<code>addr: F5783D8</code>

What this does is replace the instruction at address F5783D8 with a <code>nop</code> instruction which does nothing. This should work right? Well, let's test it out.


(insert video of crash)
(insert video of crash)
Line 40: Line 34:
The correct way of doing this, is to instead do a <code>blr</code> instruction, which will skip the function and return. The thing is, the function returns a bool (a 1 or a 0), but a blr would just return what is in register 3 (the return register). So what we need to do is set register 3 to zero, or <code>0x0</code> and ''then'' return with <code>blr</code>. Another issue we will run into is that a YAML hook cannot just do this by itself. For that we will need a <code>.S</code>, or '''assembly''' file.</code>
The correct way of doing this, is to instead do a <code>blr</code> instruction, which will skip the function and return. The thing is, the function returns a bool (a 1 or a 0), but a blr would just return what is in register 3 (the return register). So what we need to do is set register 3 to zero, or <code>0x0</code> and ''then'' return with <code>blr</code>. Another issue we will run into is that a YAML hook cannot just do this by itself. For that we will need a <code>.S</code>, or '''assembly''' file.</code>
====Creating the assembly file====
====Creating the assembly file====
Let's create a file in /source/ called <code>nohurryup.S</code>. The assembly we will be writing is quite simple. All it has to do is set register 3 to 0x0 and then return. In addition to that we also need to add some setup lines.
Let's create a file in /source/ called <code>nohurryup.S</code>. The assembly we will be writing is quite simple. All it has to do is set register 3 to 0x0 and then return. In addition to that we also need to add some setup lines.<syntaxhighlight lang="asm" line="1">
.text


.include "asmsetup.S"
<code>.text</code>


.global NoHurryUp
NoHurryUp:
li r3, 0x0
blr


</syntaxhighlight>Let's break down what this does. The <code>.text</code> indicates that the following is code to be executed. The <code>.include</code> will include the <code>asmsetup.S</code> file into our own file. The NoHurryUp label contains a load immediate (<code>li</code>) instruction that sets register 3 to 0x0, or <code>00 00 00 00</code>, and then it has a <code>blr</code> instruction that returns back to the link register. The <code>.global</code> means that the NoHurryUp label will be accessible from anywhere. Don't forget to end the file in a newline! (If you're confused, feel free to download the completed source files. ''YAML'', and ''Assembly''. (dead links)
<code>.include "asmsetup.S"</code>


<code>.global NoHurryUp</code>

<code>NoHurryUp:</code>

<code>li r3, 0x0</code>

<code>blr</code>

Let's break down what this does. The <code>.text</code> indicates that the following is code to be executed. The <code>.include</code> will include the <code>asmsetup.S</code> file into our own file. The NoHurryUp label contains a load immediate (<code>li</code>) instruction that sets register 3 to 0x0, or <code>00 00 00 00</code>, and then it has a <code>blr</code> instruction that returns back to the link register. The <code>.global</code> means that the NoHurryUp label will be accessible from anywhere. Don't forget to end the file in a newline! (If you're confused, feel free to download the completed source files. [https://cdn.discordapp.com/attachments/814594642595151902/819025080716886016/nohurryup.yaml YAML], and [https://cdn.discordapp.com/attachments/814594642595151902/819025026463694859/nohurryup.S Assembly].


====Creating the hook====
====Creating the hook====
Now instead of having the code in the YAML, lets include the <code>nohurryup.S</code> file that we just created. In the YAML write the following code:
Now instead of having the code in the YAML, lets include the <code>nohurryup.S</code> file that we just created. In the YAML write the following:<syntaxhighlight lang="yaml" line="1">


---
Files: [source/nohurryup.S]
Hooks:
- type: branch
instr: b
func: NoHurryUp
addr: F5783D8


</syntaxhighlight>What does this code do exactly? The <code>Files:</code> includes the nohurryup.S assembly file that we just created, from the path <code>source/</code>. The <code>Hooks:</code> section is a bit more complicated though. First we declare the type to be <code>branch</code>, because we will be branching to a different part of the code (The possible types are <code>patch</code>, <code>nop</code>, <code>branch</code>, and <code>funcptr</code>). The instruction is <code>b</code> instead of <code>bl</code> because we want it to branch without a link register so when we do <code>blr</code> it will return to the function that called the music speedup function, and not just return to the music speedup function. The function (label) it will branch to is <code>NoHurryUp</code> as that is what we named our function to be in the assembly. Finally, the address is <code>F5783D8</code> because that is what the address for the target function was in the symbol map. Make sure to include the YAML in <code>project.yaml</code> too. Let's compile and test it out!
<code>---</code>

<code>Files: [source/nohurryup.S]</code>

<code>Hooks:</code>

<code>- type: branch</code>

<code>instr: b</code>

<code>func: NoHurryUp</code>

<code>addr: F5783D8</code>

What does this code do exactly? The <code>Files:</code> includes the nohurryup.S assembly file that we just created, from the path <code>source/</code>. The <code>Hooks:</code> section is a bit more complicated though. First we declare the type to be <code>branch</code>, because we will be branching to a different part of the code (The possible types are <code>patch</code>, <code>nop</code>, <code>branch</code>, and <code>funcptr</code>). The instruction is <code>b</code>, because we want it to branch unconditionally no matter what. The function (label) it will branch to is <code>NoHurryUp</code> as that is what we named our function to be in the assembly. Finally, the address is <code>F5783D8</code> because that is what the address for the target function was in the symbol map. Make sure to include the YAML in <code>project.yaml</code> too. Let's compile and test it out!


===Conclusion and Review===
===Conclusion and Review===
<youtube align="default" size="nes">uS3-trjqwQM</youtube>
(insert video of it working)


So, what did we learn? First we have to find the address for our target function, preferably from the symbol map. Next we create a .S assembly file to patch the function with our desired effects. Finally, we include the assembly file in our YAML hook with the correct type, instruction, function, and address.
So, what did we learn? First we have to find the address for our target function, preferably from the symbol map. Next we create a .S assembly file to patch the function with our desired effects. Finally, we include the assembly file in our YAML hook with the correct type, instruction, function, and address.

[[Category:Guides]]
[[Category:Misc]]

Latest revision as of 21:14, 16 March 2024

Warning The information in this page is outdated and may be incorrect.

In order to do very low-level modifications to the game, C++ cannot just be used by itself. For these purposes we need assembly, or "ASM" hacks to patch or alter functions in the code. The game uses 32-bit PowerPC assembly code, so that is what all patches will need to be written in. To introduce you to the basic ASM build system, we will be making a small patch to disable the music speedup after 100 seconds.

Requirements[edit | edit source]

  • Setup a custom code environment
  • asmsetup.S (dead link)

Steps[edit | edit source]

All assembly hacks contain a YAML file, which contains hooks that will patch areas of the code to have branch instructions to our custom functions. These hooks can also do some basic tasks by themselves, but for more complex tasks, a .S file is also necessary, which contains pure assembly.

Preparation[edit | edit source]

Before we start creating our patch, first we need to include the asmsetup.S file in our project. Simply download the file from here (Dead link), and place it in your /include/ directory in the project files.

Finding our target function[edit | edit source]

To find our target function, we can refer to the Symbol Map to see the address for the specific function. In our case, the symbol is shouldHurryUp__11MusicPlayerFv which corresponds to 0xF5783D8. Let's make a hook to disable it!

Patching the function[edit | edit source]

To try and disable the function, we can try and insert a nop function that does nothing. To do this first we create a YAML file called nohurryup.yaml. Inside it, we can insert the following lines:

---
Files: []
Hooks:
  - type: nop
    addr: F5783D8

What this does is replace the instruction at address F5783D8 with a nop instruction which does nothing. This should work right? Well, let's test it out.

(insert video of crash)

It seems like this just crashes the game. Why is this so?

Patching the function (the correct way)[edit | edit source]

(insert technical reason of why this doesn't work)

The correct way of doing this, is to instead do a blr instruction, which will skip the function and return. The thing is, the function returns a bool (a 1 or a 0), but a blr would just return what is in register 3 (the return register). So what we need to do is set register 3 to zero, or 0x0 and then return with blr. Another issue we will run into is that a YAML hook cannot just do this by itself. For that we will need a .S, or assembly file.

Creating the assembly file[edit | edit source]

Let's create a file in /source/ called nohurryup.S. The assembly we will be writing is quite simple. All it has to do is set register 3 to 0x0 and then return. In addition to that we also need to add some setup lines.

.text

.include "asmsetup.S"

.global NoHurryUp
NoHurryUp:
    li  r3, 0x0
    blr

Let's break down what this does. The .text indicates that the following is code to be executed. The .include will include the asmsetup.S file into our own file. The NoHurryUp label contains a load immediate (li) instruction that sets register 3 to 0x0, or 00 00 00 00, and then it has a blr instruction that returns back to the link register. The .global means that the NoHurryUp label will be accessible from anywhere. Don't forget to end the file in a newline! (If you're confused, feel free to download the completed source files. YAML, and Assembly. (dead links)

Creating the hook[edit | edit source]

Now instead of having the code in the YAML, lets include the nohurryup.S file that we just created. In the YAML write the following:

---
Files: [source/nohurryup.S]
Hooks:
  - type: branch
    instr: b
    func: NoHurryUp
    addr: F5783D8

What does this code do exactly? The Files: includes the nohurryup.S assembly file that we just created, from the path source/. The Hooks: section is a bit more complicated though. First we declare the type to be branch, because we will be branching to a different part of the code (The possible types are patch, nop, branch, and funcptr). The instruction is b instead of bl because we want it to branch without a link register so when we do blr it will return to the function that called the music speedup function, and not just return to the music speedup function. The function (label) it will branch to is NoHurryUp as that is what we named our function to be in the assembly. Finally, the address is F5783D8 because that is what the address for the target function was in the symbol map. Make sure to include the YAML in project.yaml too. Let's compile and test it out!

Conclusion and Review[edit | edit source]

So, what did we learn? First we have to find the address for our target function, preferably from the symbol map. Next we create a .S assembly file to patch the function with our desired effects. Finally, we include the assembly file in our YAML hook with the correct type, instruction, function, and address.