News: 11 March 2016 - Forum Rules
Current Moderators - DarkSol, KingMike, MathOnNapkins, Azkadellia, Danke

Author Topic: Trying to get into GBA ROM hacking, any directions for a newcomer?  (Read 3373 times)

LucasRCD

  • Jr. Member
  • **
  • Posts: 23
  • Avatar by @ImmatureWaffles on Twitter
    • View Profile
Re: Trying to get into GBA ROM hacking, any directions for a newcomer?
« Reply #20 on: October 29, 2020, 10:03:38 am »
Alright, I'm back. I actually forgot to do the whole breakpoint thing with the JP meter. I need to ask something before do so, and I can't believe I haven't asked this earlier: What is the second address mean at the bottom right screen? What is that bottom right screen? I may need to revise the way I document things if it turns out I've been misinterpreting what it means.

Also, ninja'd, so I'm gonna add more to this post than I originally intended to.

"I doubt anyone nowadays would see much use in either of those."
That you can not assume, both in general (if nothing else I still get asked for the occasional multiplayer patch if a flash cart is acting up and existing ones still get downloads) and going into the future (oh no android based emulator got bluetooth support for the link cable setup).

Fair point, I just came to that conclusion because expanding the ROM itself didn't cross my mind, mostly because I have no clue how I would do that. It's probably really simple to expand it to 16 MB, but in order to make any proper use of the new space, I'd need to do a bunch of things that are beyond my current level of knowledge. A daunting task, indeed. No idea what you mean by "trimming" a ROM. Wouldn't that require recompiling the ROM, thus necessitating a disassembly of the game?
Lufia afficionado, forum game player. Former SMW hacker.

[Unknown]

  • Jr. Member
  • **
  • Posts: 37
    • View Profile
    • PPSSPP
Re: Trying to get into GBA ROM hacking, any directions for a newcomer?
« Reply #21 on: October 29, 2020, 10:57:43 am »
Alright, I'm back. I actually forgot to do the whole breakpoint thing with the JP meter. I need to ask something before do so, and I can't believe I haven't asked this earlier: What is the second address mean at the bottom right screen? What is that bottom right screen? I may need to revise the way I document things if it turns out I've been misinterpreting what it means.

This is what's called the "stack".

As I'd mentioned, there are 16 registers - hands of the octopus.  And memory is where things go when you don't need them in your hand right now.  Stack is just memory, but it's a "special" kind of memory just by convention.  There's nothing actually special about it, except the way game code uses it.

Everything I'm talking about now is a "convention".  I mention this because a programmer can do whatever they want.  If some developer working on Lufia decided to hand-write some assembly for an important function of the game, they could've not followed these conventions at all.  But for 95%+ of code, they'll be followed.

So, imagine a function call.  Let's take something simple, like "a = pow(b, c)".  This function takes b to the power of c, and returns it in a.  There's no single instruction for it (like "pow r0, r1, r2"), it requires a bunch of instructions.

The assembly for pow() would be "bl 8123456h" (address is an example.)

But, how does it know which things to multiply and where to put the result?  Convention.

We call the inputs to a function "arguments" or "parameters".  They should be r0, r1, r2, and r3.  In this case, there are only two, so r0 and r1.  If there are more than 4, it uses the stack but don't worry about this for now.

The result is then returned in r0.  So now we know pow() would look like this:

Code: [Select]
mov r0,b
mov r1,c
bl pow
mov a,r0

But, what if you had something important in r0 already?  Or what if you had important things in other registers?  This is just a jump, really, a "Branch and Link".  If pow makes a bunch of changes to registers, you'll lose their values.

This is where the stack comes in.  You save the registers you care about on the stack.  Here's the convention:

r0-r3: Arguments / return values.
r4-r11: "Callee saved".  Callee means the function itself.  If pow() wants to use these registers, it must make sure it saves them and puts them back the way it found them.

r12: "Callee saved".  This is a special temporary register.
r13: Stack pointer.  This is the address of the stack (more on that in a bit.)
r14: Link register, technically callee saved.  This is the calling code to return to.
r15: Program counter.  Code address to execute soon.

Let's say pow is complicated.  You might see this code in it:

Code: [Select]
push r4-r7,r14

... code for pow(r0, positive r1) and pow(r0, negative r1) ...

pop r4-r7,r15

In many ways, "push" is like str.  In fact, it's technically stm (store multiple.)  It does the following:

 * Decreases the value of sp (aka r13) by enough for the registers passed.  In this case, 20 bytes.
 * Supports ranges for r0-r7 only, and can specially do r14.  If you want to push r8, you'd move it to another register first.
 * Stores each register in that space, i.e. "str r4,[sp,0]" and "str r14,[sp,16]".

The pop instruction is similar, in reverse.  It's like ldr, where it reads from the stack.

So now finally to your screenshot:
https://cdn.discordapp.com/attachments/769286995779780689/771367803067432970/unknown.png

03007C00 is the current value of sp.  It started as a higher value, and goes downward as more functions are called, then back upward when they return.

If you notice 03007C28 says "Pushed r7".  That means this was stored by "push r7", or actually a "push r4-r7" if you look further down.  The extra r5, r6, r7 are probably actually r8-r10 moved to those registers.  This is very common.

The "Return from Lxx_8001a5Ch" is the r14 pushed on the stack.

"Allocated" means that the stack value was changed without using push.  For example:

Code: [Select]
push r4-r7,r14
mov r4,r8
mov r5,r9
mov r6,r10
push r4-r6
sub sp,sp,16

You would do this if you needed a quick "scratchpad" to save registers while running numbers.  Maybe your math formula is complicated, and using all of r0-r10 (11 registers) isn't enough.  So you scribble some things down into that allocated memory, temporarily.

Very important things to understand about stack:

 * It's temporary.  As soon as pow() is done, another function will use these addresses and overwrite it.
 * The address might change.  pow() might be called by different people - some might allocate more or less stack.  So the addresses pow() sees for sp are not consistent.

The second column there, like on the left, is the value stored at that address.  I'm really burying the lead here, but the above is important context for this fact.

If you see an important/useful value on the bottom right, the address is still not safe to say "this is where the game stores JP".  Even a hack you apply to another function might change that address.  It's just a temporary scratch location.

Fair point, I just came to that conclusion because expanding the ROM itself didn't cross my mind, mostly because I have no clue how I would do that. It's probably really simple to expand it to 16 MB, but in order to make any proper use of the new space, I'd need to do a bunch of things that are beyond my current level of knowledge. A daunting task, indeed. No idea what you mean by "trimming" a ROM. Wouldn't that require recompiling the ROM, thus necessitating a disassembly of the game?

You can basically just make the file larger, like using a hex editor or with ".org" in armips.
https://github.com/Kingcom/armips#set-the-output-position

-[Unknown]

FAST6191

  • Hero Member
  • *****
  • Posts: 2965
    • View Profile
Re: Trying to get into GBA ROM hacking, any directions for a newcomer?
« Reply #22 on: October 29, 2020, 11:15:14 am »
Trimming a ROM is something many flash cart users will do.

Generally speaking chips to store things on at the time at least came in power of 2 size progression (1,2,4,8,16,32,64....) and ROM dumpers would dump the whole lot. The game itself is not obligated to take up that full amount though so you can then take off the end part (trim it off if you will) and go from there. There is no value in the header but 99.999% of games will be either 00 or FF so a trimmer will work backwards to the first thing that is not 00/FF and chop it from there. It can cause problems in some cases (00 and FF are both valid things to put in a ROM, one of the Teenage Mutant Ninja Turtles being one of the examples if someone wants one) so some will skip ahead a few hundred bytes just in case.
Anyway trimming one game might get you something (we have had a few games be 256Mbit titles but only use about 140) but it is more that doing it for 30 or so to load a flash cart with gains you enough space to fit another game or two on. Today yeah SDHC means you can probably roll around with the entire ROM set, emulator set for everything the GBA emulates, all the homebrew and all the ROM hacks whilst still having room left over (depending upon how much you use the video and music homebrew anyway) but that is not everybody and even those that do have SDHC still appreciate a smaller ROM in some instances (there are often fast internal memory sections).

Now if you wanted to do a ROM rip wherein junk, or "junk", files were taken out of the ROM to reduce size (seen on many PC games, original xbox games, some Wii stuff, the DS and some other things besides) then yeah as the GBA is without a file system (unlike everything on that list in the previous bracketed section) that would be a nightmare project unless it so happens the junk is on the end of the ROM. A full decompilation (such that it ever could be on a GBA -- plenty of in line assembly on the GBA) is probably a bit excessive but would work.

As for difficulty in expansion.
Make blank file full of 00 of suitable size.
Add blank file to end of ROM. Copy and paste with a hex editor maybe, though the command line "copy /b file1.gba+blankfile.file expandedrom.gba" is what I normally use.

If you opted for the "meh I will just make a 32 meg 00 filled file and chop it back down afterwards" then chop it back down to your chosen size.

Again there are no header values, no ROM type/mapper/mbc/pages/... to change or expect fallout from. Add the space and it is there to use on any ROM you like.
You don't need to do anything you were not already doing -- pointers and maths on them work just the same*, jumps in the assembly work just the same, all internal functions as far as DMA/BIOS/SWI and memory copying work just the same...


*depending upon what guide you read then you might have read something like "all GBA ROM pointers start with 08" which is a decent enough rule of thumb (few things use the different waitstate mirrors, and most ROMs are 16 megabytes or less and thus contained within 08000000 through 08FFFFFF and thus don't need the 09 range or equivalent higher mirrors), indeed I will often search for 08 and if I see a whole sea of them mostly some set distance apart (08080808 is a valid address after all, indeed more likely than many odd ones) then I will take a look as I probably just found a pointer table which usually contains something good (even if only to eliminate from the search for something else -- if you found the music and graphics pointers then you can eliminate those regions from your text search).

LucasRCD

  • Jr. Member
  • **
  • Posts: 23
  • Avatar by @ImmatureWaffles on Twitter
    • View Profile
Re: Trying to get into GBA ROM hacking, any directions for a newcomer?
« Reply #23 on: October 29, 2020, 01:15:14 pm »
Hmm, so basically that second column isn't the part of the ROM it's pulling the information from? I've noticed before that EXP and Gold gains end up calling one thing in common, before going about the rest of their functions. I'll see if I can find some stray free space within the ROM, otherwise I'll have to do some ROM witchcraft to achieve the extra space (it at least sounds like it to me, but it's probably more a matter of patience than anything). Maybe my best hope for this would be to put up a "help wanted" post, in the worst case scenario.

On a tangential note, I just realized how much of a mess my virtual work space. I ended up accidentally making the unmodified ROM of the game blank. I should store these altered ROMs somewhere else.
Lufia afficionado, forum game player. Former SMW hacker.

FAST6191

  • Hero Member
  • *****
  • Posts: 2965
    • View Profile
Re: Trying to get into GBA ROM hacking, any directions for a newcomer?
« Reply #24 on: October 29, 2020, 01:49:27 pm »
You are seemingly grasping the fundamentals of assembly and program flow in that yet expansion seems hard? That is bizarre to me.

It really is a matter of add extra data to the end of the ROM containing all 00 hex. Best to have it line up with the 4,8,16 or 32 megabyte mark if aiming for that professional look and it tops out at 32 for most purposes. No size values nor end of file limits in any kind of header or ROM description to worry about (such a thing is actually one of the harder parts when it comes to dumping GBA games as you then have to figure out how big it should be).

In older systems it is potentially a pain as you have to deal with sections being switched in and out at will of the game such that you can never be sure it is there, or have to swap out, or have to make room in the area you want it in (which may be easier said than done if the devs used it all).
In the GBA the entire ROM is present in the memory at all points and suffers no penalty from jumping from something in the first two megs to the last two from one instruction to the next.
If you can change pointers to house your next code/graphics/music/text/whatever alteration in some reclaimed space, or simply to fix it if you altered lengths of text strings, then it is the exact same logic with the space you added to the ROM (find new location in the ROM you are using/want to use, add location value to 08000000h, this is your pointer, overwrite old pointer with newly generated value. If it is one of those rare occasions when you are not using the primary 08-09 ROM mirror then instead of 08000000 then you pick the location it uses, though frankly in most cases 08000000 will still work as it is still the ROM, just accesses at a higher priority).

LucasRCD

  • Jr. Member
  • **
  • Posts: 23
  • Avatar by @ImmatureWaffles on Twitter
    • View Profile
Re: Trying to get into GBA ROM hacking, any directions for a newcomer?
« Reply #25 on: October 29, 2020, 02:07:06 pm »
Maybe saying it's "hard" is a bit of an exaggeration on my part. I should probably be using "daunting", which would be more appropriate. I keep assuming performing these tasks would be much more complicated than they actually are. Like always, can't really confirm if it actually is until I try. Which also reminds me that I need to try the rest of the code stuff. You guys have no idea how much you're helping me, I appreciate the patience! :angel:

I'll give expanding the ROM to 16 MB a shot. Inserting the blank space at the end of the ROM isn't hard at all, what I still have doubts about is with shifting data around and what parts of the ROM constitutes what, but that'll be up to me to figure out and get the hang of.

October 29, 2020, 02:29:31 pm - (Auto Merged - Double Posts are not allowed before 7 days.)
...I didn't even have to search that hard to find that there are a couple chunks of free space on the ROM (just a bunch of chunks filled with nothing but 00's). In fact, I can find a lot of them starting with 0067C60 thanks to HxD, with a couple of stray chunklets of filled bytes. I could still make the ROM 16 MB but I doubt it'd be of much use for the things I'm trying to do.
« Last Edit: October 29, 2020, 02:29:31 pm by LucasRCD »
Lufia afficionado, forum game player. Former SMW hacker.

[Unknown]

  • Jr. Member
  • **
  • Posts: 37
    • View Profile
    • PPSSPP
Re: Trying to get into GBA ROM hacking, any directions for a newcomer?
« Reply #26 on: October 29, 2020, 03:50:05 pm »
Be warned, 00s are not always unused.  For example, games will sometimes use fixed-length strings padded out with 0s.  You might end up adding weird text at the end of item descriptions or something if it's actually that.

There may indeed be unused space, though.  Just warning that a bunch of 00s could be either.

-[Unknown]

LucasRCD

  • Jr. Member
  • **
  • Posts: 23
  • Avatar by @ImmatureWaffles on Twitter
    • View Profile
Re: Trying to get into GBA ROM hacking, any directions for a newcomer?
« Reply #27 on: October 29, 2020, 03:51:38 pm »
So wait, if the whole ROM is available at all times, then how can I feasibly branch into the expanded part if there's a limit to how far a branch can go?

I tried going the other route, of adding free space, but I have no idea what to do next. The game doesn't boot up. I think headers in this game may be marked with "estpolis_gaiden" text, because otherwise I have no idea where they could be? This same string is repeated a couple of times in the ROM. Searching for a sea of 08's doesn't yield any satisfactory results. Do I need to add free space before headers? I legit have no idea.

October 29, 2020, 04:06:34 pm - (Auto Merged - Double Posts are not allowed before 7 days.)
Nevermind, it appears it only appears in areas of the ROM related to the debug mode.
« Last Edit: October 29, 2020, 04:06:34 pm by LucasRCD »
Lufia afficionado, forum game player. Former SMW hacker.

FAST6191

  • Hero Member
  • *****
  • Posts: 2965
    • View Profile
Re: Trying to get into GBA ROM hacking, any directions for a newcomer?
« Reply #28 on: October 29, 2020, 05:04:51 pm »
If for some reason you are limited jump and jump again if you really want, though straight ARM jumps/branches have a 32 meg window.
http://problemkaputt.de/gbatek.htm#armopcodesbranchandbranchwithlinkbblbxblxswibkpt
Though get a bit creative and you could probably pull it off in THUMB as well http://problemkaputt.de/gbatek.htm#thumbopcodesjumpsandcalls .

You added blank data to the end of the ROM and it did not boot? I have had issues from trimmed ROMs before but adding stuff and it not working is very new here. Not sure what you did other than make it some kind of silly large size that confused the emulator (which if you were anywhere near 16 megs should not be the case).

As far as headers I presume you mean you are looking for some kind of indicator the data to follow is a text string or whatever. They don't have to such things, indeed it is rare for it to do so. Indeed I normally look for end of line markers (or something that is functionally akin to it) and compare those to what I am thinking are the pointers (end of line is usually pointer - say 4 bytes).

LucasRCD

  • Jr. Member
  • **
  • Posts: 23
  • Avatar by @ImmatureWaffles on Twitter
    • View Profile
Re: Trying to get into GBA ROM hacking, any directions for a newcomer?
« Reply #29 on: October 29, 2020, 05:22:57 pm »
I know where I went wrong. It worked fine when I just added the doubled space at the end of the ROM. This is gonna sound ridiculous, but with the way you described things, I thought that if I were to do this, which is to just add empty space at earlier points in the ROM and then just redirecting things later, then things would magically sort themselves out. Maybe it is possible but not with the way I went about it.

If you ignore my gigantic gaffe, then the ROM expansion was a success. It's a good thing I've got backups. Now it's time for me to experiment with writing a patch. Gonna have to read back up a few posts in order to see what I need to do.

October 29, 2020, 07:26:13 pm - (Auto Merged - Double Posts are not allowed before 7 days.)
Code: [Select]
EWRAM 0203D20C = Eldin's current JP (4 bytes)
----> 08001AC6 = Jumps here upon killing the last enemy (adds r0,r0,r4)
  \-> 03007C00 = Allocated
----> 08001AD4 = Then jumps here from 08001AC6 (ldr r3,=Lxx_5F5E0FFh)
----> 08001B2A = Then jumps here from 08001AD4 (mov r8,r2)

Did some breakpoint stuff, this was the result. I should probably do this whole documenting thing on the wiki instead of my own threads. I haven't begun work on the patch to try and get the JP meter/JP gains visible yet, I just wanted to collect the data I was overdue first.

October 29, 2020, 08:35:29 pm - (Auto Merged - Double Posts are not allowed before 7 days.)
Alright, so I got some things out of the way. I can finally start making some progress with this. I looked on the previous page for a particular string of code, and decided to alter the header for it. So here's what I've got by replacing the one presented originally with the one I unearthed earlier:

Code: [Select]
ldr r1,=5F5E0FFh ;load address of variable into r1
ldr r0,[r1] ;load what's at address r1, put it into r0
ldr r1,=6001036 ;load address of map spot for new tile into r1
str r0,[r1] ;store value from r0 to address in r1

Do I have to do anything else? Or is this good enough to patch in?
« Last Edit: October 29, 2020, 08:35:29 pm by LucasRCD »
Lufia afficionado, forum game player. Former SMW hacker.

Kajitani-Eizan

  • Hero Member
  • *****
  • Posts: 549
  • You couldn't kill me if I tried to let you
    • View Profile
    • KAJITANI-EIZAN's Patch Site: Reimagination
Re: Trying to get into GBA ROM hacking, any directions for a newcomer?
« Reply #30 on: October 29, 2020, 10:19:19 pm »
That's probably not what you'll want to do at first, especially since you don't have a handy pool available for the addresses.

Try first a very basic thing, like changing what value is added there, e.g.:

Code: [Select]
.open "lufia.gba",08000000h   ; Open ROM, map to 0x08000000 as per typical memory mapping for GBA
.gba                          ; Put armips in GBA mode/THUMB mode

.org 08001AC6h                ; Move insert point to this address
; add r0,r4                   ; Add r4 to r0 (original instruction)
  mov r0,20h                  ; Set value to always be 0x20, instead of adding r0 and r4 together

.close

Put in the appropriate filename for your ROM instead of "lufia.gba" and save as a .asm. Run armips with this .asm file (it will modify your ROM). If that changes the thing, you know it worked, good first step! To change it back, comment out the mov and uncomment the add (move the semicolon from one line to the other).

[Unknown]

  • Jr. Member
  • **
  • Posts: 37
    • View Profile
    • PPSSPP
Re: Trying to get into GBA ROM hacking, any directions for a newcomer?
« Reply #31 on: October 30, 2020, 01:18:18 am »
If you want to jump somewhere far away, first you'd identify somewhere you want to replace.  Let's say there's this function:

Code: [Select]
08069D14 B500     push    r14                                     ;10
08069D16 4B0D     ldr     r3,=3001974h                            ;9
08069D18 7818     ldrb    r0,[r3]                                 ;4
08069D1A 28FF     cmp     r0,0FFh                                 ;2
08069D1C D013     beq     8069D46h                                ;8
08069D1E 480C     ldr     r0,=3001973h                            ;9
08069D20 7800     ldrb    r0,[r0]                                 ;8
08069D22 2801     cmp     r0,1h                                   ;2
08069D24 D10F     bne     8069D46h                                ;8
08069D26 4A0B     ldr     r2,=30018BCh                            ;9
08069D28 490B     ldr     r1,=3001948h                            ;9
08069D2A 7818     ldrb    r0,[r3]                                 ;4
08069D2C 3801     sub     r0,1h                                   ;2
08069D2E 0100     lsl     r0,r0,4h                                ;2
08069D30 6809     ldr     r1,[r1]                                 ;4
08069D32 1809     add     r1,r1,r0                                ;2
08069D34 60D1     str     r1,[r2,0Ch]                             ;5
08069D36 4809     ldr     r0,=3001AD8h                            ;9
08069D38 6001     str     r1,[r0]                                 ;14
08069D3A 7B88     ldrb    r0,[r1,0Eh]                             ;4
08069D3C 7110     strb    r0,[r2,4h]                              ;5
08069D3E 7BC8     ldrb    r0,[r1,0Fh]                             ;4
08069D40 7150     strb    r0,[r2,5h]                              ;5
08069D42 F001F973 bl      806B02Ch                                ;10
08069D46 BC01     pop     r0                                      ;9
08069D48 4700     bx      r0                                      ;8
08069D4A 0000
08069D4C 1974
08069D4E 0300
08069D50 1973
08069D52 0300
08069D54 18BC
08069D56 0300
08069D58 1948
08069D5A 0300
08069D5C 1AD8
08069D5E 0300

Let's suppose that you want to add more code here (such as a bunch of code to write JP to some tiles for BG 0.)  You can't just insert some new code, that would break everything.  Branches would go the wrong places, there'd be mayhem.

But what you can do is replace some code with a large jump.  Most GBA code is Thumb, because ARM code essentially runs at 50% speed on the GBA.  It can be run at full speed by copying it into WRAM and running from there, but you only have so much WRAM, so games typically only do this with performance critical code.

Okay, so let's "insert" some new code near the top of the above function.  We'll target this part:

Code: [Select]
08069D14 B500     push    r14                                     ;10
<-- add new code here
08069D16 4B0D     ldr     r3,=3001974h                            ;9

Since we can't insert, we find some free space at the end for our code... but we can't even insert a branch to go there either - are we stuck?  Nope, we just need to *replace* some code and bring it with us.

First, let's come up with the minimum code we need to get somewhere far away:

Code: [Select]
08069D16  ldr r3,=0x087E8228  ; ldr = 2 bytes
08069D18  mov r15,r3          ; mov = 2 bytes
08069D1A  dh 0x8228           ; first part of constant loaded by ldr above = 2 bytes
08069D1C  dh 0x087E           ; final part of constant loaded by ldr above = 2 bytes

We need 8 total bytes, and our new code would end at 0x08069D1E.  Note that we have to include the constant for where we're jumping.  Everything takes space.

There was code there until 0x08069D1E before:

Code: [Select]
08069D14 B500     push    r14                                     ;10
=== We're replacing this part:
=== 08069D16 4B0D     ldr     r3,=3001974h                            ;9
=== 08069D18 7818     ldrb    r0,[r3]                                 ;4
=== 08069D1A 28FF     cmp     r0,0FFh                                 ;2
=== 08069D1C D013     beq     8069D46h                                ;8
===
08069D1E 480C     ldr     r0,=3001973h                            ;9

Bad Things will happen if we just delete that old code, so we'll bring it with us to our new home.  Here's the code we'll jump to... so far doing nothing useful beyond the original game's code:

Code: [Select]
ldr r3,=0x03001974
ldrb r0,[r3]
cmp r0,0xFF

bne @@dontbeq
ldr r0,0x08069D46
mov r15,r0

@@dontbeq:
ldr r0,0x08069D1E
mov r15,r0

.pool

Wait, you say.  This is way more complex than those 4 lines.  But, see, I picked 4 harder to replace instructions on purpose to show you: there was a beq there.  beq is an instruction that can't jump all that far, so I had to replace it with a jump that can go the distance.

I swapped the logic around, doing a shorter bne to skip the longer code I need to beq.  beq is the opposite of bne, so that's safe to do.

So far, that new code does nothing.  I've just managed to make space where I can finally insert things.  Now let's insert something:

Code: [Select]
ldr r3,=0x03001974
ldrb r0,[r3]

; INSERTED CODE:
push r1
mov r1,0x02012345
strb r0,[r1]
pop r1
; END OF INSERTED CODE

cmp r0,0xFF

bne @@dontbeq
ldr r0,0x08069D46
mov r15,r0

@@dontbeq:
ldr r0,0x08069D1E
mov r15,r0

.pool

Finally, I've done something useful.  Well, maybe useful, it's just an example.  A more likely story might be logging:

https://problemkaputt.de/gbahlp.htm#debugmessages

But I could write out the JP value here.  That's what I'd do, but it might not be for the faint of heart.

A more common tactic is to compile some code using C or similar, and then "bl" there.  It's the same idea really, you'd just insert a "bl myfunc" (to your C function) in that same place.

-[Unknown]

FAST6191

  • Hero Member
  • *****
  • Posts: 2965
    • View Profile
Re: Trying to get into GBA ROM hacking, any directions for a newcomer?
« Reply #32 on: October 30, 2020, 06:06:16 am »
Most GBA code is Thumb, because ARM code essentially runs at 50% speed on the GBA.  It can be run at full speed by copying it into WRAM and running from there, but you only have so much WRAM, so games typically only do this with performance critical code.

I am not convinced of that one.

There is certainly cause to learn both and expect to see both in any given game but most times I have gone to either hardcode a cheat, trace down, tweak a game just slightly so, fiddle with vblanks, or maybe have some fun function I encounter it as ARM mode. Thumb is great for injecting things into a game though where you have limited space/execution time.

I am not sure what the GBA duplicates list is at these days but that might actually make an interesting study if we are going to head towards whole ROM set analysis (I still want to see the results of a DS analysis for what uses SDAT sound). If we can figure out a way to differentiate between housekeeping and big boy code that might also be nice but that might be easier said than done (idle loops and housekeeping might well be predominantly thumb).

Kajitani-Eizan

  • Hero Member
  • *****
  • Posts: 549
  • You couldn't kill me if I tried to let you
    • View Profile
    • KAJITANI-EIZAN's Patch Site: Reimagination
Re: Trying to get into GBA ROM hacking, any directions for a newcomer?
« Reply #33 on: October 30, 2020, 01:21:20 pm »
Re: adding branches within the game code:

Rather than bothering with all that, I would recommend just identifying some other resource within bl range (e.g. some graphics) and move it to the end of the ROM, changing all references to that resource as well. Then use that space for program code that is in range. Voila, you can just bl straight to the new functions, only 4 bytes needed within the function to be hacked.

If you can only move a very small amount of stuff, or you don't want to move any stuff but you can identify a small amount of space you can use (so, not big enough to store your big new functions)... you can use the space to write veneers that will let you perform the large jump while keeping your actual code relatively clean. For example:

Function to hack in original game code:
Code: [Select]
  (stuff before)
  bl MyFunction  ; overwrites either a different bl or 2 instructions
  (stuff after)

Small island of space:
Code: [Select]
MyFunction:
  ldr r3,=MyFunctionForReal
  bx r3
.pool
(this is more or less what you wrote, but now not in the middle of other code)

End of the ROM:
Code: [Select]
MyFunctionForReal:
  push lr
  (replicate the code you overwrote in the hacked function)
  (do your stuff)
  pop lr
  bx lr

This should work fine as long as you can freely use one of r0-r3 for the veneer. If not, e.g., the function to be hacked was using all those registers, or you are writing a new function that takes more than 3 parameters, the veneer will have to be a bit longer... r12 is explicitly to be used for this purpose and you are not generally expected to preserve its value, but you can't load directly into r12 in THUMB. So maybe something like:

Small island of space:
Code: [Select]
MyFunction:
  push r4
  ldr r4,=MyFunctionForReal
  mov r12,r4
  pop r4
  bx r12
.pool

Just double check that the function you're hacking didn't make temporary use of r12, and you should be good. If it did use r12 and you also can't use any of r0-r3, then the solution will be ugly no matter what.
« Last Edit: October 30, 2020, 02:00:02 pm by Kajitani-Eizan »

[Unknown]

  • Jr. Member
  • **
  • Posts: 37
    • View Profile
    • PPSSPP
Re: Trying to get into GBA ROM hacking, any directions for a newcomer?
« Reply #34 on: October 30, 2020, 01:25:38 pm »
There is certainly cause to learn both and expect to see both in any given game but most times I have gone to either hardcode a cheat, trace down, tweak a game just slightly so, fiddle with vblanks, or maybe have some fun function I encounter it as ARM mode. Thumb is great for injecting things into a game though where you have limited space/execution time.

Sound and vblank code, as well as anything else related to interrupts is likely to be ARM code.  You will also see thunks in Thumb code for functions that run ARM-only instructions.

I am not sure what the GBA duplicates list is at these days but that might actually make an interesting study if we are going to head towards whole ROM set analysis (I still want to see the results of a DS analysis for what uses SDAT sound). If we can figure out a way to differentiate between housekeeping and big boy code that might also be nice but that might be easier said than done (idle loops and housekeeping might well be predominantly thumb).

I wrote a script that (with a little help in some cases it has trouble with, mostly around jump tables) scans for all reachable functions in a GBA ROM image.  This was mainly for investigation of two GBA games I was looking into.  In both cases, almost all the code is Thumb.  In these games (one early GBA lifecycle, another late) I've got a decent picture of every part of the ROM so am pretty sure I'm not missing any code.

Running this same script on Lufia, without enough help (so it's only seen about 75% of the game's code) I get 3643 functions, 99% of which are Thumb.  Even if we assume all of the functions it didn't detect are ARM, it'd still be 75% Thumb.

I've heard there are a few games that make use of ARM and swapping code into RAM, but I doubt Lufia is one of these.  Honestly, the PSP is similar: you can make good optimization of codesize by swapping in/out prx files, but only a small fraction of PSP games do this.

-[Unknown]