(Link to AcmlmWiki) Offline: thank ||bass
Register | Login
Views: 13,040,846
Main | Memberlist | Active users | Calendar | Chat | Online users
Ranks | FAQ | ACS | Stats | Color Chart | Search | Photo album
04-19-24 09:47 AM
0 users currently in ROM Hacking.
Acmlm's Board - I3 Archive - ROM Hacking - A bit of help with THUMB and jumps? New poll | |
Pages: 1 2Add to favorites | Next newer thread | Next older thread
User Post
Xenesis

Blipper








Since: 11-19-05
From: Australia

Last post: 6270 days
Last view: 6269 days
Posted on 02-02-07 03:08 AM Link | Quote
Yeah, okay, so I'm just learning this, and this point kinda has me baffled a bit.

What's the best way to jump significant distances in the ROM? I ask because there's a function that I want to add to.

Currently at 080176A6 there's the function (In Advance Wars 2) that gets the current day, increments it by 1 and then saves it and returns (BL LX I think). I want to make it write to that address as usual, copy it to another address, LSL it and copy to a third address and LSL it again and copy it to the fourth address.

Now, there's almost no empty space in the rom I could jump to within a small range (IE, Less than 0x2048). However, there's about 2Mb of free space at the end of the ROM, and I don't really understand how to jump all the way down there, even after reading the GBATEK document.

Thanks for you help guys.
Cellar Dweller +

Red Koopa









Since: 11-18-05
From: Arkansas

Last post: 6279 days
Last view: 6269 days
Posted on 02-02-07 04:15 AM Link | Quote
I don't have any experience with ARM, but I can suggest a couple of general strategies that might help. First, most CPU architectures support an instruction that jumps to an address in a register. You load the target address into a register, then jump to it. Another option some architectures support is pushing an address onto the stack and executing a return instruction.

Like I said, I have no experience with ARM, but I have yet to see a CPU architecture that doesn't support at least one of the techniques described above.
Spikeman
Newcomer








Since: 09-10-06
From: Undernet

Last post: 6269 days
Last view: 6269 days
Posted on 02-02-07 08:16 AM Link | Quote
This is generally how I do it:

ldr r0,[jump]
mov lr,pc
bx r0
b return
jump
@dcd 0x8F00000|1 ; ORing 1 keeps it in THUMB, this is somewhere at the end of the ROM
return

It's a little different if you need to preserve lr, or don't have a free register, and even harder if you don't have enough space (for example, the routine you want to jump from only has like two instructions and code jumps into it at different places).
Xenesis

Blipper








Since: 11-19-05
From: Australia

Last post: 6270 days
Last view: 6269 days
Posted on 02-02-07 08:29 AM Link | Quote
Thanks Spikeman, that helps me a lot.

Although, if I do need to preserve the lr, how would I do that? Just copy the current lr contents to another register, and then move it back into the lr when I've finished my routine?
Dwedit

Rope
フクト オン フォニクス








Since: 11-17-05
From: Chicago!

Last post: 6271 days
Last view: 6270 days
Posted on 02-03-07 01:12 AM Link | Quote
Usually you push and pop LR. Alternatively, push lr and pop pc.
Zeld

Red Paragoomba








Since: 11-05-06

Last post: 6273 days
Last view: 6270 days
Posted on 02-03-07 03:47 AM Link | Quote
The alternate is actually the standard...you can't pop LR in thumb mode.

You could use a load SP relative as an alternate...and decrement it yourself to emulate a full pop (it is decrement, right? I don't pay much attention to that).
Spikeman
Newcomer








Since: 09-10-06
From: Undernet

Last post: 6269 days
Last view: 6269 days
Posted on 02-04-07 06:13 AM Link | Quote
Since you can't pop lr, you should do something like this:

push {lr}
ldr r0,[jump]
mov lr,pc
bx r0
b return
jump
@dcd 0x8F00000|1 ; ORing 1 keeps it in THUMB, this is somewhere at the end of the ROM
return
pop r0,lr
mov lr,r0
Zeld

Red Paragoomba








Since: 11-05-06

Last post: 6273 days
Last view: 6270 days
Posted on 02-08-07 01:38 AM Link | Quote
A bit late for this, but I just thought of something neat:

Hector of Chad: Wait
Hector of Chad: I've got it
Hector of Chad: push {r0}
Hector of Chad: mov r0, #0x[somebyte]
Hector of Chad: lsl r0, r0, #0x[some shift amount]
Hector of Chad: mov pc, r0
Hector of Chad: You'd only be able to go to a small handful of addresses
Hector of Chad: but if you used it to jump to the end of the ROM
Hector of Chad: and made a loop that determines where you branched from based on LR
Hector of Chad: You could insert assembly hacks without losing registers and with minimum necessary space in the original routine to branch from

So, like,

push {r0}
mov r0, #0x9
lsl r0, r0, #0x18
mov pc, r0

That takes you to the end of the ROM, preserves all registers, and only requires 4 instructions out of the original routine, which should be easy enough to find, right?

The LR loop check is inefficient, but the preservation is nice. I haven't had any problems with any games I've changed that were caused by having too long of a custom sub routine.

Any ideas of improvement?

Edit: Arg, I forgot about the thumb bit. Well, that would cost an add r0, #0x1. Only one instruction...hopefully not going to be a problem

Not like you can't just go there in ARM mode and switch back to thumb, to handle situations where you can't get in 5 replacement opcodes but can do 4.


(edited by Zeld on 02-07-07 07:43 PM)
(edited by Zeld on 02-07-07 07:45 PM)
(edited by Zeld on 02-07-07 07:45 PM)
(edited by Zeld on 02-07-07 07:46 PM)
(edited by Zeld on 02-07-07 07:47 PM)
Xenesis

Blipper








Since: 11-19-05
From: Australia

Last post: 6270 days
Last view: 6269 days
Posted on 02-08-07 06:55 AM Link | Quote
Zeld, that's so simple it's insanely stupid. I approve. And it wouldn't be too hard to get a range of addresses to jump to anyhow. Just add an offset to the jump address after you lsl it.

*goes to fiddle*
HyperHacker

Star Mario
Finally being paid to code in VB! If only I still enjoyed that. <_<
Wii #7182 6487 4198 1828


 





Since: 11-18-05
From: Canada, w00t!
My computer's specs, if anyone gives a damn.
STOP TRUNCATING THIS >8^(

Last post: 6270 days
Last view: 6270 days
Posted on 02-08-07 09:32 AM Link | Quote
That's clever. Doesn't the mov instruction allow shifting though? So instead of:
mov r0, #0x9
lsl r0, r0, #0x18

you could just do:
mov r0, #0x9 LSL #0x18

or however that's written. Maybe I'm just tired but I seem to recall ARM supporting that.
MathOnNapkins

1100

In SPC700 HELL


 





Since: 11-18-05

Last post: 6269 days
Last view: 6269 days
Posted on 02-08-07 09:38 AM Link | Quote
^ You can do that with ARM, but I'm pretty sure you can't do that with THUMB, and the poster is having problems with THUMB jumps in particular.
Xenesis

Blipper








Since: 11-19-05
From: Australia

Last post: 6270 days
Last view: 6269 days
Posted on 02-08-07 11:26 AM Link | Quote
Zeld, that worked like a treat. Now to actually go about writing my new routine.

Here's the jump code:

B401 Push r0
2087 mov r0, #0x87
0500 lsl r0, r0 #0x14
1c40 add r0, r0, #0x1
4687 mov pc, r0

That jumps to address 08700001, the pc increments by 1 and it continues in THUMB mode.


(edited by Xenesis on 02-08-07 05:29 AM)
Zeld

Red Paragoomba








Since: 11-05-06

Last post: 6273 days
Last view: 6270 days
Posted on 02-08-07 03:51 PM Link | Quote
Wait, wouldn't that be a decrement? Or does it "increment" because of pipelining? :\

You can set a register to a range of 255 (not 256, because 0 would be useless) values with the mov function (and no, you can't shift while moving, because that is indeed an ARM only feature. Also, I haven't seen even ARM mode do that with an immediate value, but I don't see why it couldn't). That gives lots of nice ROM addresses to jump to...factor in the concept of different shift amounts, and that expands it even more. Yeah, I guess you might not have to use an LR loop.

It's just, I don't want to have my assembly hacks spaced all over the expanded area of a ROM, because I'm working on expanding Fire Emblem 7, and there's lots of tables that will be going there. I'll have to place them accordingly with my assembly hacks in between with this new method, but I like it.

For Fire Emblem 8, I already used a

push {lr}
bl $[Table, where LR is popped and compared to possible LRs to determine which subroutine to execute]
pop {lr} - as stated above
ldr first possible LR
cmp register with loaded possible LR, current LR
bne [Next compare]
bl $[Hack]

Then, at the hack routine, I do my business and load some numbers into the 8 base registers that I use to repair LR before popping 0-7. From there, I usually load one last word into a register that won't be used by the next routine and mov pc, that register.

The returning issue is still there, I guess. You could still find registers that will be overwritten anyway and load a return address into it...or you could be a sneaky bastard and write your code in ARM, and load directly into PC (that works, doesn't it?)

Oh, I have another question. I just got done writing my IEEE 32 bit floating point processing functions that handle addition, reciprocation, and multiplication (which allows me to do all 4 basic math operations, since subtraction is a variant of addition and division is multiplying by the reciprocal). I had to write my mutliplication function in ARM to make use of "umull" (thanks to whoever pointed out the umull operation in the programming thread I made >.>).

After I assembled it and saw how big it was (400 bytes XP) I thought it would be slow, but it seems to actually calculate faster than the thumb scripts for addition and reciprocation. Is ARM mode just faster or something?

If anyone cares, my reciprocator and my addition programs have 1:1 results with an actual java-based floating point calculator, but my multiplication function tends to give outputs that are just 0x1 off from the expected output. I debugged it to see why and it turns out the error occurs during the umull instruction. I can't do anything about that :\


(edited by Zeld on 02-08-07 09:52 AM)
(edited by Zeld on 02-08-07 09:58 AM)
Xenesis

Blipper








Since: 11-19-05
From: Australia

Last post: 6270 days
Last view: 6269 days
Posted on 02-08-07 04:20 PM Link | Quote

Wait, wouldn't that be a decrement? Or does it "increment" because of pipelining? :\


I don't know. I just know it works. And yes, I was wrong, it is actually a decrement, I forgot that I just put an mov r0, r0 there. XD

Anyhow, I managed to complete my first assembly hack, using two jumps from code in Advance Wars 2. One is run once when starting a game and I use it to initialise some values, the other is updated every time the 'current day' is increased.

It needs a clean AW2 US rom (See releases for a cleaner if necessary), but here it is. It gives Adder the ability to power up over battle. He gets a firepower bonus based on what the current day is.

Attachments

venomadder.ips (528b) - views: 2
Zeld

Red Paragoomba








Since: 11-05-06

Last post: 6273 days
Last view: 6270 days
Posted on 02-08-07 09:52 PM Link | Quote
You know, if you debug the process of a mov pc, it will take you to the address&fffffff7, but r15 will be equal to address&fffffff7 plus 2 or 4, depending on the processor mode. It actually DOES increment because of pipelining >.>

What's the relationship you decided on between the day number and Adder's firepower? If it's directly proportional it's gonna be broken, no?
Xenesis

Blipper








Since: 11-19-05
From: Australia

Last post: 6270 days
Last view: 6269 days
Posted on 02-09-07 01:23 AM Link | Quote
Yeah, it is pretty broken.

While I'm normally a balance freak when it comes to AW2, this was something more to cut my teeth on before I go onto bigger and greater things.

Edit: I've discovered that the patch doesn't work in Campaign or War Room. It appears that those memory addresses are used for other things. ;

Oh well, I'll fix it up when I have time. Still works flawlessly in versus.

Edit 2: Fixed Version. Huzzah. That'll teach me to be sloppy with choosing my memory addresses. ;


(edited by Xenesis on 02-09-07 06:18 AM)
RadioShadow









Since: 06-25-06

Last post: 6278 days
Last view: 6269 days
Posted on 02-09-07 05:52 PM Link | Quote
Yay! Xen fixed it! 'plays'
Xenesis

Blipper








Since: 11-19-05
From: Australia

Last post: 6270 days
Last view: 6269 days
Posted on 02-11-07 07:26 AM Link | Quote
Okay, I've got my head around jumps and stuff now, so I've got a new question.

Comparisons.

I want something to branch if I compare it.

Eg, if r0 = 0, Add 0x10 to the PC or something. However, looking at the Conditional Branches section of the GBATEK document, all I can see is that you can't do direct register comparisons, yes? You have to compare the CPSR condition flags right?

Now, for my code I want it to skip them if r0 = 1.

Hence:
cmp r0, 0x1

Hence then if r0 = 1, then the Z would be set to 0, right?
then I go
bne (0xjump).

Is that correct, or am I going about this the wrong way?
HyperHacker

Star Mario
Finally being paid to code in VB! If only I still enjoyed that. <_<
Wii #7182 6487 4198 1828


 





Since: 11-18-05
From: Canada, w00t!
My computer's specs, if anyone gives a damn.
STOP TRUNCATING THIS >8^(

Last post: 6270 days
Last view: 6270 days
Posted on 02-11-07 09:19 AM Link | Quote
A Compare operation simply performs a subtraction and doesn't store the result. So when you do for example cmp r0, 0x10, the CPU does r0 - 0x10 and updates the flags accordingly. If r0 == 0x10, then the result will be zero, so the Z(ero) flag will be set. If r0 < 0x10, the result will be negative, so the N(egative) or C(arry) flag will be set. (Not sure which ARM/Thumb has, most likely carry.)
Xenesis

Blipper








Since: 11-19-05
From: Australia

Last post: 6270 days
Last view: 6269 days
Posted on 02-11-07 10:46 AM Link | Quote
The processor has NCZV flags, so it does both carry and negative, I would assume. But thanks, I seem to have gotten the compare operation the other way around. ;
Pages: 1 2Add to favorites | Next newer thread | Next older thread
Acmlm's Board - I3 Archive - ROM Hacking - A bit of help with THUMB and jumps? |


ABII

Acmlmboard 1.92.999, 9/17/2006
©2000-2006 Acmlm, Emuz, Blades, Xkeeper

Page rendered in 0.021 seconds; used 447.68 kB (max 581.05 kB)