• 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.

Blah

Free supporter
  • 1,924
    Posts
    11
    Years
    Ok thanks, I'll fix up those bits about ldr :). I think I'm clearer on what's happening now after rereading SQ's and your tutorials (in particular, looking at definitions and patterns of coding).

    With the hook, I was worried exactly where I'd be needing it. In my head I still think in terms of scripts I'm afraid >< checking flags is easy in scripts, so I didn't see any need to hook. I think I'm going to drop the badges thing for now and instead focus on getting the change done.

    So my routine so far does half it's job, once I've added the 0x5 how do I get it to store at the location? Storing at the variable seemed easy enough, but then again that's RAM location not ROM, I tried using strb to get it back to 8250cb9, but that seems illogical anyway (and didn't work).

    Oh you're thinking about the problem wrong in general. Even ASM can't write to the ROM. Here's what you do:

    Hook at where Cut's power is loaded (lets pretend it was loaded into r0).
    So when you reach your routine, r0 will contain Cut's power. You will merely add five to r0 (for 5 extra power) and then return. This way it's like the game read Cut's power as 5 more than what it is. You don't need to store anything, you just need to modify the power and return. Simple simple :D

    EDIT:
    It's like this in scripting terms:

    Code:
    #dyn 0x740000
    #org @start
    setvar 0x8000 0x0
    call addFive
    'then game applies it's formula
    end
    
    'Think of add five as your routine. The call addFive is like the hook
    #org @addFive
    addvar 0x8000 0x5
    return
     
  • 10,078
    Posts
    15
    Years
    • UK
    • Seen Oct 17, 2023
    Oh you're thinking about the problem wrong in general. Even ASM can't write to the ROM. Here's what you do:

    Hook at where Cut's power is loaded (lets pretend it was loaded into r0).
    So when you reach your routine, r0 will contain Cut's power. You will merely add five to r0 (for 5 extra power) and then return. This way it's like the game read Cut's power as 5 more than what it is. You don't need to store anything, you just need to modify the power and return. Simple simple :D

    My poor brain. Still going at this even now ;-;.

    I'm still confused as to how I modify the power and return to where - maybe it's because I'm being awkward and trying to modify a HM's power? It's not just about it being read and changed for damage, but also for the HM info and on the moves list on a summary.

    Anywho. I followed your guidance to find to hook the power - I tried it from two places, the TM menu and the Summary page.

    The breaks that loaded 32 into a register were at 081334CE and 08136A34 respectively. I then used VBA disassemble thingy to look for a starting push function at each of these (does this sound right so far? XD).

    Problem is the push functions were waaay waaaaay up from where I started. Including a lot of functions that didn't make sense even with the help of the tutorials. >< I pretty much ignored this, grabbed the offset for the push command, and tried to find another breaking point. It broke repeatedly at the same place, without showing 32 being loaded. So... stumped DX.

    I'm sure this is way easier than I'm making it. 4 hours in.
     

    Blah

    Free supporter
  • 1,924
    Posts
    11
    Years
    My poor brain. Still going at this even now ;-;.

    I'm still confused as to how I modify the power and return to where - maybe it's because I'm being awkward and trying to modify a HM's power? It's not just about it being read and changed for damage, but also for the HM info and on the moves list on a summary.

    Anywho. I followed your guidance to find to hook the power - I tried it from two places, the TM menu and the Summary page.

    The breaks that loaded 32 into a register were at 081334CE and 08136A34 respectively. I then used VBA disassemble thingy to look for a starting push function at each of these (does this sound right so far? XD).

    Problem is the push functions were waaay waaaaay up from where I started. Including a lot of functions that didn't make sense even with the help of the tutorials. >< I pretty much ignored this, grabbed the offset for the push command, and tried to find another breaking point. It broke repeatedly at the same place, without showing 32 being loaded. So... stumped DX.

    I'm sure this is way easier than I'm making it. 4 hours in.

    Aww man Magic. I feel almost bad to tell you that the offsets you found have nothing to do with the move's damage calculations. Those are offsets to the routines which are graphically loading a move's power when looking at the summary page.

    What you need to do is:
    a) Have a Pokemon have the move cut

    b) Get into battle with said Pokemon, and set a bpr @ the move table
    Please note that the game will break before you use the move. This is probably for the "fight" menu where it will graphically display the move and it's PP. Make sure to write down all of the offsets it's breaking at anyways (even if you think it's graphical).

    c) When the game breaks at the move table (and it's not for graphics) take note of that offset (write it down on notepad/stickynote). Once you get there, report back for further instruction.

    I just want to first make sure you're finding the right offsets. In the beginning it will take you some time, as you get better these things will be MUCH faster. When I started, it took me 3 days to find the Surf routine with Touched holding my hand through it all. Don't feel bad, just keep at it :P
     
  • 10,078
    Posts
    15
    Years
    • UK
    • Seen Oct 17, 2023
    That actually worked surprisingly well, I narrowed down how many bytes to search for (so PP wouldn't set it off) and got an offset of 0803ed32 pre-break.

    It was the only time the game broke after selecting the move.
     

    Blah

    Free supporter
  • 1,924
    Posts
    11
    Years
    That actually worked surprisingly well, I narrowed down how many bytes to search for (so PP wouldn't set it off) and got an offset of 0803ed32 pre-break.

    It was the only time the game broke after selecting the move.

    Alright, so around 0803ED32, we have this code:
    Code:
    0803ED30                 add    r0, r0, r1
    0803ED32                 ldrb    r0, [r0, #0x1]
    0803ED34                 strh    r0, [r2]
    0803ED36                 b       0x803ED44

    Obviously after the addition at 0803ED30, r0 will be the address to "Cut". Then the next line, we're loading the move's power into r0 and the third line we're storing it in r2. The last line we're going to branch unconditionally to 0x803ED44.

    OK, I'll tell you that for your hook you should use R3. I know this because I took a look at what happens at the
    "b 0x803ED44" 's code and noticed that R3 gets overwritten anyways, so we can use it for our hook. You also lucked our pretty hard here because to place a hook we need to overwrite 8 bytes and ldrb takes 4 bytes, of space, while most other instructions take 2. Which means we can place our hook using R3 at 0803ED30 without overwriting anything besides the instructions I've referenced in the above code block.

    However, we ARE replacing them to place our hook, so we do need to restore them in our routine. Specifically you need to restore:
    Code:
    add r0, r0, r1 @get cut's pointer
    ldrb r0, [r0, #0x1] @get cut's power and put it in r0

    before starting your code, because we need to know cut's power before we add to it. So your routine needs to START with those two lines. After those two lines, you will do your own modifications to r0 inorder to boost the power (remember only r3 is known to be safe, so if you need an extra register push them or use r3).

    Finally after you've increased the power by editing the value in r0, you want to do the rest of the code which we overwrote. That would obviously be:

    Code:
    strh    r0, [r2]
    b       0x803ED44

    EDIT:
    Actually for the b 0x803ED44 you need to replace that line with:
    ldr r3, =(0x803ED44 +1)
    bx r3

    Because "b" is limited in the distance it can branch to, bx is unlimited. Your compiler won't let you compile unless you use the bx way I've mentioned. R3 as I said earlier was safe to use, so this is fine.
     
    Last edited:
  • 10,078
    Posts
    15
    Years
    • UK
    • Seen Oct 17, 2023
    Spoiler:

    Ok so I should throw a

    Code:
    ldr r3, =(08800101)
    bx r3

    At 0803ED30 to hook to my new routine.

    Spoiler:

    Does this make sense? :< My compiler is giving errors saying number too big?
     

    Blah

    Free supporter
  • 1,924
    Posts
    11
    Years
    Ok so I should throw a

    Code:
    ldr r3, =(08800101)
    bx r3

    At 0803ED30 to hook to my new routine.

    Spoiler:

    Does this make sense? :< My compiler is giving errors saying number too big?

    OK a few things going on here which shouldn't be going on.
    Code:
    var:
    	.word 0x020270B6 + (0x4075 * 2)
    I don't know what this is, but I can tell you it's not doing what you want it to do. Only variables 0x8000-0x8014 should be accessed via direct address. Variables that are not those temporary variables are stored dynamically, as in their address changes. To access them you need to use the var decrypter function, and that sort of complicates things. I like where you're going with this idea, it's definitely better than manually checking all the badges. If you set a non-temporary variable to 0x0 at the start of the game, then every time you get a badge just add 1 to it. It would save you some space for your routine, which is good.

    I think what you have here is a spin-off of HackMew's formula, which as I explained, isn't meant to be used like this. Actually his formula sucks in general, it should've been:
    Code:
    var:
    	.word 0x20370B8 + (2 * ([your var] - 0x8000))
    Where [your var] is the temporary variable you want the value to. Anyways that's not important here.

    Also you've pushed r4, while not needing to, and on top of that haven't popped it. Finally your hook is fine, but you forgot the "0x" part to signify hex, Try again and check back here.

    Solution when you give up:
    Spoiler:
     
  • 10,078
    Posts
    15
    Years
    • UK
    • Seen Oct 17, 2023
    Me again

    I got the first routine working! :D You were right, r3 did hold the attack ID - switched around some registers so it wasn't overwritten by a pointer and all was good.

    Graphics side~

    So my first attempt was inserting this (based on the other routine) by derailing a routine and looping back into it. IDK what happened, but the game crashed trying to view the TM box : <. So I'm guessing my hook was in the wrong place? Where would be best to put it?

    Spoiler:


    The blue-highlight is where my break was detected. I hooked at 081334BE. At that point r7 should be equal to 0xF (Cut's value). The sums seem to be adding 0xF up to B4 - which is how far into the [S-HIGHLIGHT]table[/S-HIGHLIGHT] cut's data would be. Would hooking at c8/CA be better - that way I can end my routine with the bl command already there?

    Code:
    .text
    .align 2
    .thumb
    .thumb_func
    
    main:
    	cmp r7, #0xF
    	bNE shift
    	mov r0, #0xFF
    	lsl r0, r0, #0x6
    	add r0, r0, #0xB5
    	ldr r2, =(0x806E454 +1)
    	bl linker
    	ldrh r3, [r0]
    	mov r2, #0x5
    	mul r3, r3, r2
    	add r1, r1, r3
    	b shift
    
    shift:
    	add r1, #0x1
    	lsl r1, r1, #0x18
    	lsr r1, r1, #0x18
    	mov r0, #0x5
    	mov r2, #0x0
    	mov r3, #0x0
    	bl =(0x8107d68)
    
    linker:
    	bx r1
    
    .align 2

    Code:
    .align 2
    .thumb
    
    main:
    	ldr r3, =(0x8800161)
    	bx r3
     
    Last edited:

    Blah

    Free supporter
  • 1,924
    Posts
    11
    Years
    Me again

    I got the first routine working! :D You were right, r3 did hold the attack ID - switched around some registers so it wasn't overwritten by a pointer and all was good.

    Graphics side~

    So my first attempt was inserting this (based on the other routine) by derailing a routine and looping back into it. IDK what happened, but the game crashed trying to view the TM box : <. So I'm guessing my hook was in the wrong place? Where would be best to put it?

    Spoiler:


    The blue-highlight is where my break was detected. I hooked at 081334BE. At that point r7 should be equal to 0xF (Cut's value). The sums seem to be adding 0xF up to B4 - which is how far into the [S-HIGHLIGHT]table[/S-HIGHLIGHT] cut's data would be. Would hooking at c8/CA be better - that way I can end my routine with the bl command already there?

    Code:
    .text
    .align 2
    .thumb
    .thumb_func
    
    main:
    	cmp r7, #0xF
    	bNE shift
    	mov r0, #0xFF
    	lsl r0, r0, #0x6
    	add r0, r0, #0xB5
    	ldr r2, =(0x806E454 +1)
    	bl linker
    	ldrh r3, [r0]
    	mov r2, #0x5
    	mul r3, r3, r2
    	add r1, r1, r3
    	b shift
    
    shift:
    	add r1, #0x1
    	lsl r1, r1, #0x18
    	lsr r1, r1, #0x18
    	mov r0, #0x5
    	mov r2, #0x0
    	mov r3, #0x0
    	bl =(0x8107d68)
    
    linker:
    	bx r1
    
    .align 2

    Code:
    .align 2
    .thumb
    
    main:
    	ldr r3, =(0x8800161)
    	bx r3

    Nooo!!! Magic what have you done?! You've broken the alignment :X

    When you hook to a routine, make sure it's at an offset which is divisible by 4. ldr requires word alignment inorder to work like you think it works. There are some ways you can avoid word alignment with ldr, but in the end, you'll be taking the same amount of space (and it's a little harder to explain how that works). Either hook earlier and have more code at the start of your routine, or hook later.

    Code:
    	...stuff...
    	b shift
    
    shift:
    	...stuff...
    This is unneeded. ASM is read top to bottom, so the "b" isn't required. It will automatically go to the code at shift,

    Code:
    	bl =(0x8107d68)
    Like I explained earlier this "bl" won't work. "bl" has limited range in terms of how far it can go.

    Here's a little bit about it from my new tutorial:
    Spoiler:


    So to get the "bl" effect you want to do the linker thing I've shown. Then, right after it will return to YOUR routine. So your routine wants to point it to the next Opcode AFTER the "bl" was in the original code.

    This part is a little tricky, about where you want to place the hook. It'll end up having to be at 081334C8. However, you're going to have to handle the "bl" at 081334CA and the "bhi" at 081334D2 in your own routine. For the "bhi" it's important to note that "bhi" doesn't write to the link register so you don't want to use a linker. Just use bx. Something like this:

    Code:
    	cmp r0, #0x1
    @instead of bhi we'll use ble for easier code formatting
    	ble continue
    	ldr r4, =(0x81334E0 + 1)
    	bx r4
    
    continue:
    @the last bit translated so the "b" commands work properly
    	ldr r2, =(0x81334DC)
    	ldr r2, [r2]
    	ldr r0, =(0x81334F0 +1)
    	bx r0
     
  • 10,078
    Posts
    15
    Years
    • UK
    • Seen Oct 17, 2023
    Spoiler:

    WIP, but moving towards the right direction I hope. It's not crashing the game, but it's also not doing what it's meant to... I had to tweak some registers, and for some reason the type image isn't showing at the moment ><.

    Nooo!!! Magic what have you done?! You've broken the alignment :X

    DX but but but.

    In terms of aligning for ldr - does that mean I have to fill/remove functions from my routine to fit the pattern? At the moment the very first ldr is resting on an [a] offset, so I guess that needs shifting to [c]. Is there a basic filler function to help?
     

    Blah

    Free supporter
  • 1,924
    Posts
    11
    Years
    Spoiler:

    WIP, but moving towards the right direction I hope. It's not crashing the game, but it's also not doing what it's meant to... I had to tweak some registers, and for some reason the type image isn't showing at the moment ><.



    DX but but but.

    In terms of aligning for ldr - does that mean I have to fill/remove functions from my routine to fit the pattern? At the moment the very first ldr is resting on an [a] offset, so I guess that needs shifting to [c]. Is there a basic filler function to help?

    Nope. You only need to ensure ldr's alignment when you're reading an offset or something similar.
    If you were doing something like ldr r0, [r1] then r1 needs to be word aligned. There are some technical stuff in between.

    For the most part only insure ldr is word aligned if
    a) you're reading 4 bytes from an offset, that offset MUST be word aligned
    b) you're hooking (kinda the same as "a" :P)
     
  • 10,078
    Posts
    15
    Years
    • UK
    • Seen Oct 17, 2023
    So how can I go about aligning them in my routine? Should I add random add rx commands or something to push things down two bytes? idk.
     

    Blah

    Free supporter
  • 1,924
    Posts
    11
    Years
    So how can I go about aligning them in my routine? Should I add random add rx commands or something to push things down two bytes? idk.

    Well, normally you don't need to. Most instructions in thumb takes 2 bytes (some 4) but when you insert your routine it will be at a word aligned offset. You don't have to worry about that. It's only something to worry about if you're hooking or reading tables which aren't word aligned.
     
  • 794
    Posts
    10
    Years
    Hi, I've been reading some ASM tutorials and decided to create a simple routine. The goal was to have a person say your pokemon's(at first slot) current ant total HP. It didn't work and I have no clue why. My code:
    Spoiler:


    There's also a possibility that my XSE code is wrong. So here it is:
    Spoiler:


    What happens in the game: https://i.imgur.com/DzRPS2i.png
    I also tried changing "lrdh" to "lrdb"(even though the values are halfwords) but still no success. So, does anybody know the reason why it's not working?

    EDIT: I forgot to put 0x before my HEXADEMICAL number. Ehhh...Thanks Spherical Ice for pointing that out
     
    Last edited:
  • 5,256
    Posts
    16
    Years
    In your routine you're loading from the offset +56 decimal bytes, but they are actually 86 bytes past that offset, so try adding the '0x' because otherwise you're loading the ???? part of the Pokemon data structure (at least I think that's what the problem is).
     
  • 40
    Posts
    10
    Years
    Hi, I'm trying to make the effect for Oblivion Wings. It is the same as Absorb, but the user recovers 3/4 of the inflicted damages instead of the half.
    So here is my code :
    Spoiler:

    It doesn't compile.
     

    Blah

    Free supporter
  • 1,924
    Posts
    11
    Years
    Hi, I'm trying to make the effect for Oblivion Wings. It is the same as Absorb, but the user recovers 3/4 of the inflicted damages instead of the half.
    So here is my code :
    Spoiler:

    It doesn't compile.

    Code:
     beq add r1, #0x1      //r0 multiplies by 0.75 and strores in r1
    Code:
    bhi strh  r2, [r0]
    Code:
    blo strh  r1, [r0]
    You can't do that. Branch to a label, then at the label do your other operations. This is a syntax error.
     

    jiangzhengwenjzw

    now working on katam
  • 181
    Posts
    11
    Years
    • Seen today
    JPAN said in his guide:

    You may have noticed something odd, but I'll point it out anyway. Notice that I load the labels always separated by two, or multiples of two. That is because the Load Lable operation can only fetch the addresses that are four bytes away from them, or multiples of four. That is because Ldr is a 32-bit Word fetching operation, and when added to the PC offset, the offset is shifted by two before adding to the address. That was made to make people's lives easier, allowing to fetch words that are not 127 but 508 bytes away.

    After that he said a lot to explain how to solve the problem of misaligned code, such as adding "add r0, r0, #0x0" or other code without real meaning. I could not understand the above quoted words so I couldn't get what he said.
    Could anyone help or give me an example? That will be very appreciated. :)
     
    Last edited:
  • 40
    Posts
    10
    Years
    You can't do that. Branch to a label, then at the label do your other operations. This is a syntax error.

    So I have to do something like that :
    Code:
    main :
    ...
    cmp r1, r2
    bhi r1higherthanr2
    cmp r1, r2
    blo r1lowerthanr2
    	
    r1lowerthanr2 :
    strh  r1, [r0]
    	
    r1higherthanr2 :
    strh  r2, [r0]
     

    Blah

    Free supporter
  • 1,924
    Posts
    11
    Years
    So I have to do something like that :
    Code:
    main :
    ...
    cmp r1, r2
    bhi r1higherthanr2
    cmp r1, r2
    blo r1lowerthanr2
    	
    r1lowerthanr2 :
    strh  r1, [r0]
    	
    r1higherthanr2 :
    strh  r2, [r0]

    Yes. Be careful though, you cannot use keywords in your label names also some label names don't work. I'm 95% sure that it's compiler dependent.
     
    Status
    Not open for further replies.
    Back
    Top