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

jiangzhengwenjzw

now working on katam
  • 181
    Posts
    11
    Years
    • Seen yesterday
    All of them are available in thumb mode unless stated otherwise (divARM for example is ARM obviously, and the ones marked as NDS aren't GBA)
    Actually that's not what happens in the ldmia still. It's like a looped ldr. The word sequence at the RAM offset (in r0) is being stored in the registers in the Rlist, ldr != str.

    I was just suspicious that you were curious about things, while not understanding the basics. If you've read tutorials, then you can dismiss my random suspicions :P

    I'm still wrong? But I could only get those from your words...
    You say
    The word sequence at the RAM offset (in r0) is being stored in the registers in the Rlist, ldr != str.

    I think that's the same as my understanding...
     

    Blah

    Free supporter
  • 1,924
    Posts
    11
    Years
    I'm still wrong? But I could only get those from your words...
    You say


    I think that's the same as my understanding...

    Code:
    ........
    ldr r0, ramoffset
    ........
    ldmia r0!, {r2-r6}
    ........
    
    .align 2
    ramoffset:
    .word 0x02000000

    Is conceptually the same as:

    Code:
    main:
    	mov r1, #0x0
    
    loop:
    	ldr r0, .ramoffset
    	add r0, r0, r1
    	ldr r(Next), [r0] @so the register we're storing into is basically taken as "next register in the list"
    	add r1, r1, #0x1
    	cmp r1, #Number of registers in Rlist
    	ble loop
    
    .align 2
    ramoffset:
    .word 0x02000000

    We're writing to the registers in Rlist, not to the RAM offset. Hence my saying,
    The word sequence at the RAM offset (in r0) is being stored in the registers in the Rlist, ldr != str.
     

    jiangzhengwenjzw

    now working on katam
  • 181
    Posts
    11
    Years
    • Seen yesterday
    Code:
    ........
    ldr r0, ramoffset
    ........
    ldmia r0!, {r2-r6}
    ........
    
    .align 2
    ramoffset:
    .word 0x02000000

    Is conceptually the same as:

    Code:
    main:
    	mov r1, #0x0
    
    loop:
    	ldr r0, .ramoffset
    	add r0, r0, r1
    	ldr r(Next), [r0] @so the register we're storing into is basically taken as "next register in the list"
    	add r1, r1, #0x1
    	cmp r1, #Number of registers in Rlist
    	ble loop
    
    .align 2
    ramoffset:
    .word 0x02000000

    We're writing to the registers in Rlist, not to the RAM offset. Hence my saying,

    Yes, Actually I think I knew that the words at the RAM address were written into the registers in the Rlist in sequence.
    I think I have the same meaning as yours. Maybe I didn't convey what I wanted to say clearly...
    Thank you for your reply. :P
     

    daniilS

    busy trying to do stuff not done yet
  • 409
    Posts
    10
    Years
    • Seen Jan 29, 2024
    OK I want to use sound in my ASM routine. I settled the register to appropriate values and called the fanfare routine
    Sound did play. But the game froze. Can anyone help me?

    Please show us your routine, we can't really say much without looking at it.
     

    Chaotix

    Love to test
  • 59
    Posts
    17
    Years
    • Seen Jan 11, 2020
    I'm trying to get the EVs for Trainers hack detailed in https://www.pokecommunity.com/showthread.php?t=307117 to work for Fire Red.

    The code I am working with is:

    Spoiler:


    After compiling the bin file, there are supposedly three areas in the rom I need to replace with bytes from the bin file. Those locations being at 0x115f6, 0x3dc70, and 0xF90000. I am having problems determining how much I am supposed to replace at 0x115f6 and 0x3dc70.

    Starting offset 0x115f0 in the bin file the bytes are:

    Spoiler:


    and at offset 0x3dc70 the bytes in the bin file are:

    Spoiler:


    With all the 0's I don't know where to stop replacing bytes in the rom.

    For consistency, the bytes at 0xF90000 in the bin are:

    Spoiler:


    but I'm fairly sure I inserted those correctly at 0xF90000 in the rom.

    If anyone can help me out I would appreciate it greatly. As I have it right now when I begin a trainer battle with Custom moves and Custom items it restarts and goes back to the title screen.

    I also have applied JPAN's hacked engine, would that cause problems with this?
     

    Mystery Man

    Don't be like me!
  • 207
    Posts
    12
    Years
    • Seen Aug 21, 2023
    @Chaotix
    If I remember correctly, you do not do anything with the sea of 00s the bin file gives you. Firstly, look at the ASM code. Locate all of the offsets that are not at the end of the ASM code (i.e. 0x115f6). That should tell you the starting point of what to copy from the bin file and replace in your ROM. So for the first offset, go to 0x115f6 in the bin file, copy all of the bytes before the vast sea of zeros (in this particular one, "08 1c 06 1c 03 e0"), and go to the exact location in your ROM (0x115f6) and replace whatever bytes are there with the ones you copied from the bin file.

    As far as compatability with JPAN's hacked engine, I remember having issues with the set trainer level specials. That's all I know as I used the hack applier tool and have only selected a few hacks.
     

    Chaotix

    Love to test
  • 59
    Posts
    17
    Years
    • Seen Jan 11, 2020
    @Chaotix
    If I remember correctly, you do not do anything with the sea of 00s the bin file gives you. Firstly, look at the ASM code. Locate all of the offsets that are not at the end of the ASM code (i.e. 0x115f6). That should tell you the starting point of what to copy from the bin file and replace in your ROM. So for the first offset, go to 0x115f6 in the bin file, copy all of the bytes before the vast sea of zeros (in this particular one, "08 1c 06 1c 03 e0"), and go to the exact location in your ROM (0x115f6) and replace whatever bytes are there with the ones you copied from the bin file.

    As far as compatability with JPAN's hacked engine, I remember having issues with the set trainer level specials. That's all I know as I used the hack applier tool and have only selected a few hacks.

    Thanks for replying.

    I just tried your suggestion and unfortunately its a similar problem. When battles against trainers with custom moves and items start now the game freezes and the screen stays black.

    Something just doesn't seem right about the values I'm getting in the bin to replace at 0x3dc70, to me; just two bytes, that's all?
     

    Mystery Man

    Don't be like me!
  • 207
    Posts
    12
    Years
    • Seen Aug 21, 2023
    Thanks for replying.

    I just tried your suggestion and unfortunately its a similar problem. When battles against trainers with custom moves and items start now the game freezes and the screen stays black.

    Something just doesn't seem right about the values I'm getting in the bin to replace at 0x3dc70, to me; just two bytes, that's all?

    It might be the set trainer level specials now that I remember correctly. I would try reverting the bytes that the set trainer level special hack changes to those of an unhacked Firered, as it interferes with the EV hack. Here is what fixed it for me: go to 0x011624. The bytes there should be "00 48 00 47 ?? ?? ?? 08". Overwrite that with Firered's original coding, which is: "20 1C 33 1C 2C F0 14 FA". It should work now (that, or there might be another thing I forgot.)

    Yes, it is only two bytes. In ASM code, this is all that is being done:
    Spoiler:
     

    Red John

    Progressing Assembly hacker
  • 137
    Posts
    10
    Years
    You need to call the script executor function. It's at 08069AE4 and takes one paramater, the script pointer, in r0. There are some limitations involved however, so be careful.

    Are you sure? I know that place has something to do with script, but I saw it using the r5 for something. And also what are the limitations to be precise?
     

    Blah

    Free supporter
  • 1,924
    Posts
    11
    Years
    Are you sure? I know that place has something to do with script, but I saw it using the r5 for something. And also what are the limitations to be precise?

    There are recursion limitations. Also, it doesn't use r5 for parameters, the actual routine even pushes r5.
     

    Red John

    Progressing Assembly hacker
  • 137
    Posts
    10
    Years
    There are recursion limitations. Also, it doesn't use r5 for parameters, the actual routine even pushes r5.

    Its not working. Here is the script and code
    Spoiler:
     

    Blah

    Free supporter
  • 1,924
    Posts
    11
    Years
    Its not working. Here is the script and code
    Spoiler:

    Uhh, you've got issues with your script AND your routine. I'll address the routine issues here.

    Code:
    .text
    .align 2
    .thumb
    .thumb_func
    
    main:
    	push {r0-r3, lr}
    	ldr r0, =(0x8720000)
    	ldr r1, =(0x8069AE4 +1)
    	bl linker
    	pop {r0-r3, pc}
    	
    linker:
    	bx r1
    	
    .align 2

    In your routine, you pushed the registers, but haven't popped them. This creates misaligned pushes and pops. That being said, because we have to use bx to reach the function (in this case), we need to use the "bl linker" tactic of branching in order to write to the link register so you CAN pop. That's the error with your routine.

    For your scripts, I notice you're not using dynamic offsets, which is fine if you know what you're doing. However, 72000 is not free space (for your first script). I suggest just using dynamic offsets all the time, unless you're editing something specific. On top of that, you're missing a few other commands like "end" in your scripts. Read up on a few scripting tutorials and such for more on that stuff.
     

    daniilS

    busy trying to do stuff not done yet
  • 409
    Posts
    10
    Years
    • Seen Jan 29, 2024
    I think the actual reason it isn't working is because you need 08 before the callasm offset.
     

    jiangzhengwenjzw

    now working on katam
  • 181
    Posts
    11
    Years
    • Seen yesterday
    There are recursion limitations. Also, it doesn't use r5 for parameters, the actual routine even pushes r5.

    Hello, I've read your ""Hooking" from existing routines" tutorial, but I have a small problem.
    When setting the bx to the new program, the value of R2 was changed. Though it will be changed again by r0 (in the program at 08008DA4) after that in this case, but I think there maybe another case which do not refresh value of r2 after the program so it's not safe to use R2 to load other values.
    So can you tell me the reason to not use push {r2} & pop {r2}?
     

    Blah

    Free supporter
  • 1,924
    Posts
    11
    Years
    I think the actual reason it isn't working is because you need 08 before the callasm offset.
    No you don't, XSE and PKSV both add the 08 prefix during compile time if it's not already there. Noob scripter daniilS, pls :P

    Hello, I've read your ""Hooking" from existing routines" tutorial, but I have a small problem.
    When setting the bx to the new program, the value of R2 was changed. Though it will be changed again by r0 (in the program at 08008DA4) after that in this case, but I think there maybe another case which do not refresh value of r2 after the program so it's not safe to use R2 to load other values.
    So can you tell me the reason to not use push {r2} & pop {r2}?

    Hi, by ASM standards r0-r3 are assumed by functions to be safe to be parameters. In the case the function doesn't require 4 parameters, it still assumes that these registers are safe to used. You'll notice that all functions will push any register equal or higher than r4. You avoid these kinds of scenarios by either pushing the low registers then modifying them accordingly, or by writing their values into higher registers before function calling so that they can be easily restored.

    Ex:
    Code:
    .text
    .align 2
    .thumb
    .thumb_func
    
    main:
    	push {r0-r3, lr}
    	
    	@r0 is the address for the first pokemon in the party
    	ldr r0, =(0x2024284)
    
    	@we save r0 by setting r4 to it.
    	mov r4, r0
    
    	@call decrypter func to return species
    	mov r1, #0xB
    	ldr r3, =(0x803FBE8 +1)
    	bl linker
    
    	@put the return of decrypter (species ID) into r1
    	mov r1, r0
    
    	@restore first pokemon, then do whatever to that address
    	@adding 0x64 is ofcourse getting the next 'Mon
    	mov r0, r4
    	add r0, r0, #0x64
    	....
    	....
    	pop {r0-r3, pc}
    	
    linker:
    	bx r3
    	
    .align 2

    Here we utilize the fact that functions will push all registers higher or equal to r4 which they use. So if we write into r4 something which we want to save that was previously in r0, then the function (if it uses r4) will push r4 (but not r0-r3), thus saving the values in r4. I.e it will not consume what's in r4, but there's no guarantee that r0-r3 is saved.

    Here's an example using the pushing method
    Code:
    .text
    .align 2
    .thumb
    .thumb_func
    
    main:
    	@suppose we're hooking from a function
    	@at this point, say r0 has the OTID. But we want to
    	@call a function which requires r0 to be 0x5 to work
    	ldr r0, =(OTID)
    	push {r0}
    	mov r0, #0x5
    	
    	@assuming r1 is not a required paramater
    	ldr r1, =(0x8Function +1)
    	bl linker
    
    	@functions return values are kept in r0, if not void
    	mov r1, r0
    	pop {r0}
    
    	@now r0 is back to being the OTID.	
    	
    linker:
    	bx r1
    	
    .align 2

    I prefer the writing to bigger sized registers method. However, it's likely, especially when you're hooking, that these registers contain data which shouldn't be overwritten. In such cases, you will need to push said registers.
     

    jiangzhengwenjzw

    now working on katam
  • 181
    Posts
    11
    Years
    • Seen yesterday
    No you don't, XSE and PKSV both add the 08 prefix during compile time if it's not already there. Noob scripter daniilS, pls :P



    Hi, by ASM standards r0-r3 are assumed by functions to be safe to be parameters. In the case the function doesn't require 4 parameters, it still assumes that these registers are safe to used. You'll notice that all functions will push any register equal or higher than r4. You avoid these kinds of scenarios by either pushing the low registers then modifying them accordingly, or by writing their values into higher registers before function calling so that they can be easily restored.

    Ex:
    Code:
    .text
    .align 2
    .thumb
    .thumb_func
    
    main:
    	push {r0-r3, lr}
    	
    	@r0 is the address for the first pokemon in the party
    	ldr r0, =(0x2024284)
    
    	@we save r0 by setting r4 to it.
    	mov r4, r0
    
    	@call decrypter func to return species
    	mov r1, #0xB
    	ldr r3, =(0x803FBE8 +1)
    	bl linker
    
    	@put the return of decrypter (species ID) into r1
    	mov r1, r0
    
    	@restore first pokemon, then do whatever to that address
    	@adding 0x64 is ofcourse getting the next 'Mon
    	mov r0, r4
    	add r0, r0, #0x64
    	....
    	....
    	pop {r0-r3, pc}
    	
    linker:
    	bx r3
    	
    .align 2

    Here we utilize the fact that functions will push all registers higher or equal to r4 which they use. So if we write into r4 something which we want to save that was previously in r0, then the function (if it uses r4) will push r4 (but not r0-r3), thus saving the values in r4. I.e it will not consume what's in r4, but there's no guarantee that r0-r3 is saved.

    Here's an example using the pushing method
    Code:
    .text
    .align 2
    .thumb
    .thumb_func
    
    main:
    	@suppose we're hooking from a function
    	@at this point, say r0 has the OTID. But we want to
    	@call a function which requires r0 to be 0x5 to work
    	ldr r0, =(OTID)
    	push {r0}
    	mov r0, #0x5
    	
    	@assuming r1 is not a required paramater
    	ldr r1, =(0x8Function +1)
    	bl linker
    
    	@functions return values are kept in r0, if not void
    	mov r1, r0
    	pop {r0}
    
    	@now r0 is back to being the OTID.	
    	
    linker:
    	bx r1
    	
    .align 2

    I prefer the writing to bigger sized registers method. However, it's likely, especially when you're hooking, that these registers contain data which shouldn't be overwritten. In such cases, you will need to push said registers.

    Sorry as I do not really understand your meanings. TAT

    First, below is what I get from your words.
    I think in your reply you showed two ways of restoring data in low registers:
    1. Storing it into registers higher than r3 and then restoring it through that rX because when X is higher than 3 it's always pushed if used.
    2.Using push and pop command to keep the value of a register.

    But you have said "but there's no guarantee that r0-r3 is saved".
    In your tutorial ""Hooking" from existing routines" you use r2 to make a branch (ldr r2, =(0x8[where we plan to insert our snipplet] +1)) so that the value of r2 is changed to the pointer of the new program. My meaning is that if the modified program "0809A8BC" is called before another function which use R2 as a parameter, then why won't it cause problems?

    Maybe the question is kinda silly, but I really want to know it.
     

    Blah

    Free supporter
  • 1,924
    Posts
    11
    Years
    Sorry as I do not really understand your meanings. TAT

    First, below is what I get from your words.
    I think in your reply you showed two ways of restoring data in low registers:
    1. Storing it into registers higher than r3 and then restoring it through that rX because when X is higher than 3 it's always pushed if used.
    2.Using push and pop command to keep the value of a register.

    But you have said "but there's no guarantee that r0-r3 is saved".
    In your tutorial ""Hooking" from existing routines" you use r2 to make a branch (ldr r2, =(0x8[where we plan to insert our snipplet] +1)) so that the value of r2 is changed to the pointer of the new program. My meaning is that if the modified program "0809A8BC" is called before another function which use R2 as a parameter, then why won't it cause problems?

    Maybe the question is kinda silly, but I really want to know it.

    I see now. You're confused as to why we can use r2 as the bx register for our jump when it's not safe to use in general. Allow me to explain.

    Lets first take a look at the routine at 0809A8BC.

    Spoiler:

    As you can see, the whole function doesn't use r2. However, this is just something that happened in this specific case. We can tell by just looking at the above routines that this function doesn't use r2 as a parameter AND that r2 isn't used for any of the calculations. However, there can be routines which don't take r2 as a parameter but use it for calculation inside the routine.

    In general, if the registers aren't specifically used as parameters, you can use them to call the function. If they're not parameters, the only way for them to be used inside the routine is for calculations. For example, lets look at the other routine you were talking about.

    Code:
    ROM:08008DA4 gf_strcat:                              
    ROM:08008DA4                                         
    ROM:08008DA4                 PUSH    {LR}
    ROM:08008DA6                 MOV    R2, R0
    ROM:08008DA8                 B       loc_8008DAC
    ROM:08008DAA @ ---------------------------------------------------------------------------
    ROM:08008DAA
    ROM:08008DAA loc_8008DAA:                            
    ROM:08008DAA                 ADD    R2, #1
    ROM:08008DAC
    ROM:08008DAC loc_8008DAC:                           
    ROM:08008DAC                 LDRB    R0, [R2]
    ROM:08008DAE                 CMP     R0, #0xFF
    ROM:08008DB0                 BNE     loc_8008DAA
    ROM:08008DB2                 MOV    R0, R2          @ dst
    ROM:08008DB4                 BL      strcpy_xFF_terminated
    ROM:08008DB8                 POP     {R1}
    ROM:08008DBA                 BX      R1

    Clearly here, r2 cannot be a Parameter because it's overwritten by r0 in the first OP code after the push statement. In fact, if r2 or r1 isn't a parameter, but it used in calculations, the routine must first make measures to "clean" or set them. This is because the function doesn't know from where it may be getting called from. In this case r2 is overwritten with r0, so the old value of r2 is irrelevant to the function. Notice that because r2 is overwritten, the function which calls this one had it's old value of r2 changed. This is what I mean by "we cannot guarantee registers r0-r3 aren't overwritten".

    To take away from this, basically if a register isn't used specifically as a parameter for the function, and is a low register, then it's safe to use as a caller register.
     

    Chaotix

    Love to test
  • 59
    Posts
    17
    Years
    • Seen Jan 11, 2020
    It might be the set trainer level specials now that I remember correctly. I would try reverting the bytes that the set trainer level special hack changes to those of an unhacked Firered, as it interferes with the EV hack. Here is what fixed it for me: go to 0x011624. The bytes there should be "00 48 00 47 ?? ?? ?? 08". Overwrite that with Firered's original coding, which is: "20 1C 33 1C 2C F0 14 FA". It should work now (that, or there might be another thing I forgot.)

    Yes, it is only two bytes. In ASM code, this is all that is being done:
    Spoiler:

    Thanks for the help, I really appreciate it.

    Changing the bytes you listed have seemingly allowed it to work; at least the pokeball they use to send out pokemon has changed so I know that much is working.

    I wasn't intending on using JPAN's trainer level hack for what I'm currently working on anyway, so that is fine.
     
    Status
    Not open for further replies.
    Back
    Top