Skip to content

Commit 9fc9632

Browse files
committed
type up first decomp guide
1 parent 9a65732 commit 9fc9632

File tree

7 files changed

+279
-7
lines changed

7 files changed

+279
-7
lines changed

.vscode/settings.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
"decomp",
44
"decompiled",
55
"Ghidra",
6+
"mwcceppc",
67
"objdiff",
78
"rodata",
89
"sbss",

src/decomp-guide/main.typ

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,19 @@
11

22
#let functions = (
3-
("The Simplest Function: Nothing", <fn.nothing>),
4-
("Returning Values", <fn.return>),
5-
("A Function with Some Logic", <fn.nothing>),
6-
("A Function with a For Loop", <fn.for>),
7-
("A Function with a Switch Statement", <fn.switch>),
8-
("A Large Function", <fn.large>),
3+
("The Simplest Function: Nothing", <fn.nothing>, "nothing.typ"),
4+
("Returning Values", <fn.return>, "return.typ"),
5+
("A Function with Some Logic", <fn.small>, "return.typ"),
6+
("A Function with a For Loop", <fn.for>, "return.typ"),
7+
("A Function with a Switch Statement", <fn.switch>, "return.typ"),
8+
("A Large Function", <fn.large>, "return.typ"),
99
)
1010

1111

12+
1213
= Decompilation Guides
1314

15+
Welcome to the exciting part of the book!
16+
We finally get to get our hands dirty and start decompiling some code.
1417
This chapter is going to walk you through the process of decompiling
1518
#functions.len() functions.
1619
They are going to start off as easy as possible
@@ -23,6 +26,6 @@ C++ language features into assembly language.
2326
#let i = 1
2427
#for value in functions [
2528
== #i. #value.at(0) #value.at(1)
26-
#lorem(20)
29+
#include value.at(2)
2730
#(i += 1)
2831
]

src/decomp-guide/nothing.typ

Lines changed: 265 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,265 @@
1+
2+
We're going to start off by decompiling
3+
the simplest type of function in the game:
4+
A function that does nothing.
5+
6+
An empty function is a function that has no logic.
7+
It literally doesn't do anything.
8+
In C++ a function that does nothing could look like this:
9+
10+
#grid(
11+
columns: (50%, 50%),
12+
```cpp
13+
void DoNothing()
14+
{
15+
}
16+
```,
17+
```cpp
18+
void DoNothing()
19+
{
20+
return;
21+
}
22+
```
23+
)
24+
25+
Note that we can choose whether or not to write the `return;` keyword.
26+
It doesn't make a difference whether we write it out or not.
27+
28+
#grid(
29+
columns: (50%, 50%),
30+
[
31+
Since the function is void, nothing is returned,
32+
so both of these functions
33+
are compiled down to a single `blr` assembly instruction:
34+
],
35+
image("nothing/nothing.png")
36+
)
37+
38+
What does the assembly instruction `blr` mean?
39+
40+
#v(0.5cm)
41+
/ blr: "Branch to Link Register". Jumps to lr. Used to end a subroutine.
42+
#v(0.5cm)
43+
44+
What is a Link Register?
45+
46+
_A link register (LR for short) is a register which holds the address to return to when a subroutine call completes. This is more efficient than the more traditional scheme of storing return addresses on a call stack, sometimes called a machine stack. The link register does not require the writes and reads of the memory containing the stack which can save a considerable percentage of execution time with repeated calls of small subroutines.
47+
The IBM POWER architecture, and its PowerPC and Power ISA successors, have a special-purpose link register, into which subroutine call instructions put the return address._
48+
#footnote("https://en.wikipedia.org/wiki/Link_register")
49+
50+
So the `lr` register is special and holds the return address for the CPU to
51+
jump back to when the current subroutine finishes.
52+
This means that every function in the game is going to end with a `blr` instruction.
53+
54+
This example function `DoNothing` is only made up of one instruction.
55+
Since every PowerPC assembly instruction is 4 bytes in size,
56+
The total size of this function is 4 since it is just one `blr` instruction.
57+
Size 4 functions are the smallest functions you will find.
58+
59+
Fun fact: There are 318 functions in the game that do nothing.
60+
If we add up their size,
61+
we get a total size of $318 * 4 = 1272$ bytes.
62+
One other way of saying this is that
63+
$0.07%$ of the entire game's code does nothing!
64+
65+
Since we have a general idea of what an empty function is like,
66+
let's now decompile an empty function in BFBB.
67+
68+
==== Our First Function -- NPCWidget::Reset()
69+
We are going to look at the function `NPCWidget::Reset()`.
70+
It is a size 4 function located in the file
71+
`/Game/zNPCSupport.cpp`.
72+
73+
If we open up `zNPCSupport` in Objdiff and click on `NPCWidget::Reset()`,
74+
we can see the original assembly on the left, and nothing on the right.
75+
76+
#image("nothing/reset.png")
77+
78+
We can see that the original assembly on the left just has one instruction,
79+
a `blr` instruction like we expect.
80+
When the right side says "Missing", this means that
81+
we have yet to define the function in our game source file.
82+
This is to be expected at this point because we haven't decompiled this function yet.
83+
84+
Let's go ahead and define this function in our C++ source file `zNPCSupport.cpp`:
85+
86+
```cpp
87+
void NPCWidget::Reset()
88+
{
89+
}
90+
```
91+
92+
Great! We've defined our function.
93+
When we go back and look at Objdiff,
94+
it looks like there was an error compiling `zNPCSupport.cpp`:
95+
96+
```
97+
### mwcceppc.exe Compiler:
98+
# File: src\SB\Game\zNPCSupport.cpp
99+
# ------------------------------------
100+
# 25: void NPCWidget::Reset()
101+
# Error: ^^^^^^^^^
102+
# undefined identifier 'NPCWidget'
103+
# Too many errors printed, aborting program
104+
```
105+
106+
The error is pretty straight-forward.
107+
The compiler can't find any kind of definition for the type `NPCWidget`.
108+
109+
*Classes and Member Functions*
110+
111+
This function isn't _quite_ as simple as our example `DoNothing` function we saw earlier.
112+
In this case, `Reset()` is actually a member function of the `NPCWidget` class,
113+
which is why we see the scope resolution operator, AKA double-colon (`::`) in `NPCWidget::Reset()`.
114+
115+
We need to define the type of `NPCWidget`.
116+
117+
// TODO: replace this link with the proper dwarf section
118+
We can search all of the files in the BFBB repository and we can see that
119+
we haven't yet defined `NPCWidget` in any of our source headers.
120+
This means that we need to add it ourselves.
121+
122+
But how do we know what the type of `NPCWidget` is?
123+
To answer this question, we're going to reference the PS2 DWARF Data.
124+
If we search for `NPCWidget` in the PS2 DWARF data file, (defined in Section TODO)
125+
We can see the definition for the class here:
126+
127+
```cpp
128+
class NPCWidget {
129+
// total size: 0xC
130+
public:
131+
enum en_NPC_UI_WIDGETS idxID; // offset 0x0, size 0x4
132+
class xBase * base_widge; // offset 0x4, size 0x4
133+
class zNPCCommon * npc_ownerlock; // offset 0x8, size 0x4
134+
};
135+
```
136+
137+
We can simply copy and paste this into the accompanying header file `zNPCSupport.h`.
138+
After we do this, Objdiff thanks us for our effort by greeting us with a new error:
139+
140+
```
141+
### mwcceppc.exe Compiler:
142+
# In: src\SB\Game\zNPCSupport.h
143+
# From: src\SB\Game\zNPCSupport.cpp
144+
# ------------------------------------
145+
# 22: enum en_NPC_UI_WIDGETS idxID; // offset 0x0, size 0x4
146+
# Error: ^^^^^
147+
# undefined identifier 'en_NPC_UI_WIDGETS'
148+
# Too many errors printed, aborting program
149+
```
150+
151+
Again, the error message is pretty clear.
152+
We need to define `en_NPC_UI_WIDGETS`.
153+
Once again, we can't find this enum defined anywhere in
154+
our source header files yet, so it means that it hasn't
155+
been copied over yet.
156+
Let's do that now.
157+
Heading back over to the PS2 DWARF file, we can search for
158+
`en_NPC_UI_WIDGETS` and we find this enum:
159+
160+
```cpp
161+
enum en_NPC_UI_WIDGETS {
162+
NPC_WIDGE_TALK = 0,
163+
NPC_WIDGE_NOMORE = 1,
164+
NPC_WIDGE_FORCE = 2,
165+
};
166+
```
167+
168+
Once again, we want to copy this type over into our `zNPCSupport.h` file.
169+
We have to make sure that we put this definition before the definition of
170+
`NPCWidget`, as that class references the enum.
171+
172+
Back in Objdiff, unsurprisingly, we have another error:
173+
```
174+
### mwcceppc.exe Compiler:
175+
# File: src\SB\Game\zNPCSupport.cpp
176+
# ------------------------------------
177+
# 26: {
178+
# Error: ^
179+
# undefined identifier 'Reset'
180+
# Too many errors printed, aborting program
181+
```
182+
183+
This one is simple though. It's just saying that
184+
the `Reset()` function isn't defined in `NPCWidget`.
185+
We can fix this by defining the `Reset` method with a `void` return type on our class:
186+
187+
```cpp
188+
class NPCWidget
189+
{
190+
// total size: 0xC
191+
public:
192+
enum en_NPC_UI_WIDGETS idxID; // offset 0x0, size 0x4
193+
class xBase* base_widge; // offset 0x4, size 0x4
194+
class zNPCCommon* npc_ownerlock; // offset 0x8, size 0x4
195+
void Reset();
196+
};
197+
```
198+
199+
When we save this and look at Objdiff now, we finally have no more error messages.
200+
Not only that, but now the function is a 100% match!
201+
202+
#image("nothing/OK.png")
203+
204+
We've done it!
205+
We have successfully decompiled our first function in Battle For Bikini Bottom.
206+
It's a humble little function, but we should be proud nonetheless.
207+
208+
Throughout this process, we have learned quite a few things:
209+
210+
+ How to use Objdiff to view and compare assembly code
211+
+ What our first assembly instruction `blr` means and why it is generated
212+
+ How to copy over the correct class and enum types from the PS2 DWARF data
213+
+ How to define a new class member function
214+
215+
This all might have seemed like a lot of work just to decompile a function
216+
that does literally nothing.
217+
218+
At this point you may have a few questions, such as
219+
220+
1. Is it always this much trouble to simply get a function that does nothing to compile?
221+
222+
The answer to this is that it depends.
223+
It depends largely on the function that you're decompiling and a combination of factors.
224+
If the function is a member of a class, and that class is not defined in a header file
225+
yet, then you will have to define it like we did in this example.
226+
In this case, we also had to recursively define the properties which were included
227+
in the class we added.
228+
You can imagine that in some cases this could become a bit of work.
229+
230+
The same idea also applies for functions that do nothing but accept parameters
231+
who's types are not defined yet.
232+
Consider this example:
233+
```cpp
234+
void xDebugAddTweak(const char*, xVec3*, const tweak_callback*, void*, U32)
235+
{
236+
}
237+
```
238+
This function accepts types such as `xVec3*`, and `tweak_callback*` which are non-primitive types.
239+
We already have these types included in the project header files,
240+
so solving the type errors would be as simple as including the appropriate headers:
241+
```cpp
242+
#include "xVec3.h"
243+
#include "zFX.h"
244+
```
245+
If we didn't already have those types defined in those header files,
246+
you would have to copy the types for these parameters from
247+
the PS2 DWARF again.
248+
This is needed to get the file to compile
249+
despite the fact that the function itself does nothing.
250+
251+
Then of course there are functions like `NPCWidget_Shutdown`
252+
which are not part of a class nor accept any parameters,
253+
so decompiling them is as simple as just writing:
254+
255+
```cpp
256+
void NPCWidget_Shutdown()
257+
{
258+
}
259+
```
260+
261+
And that's that.
262+
263+
2. Why are functions that do nothing even in the game?
264+
265+
This is a commonly asked question

src/decomp-guide/nothing/OK.png

17.1 KB
Loading
7.61 KB
Loading

src/decomp-guide/nothing/reset.png

18.9 KB
Loading

src/decomp-guide/return.typ

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
2+
3+
Hi mom

0 commit comments

Comments
 (0)