[ASM] Need a wizard's help with this ASM >_>

#1

My 1st ASM and it’s ugly.
What I try to do:
Have Critical DMG calculation check for Class ID to
either apply a x3DMG (vanilla [DMGx2]+DMG) on generic criticals
or a x5DMG [(DMGx4)+DMG] on specified class (in this example, Eirik’as Lord ID 0x2)

Vanilla CRT claculation (Taken from CrazyColors' doc)

0802B50C 683B ldr r3,[r7] @Critical but no lethality.
0802B50E 681A ldr r2,[r3]
0802B510 0351 lsl r1,r2,#0xD
0802B512 0B49 lsr r1,r1,#0xD
0802B514 4321 orr r1,r4
0802B516 4815 ldr r0,=#0x7FFFF
0802B518 4001 and r1,r0
0802B51A 4815 ldr r0,=#0xFFF80000

0802B51C 4010 and r0,r2
0802B51E 4308 orr r0,r1
0802B520 6018 str r0,[r3]
0802B522 2004 mov r0,#0x4
0802B524 5E29 ldsh r1,[r5,r0] @Load damage
0802B526 0048 lsl r0,r1,#0x1
0802B528 1840 add r0,r0,r1
0802B52A 80A8 strh r0,[r5,#0x4] @Store back.


I try to insert a CallHack jump in @2B51C which will bring me in front of @2B528
where the multiplied DMG is getting added once more by itself.

The EA file:

#ifndef FE8
ERROR “You’re not assembling to an FE8 ROM!”
#endif

#include EAStdlib.event
#include “Extensions/Hack Installation.txt”

#ifndef Free_Space
#define Free_Space 0xB2A610 // Vanilla free space
ORG Free_Space
#endif

PUSH

ORG $2B51C
callHack_r0(Hack)

POP

ALIGN 4
Hack:
#incbin “Lord(0x2)CRTx5.dmp”


^Use r0 for the CallHack which I feel is wrong but can’t get it work even with r1-3.

The ASM file:

.thumb

@called from 2B51C

push {r0-r5,r14}
and r0,r2
orr r0,r1
str r0,[r3]
mov r0,#0x4 @This and the above 3 lines are copied from the original
ldsh r1,[r5,r0] @Load DMG in r1
ldr r3,[r6,#0x4] @Load Class data in r3
ldrb r3,[r0,#0x4] @Load byte 0x4 (Class ID) in r3
cmp r3,#0x2 @Compare and check for Lord(0x2) class
bne NotALord @If not a Lord(0x2) go to NotALord
lsl r1,#2 @Multiply r1 by 4 (r1 being the stored DMG)
b JoinUp

NotALord:
lsl r1,#1 @Multiply r1 by 2 (r1 being the stored DMG)

JoinUp:
pop {r0-r5}
bx r0


^Which is wrong because the game crashes on a save load.

Someone please help me fix this.

#2

Have you forgotten pop?
it seems that push and pop are not balanced.

pop {r0-r5}
pop {r0}
bx r0
1 Like
#3

This fixes the game crashes.
(But why pop again?)

But now criticals don’t do DMG, and enemies on enemy phase attack 3 times.
Seems I broke the content of the registers.

#4

Explain why, it’s a story about C language prologues and epilogues.

push {r0-r5、r14}

You pushed r0-r5 and r14.
In other words, 6 + 1 = 7 pushes.
r14 (lr) is the return destination of the function.

pop {r0-r5}
bx r0

You popped r0-r5.
That means 6 + 0 = 6 popped.

7 and 6 are different.
So the balance is broken and the game is broken.

If you pop again, you can take out the r14 that was pushed 7th.
In r14, the return destination of the function was written.
So return to it with bx.

1 Like
#5

I see. Thanks!
I thought r14 returns by itself. I understand now.

#6

This routine was a simple reason for the crash.
It is a problem that can be understood simply by looking at it.

However, the reason why it does not work as expected is not understood without investigation.
Please do your best to investigate it.

track with no$gba debugger.
Somewhere in your code, something you’re not expecting should have occurred.
Please verify it one by one.

1 Like
#7

Solved the problem with the units acting of turn multiple times.
However, CRT (only) DMG is still 0.

New ASM:

I think the problem are the registers.
r0-r3 are needed in the formula.
In the EA “CallHack” needs a register.
Using r0-r3 for “CallHack” won’t play the CRT Animations and CRT DMG is 0.
Using r4 for “CallHack” will play the CRT Animations but CRT DMG is 0.

#8

You’ve got quite a few issues.

  1. You’re trying to return a value in r1, but since you pop r0-r5 at the end, whatever’s in r1 gets overwritten.

  2. The first opcode encountered when you return is add r0,r1; since you’re doing pop {r0}; bx r0, r0 is going to be the return address, and not the damage value.

  3. The place where you put your hook has no free registers to use callHack with. r0 gets and'd with r2, orr'd with r1, and stored in r3, meaning all 4 of your scratch registers are being used. You can actually use r4 here because it gets overwritten at 2B52C, but you have to be careful.

My recommendation would be to move your hook from 2B51C to 2B520, allowing you to use either r1 or r2 with callHack. You don’t need to push r0-r3 normally, since they’re scratch registers, and you don’t need to push r4 or r5 unless you’re changing them (which you’re not; you’re just using the existing values).

I’ve included how I’d rewrite the asm file; try and rewrite it yourself and check.

My answer
.thumb

@called from 2B520

    push {r14}
    str r0,[r3]
    mov r0,#0x4
    ldsh r1,[r5,r0]
    ldr r2,[r6,#0x4]
    ldrb r2,[r6,#0x4] OOPS this should actually be ldrb r2,[r2,#0x4]
    cmp r2,#0x2
    bne NotALord
    lsl r0,r1,#2
    b JoinUp

    NotALord:
    lsl r0,r1,#1

    JoinUp:
    add r0,r0,r1
    strh r0,[r5,#0x4]
    pop {r0}
    bx r0

And update the EA installer with
ORG $2B520
callHack_r1(Hack)

3 Likes
#9

I thought that the new values in r1-r5 return back, not that the old values are reloaded. I see.

Does No.2 happen because I pushed r0 at the start?
Otherwise pop {r0}; bx r0 doesn’t overwrite r0 right (or did I misunderstand)?

I had tried No.3 (try @25B20) to “save up” o registers
but because I pushed r0-5, the AssembleARM wouldn’t accept the file
as “incorrect strh r0,[r5,#0x4]”. Now I understand why.

Yes the ASM is identical except for this line: ldrb r2,[r6,#0x4]
where in r6 i put r2 but works fine now (both melee, ranged, physical and magical attacks)

I understand a bit better now how ASM works.
Thank you Tequila and 7743 for this fast crash course.

#10

Push copies the values in the registers to the stack; pop copies values from the stack to the registers, overwriting whatever was there previously. It’s used to save stuff that you need later.

No. 2 happens because pop {r0} puts the top value from the stack into r0. In this case, that value is what used to be in r14 at the beginning (the return address). Although, even if you hadn’t done this (ie, popped into r2, for instance), r0 would still have been overwritten by its original value due to the pop {r0-r5}, yes.

Not sure why strh r0,[r5,#0x4] wouldn’t work. It certainly should.

I actually messed up on that line and it should indeed be ldrb r2,[r2,#0x4]. Good catch!

1 Like
#11

I highly recommend Teq’s guide. It’s good for learning opcodes and getting used to convention stuff.

1 Like
#12

Yes, I’ve read that already.