• Just a reminder that providing specifics on, sharing links to, or naming websites where ROMs can be accessed is against the rules. If your post has any of this information it will be removed.
  • Ever thought it'd be cool to have your art, writing, or challenge runs featured on PokéCommunity? Click here for info - we'd love to spotlight your work!
  • Our weekly protagonist poll is now up! Vote for your favorite Trading Card Game 2 protagonist in the poll by clicking here.
  • 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.
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...
 
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.
 
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
 
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?
 
@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
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?
 
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:
 
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?
 
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.
 
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:
 
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.
 
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}?
 
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.
 
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.
 
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.
 
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