• Welcome to Smashboards, the world's largest Super Smash Brothers community! Over 250,000 Smash Bros. fans from around the world have come to discuss these great games in over 19 million posts!

    You are currently viewing our boards as a visitor. Click here to sign up right now and start on your path in the Smash community!

Completed EOS - End of Scene Event

Punkline

Dr. Frankenstack
Joined
May 15, 2015
Messages
423
This mod allows multiple injection codes to be stacked on top of a single hook at the end of the scene function. This is a valuable hook location, as it can be used to inject code into the game for the purpose of cleaning up static references to the heap just before it is wiped. This can be useful for nullifying pointers, saving information, resetting defaults, or anything else that needs to be done before a scene is over. With this mod, any number of codes can make use of the same context to do these things.

“Events” like this simply serve as a platform for executing other code without hogging the hook space. I have a lot of ideas that I would like to explore concerning this type of mod, but this one in particular experiments with the idea of using “bctr” in place of a “blrl” instruction to include the callback code as part of the parser’s execution context. (This basically eliminates the need to create stack frames for anything included in the hooks list, allowing new routines to make calls to other functions and use saved registers without requiring any setup.)

EOS - End of Scene Event:
uses mytoc block 267

Code:
-==-

EOS - End of Scene Event
Event can be used to run multiple injections at the end of each scene.
Add to injection list by appending a branch to the function <EOS_hooks>
Each hook must return to the event parser using a branch to <EOS_continue>
For more info, see (https://smashboards.com/threads/eos-end-of-scene-event.459049/)
[Punkline]
<EOS_hooks>
4E800021

b <EOS_PlCo_pointer>  # example hook
# <- place additional hooks here

00000000
1.02 ----- 801a4268 --- bb21001c -> Branch
7C791B78
bl <EOS_event>
7F23CB78 BB21001C 00000000
<EOS_event>
7C0802A6 90010004 9421EF00 BE011000 7C000026 90011080 48000019 7C0802A6 900110F0
bl <EOS_hooks>
7FE802A6 48000010 4E800021 83E110EC 3BFF0004 801F0000 2C000000 41820010 93E110EC 7FE903A6 4E800420 80011080 7C0FF120 BA011000 38211100 80010004 7C0803A6 4E800020
<EOS_continue>
800110F0 7C0903A6 4E800420
1.02 ----- 8038033c --- 8001002c -> Branch
93C2CDBC 8001002C 00000000
1.02 ----- 80067ae8 --- 80610008 -> Branch
8062CDBC 9062CDB8 80610008 00000000
1.02 ----- 80279608 --- C822CDB8 -> C8228000
1.02 ----- 80279574 --- C842CDB8 -> C8428000
1.02 ----- 8027920C --- C822CDB8 -> C8228000
1.02 ----- 802791B4 --- C842CDB8 -> C8428000
1.02 ----- 80278F5C --- C822CDB8 -> C8228000
1.02 ----- 804DC798 --- 4330000000000000 -> 0000000000000000
<EOS_PlCo_pointer>
38000000 9002CDB8
b <EOS_continue>
#
-==-
!
ASM - EOS - End of Scene Event
Event can be used to run multiple injections at the end of each scene.
Add to injection list by appending a branch to the function <EOS_hooks>
Each hook must return to the event parser using a branch to <EOS_continue>
For more info, see (https://smashboards.com/threads/eos-end-of-scene-event.459049/)
[Punkline]

<EOS_hooks>
blrl # list begins below this blrl

b <EOS_PlCo_pointer> # example hook
# <- place additional hooks here

_end_list:
.long 0 # terminates the list




1.02 ----- 801a4268 --- bb21001c -> Branch
mr r25, r3 # save r3 return value

bl <EOS_event>

_return:
mr r3, r25 # restore r3 return value
lmw r25, 0x001C (sp)
.long 0




<EOS_event>
# no arguments, no returns
# event creates a stack frame and shares it with each hook intended to be executed
# -- this allows each hook to forgo the creation of individual stack frames

mflr r0
stw r0, 0x4(sp)
stwu sp, -0x1100(sp)
stmw r16, 0x1000(sp)
mfcr r0
stw r0, 0x1080(sp)
# saved registers are now safe to use
# saved cr is now safe to use

_set_continue_pointer:
bl _get_continue
mflr r0
stw r0, 0x10F0(sp)
# branching to <EOS_continue> from a callback injection will now iterate the event loop

_setup_parse:
bl <EOS_hooks>
mflr r31
b _next_hook
# r31 start of hooks index, to begin parse

_get_continue:
blrl
# blrl helps us exploit the link register to inquire about local address
# the address of _continue gets saved to the stack frame for use with <EOS_continue>


_continue:
lwz r31, 0x10EC(sp)
addi r31, r31, 4
# load next hook after coming back from an injection callback

_next_hook:
lwz r0, 0(r31)
cmpwi r0, 0
beq- _return
# check for null termination

stw r31, 0x10EC(sp)
# if not terminating, stack param will save our place for the next iteration

mtctr r31
bctr
# execute hook
# return from bctr is handled by <EOS_continue> -- and will arrive at the _continue label

_return:
lwz r0, 0x1080(sp)
mtcr r0
lmw r16, 0x1000(sp)
addi sp, sp, 0x1100
lwz r0, 0x4(sp)
mtlr r0
blr




<EOS_continue>
lwz r0, 0x10F0(sp)
mtctr r0
bctr




#####
##### Example Plugin Code -- PlCo.dat pointer in -0x3248(rtoc)
#####

# 1 - PlCo load function will intercept header object generated for file
# 2 - mytoc 267 will be used to store the pointer in a globally accessible rtoc location
# 3 - EOS event will be used to nullify the pointer on scene changes

1.02 ----- 8038033c --- 8001002c -> Branch
stw r30, -0x3244(rtoc)
# log each header object as it is created

lwz r0, 0x002C (sp)
.long 0



1.02 ----- 80067ae8 --- 80610008 -> Branch
lwz r3, -0x3244(rtoc)
stw r3, -0x3248(rtoc)
# save PlCo.dat header object

lwz r3, 0x0008 (sp)
.long 0



1.02 ----- 80279608 --- C822CDB8 -> C8228000
1.02 ----- 80279574 --- C842CDB8 -> C8428000
1.02 ----- 8027920C --- C822CDB8 -> C8228000
1.02 ----- 802791B4 --- C842CDB8 -> C8428000
1.02 ----- 80278F5C --- C822CDB8 -> C8228000
1.02 ----- 804DC798 --- 4330000000000000 -> 0000000000000000
# mytoc 267 has been enabled for creating custom read/write variables


<EOS_PlCo_pointer>
li r0, 0
stw r0, -0x3248(rtoc)
b <EOS_continue>
# EOS event nullifies pointer at end of scene
#

---

Included Example -- PlCo.dat header object pointer:

Included with the event is a simple example code that creates a global pointer to the header object for PlCo.dat each time it is loaded.
Header objects may be used to locate a loaded file in RAM, relocate file data offsets, and navigate the symbols in search for named data regions:


The pointer created for this object is located at 804DC798, and can be reached anywhere with a single instruction via -0x3248(rtoc). On scene transitions, the pointer is nullified using a routine plugged into the EOS event. This makes it so that the pointer’s status may be checked to determine whether or not PlCo.dat is currently loaded:

Notice that the pointer nullifies at the end of each scene.
(See attachment file for memory engine table.)​

The EOS routine for this pointer code is written within a standalone function, and uses a branch to return to the parser, like this:


As you can see, this routine simply stores a 0 in place of the pointer and then returns. Note however that to return, you only need to branch to the included function <EOS_continue>.

In order to plug this routine into the event, a branch is placed in the <EOS_hooks> function:


Any number of additional routines may be added to this hooks list. All routines will be executed in the order they are given.
  • Each EOS routine can make use of r16...r31, and all condition registers without saving parameters.
  • Making calls with bl, blrl, or bctrl instructions will not require a new activation record in the stack frame of a new routine.
  • Variables important to the parser are stored in a 0x100 byte table starting at 0x1000(sp), so the first 0x1000 bytes of the stack frame may be used by each routine as volatile storage. Additional space may be created by creating a new (bigger) stack frame.
 

Attachments

Last edited:

DRGN

Technowizard
Moderator
Joined
Aug 20, 2005
Messages
2,178
Location
Sacramento, CA
In this point in execution, have the heaps containing files of the previous/current scene already been erased? Are they unallocated, but still present in RAM, or is the area zeroed out? And would I be correct in guessing that the heap sizes have not yet been readjusted for the next scene? (Since I would consider that to be something in the next scene's beginning or intialization.)
 

Punkline

Dr. Frankenstack
Joined
May 15, 2015
Messages
423
In this point in execution, have the heaps containing files of the previous/current scene already been erased? Are they unallocated, but still present in RAM, or is the area zeroed out? And would I be correct in guessing that the heap sizes have not yet been readjusted for the next scene? (Since I would consider that to be something in the next scene's beginning or intialization.)
It seems that the code executes before the heap is destroyed, but after the scene destructor callback is executed.

Perhaps it would be better to move the injection to before the destructor callback, so that the scene is still wholly intact when the code executes. I wasn’t very informed about the way the ‘heart’ of Melee beats when writing this code, so I just put the hook at the end of the function I knew to contain minor scene transitions.


My breakpoints showed me the following order of breaks:
Rich (BB code):
# 0: (this scene ends...) 
  
801a4144  
# 1: minor scene cleanup callback event... 
  
801a4268 # <--- 
# 2: EOS code executes here 
  
801a4418 
# 3: major scene setup callback event (only on major scene transitions) 
  
801a4098 -> 801a3f60 -> 80018f34 -> 80015ad8 -> 803754e0 
# 4: destroy the topmost heap before next minor scene's setup callback 
# - it then promptly re-creates it 
  
801a40b0  
# 5: minor scene setup callback event 
# 6: (next scene begins...) 

 
Top Bottom