Help Thread ASM & Disassembly Page 25

Started by Spherical Ice December 1st, 2014 11:05 AM
  • 65283 views
  • 626 replies

miksy91

Dark Energy is back in action! ;)

Male
Finland
Seen September 21st, 2022
Posted September 21st, 2022
1,480 posts
14.6 Years
Ok... You kind of made me both less and more confused at the same time. I assumed jr z was something like "jump if equal to" but seeing as it means "jump if zero" makes more sense.

So, as I want it to be 0 if the values are the same, would my code example
ld a,[wcf91] cp a,GREAT_BALL ld a,8 jr z,.skip1 ld a,[wcf91] cp a,ULTRA_BALL ld a,4 jr z,.skip1 ld a,12be what I want to use to make it work properly?
P.S. The .skip1 is right after "ld a,12", so that thing about being near in bytes I don't need to worry about.
In that case when the CPU starts executing code starting at address ".skip1", register a would have value 0x8 if you had Great Ball, 0x4 if you had Ultra Ball and 0x12 otherwise. In case that's what you're intending to do, surely works :)

Better programming style would probably be storing the value of [wcf91] in some other register while this code is run though. You could for example push one of the other register pairs onto stack (which is for example a memory area in work ram between $DF00-$DFFF in Gold and Silver) and then use one of its registers for storing the value.
Basically, you could do the following:

push bc
ld a,[wcf91]
ld b, a
cp a, GREAT BALL
ld a, 8
jr z, .skip1
ld a, b
cp a, ULTRA BALL
...
and so on. At ".skip1" you could simply make the game execute pop bc to get the value back from stack. This would make registers b and c get their original values back and set the stack pointer (= SP register pair) to point to the value that was originally at the top of the stack.

In case you're wondering what stack (in GB/C hardware) is, it's a data structure that is used for storing values of register pairs for further usage. One good example of stack usage is calling subroutines.

Whenever "call" command is executed, the address of the instruction that is "after" the call command is pushed onto stack, and "jump" to the called address is executed. Now a subroutine is called. When the subroutine finally ends (after possibly calling several other subroutines which could have also called other subroutines and so on) by "ret" command, two bytes are popped out of the top of the stack and "jump code is executed to the address these bytes refer/point to". This "jump" basically means setting the those bytes as the new 16-bit (or 2-byte) value of program counter (= PC register pair which tells where the next instruction to be executed is loaded from). Now because the address of the instruction after call command was pushed onto stack (when the subroutine was called), this address is put into PC and the next instruction to be executed is that (and this is how call command works).

Similarly you can push other register pairs onto stack as well, save their original values there, and pop them out of the stack when you don't need to use them "for your own purposes" anymore. Doing stuff like this might be "cleaner" in the code you're writing.
Pokémon Dark Energy
Some ROM hacking related stuff

i0Bjhansen0

Age 27
Male
Seen 1 Week Ago
Posted August 30th, 2017
130 posts
7.2 Years
In that case when the CPU starts executing code starting at address ".skip1", register a would have value 0x8 if you had Great Ball, 0x4 if you had Ultra Ball and 0x12 otherwise. In case that's what you're intending to do, surely works :)
Yes that's exactly what I'm trying to do. That's all I needed to know, if it works or not. I didn't want to use b (or any other letter) because a was already being used in that section by the value of the Pokeball and then the ball factor. So at the small chance that by changing b, I could be changing a value already set, I could ultimately be creating another bug (but then I read again that you said push and pop. nvm). But thanks anyway. My first GAMEFREAK bug squashed ^_^ (and without any prior knowledge of ASM).

[EDIT] I posted on the ASM resource thread but totally forgot about this help thread which I should have put my post on. I want to make abilities like Overgrow, Torrent, Blaze, and Swarm that power up moves when the user is 33% HP or less.

But could someone please... (for Fire Red)
1. Provide an offset to change to hook a new routine off of to make a new ability.
2. Provide something similar to the original "power up" ability that has notes to what can be changed.
3. And provide a bit of code to allow the routine to return to the original routine.

So, for instance.
Spoiler:
this may not even be remotely close to actual asm. just me trying to be less obscure.
[Start routine]
(code needed to start)
insert XX XX XX (As many times necessary) YY(+1 if necessary) YY YY (offset) XX XX at 0xXXXXXX

.main
check health
if <33% goto .abilitycheck
if not goto .return

.abilitycheck
check ability
if Torrent goto .powerupwater
if Blaze goto .powerupfire
if Overgrow goto .powerupgrass
if Swarm goto .powerupbug
if (new ability) goto .powerup(new type)
if not goto .return

.powerupwater
check movetype
if notwater goto .return
increase power
goto .return

.powerupfire
checkmovetype
if notfire goto .return
increase power
goto .return

.powerupgrass
checkmovetype
if notgrass goto .return
increase power
goto .return

.powerupbug
checkmovetype
if notbug goto .return
increase power
goto .return

.powerup(new type)
checkmovetype
if not(new type) goto .return
increase power
goto .return

.return
(code to return back to the original routine)

(any other remaining code to tie up loose ends or whatnot)

Hopefully someone with the knowledge can understand what I typed.

AkameTheBulbasaur

Akame Marukawa of Iyotono

Age 25
Male
A place :D
Seen 2 Weeks Ago
Posted January 11th, 2023
408 posts
10 Years
I'm trying to make the Ability Aerilate be an item instead of an ability. I used Mr.DollSteak's Aerilate routine as a base.

I'm using an item called the Flame Orb to be a Fire Type version of Aerilate (where it turns Normal Type moves into Fire Type moves and boosts their power).

Here's what I did:

Spoiler:
.text
.align 2
.thumb
.thumb_func

main:
mov r3, r10
cmp r3, #0xKK
beq NormalCheck

NormalCheck:
mov r0, r10
cmp r0, #0x0
beq FlameOrb

FlameOrb:
mov r0, #0xA
b Boost

Boost:
push {r0-r1}
mov r0, r8
mov r1, #0xA7
mul r0, r1
lsr r0, #0x7
mov r8, r0
mul r7, r1
lsr r7, #0x7
pop {r0-r1}
b StoreType

StoreType:
mov r10, r0
ldr r0, .ChangeTypeLoc
ldr r1, [r0]
add r1, #0x13
ldrb r2, [r1]
cmp r2, #0x0
bne Return
mov r2, r10
strb r2, [r1]

Return:
ldr r0, [sp, #0x4]
ldrh r0, [r0, #0xA]
str r0, [sp, #0x18]
ldrh r0, [r6, #0x2E]
cmp r0, #0xAF
bne NoEnigmaBerry
ldr r1, .Return
bx r1

NoEnigmaBerry:
ldr r0, .Return2
bx r0

.align 2
ChangeTypeLoc: .word 0x02023FE8
Return: .word 0x0803ED87
Return2: .word 0x0803EDA1


I want to know if this would actually work before I put it in the game. Thanks in advance for any help!
"The human sacrificed himself, to save the Pokemon. I pitted them against each other, but not until they set aside their differences did I see the true power they all share deep inside. I see now that the circumstances of one's birth are irrelevant; it is what you do with the gift of life that determines who you are." -Mewtwo
Male
Seen October 1st, 2016
Posted July 13th, 2016
4 posts
9.6 Years
Hi, i get a bug with this routine:
.align 2
.thumb


So:
push {r4-r6, lr}
ldr r1, .VAR_8001
ldrb r1,[r1]
mov r2,#0x8
mul r2,r1
ldr r0, .OFF_TABLE
add r6,r0,r2
ldr r1,[r6]
ldr r3, =0x80086DD @gpu_tile_obj_alloc_tag_and_upload
bl bx_r3
add r6,#0x4
ldr r1,[r6]
ldr r3, =0x8008929 @gpu_pal_obj_alloc_tag_and_apply
bl bx_r3
LDR R5, =0x203AD40 @TEMPLATE
LDR R0, =0X08453184 @OAM
STR R0, [R5,#0x4]
LDR R0, ANIMATION
STR R0, [R5,#0x8]
ldr r0, =0x8231CFC @Rotscale
str r0, [r5, #0x10]
ldr r0, =0x810BB89 @Callback
str r0, [r5, #0x14]
@posx
ldr r1, =0x20370BC
ldrh r1, [r1]
LSL R1, R1, #0x14
mov r2, #0x80
lsl r2, r2, #0x11
add r1, r1, r2
lsr r1, r1, #0x10
mov r2, #0x0
@PosY
ldr r6, =0x20370BE
ldrh r2, [r6, #0x0]
lsl r2, r2, #0x14
mov r3, #0x80
lsl r3, r3, #0x11
add r2,r2,r3
lsr r2, r2, #0x10
@right
ldr r4, =0x8006F8D
bl bx_r4
pop {r4-r6}
POP {R1}
BX R1

bx_r3:
bx r3

bx_r4:
bx r4

.align 2
.VAR_8001:
.word 0x020370ba

.OFF_TABLE:
.word 0x08800000

.align 2
ANIMATION: .word OAMANIM + 0x08F00000
OAMANIM:
.hword 0x201
.hword 0xA
.hword 0xFFFE
.hword 0x0

My problem is with the:
POP {R1}
BX R1
If you see the routine In the NOGBA debugger says this:
CPU BAD OPERATION:
Undefined opcode - with no debug vector defined.
So, i can´t know what is the problem.
Male
Texas
Seen June 8th, 2022
Posted September 13th, 2016
16 posts
8.4 Years
So I have an error regarding the player's PC in their bedroom. Whenever the player uses the PC, and tries to turn it off, the blue screen stays on and the text box that says "What would you like to do" stays up. However, you aren't locked into the PC and can walk around, reuse the PC, and leave the room. Leaving the room turns off the PC, however if you go back and turn it on, the problem will occur again. I'm using the exact same script from normal FireRed, and I don't understand why this is happening. I did use the JPAN cleaning patch to wipe out some scripts, so I'm not sure if that's causing an issue. Anywho, here's the script.

Spoiler:
'---------------
#org 0x168CE4
special 0x187
compare LASTRESULT 0x2
if 0x1 goto 0x81A7AE0
lockall
setvar 0x8004 0x20
special 0x17D
setvar 0x8004 0x1
special 0xD6
sound 0x4
msgbox 0x81A5420 MSG_KEEPOPEN '"[player] booted up the PC."
special 0xF9
waitstate
special 0x190
releaseall
end

'---------------
#org 0x1A7AE0
release
end


'---------
' Strings
'---------
#org 0x1A5420
= [player] booted up the PC.


Hope someone can help me fix this, as why it doesn't affect gameplay at all, it's pretty annoying.
Pokémon Caelus
Make sure to check this out^

BluRose

blu rass

Age 22
Male
michigan tech
Seen 1 Week Ago
Posted April 9th, 2023
812 posts
9.1 Years
so um
i have an extremely simple question
basically, how does one remove an item from a pokémon in-battle?
Spoiler:
i'd imagine that it would be as simple as something like
ldr r0, .Item @(which would be like 0x2023D68 (held item) or 0x2023C12 (held item in-battle))
ldrh r1, [r0, #0x0] @load value of r0 into r1, right?
mov r1, #0x0 @overwrite the value to make it 0/no item

i'm probably totally misunderstanding the asm behind this, so...
do we then want to add something like:

str r1, r0

in order to store the byte in the address denoted by r0

EDIT: i did, in fact, look at battle command 0x6A (removeitem, referred to as atk6A_stash_item_for_side by IDA) for a little reference, and i just can't seem to really do anything with it ahaha
i've already found the branch point and everything. i just need to find out how to do this lol

EDIT2: i'm stupid, don't read the above
Spoiler:
ldr r0, =(0x02023D68)
mov r1, #0x1
strb r1, [r0]
ldr r0, =(0x02023C12)
strb r1, [r0]

the code above doesn't seem to work for making an item's index 0x0, effectively removing it
EDIT3: when in VBA's RAM-viewer, the two bytes that represent the hold items don't change at all despite the above code happening...
heyo check out my github:

BluRosie
highlights:
battle engine for heartgold
various feature branches in heart gold (fairy type, odd egg, mud slopes)

i'm a big part of the development team of pokemon firegold! all the code that i develop for that hack is also on my github

also on discord: BluRose#0412
Male
India
Seen November 9th, 2016
Posted September 11th, 2016
44 posts
8.6 Years
Hi, i get a bug with this routine:
.align 2
.thumb


So:
push {r4-r6, lr}
ldr r1, .VAR_8001
ldrb r1,[r1]
mov r2,#0x8
mul r2,r1
ldr r0, .OFF_TABLE
add r6,r0,r2
ldr r1,[r6]
ldr r3, =0x80086DD @gpu_tile_obj_alloc_tag_and_upload
bl bx_r3
add r6,#0x4
ldr r1,[r6]
ldr r3, =0x8008929 @gpu_pal_obj_alloc_tag_and_apply
bl bx_r3
LDR R5, =0x203AD40 @TEMPLATE
LDR R0, =0X08453184 @OAM
STR R0, [R5,#0x4]
LDR R0, ANIMATION
STR R0, [R5,#0x8]
ldr r0, =0x8231CFC @Rotscale
str r0, [r5, #0x10]
ldr r0, =0x810BB89 @Callback
str r0, [r5, #0x14]
@posx
ldr r1, =0x20370BC
ldrh r1, [r1]
LSL R1, R1, #0x14
mov r2, #0x80
lsl r2, r2, #0x11
add r1, r1, r2
lsr r1, r1, #0x10
mov r2, #0x0
@PosY
ldr r6, =0x20370BE
ldrh r2, [r6, #0x0]
lsl r2, r2, #0x14
mov r3, #0x80
lsl r3, r3, #0x11
add r2,r2,r3
lsr r2, r2, #0x10
@right
ldr r4, =0x8006F8D
bl bx_r4
pop {r4-r6}
POP {R1}
BX R1

bx_r3:
bx r3

bx_r4:
bx r4

.align 2
.VAR_8001:
.word 0x020370ba

.OFF_TABLE:
.word 0x08800000

.align 2
ANIMATION: .word OAMANIM + 0x08F00000
OAMANIM:
.hword 0x201
.hword 0xA
.hword 0xFFFE
.hword 0x0

My problem is with the:
POP {R1}
BX R1
If you see the routine In the NOGBA debugger says this:
CPU BAD OPERATION:
Undefined opcode - with no debug vector defined.
So, i can´t know what is the problem.
You haven't pushed r1, but it's used in the code. As an ASM beginner, how does that work?

miksy91

Dark Energy is back in action! ;)

Male
Finland
Seen September 21st, 2022
Posted September 21st, 2022
1,480 posts
14.6 Years
You haven't pushed r1, but it's used in the code. As an ASM beginner, how does that work?
That's most likely the reason the routine isn't working properly. When it "pops" R1 at the end of the routine, it takes the next value off the stack, loads that into R1, and adjusts the stack pointer to point to the value after that one. What probably happens here is that R1 gets the value where CPU is supposed to execute code next (because when your routine ended, it would return executing code to the location where this routine was called from. This happens by popping the next value off the stack onto PC (program counter) register (if that's what it is called in ARM/Thumb asm as well)).
CPU doesn't reach the point when this subroutine ends though because instruction "BX R1" seems to fail on "invalid" value that R1 has as NOGBA points out.

But simply pushing R1 before "push {r4-r6, lr}" ought to work. That way R1 gets its original value back before BX R1 is executed.
Pokémon Dark Energy
Some ROM hacking related stuff
Female
Seen December 13th, 2021
Posted December 13th, 2021
5 posts
8.3 Years
Hello, I'm new to ASM and I am trying to understand this function contained inside the firered rom. It is the executeram function at offset, 0806A28C. What it does is it uses what appear to be checksums at [0x03005008] + 0x32E0 and [0x03005008] + 0x361C to validate data pointed to by pointers at [0x03005008] + 0x32E4 (target is 332 bytes) and [0x03005008] + 0x3620 (target is 1000 bytes). But the problem I am having is understanding what each of the calls in this function are, and then how I would run this function outside of this rom. Would I have to convert it to C and then pass in the data 332 and 1000 byte data?

i.imgur.com/QD7Fvt0.png (Sorry, couldn't hyperlink)

Kimonas

%string not found

Age 27
Male
Greece
Seen December 19th, 2022
Posted December 26th, 2019
91 posts
12.8 Years
I'm trying to insert this asm script

Spoiler:
.text
.align 2
.thumb

main:
and r0, r1
lsr r0, r1
ldr r1, =(0x707)
cmp r0, 0x14
ble is_monster
cmp r0, 0x16
bhi is_monster
b end

is_monster:
ldr r1, =(0x808)

end:
ldr r0, =(0x6005a00)

ldr r4, =(0x08082c3c + 1)
bl linker

add r13, 0x80
pop {r4}
pop {r0}
bx r0

linker:
bx r4

.align 2


into the rom with the 'Project Template' way. But when I hit "python3 scripts/build" it gives me this error:

Spoiler:
./src/divine_white_text.s: Assembler messages:
./src/divine_white_text.s:9: Error: immediate expression requires a # prefix -- `cmp r0,0x14'
./src/divine_white_text.s:11: Error: immediate expression requires a # prefix -- `cmp r0,0x16'
./src/divine_white_text.s:24: Error: immediate expression requires a # prefix -- `add r13,0x80'


Any ideas what's the issue here?

edit: Just figured it out

DizzyEgg

Age 25
Male
Poland
Seen March 23rd, 2023
Posted April 23rd, 2020
794 posts
9.3 Years
I'm trying to insert this asm script

Spoiler:
./src/divine_white_text.s: Assembler messages:
./src/divine_white_text.s:9: Error: immediate expression requires a # prefix -- `cmp r0,0x14'
./src/divine_white_text.s:11: Error: immediate expression requires a # prefix -- `cmp r0,0x16'
./src/divine_white_text.s:24: Error: immediate expression requires a # prefix -- `add r13,0x80'


Any ideas what's the issue here?
The error log actually tells you what's the issue there. 'Immediate expressions' aka numbers like 20 or 0x14 require a '# prefix' aka you need to have that thingy '#' before the number. So, it should be:
cmp r0, #0x14
cmp r0, #0x16
add r13, #0x80

DizzyEgg

Age 25
Male
Poland
Seen March 23rd, 2023
Posted April 23rd, 2020
794 posts
9.3 Years
Is there a tutorial somewhere for someone who is a beginner? I found Shiny Quagsire's tutorial but the ASM pack download link returns a 404 error and the tutorial itself has some missing images.
Yeah. http://www.pokecommunity.com/showthread.php?t=343871

Lance32497

LanceKoijer of Pokemon_Addicts

Male
Criscanto town-Ginoa Region xD
Seen August 13th, 2017
Posted January 1st, 2017
792 posts
8.7 Years
So I have an error regarding the player's PC in their bedroom. Whenever the player uses the PC, and tries to turn it off, the blue screen stays on and the text box that says "What would you like to do" stays up. However, you aren't locked into the PC and can walk around, reuse the PC, and leave the room. Leaving the room turns off the PC, however if you go back and turn it on, the problem will occur again. I'm using the exact same script from normal FireRed, and I don't understand why this is happening. I did use the JPAN cleaning patch to wipe out some scripts, so I'm not sure if that's causing an issue. Anywho, here's the script.

Spoiler:
'---------------
#org 0x168CE4
special 0x187
compare LASTRESULT 0x2
if 0x1 goto 0x81A7AE0
lockall
setvar 0x8004 0x20
special 0x17D
setvar 0x8004 0x1
special 0xD6
sound 0x4
msgbox 0x81A5420 MSG_KEEPOPEN '"[player] booted up the PC."
special 0xF9
waitstate
special 0x190
releaseall
end

'---------------
#org 0x1A7AE0
release
end


'---------
' Strings
'---------
#org 0x1A5420
= [player] booted up the PC.


Hope someone can help me fix this, as why it doesn't affect gameplay at all, it's pretty annoying.
Not sure if this is the right place to ask this question 'cuz a simple scripting command called special can solve this. Anyway, just put special 0xD7 at the end of the script.
This signature has been disabled.
Scrollbar appears
Please review and fix the issues by reading the signature rules.

You must edit it to meet the limits set by the rules before you may remove the [sig-reason] code from your signature. Removing this tag will re-enable it.

Do not remove the tag until you fix the issues in your signature. You may be infracted for removing this tag if you do not fix the specified issues. Do not use this tag for decoration purposes.
Age 25
Male
Seen 2 Weeks Ago
Posted September 2nd, 2020
534 posts
10.7 Years
Hey I guys~! I was trying to implement FBI's BW HP Bars found at the community's hack section but after a few errors that I've fixed, a new error popped up that I do not know how to fix. Here's the error. :(
Where is: 8388608<class 'int'>
data is: <class 'bytes'>
Traceback (most recent call last):
File &quot;scripts//insert&quot;, line 142, in <module>
array.append(int(&quot;0x&quot; + hex(last)[7:], 0))
ValueError: invalid literal for int() with base 0: '0x

Blah

Free supporter

Male
Unknown Island
Seen 52 Minutes Ago
Posted February 28th, 2023
1,924 posts
10.3 Years
Hey I guys~! I was trying to implement FBI's BW HP Bars found at the community's hack section but after a few errors that I've fixed, a new error popped up that I do not know how to fix. Here's the error. :(
Where is: 8388608<class 'int'>
data is: <class 'bytes'>
Traceback (most recent call last):
File &quot;scripts//insert&quot;, line 142, in <module>
array.append(int(&quot;0x&quot; + hex(last)[7:], 0))
ValueError: invalid literal for int() with base 0: '0x
Can you provide a paste of insert.py that you're using? That looks like a custom one I used a while back for changing a pointer in a script some time ago, might have been left over junk.
...
Age 25
Male
Seen 2 Weeks Ago
Posted September 2nd, 2020
534 posts
10.7 Years
Can you provide a paste of insert.py that you're using? That looks like a custom one I used a while back for changing a pointer in a script some time ago, might have been left over junk.
Well, here it is. :)
Spoiler:
#!/usr/bin/env python
    
import os
import subprocess
import sys
import shutil
import binascii
import textwrap
import sys
import argparse

if sys.version_info < (3, 4):
        print('Python 3.4 or later is required.')
        sys.exit(1)

# Parse arguments
parser = argparse.ArgumentParser()
parser.add_argument('--offset', metavar='offset', type=int, 
                    help='offset to insert at', default=0x800000)
parser.add_argument('--input', metavar='file', 
                    help='input filename', default='BPRE0.gba')
parser.add_argument('--output', metavar='file', 
                    help='output filename', default='test.gba')
parser.add_argument('--debug', action='store_true',
                    help='print symbol table')

args = parser.parse_args()

PATH = 'C://devkitPro//devkitARM//bin'
PREFIX = 'arm-none-eabi-'
OBJCOPY = os.path.join(PATH, PREFIX + 'objcopy')
OBJDUMP = os.path.join(PATH, PREFIX + 'objdump')
NM = os.path.join(PATH, PREFIX + 'nm')
AS = os.path.join(PATH, PREFIX + 'as')
CC = os.path.join(PATH, PREFIX + 'gcc')
CXX = os.path.join(PATH, PREFIX + 'g++')

def get_text_section():
        # Dump sections
        out = subprocess.check_output([OBJDUMP, '-t', 'build/linked.o'])
        lines = out.decode().split('\n')
        
        # Find text section
        text = filter(lambda x: x.strip().endswith('.text'), lines)
        section = (list(text))[0]
        
        # Get the offset
        offset = int(section.split(' ')[0], 16)
        
        return offset
        
def symbols(subtract=0):
        out = subprocess.check_output([NM, 'build/linked.o'])
        lines = out.decode().split('\n')
        
        name = ''
        
        ret = {}
        for line in lines:
                parts = line.strip().split()
                
                if (len(parts) < 3):
                        continue
                        
                if (parts[1].lower() != 't'):
                        continue
                        
                offset = int(parts[0], 16)
                ret[parts[2]] = offset - subtract
                
        return ret
        
def insert(rom):
        where = args.offset
        rom.seek(where)
        print("Where is: " + str(where) + str(type(where)))
        with open('build\output.bin', 'rb') as binary:
                data = binary.read()
        rom.write(data)
        print("data is: " + str(type(data)))
        return where
                       
def hook(rom, space, hook_at, register=0):
        # Align 2
        if hook_at & 1:
            hook_at -= 1
            
        rom.seek(hook_at)
        
        register &= 7
        
        if hook_at % 4:
            data = bytes([0x01, 0x48 | register, 0x00 | (register << 3), 0x47, 0x0, 0x0])
        else:
            data = bytes([0x00, 0x48 | register, 0x00 | (register << 3), 0x47])
            
        space += 0x08000000
        data += (space.to_bytes(4, 'little'))
        rom.write(bytes(data))
        
def rom_write(new_ptr, address):
        rom.seek(int(address, 0))
        array = bytearray()
        array.append(int("0x" + hex(new_ptr)[7:], 0))
        array.append(int("0x" + hex(new_ptr)[5:7], 0))
        array.append(int("0x" + hex(new_ptr)[3:5], 0))
        array.append(int(hex(new_ptr)[:3], 0))
        rom.write(array)
        
shutil.copyfile(args.input, args.output)
with open(args.output, 'rb+') as rom:
        offset = get_text_section()
        table = symbols(offset)
        where = insert(rom)
        # Adjust symbol table
        for entry in table:
                table[entry] += where

        # Read hooks from a file
        with open('hooks', 'r') as hooklist:
                for line in hooklist:
                        if line.strip().startswith('#'): continue
                        
                        symbol, address, register = line.split()
                        offset = int(address, 16) - 0x08000000
                        try:
                                code = table[symbol]
                        except KeyError:
                                print('Symbol missing:', symbol)
                                continue

                        hook(rom, code, offset, int(register))
        last = 0;                     
        if args.debug:
                width = max(map(len, table.keys())) + 1
                for key in sorted(table.keys()):
                        fstr = ('{:' + str(width) + '} {:08X}')
                        print(fstr.format(key + ':', table[key] + 0x08000000))
                        last = (table[key] + 0x08000000)
        rom.seek(int(0x168CDB))
        array = bytearray()
        array.append(int("0x" + hex(last)[7:], 0))
        array.append(int("0x" + hex(last)[5:7], 0))
        array.append(int("0x" + hex(last)[3:5], 0))
        array.append(int(hex(last)[:3], 0))

        # bin data for replaced images
        with open('bin_replace', 'r') as bin_files:
                for line in bin_files:
                        x = line.split(" ")
                        rom.seek(int(x[1].strip("\n"), 0))
                        fname = 'src\\bins\\' + x[0]
                        with open(fname, 'rb') as binary:
                                data = binary.read()
                                rom.write(data)
                                
        # Pointer list
        print("\n")
        with open('place', 'r') as to_place:
                for line in to_place:
                        if line.strip().startswith('#'): continue
                        symbol, address = line.split()
                        rom_write(int(symbol, 0), address)
        rom.write(array)

Blah

Free supporter

Male
Unknown Island
Seen 52 Minutes Ago
Posted February 28th, 2023
1,924 posts
10.3 Years
Well, here it is. :)
Spoiler:
#!/usr/bin/env python
    
import os
import subprocess
import sys
import shutil
import binascii
import textwrap
import sys
import argparse

if sys.version_info < (3, 4):
        print('Python 3.4 or later is required.')
        sys.exit(1)

# Parse arguments
parser = argparse.ArgumentParser()
parser.add_argument('--offset', metavar='offset', type=int, 
                    help='offset to insert at', default=0x800000)
parser.add_argument('--input', metavar='file', 
                    help='input filename', default='BPRE0.gba')
parser.add_argument('--output', metavar='file', 
                    help='output filename', default='test.gba')
parser.add_argument('--debug', action='store_true',
                    help='print symbol table')

args = parser.parse_args()

PATH = 'C://devkitPro//devkitARM//bin'
PREFIX = 'arm-none-eabi-'
OBJCOPY = os.path.join(PATH, PREFIX + 'objcopy')
OBJDUMP = os.path.join(PATH, PREFIX + 'objdump')
NM = os.path.join(PATH, PREFIX + 'nm')
AS = os.path.join(PATH, PREFIX + 'as')
CC = os.path.join(PATH, PREFIX + 'gcc')
CXX = os.path.join(PATH, PREFIX + 'g++')

def get_text_section():
        # Dump sections
        out = subprocess.check_output([OBJDUMP, '-t', 'build/linked.o'])
        lines = out.decode().split('\n')
        
        # Find text section
        text = filter(lambda x: x.strip().endswith('.text'), lines)
        section = (list(text))[0]
        
        # Get the offset
        offset = int(section.split(' ')[0], 16)
        
        return offset
        
def symbols(subtract=0):
        out = subprocess.check_output([NM, 'build/linked.o'])
        lines = out.decode().split('\n')
        
        name = ''
        
        ret = {}
        for line in lines:
                parts = line.strip().split()
                
                if (len(parts) < 3):
                        continue
                        
                if (parts[1].lower() != 't'):
                        continue
                        
                offset = int(parts[0], 16)
                ret[parts[2]] = offset - subtract
                
        return ret
        
def insert(rom):
        where = args.offset
        rom.seek(where)
        print("Where is: " + str(where) + str(type(where)))
        with open('build\output.bin', 'rb') as binary:
                data = binary.read()
        rom.write(data)
        print("data is: " + str(type(data)))
        return where
                       
def hook(rom, space, hook_at, register=0):
        # Align 2
        if hook_at & 1:
            hook_at -= 1
            
        rom.seek(hook_at)
        
        register &= 7
        
        if hook_at % 4:
            data = bytes([0x01, 0x48 | register, 0x00 | (register << 3), 0x47, 0x0, 0x0])
        else:
            data = bytes([0x00, 0x48 | register, 0x00 | (register << 3), 0x47])
            
        space += 0x08000000
        data += (space.to_bytes(4, 'little'))
        rom.write(bytes(data))
        
def rom_write(new_ptr, address):
        rom.seek(int(address, 0))
        array = bytearray()
        array.append(int("0x" + hex(new_ptr)[7:], 0))
        array.append(int("0x" + hex(new_ptr)[5:7], 0))
        array.append(int("0x" + hex(new_ptr)[3:5], 0))
        array.append(int(hex(new_ptr)[:3], 0))
        rom.write(array)
        
shutil.copyfile(args.input, args.output)
with open(args.output, 'rb+') as rom:
        offset = get_text_section()
        table = symbols(offset)
        where = insert(rom)
        # Adjust symbol table
        for entry in table:
                table[entry] += where

        # Read hooks from a file
        with open('hooks', 'r') as hooklist:
                for line in hooklist:
                        if line.strip().startswith('#'): continue
                        
                        symbol, address, register = line.split()
                        offset = int(address, 16) - 0x08000000
                        try:
                                code = table[symbol]
                        except KeyError:
                                print('Symbol missing:', symbol)
                                continue

                        hook(rom, code, offset, int(register))
                    
        if args.debug:
                width = max(map(len, table.keys())) + 1
                for key in sorted(table.keys()):
                        fstr = ('{:' + str(width) + '} {:08X}')
                        print(fstr.format(key + ':', table[key] + 0x08000000))
                        last = (table[key] + 0x08000000)

        # bin data for replaced images
        with open('bin_replace', 'r') as bin_files:
                for line in bin_files:
                        x = line.split(" ")
                        rom.seek(int(x[1].strip("\n"), 0))
                        fname = 'src\\bins\\' + x[0]
                        with open(fname, 'rb') as binary:
                                data = binary.read()
                                rom.write(data)
                                
        # Pointer list
        print("\n")
        with open('place', 'r') as to_place:
                for line in to_place:
                        if line.strip().startswith('#'): continue
                        symbol, address = line.split()
                        rom_write(int(symbol, 0), address)
        rom.write(array)
I deleted a couple of lines, check the spoilers. Also make sure you are running python build and then python insert after the build.
...
Age 25
Male
Seen 2 Weeks Ago
Posted September 2nd, 2020
534 posts
10.7 Years
I deleted a couple of lines, check the spoilers. Also make sure you are running python build and then python insert after the build.
Now I'm getting this one. :(
Where is: 8388608<class 'int'>
data is: <class 'bytes'>


Traceback (most recent call last):
  File "scripts//insert", line 158, in <module>
    rom.write(array)
NameError: name 'array' is not defined
I tried "from array import array" and "from numpy import array" but it didn't work. :(

Blah

Free supporter

Male
Unknown Island
Seen 52 Minutes Ago
Posted February 28th, 2023
1,924 posts
10.3 Years
Now I'm getting this one. :(
Where is: 8388608<class 'int'>
data is: <class 'bytes'>


Traceback (most recent call last):
  File "scripts//insert", line 158, in <module>
    rom.write(array)
NameError: name 'array' is not defined
I tried "from array import array" and "from numpy import array" but it didn't work. :(
whoops, delete the last line of the quoted code too.
...
Age 25
Male
Seen 2 Weeks Ago
Posted September 2nd, 2020
534 posts
10.7 Years
whoops, delete the last line of the quoted code too.
Well, now no other errors except this one.
Where is: 8388608<class 'int'>
data is: <class 'bytes'>
It keeps appearing and of course I still tried to test the output test.gba, it crashes the moment it enters the battle. :(

Blah

Free supporter

Male
Unknown Island
Seen 52 Minutes Ago
Posted February 28th, 2023
1,924 posts
10.3 Years
Well, now no other errors except this one.
Where is: 8388608<class 'int'>
data is: <class 'bytes'>
It keeps appearing and of course I still tried to test the output test.gba, it crashes the moment it enters the battle. :(
That's not an error, that's print statements in the insert code I put in there some time ago while trying to debug a few things. Leftovers I haven't removed :D

It's probably not working because it's overwriting data you're using in your hack. Try it on a clean ROM without save states.
...
Age 25
Male
Seen 2 Weeks Ago
Posted September 2nd, 2020
534 posts
10.7 Years
That's not an error, that's print statements in the insert code I put in there some time ago while trying to debug a few things. Leftovers I haven't removed :D

It's probably not working because it's overwriting data you're using in your hack. Try it on a clean ROM without save states.
Oh... Well, I've been using a clean ROM aaand I am not using any saves. :( I really don't know what's happening.

EDIT: I just turned on the sounds while playing so it is actually just a blackscreen but the sound for battle is still playing.