• Our software update is now concluded. You will need to reset your password to log in. In order to do this, you will have to click "Log in" in the top right corner and then "Forgot your password?".
  • Welcome to PokéCommunity! Register now and join one of the best fan communities on the 'net to talk Pokémon and more! We are not affiliated with The Pokémon Company or Nintendo.

Help Thread: ASM & Disassembly

Status
Not open for further replies.

Touched

Resident ASMAGICIAN
  • 625
    Posts
    9
    Years
    • Age 122
    • Seen Feb 1, 2018
    An admittedly newbish question, but I suppose that's what the thread is for: Is it possible to edit the data contained in multichoice boxes dynamically in a script through ASM, or is all this information stored strictly in the ROM and therefore unalterable?

    The table for the multichoice boxes is stored in the ROM. However, it is a table of pointers, so you could just point it to a RAM location if you really wanted. Also, it's relatively easy to change the actual command to conditionally load from a RAM location.
     

    colonelsalt

    Guaranteed to raise the smile
  • 111
    Posts
    11
    Years
    The table for the multichoice boxes is stored in the ROM. However, it is a table of pointers, so you could just point it to a RAM location if you really wanted. Also, it's relatively easy to change the actual command to conditionally load from a RAM location.

    Oooh, that is terribly exciting; I figured (from my limited ASM exposure) it was a lost cause -- thanks for clarifying.
     
  • 76
    Posts
    9
    Years
    An admittedly newbish question, but I suppose that's what the thread is for: Is it possible to edit the data contained in multichoice boxes dynamically in a script through ASM, or is all this information stored strictly in the ROM and therefore unalterable?
    What may also be of interest to you is that JPAN's hacked engine already has built-in routines for that. The multichoices 0x20-0x25 now point to a free RAM area, all you need to do is pick the right multichoice ID based on how many options you want, and then add the different options by use of setvar, loadpointer and special. For more precise information, you can check out the instruction manual, which is in the same folder as the patch. So if you don't mind using his base, this should be the easiest way for you!
     

    Lance32497

    LanceKoijer of Pokemon_Addicts
  • 792
    Posts
    9
    Years
    Aaaaaahhhhhh!

    I tried to make a basic routine that stores a byte in a RAM ADDRESS but I can't get it work,

    Spoiler:


    when I call it in a script, nothing happened, nothing changed in 0x2b50000, didn't freeze the game
     
  • 23
    Posts
    9
    Years
    • Seen Sep 2, 2015
    Aaaaaahhhhhh!

    I tried to make a basic routine that stores a byte in a RAM ADDRESS but I can't get it work,

    Spoiler:


    when I call it in a script, nothing happened, nothing changed in 0x2b50000, didn't freeze the game

    "ldrb r0, [r0]" overwrites the value in r0.
    When storing a value, make sure that you have not set any value in the same register as the one you'll use as the address.
    If you're not sure, simply write the address into the register before storing the value.
    If you only want to store a byte without bothering the original value, it's useless to load it.
     

    daniilS

    busy trying to do stuff not done yet
  • 409
    Posts
    10
    Years
    • Seen Jan 29, 2024
    Exactly. You don't need the push and pop either because you can just use bx lr at the end.
     

    colonelsalt

    Guaranteed to raise the smile
  • 111
    Posts
    11
    Years
    So having through some means or another having gotten my hands on a copy of IDA v6.5 and Knizz's FIreRed database, I'm greeted with a prompt that reads: "Sorry, this database has been created by a pirate version of IDA".
    What do I make of this? From what I understand, Knizz wrote the newest version of his database for v6.5, but would I be better off trying to load it into an older version to prevent this from happening?
     

    daniilS

    busy trying to do stuff not done yet
  • 409
    Posts
    10
    Years
    • Seen Jan 29, 2024
    So having through some means or another having gotten my hands on a copy of IDA v6.5 and Knizz's FIreRed database, I'm greeted with a prompt that reads: "Sorry, this database has been created by a pirate version of IDA".
    What do I make of this? From what I understand, Knizz wrote the newest version of his database for v6.5, but would I be better off trying to load it into an older version to prevent this from happening?

    Click the link in my sig to join the chat; I'll explain everything there.
     

    daniilS

    busy trying to do stuff not done yet
  • 409
    Posts
    10
    Years
    • Seen Jan 29, 2024
    ida for disassembling
    vba-sdl-h or no$gba for debugging
     

    colonelsalt

    Guaranteed to raise the smile
  • 111
    Posts
    11
    Years
    How would I go about finding free space in RAM to store temporary values and buffer strings? FBI, for example, references offset 0x02021D18 (location of displayed strings) a number of times in his tutorials as a reliable place to store temporary data because of the "vast amount of free space" there. After poking around with VBA-SDL-H, though, I don't exactly see any strikingly obvious reason why this is the case. Is finding this free RAM space, then, largely a process of trial and error, or are there distinctive patterns one can look for in the code to find suitable locations?
     

    Touched

    Resident ASMAGICIAN
  • 625
    Posts
    9
    Years
    • Age 122
    • Seen Feb 1, 2018
    How would I go about finding free space in RAM to store temporary values and buffer strings? FBI, for example, references offset 0x02021D18 (location of displayed strings) a number of times in his tutorials as a reliable place to store temporary data because of the "vast amount of free space" there. After poking around with VBA-SDL-H, though, I don't exactly see any strikingly obvious reason why this is the case. Is finding this free RAM space, then, largely a process of trial and error, or are there distinctive patterns one can look for in the code to find suitable locations?

    To expand on daniilS's anwser: You have to be aware that much of the space in EWRAM (0x02000000) is reserved for malloc. If you need a lot of space, you can always just use malloc. You give the function a size and it returns a pointer to some free RAM of the specified size. Remember to use "free" on that pointer when you're done with that memory though!

    Otherwise, if you need temporary RAM, just use the stack.
    Code:
    sub sp, #100
    mov r0, sp
    
    @ Have a pointer to 100 bytes of free RAM in r0 for the duration of this function
    
    add sp, #100

    If you need it to last a bit longer than that, you can use space that's just overwritten, like the text buffer FBI uses. That is only overwritten when a message is displayed. There are no real techniques for finding stuff like this. It's more of an educated guess, confirmed by debugging. We all knew that the text functions used some RAM to expand strings (when there is a buffer, it needs to change that buffer to actual text before changing each byte to a tile). We also guessed it didn't really matter what was there if the text renderer wasn't running. A quick check in IDA would've confirmed this.

    Another technique I use is to find padding bytes. Most memory must be word aligned, so there is often a free hword or byte at the end of structures in the RAM. The IWRAM (0x03000000) isn't used by malloc, so you can just look in IDA for unused RAM there. Unused RAM has no XREFs and is therefore safe. I generally find a free word there, and malloc more space if I need it.

    Things you can use (off the top of my head):
    • Banks in scripts (up to four free words until a new script is run)
    • Script variables (especially 0x8000 - 0x800F)
    • Text renderer space
    • Battle struct data (probably overwritten at the start of a battle anyway, up to 0x58 * 4 bytes if this is the case)
    • Other battle structures, see above

    Be aware that most times, this memory is temporary. If you need the memory to persist over saves and continues, you'll need to find free save block space. Often, this needs JPANs save block hack. Larger amounts of contiguous space are substantially harder to find.
     

    colonelsalt

    Guaranteed to raise the smile
  • 111
    Posts
    11
    Years
    That's awesome. Thanks for the in-depth reply. Was about to type up a confused post about not getting malloc to work only to realize I derped and forgot to add 1 to the offset when calling the function. As it turns out it works like a charm; so does the stack pointer tip you mentioned-- sweet. I guess this stuff is just the kind of thing you get an intuitive feel for after a while.
     

    colonelsalt

    Guaranteed to raise the smile
  • 111
    Posts
    11
    Years
    So I wrote a routine that hooks from the givepokemon function to allow for the level of the given Pokémon to be loaded from a variable. A quick check in VBA-SDL-H shows that it hooks alright and runs till the end just as it should. Upon trying to return to the givepokemon function again (through a pop {pc}), though, the game begins loading from the BIOS header and, naturally, crashes. JPAN actually mentions this problem as a common pitfall to avoid in his THUMB tutorial, but I can't seem to understand what's causing it to happen here. Something obvious, no doubt.

    Here's what my code looks like:
    hook @0x0806BFF0:
    Spoiler:
    routine @0x0880322C:
    Spoiler:
     
    Last edited:

    Touched

    Resident ASMAGICIAN
  • 625
    Posts
    9
    Years
    • Age 122
    • Seen Feb 1, 2018
    So I wrote a routine that hooks from the givepokemon function to allow for the level of the given Pokémon to be loaded from a variable. A quick check in VBA-SDL-H shows that it hooks alright and runs till the end just as it should. Upon trying to return to the givepokemon function again (through a pop {pc}), though, the game begins loading from the BIOS header and, naturally, crashes. JPAN actually mentions this problem as a common pitfall to avoid in his THUMB tutorial, but I can't seem to understand what's causing it to happen here. Something obvious, no doubt.

    Here's what my code looks like:
    hook @0x0806BFF0:
    Spoiler:
    routine @0x0880322C:
    Spoiler:

    POP {PC} will take the top value on the stack and set PC to that. If LR was the last register that was pushed, this will return you. However, since you're hooking, you're in the middle of a routine. What you want to do is BX back to the routine your're hooking into.

    From the location of your hook, I assume you'd want to do this instead of POP {PC}

    Code:
    ldr r1, =(0x0806BFFA + 1)
    bx r1

    This will take you back to the BL script_read_halfword.
     

    colonelsalt

    Guaranteed to raise the smile
  • 111
    Posts
    11
    Years
    Thanks a ton; I really appreciate the help. I assumed there was a conceptual understanding I was just not getting here. Routine works perfectly now with your solution. I had somehow gotten into my head that you couldn't bx to an offset that's not word-aligned, but I guess that's not an issue.
    As a side note, am I correct in assuming that sticking to the pop {pc} would still not work even if I did push {lr} at the start of my routine, because calling by bx does not influence the link register? Could using a bl-bx combo in the hook itself, then, circumvent having to load the pointer to the return location in the routine itself? Just trying to wrap my head around this.
     

    Touched

    Resident ASMAGICIAN
  • 625
    Posts
    9
    Years
    • Age 122
    • Seen Feb 1, 2018
    Thanks a ton; I really appreciate the help. I assumed there was a conceptual understanding I was just not getting here. Routine works perfectly now with your solution. I had somehow gotten into my head that you couldn't bx to an offset that's not word-aligned, but I guess that's not an issue.
    As a side note, am I correct in assuming that sticking to the pop {pc} would still not work even if I did push {lr} at the start of my routine, because calling by bx does not influence the link register? Could using a bl-bx combo in the hook itself, then, circumvent having to load the pointer to the return location in the routine itself? Just trying to wrap my head around this.

    Well, you're almost right. You can't BX to a routine that isn't halfword aligned. The LSB is just used to mark THUMB code. Routines don't actually have to be word aligned. Literal pools must be word aligned on the other hand (that's why you .align 2 before any .words).

    If you did BL then BX to your hook code, the calling routine would set LR = PC + 4 on the BL. So when you return via popping LR onto PC, BX LR, etc. you would move to the instruction directly after the BL. Since your hook code overwrites some stuff, this would not work as intended:

    Code:
    ldr rX, =(HOOK_ADDR)
    bl linker
    ;; Return here
    
    linker:
       bx rX

    Since it returns there, you'd return and encounter the "bx rX" under the linker label, which would end up crashing. You could solve this by putting a relative branch underneath, but why bother? This routine above uses 12 bytes, 14 (maybe even 16, depending where the literal pool is placed) with an additional branch to make it work. Standard hook code uses 8 bytes on a word aligned address. You generally want the hook code to be the most compact so you can put it anywhere. Losing 8 bytes of free space to branch back doesn't really matter all that much.
    Additionally, manually returning allows more control over where you return to. This can be useful if your hook code forces some routine to exit early if a certain condition is true.
     

    colonelsalt

    Guaranteed to raise the smile
  • 111
    Posts
    11
    Years
    Gotcha. So I guess the bottom line, then, is that you're essentially dependent on having at least one free/safe register in which to store the return address when choosing where to insert hooks. Thanks for clarifying.
     
  • 154
    Posts
    9
    Years
    • Seen Jun 23, 2018
    Hi Guys I need to ask that I am making an ROM hack of ash adventure from kanto to hoenn region.
    I am hacking fire red ROM,but fire red contain only kanto region badges cammands and there is no jotho and hoenn region badges cammands and there is no space on trainer card for more badges and no pic for jotho and hoenn badges so I know it can be added and down by ASM
    So I want help in ASM in making this ASM so there will an Jotho and hoenn badges will available
    Please replay me I need help in this to continue my hack please help and reply
     
    Status
    Not open for further replies.
    Back
    Top