• 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
    Since the only pokemon game I've ever hacked is R/S, I don't have any good example. In other GBA games, there are times where I need to push some registers (r0-r3) to insert a routine. I'm putting those just for insurance.

    To check the availability of the stack, I'm checking all routines before and after this function. A function with SP modifying instruction can limit the space on the stack. If he calls the function inside a SP modifying function, there is a chance that pushing will overwrite important data.

    Since the game was compiled, it follows a rather strict calling convention. This means that routines that are designed to be called as functions (i.e. they are called and then return) do not need push/pop r0-r3 because these are reserved for arguments and return values - a caller assumes the callee will alter these values. This is always the case for functions. However, you may need to push these registers if you are modify existing functions by hooking into a routine. However, since the question was about a routine that was called from a script, we know it is a function; the script handler and function code for callasm expect r0-r3 to be messed up, thus we need not push them. Another point I should make is that LR is not used therefore pushing it is not necessary.

    I assume stack overflow (for the user stack at least) is incredibly unlikely unless you are implementing a recursive function that uses stack space or you are allocating an absurd amount of space on the stack; I highly doubt you could overflow the stack just by pushing once. Have you ever seen the stack overflow?
     

    daniilS

    busy trying to do stuff not done yet
  • 409
    Posts
    10
    Years
    • Seen Jan 29, 2024
    I think he was referring to functions reserving space on the stack. But even then, those adjust the stack pointer, so there's nothing to worry about.
     
  • 29
    Posts
    9
    Years
    • Seen Apr 17, 2016
    Hi, so I am still a bit new to asm (very new actually..) and I am trying to copy an 8 byte long piece of code from FireRed's RAM, and place it somewhere else. Is there any way I can do that? For example, it takes whatever is at (said offset) and places it somewhere else. It doesn't have to be cut and pasted either (it can) but it could also just be copied and pasted. Thank you
     

    Lance32497

    LanceKoijer of Pokemon_Addicts
  • 792
    Posts
    9
    Years
    Very soon I can fix the errors,
    Loading the party slot is fine, it works perfectly
    while Loading the Correct Stat isn't yet working, and
    it only stores the value from 8006 in the stat, it doesn't add the current stat and the value in 8006

    Spoiler:
     
  • 534
    Posts
    11
    Years
    • Age 26
    • Seen Jul 24, 2023
    Hey guys! I'm actually writing my very first (free-handed or should I say free-minded) routine and I'm stuck.
    Is there something like a compare command in ASM?

    Here's what I'm trying to do: Compare the values of 2 vars (0x8000 and 0x800D) and make it return to 0x800D 0x0 if 0x8000 is lower, 0x1 if it is equal and 0x2 if 0x8000 is greater than 0x800D. I just need instructions, not the code itself.

    Oh and on a side note, when a var's value is 0 and when something is subtracted to it, it becomes 65535 minus the value you subtracted. Is there a way to counter this using ASM?
     

    Touched

    Resident ASMAGICIAN
  • 625
    Posts
    9
    Years
    • Age 122
    • Seen Feb 1, 2018
    Hi, so I am still a bit new to asm (very new actually..) and I am trying to copy an 8 byte long piece of code from FireRed's RAM, and place it somewhere else. Is there any way I can do that? For example, it takes whatever is at (said offset) and places it somewhere else. It doesn't have to be cut and pasted either (it can) but it could also just be copied and pasted. Thank you

    There are a variety of ways you can do this, and most depend on the alignment of the destination and source addresses. If both addresses are word aligned, one can simply:

    Code:
    ldr r0, source
    ldmia r0!, {r1-r2} @ loads two words (8 bytes) into r1 and r2 starting from r0
    ldr r0, dest
    stmia r0!, {r1-r2} @ opposite of ldmia - stores to r0
    
    @ This is the same as swi 0xC and the word variant of swi 0xB
    @ Use those for bigger copies

    However if the addresses aren't word aligned, or you can't guarantee that they will be, you must resort to memcpy. There is already an implementation of this function - see the FireRed IDB for addresses and parameters. Its basically a loop with ldrb and strb.

    Very soon I can fix the errors,
    Loading the party slot is fine, it works perfectly
    while Loading the Correct Stat isn't yet working, and
    it only stores the value from 8006 in the stat, it doesn't add the current stat and the value in 8006

    Spoiler:

    To add to the stat, load the current value of the stat, add to it, then store it. Keep in mind that this stat increase will be lost when the stats are recalculated, which is quite often.

    I have commented where you can improve. You should also comment your routines (and don't just explain the opcodes, explain your intention) and break them up into logical sections so its easier on the eye to read.

    Hey guys! I'm actually writing my very first (free-handed or should I say free-minded) routine and I'm stuck.
    Is there something like a compare command in ASM?

    Here's what I'm trying to do: Compare the values of 2 vars (0x8000 and 0x800D) and make it return to 0x800D 0x0 if 0x8000 is lower, 0x1 if it is equal and 0x2 if 0x8000 is greater than 0x800D. I just need instructions, not the code itself.

    Oh and on a side note, when a var's value is 0 and when something is subtracted to it, it becomes 65535 minus the value you subtracted. Is there a way to counter this using ASM?

    You will need to use a series of CMPs and conditional branches to set a register to the desired value. Then store the value in the target variable.

    As for your second question on subtracting a value from 0: variables are treated as unsigned values by the scripting engine, so you couldn't use saved signed values reliably in a script. However, if you were to use the value only in ASM, you could use the load sign-extended halfword opcode (LDSH) to use that value as a signed half-word. This could represent -0x8000 to 0x7FFF. You would have to be careful to only load values you KNEW were signed with this, otherwise it could corrupt large unsigned values. It depends on what you want to use it for.
     
  • 29
    Posts
    9
    Years
    • Seen Apr 17, 2016
    There are a variety of ways you can do this, and most depend on the alignment of the destination and source addresses. If both addresses are word aligned, one can simply:

    Code:
    ldr r0, source
    ldmia r0!, {r1-r2} @ loads two words (8 bytes) into r1 and r2 starting from r0
    ldr r0, dest
    stmia r0!, {r1-r2} @ opposite of ldmia - stores to r0
    
    @ This is the same as swi 0xC and the word variant of swi 0xB
    @ Use those for bigger copies

    However if the addresses aren't word aligned, or you can't guarantee that they will be, you must resort to memcpy. There is already an implementation of this function - see the FireRed IDB for addresses and parameters. Its basically a loop with ldrb and strb.

    Thanks a ton! Hmm.. Well the address I'm trying to copy is a pointer to the code (the code is in different locations depending on the length the player chooses in game.. Its the player's name) so I can't exactly put the exact address of the code. I can put the offset of the pointer to it though right? (300500C)? Also, does the destination have to be in the ram or can it be in the game's offsets? Either should be fine. Thanks again.
     
  • 534
    Posts
    11
    Years
    • Age 26
    • Seen Jul 24, 2023
    You will need to use a series of CMPs and conditional branches to set a register to the desired value. Then store the value in the target variable.

    As for your second question on subtracting a value from 0: variables are treated as unsigned values by the scripting engine, so you couldn't use saved signed values reliably in a script. However, if you were to use the value only in ASM, you could use the load sign-extended halfword opcode (LDSH) to use that value as a signed half-word. This could represent -0x8000 to 0x7FFF. You would have to be careful to only load values you KNEW were signed with this, otherwise it could corrupt large unsigned values. It depends on what you want to use it for.

    Not to sound super noobish but how would I use THUMB.16 in a code? Like a sample or something?

    I'd guess. THUMB.16 C I got that wrong didn't I?
     

    Touched

    Resident ASMAGICIAN
  • 625
    Posts
    9
    Years
    • Age 122
    • Seen Feb 1, 2018
    Thanks a ton! Hmm.. Well the address I'm trying to copy is a pointer to the code (the code is in different locations depending on the length the player chooses in game.. Its the player's name) so I can't exactly put the exact address of the code. I can put the offset of the pointer to it though right? (300500C)? Also, does the destination have to be in the ram or can it be in the game's offsets? Either should be fine. Thanks again.

    You can't use a pointer to the pointer. You have to dereference it before copying, otherwise you'll copy the wrong thing. E.g.

    Code:
    ldr r0, =0x300500C
    @ r0 is pointing to another pointer so copying from here will result in 
    @ the pointer being copied, not the data
    ldr r0, [r0] @ dereference
    @ Now you can copy from/to r0 as it is now pointing to data

    Of course, since the data is being moved constantly (probably with DMA), it's almost certainly word or halfword aligned (aligned copies will be faster). Check the alignment of the pointers in a debugger if you are unsure.

    The destination of course has to be in the RAM, as you can't write to the ROM. The source can be in the ROM.

    Not to sound super noobish but how would I use THUMB.16 in a code? Like a sample or something?

    I'd guess. THUMB.16 C I got that wrong didn't I?

    Uhh, that's the section number. I was referring to the opcodes BEQ, BNE, BCS etc. Those are called conditional branches because they jump to a different location if a certain condition is true. If you look at a tree diagram of the code, it forks the path of execution at the branches, hence the name. They're a way of performing certain actions only if a condition is true. You can do:

    Code:
    cmp r0, r1
    beq equal
    blo unsigned_lower
    bhi unsigned_higher

    Multiple branches in a row are okay because branches do not alter the CPSR, thus preserving the state set by the CMP operation.
     
  • 29
    Posts
    9
    Years
    • Seen Apr 17, 2016

    Touched

    Resident ASMAGICIAN
  • 625
    Posts
    9
    Years
    • Age 122
    • Seen Feb 1, 2018
    That was a pretty foolish question, the ram or rom question.. Wasn't thinking straight :/ But anyway I tried dereferencing 300500C (at least I think) and it still will not copy it to the offset stated. Well, this is what I have:

    Spoiler:


    As you can see I did what you said by loading r0 again with ldr r0, [r0]. I guess it should copy it to 0x84EE00 (just a test offset I used), do you spot anything thats wrong or anything I'm missing? Sorry for so many questions.. I hope I'm not sounding rude :/ )

    Don't worry about asking questions, that's what this thread is for ;)

    The problem your destination pointer 0x84EE00. It isn't a pointer at all; that address is invalid. You need some location in the RAM to write to.
     
  • 29
    Posts
    9
    Years
    • Seen Apr 17, 2016
    Don't worry about asking questions, that's what this thread is for ;)

    The problem your destination pointer 0x84EE00. It isn't a pointer at all; that address is invalid. You need some location in the RAM to write to.

    Oh my god it worked, the data copied to my new location!! I can't you enough Touched, I REALLY appreciate the help!!
     

    Squeetz

    ROM Hacker
  • 191
    Posts
    10
    Years
    Not sure if this is the correct thread to ask this, but it's ASM related either way.
    So, I discovered this: https://assembly.ynh.io/
    A C/C++ to ASM converter.
    Would converting code from C lose out on anything? Is it safe to use? Would I have to edit some of the code after converting it, before inserting the routine?
     

    Touched

    Resident ASMAGICIAN
  • 625
    Posts
    9
    Years
    • Age 122
    • Seen Feb 1, 2018
    Not sure if this is the correct thread to ask this, but it's ASM related either way.
    So, I discovered this: https://assembly.ynh.io/
    A C/C++ to ASM converter.
    Would converting code from C lose out on anything? Is it safe to use? Would I have to edit some of the code after converting it, before inserting the routine?

    This "converter" is known as a compiler. GCC (GNU Compiler Collection) is packaged with devkitARM, so you don't need to use an online version. This means that there are a lot of languages that can be compiled to THUMB code. I have used C for a couple of hacking projects; there were a few kinks that needed to be worked out, but it is definitely possible (and often worthwhile). There is a thread somewhere in R&D that uses C. C++ is also possible: Jambo uses C++ for his engine. Again, there are limitations, but it can all be worked around. If you are interested in trying this, you might want to check out my Mega Evolution project on GitHub. It is a good, recent example of how to use C (and mix it with ASM) in FireRed.

    Be warned that this won't eliminate your need to understand ASM - you probably need more understanding to work this. You still need ASM to hook, and it is often necessary to be aware of how your C code compiles to ASM.
     

    Exodrake

    The Manliest Chick that Ever Manlied
  • 163
    Posts
    11
    Years
    • Seen Nov 30, 2016
    I made some adjustments to KDS' Freeze-Dry code to make a move that is unnaturally supereffective against my Oil-type (index number is 0x18 in hex). The problem is, now I don't know how to actually implement this code in my game WITH the Freeze-Dry code along with it. I don't want one or the other, I want both.

    The only changes I made to the Freeze-Dry codes is I changed cmp r4, #0xB to cmp r4, #0x18, and the move ID to 0x0068 so it will replace Minimize (which I find redundant as Double Team is all I need really). The move will be Water-type which Oil is normally immune to, but the plan is for this move, Soapy Water, to hit Oil supereffectively instead of failing against it. If there's other lines of code I need to change (note that I have the ASM skills of a grapefruit) I really need to know.
     

    Touched

    Resident ASMAGICIAN
  • 625
    Posts
    9
    Years
    • Age 122
    • Seen Feb 1, 2018
    I made some adjustments to KDS' Freeze-Dry code to make a move that is unnaturally supereffective against my Oil-type (index number is 0x18 in hex). The problem is, now I don't know how to actually implement this code in my game WITH the Freeze-Dry code along with it. I don't want one or the other, I want both.

    The only changes I made to the Freeze-Dry codes is I changed cmp r4, #0xB to cmp r4, #0x18, and the move ID to 0x0068 so it will replace Minimize (which I find redundant as Double Team is all I need really). The move will be Water-type which Oil is normally immune to, but the plan is for this move, Soapy Water, to hit Oil supereffectively instead of failing against it. If there's other lines of code I need to change (note that I have the ASM skills of a grapefruit) I really need to know.

    Looks fine
     

    Joexv

    ManMadeOfGouda joexv.github.io
  • 1,037
    Posts
    11
    Years
    Can someone help me out? This routine is Jpans special 0x64 translated to EM(hopefully). The routine just does nothing, no freeze or nothing.
    Spoiler:
     

    daniilS

    busy trying to do stuff not done yet
  • 409
    Posts
    10
    Years
    • Seen Jan 29, 2024
    Can someone help me out? This routine is Jpans special 0x64 translated to EM(hopefully). The routine just does nothing, no freeze or nothing.
    Spoiler:

    Have you already tried debugging it?
     

    Joexv

    ManMadeOfGouda joexv.github.io
  • 1,037
    Posts
    11
    Years
    Have you already tried debugging it?
    Yea, turns out I just had the wrong variable offset.-.-
    But it will only set the Pokemon to sleep, is there something I'm missing in order to no have to worry about the sleep bits? Cause the documentation on that area of the data structure is pretty vague.
    Nevermind, I'm stupid.-.-
     
    Last edited:

    colonelsalt

    Guaranteed to raise the smile
  • 111
    Posts
    11
    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?
     
    Status
    Not open for further replies.
    Back
    Top