Skip to content

Commit

Permalink
eh
Browse files Browse the repository at this point in the history
  • Loading branch information
Crain-32 committed Apr 3, 2024
1 parent a331483 commit 931d0fe
Show file tree
Hide file tree
Showing 7 changed files with 200 additions and 8 deletions.
Binary file added asm/d_a_demo_item.plf
Binary file not shown.
144 changes: 144 additions & 0 deletions asm/elf2rel.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
from gclib import fs_helpers as fs
from gclib.rel import REL, RELSection, RELRelocation, RELRelocationType
from asm.elf import ELF, ELFSectionType, ELFSectionFlags, ELFRelocationType, ELFSymbolSpecialSection

ALLOWED_SECTIONS = [
".text",
".ctors",
".dtors",
".rodata",
".data",
".bss",
".rodata.str1.4",
".rodata.cst4",
".rodata.cst8",
".sdata",
]


def convert_elf_to_rel(in_elf_path, rel_id, main_symbols, actor_profile_name):
elf = ELF()
elf.read_from_file(in_elf_path)

rel = REL()

rel.id = rel_id

# First convert the sections we want to include in the REL from ELF sections to REL sections.
section_name_to_rel_section = {}
elf_section_index_to_rel_section = {}
for elf_section_index, elf_section in enumerate(elf.sections):
if elf_section.name in ALLOWED_SECTIONS or elf_section.type == ELFSectionType.SHT_NULL:
# Sections we will add to the REL.
rel_section = RELSection()
rel_section.data = fs.make_copy_data(elf_section.data)
rel.sections.append(rel_section)

if elf_section.flags & ELFSectionFlags.SHF_EXECINSTR.value:
rel_section.is_executable = True

section_name_to_rel_section[elf_section.name] = rel_section
elf_section_index_to_rel_section[elf_section_index] = rel_section

if elf_section.type == ELFSectionType.SHT_NOBITS:
assert elf_section.size > 0
assert rel.bss_size == 0
rel.bss_size = elf_section.size
rel_section.is_uninitialized = True
rel_section.is_bss = True
elif elf_section.type == ELFSectionType.SHT_NULL:
rel_section.is_uninitialized = True
rel_section.is_bss = False
else:
rel_section.is_uninitialized = False
rel_section.is_bss = False

# Then generate the relocations.
for elf_section in elf.sections:
if elf_section.type == ELFSectionType.SHT_RELA:
assert elf_section.name.startswith(".rela")
relocated_section_name = elf_section.name[len(".rela"):]

if relocated_section_name not in section_name_to_rel_section:
# Ignored section
continue

rel_section = section_name_to_rel_section[relocated_section_name]
section_index = rel.sections.index(rel_section)
for elf_relocation in elf.relocations[elf_section.name]:
rel_relocation = RELRelocation()

elf_symbol = elf.symbols[".symtab"][elf_relocation.symbol_index]
rel_relocation.relocation_type = RELRelocationType(elf_relocation.type.value)
# print("%X" % elf_symbol.section_index)

if elf_symbol.section_index == 0:
if elf_symbol.name in main_symbols:
elf_symbol.section_index = ELFSymbolSpecialSection.SHN_ABS.value
elf_symbol.address = main_symbols[elf_symbol.name]
else:
raise Exception("Unresolved external symbol: %s" % elf_symbol.name)

if elf_symbol.section_index == ELFSymbolSpecialSection.SHN_ABS.value:
# Symbol is located in main.dol.
module_num = 0

# I don't think this value is used for dol relocations.
# In vanilla, this was written as 4 for some reason?
rel_relocation.section_num_to_relocate_against = 0
elif elf_symbol.section_index >= 0xFF00:
raise Exception("Special section number not implemented: %04X" % elf_symbol.section_index)
else:
# Symbol is located in the current REL.
# TODO: support for relocating against other rels besides the current one
module_num = rel.id

section_name_to_relocate_against = elf.sections[elf_symbol.section_index].name
if section_name_to_relocate_against not in section_name_to_rel_section:
raise Exception("Section name \"%s\" could not be found for symbol \"%s\"" % (
section_name_to_relocate_against, elf_symbol.name))
rel_section_to_relocate_against = section_name_to_rel_section[section_name_to_relocate_against]
rel_section_index_to_relocate_against = rel.sections.index(rel_section_to_relocate_against)
rel_relocation.section_num_to_relocate_against = rel_section_index_to_relocate_against

rel_relocation.symbol_address = elf_symbol.address + elf_relocation.addend
rel_relocation.relocation_offset = elf_relocation.relocation_offset
rel_relocation.curr_section_num = section_index

if module_num not in rel.relocation_entries_for_module:
rel.relocation_entries_for_module[module_num] = []
rel.relocation_entries_for_module[module_num].append(rel_relocation)

symbol = elf.symbols_by_name[".symtab"]["_prolog"]
rel_section = elf_section_index_to_rel_section[symbol.section_index]
rel_section_index = rel.sections.index(rel_section)
rel.prolog_section = rel_section_index
rel.prolog_offset = symbol.address

symbol = elf.symbols_by_name[".symtab"]["_epilog"]
rel_section = elf_section_index_to_rel_section[symbol.section_index]
rel_section_index = rel.sections.index(rel_section)
rel.epilog_section = rel_section_index
rel.epilog_offset = symbol.address

symbol = elf.symbols_by_name[".symtab"]["_unresolved"]
rel_section = elf_section_index_to_rel_section[symbol.section_index]
rel_section_index = rel.sections.index(rel_section)
rel.unresolved_section = rel_section_index
rel.unresolved_offset = symbol.address

rel.save_changes()

if actor_profile_name not in elf.symbols_by_name[".symtab"]:
raise Exception(
"Could not find the actor profile. The specified symbol name for it was \"%s\", but that symbol could not be found in the ELF." % actor_profile_name)
profile_section = section_name_to_rel_section[".rodata"]
profile_section_index = rel.sections.index(profile_section)

profile_symbol = elf.symbols_by_name[".symtab"][actor_profile_name]
rel_section = elf_section_index_to_rel_section[profile_symbol.section_index]
rel_section_index = rel.sections.index(rel_section)
profile_section_index = rel_section_index
profile_address = profile_symbol.address

return rel, profile_section_index, profile_address
2 changes: 2 additions & 0 deletions asm/linker.ld
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ Set__8dCcD_SphFRC11dCcD_SrcSph = 0x800abfc0;
calc__14mDoExt_McaMorfFv = 0x800132e8;
fopAcM_SearchByID__FUiPP10fopAc_ac_c = 0x800241c0;
dComIfGp_setNextStage__FPCcsScScfUliSc = 0x800537c8;
g_dComIfG_gameInfo = 0x803C4C08;

subBgmStop__11JAIZelBasicFv = 0x802a4cdc;
GetTgHitObj__12dCcD_GObjInfFv = 0x800aba48;
fopScnM_ChangeReq__FP11scene_classssUs = 0x80029e6c;
Expand Down
10 changes: 8 additions & 2 deletions asm/patch_diffs/multiworld_scripts_diff.txt
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,16 @@ sys/main.dol:
0x60, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00]
0x8005CB04:
Data: [0x7C, 0xC8, 0x02, 0xA6, 0x48, 0x3A, 0x23, 0x51]
0x80026A30:
Data: [0x53, 0xE4, 0x80, 0x1E]
0x800C2E08:
Data: [0x48, 0x33, 0xBF, 0x2D, 0x60, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00,
0x60, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00]
0x800CCAA4:
Data: [0x48, 0x33, 0x22, 0x31]
files/rels/d_a_obj_toripost.rel:
0x500:
Data: [0x38, 0xA0, 0x69, 0x00]
files/rels/d_a_tbox.rel:
0x2764:
Data: [0x48, 0x00, 0x00, 0x01]
Expand Down Expand Up @@ -123,10 +128,11 @@ files/rels/d_a_bwd.rel:
files/rels/d_a_obj_hsehi1.rel:
0x29D0:
Data: [0x3C, 0xA0, 0x00, 0x00, 0x38, 0xA5, 0x00, 0x00, 0x3B, 0xC0, 0x00, 0x69,
0x93, 0xC5, 0x00, 0x00, 0x7C, 0x7E, 0x1B, 0x78, 0x3C, 0x60, 0x80, 0x3C, 0x4B,
0x93, 0xC5, 0x00, 0x00, 0x7C, 0x7E, 0x1B, 0x78, 0x3C, 0x60, 0x00, 0x00, 0x4B,
0xFF, 0xF1, 0x68]
Relocations: [{SymbolName: world_id, Offset: 0x02, Type: R_PPC_ADDR16_HA}, {SymbolName: world_id,
Offset: 0x06, Type: R_PPC_ADDR16_LO}]
Offset: 0x06, Type: R_PPC_ADDR16_LO}, {SymbolName: g_dComIfG_gameInfo, Offset: 0x16,
Type: R_PPC_ADDR16_HA}]
0x1B48:
Data: [0x48, 0x00, 0x00, 0x00]
Relocations: [{SymbolName: store_tablet_world_id, Offset: 0x00, Type: R_PPC_REL24}]
16 changes: 11 additions & 5 deletions asm/patches/multiworld_scripts.asm
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@
.org @NextFreeSpace

; Basically is a multiplayer struct we work with. Just in... Assembly...
; byte worldId
; byte itemId
; byte stageId
; u32 | u8 World Type (0: None, 1: Co-op, 2: Multiworld) | u8 Max Worlds (MW Only) | u8 World Id (MW Only) | u8 padding
; u32 worldId
; u32 itemId
; u32 stageId
; bool eventHappenFlag
; pointer* pointerStorage

Expand Down Expand Up @@ -239,6 +240,8 @@ get_item_detour:
mflr r6
bl mark_story_event

.org 0x80026A30 ; "fopAcm_createDemoItem"
rlwimi r4, r31, 16, 0, 15 ; r |= r31 << 0x10 & 0xFFFF0000

.org 0x800C2E08
bl get_item_detour
Expand All @@ -249,7 +252,10 @@ get_item_detour:
nop
.close


.open "files/rels/d_a_obj_toripost.rel"; Post Box
.org 0x500 ; cutPresentProc
li r5, 0x6900
.close

.open "files/rels/d_a_tbox.rel" ; Treasure Chests
.org 0x2764 ; In actionOpenWait__8daTbox_cFv
Expand Down Expand Up @@ -377,6 +383,6 @@ tablet_world_id:
li r30, 0x69
stw r30, 0x0 (r5)
mr r30, r3
lis r3,-0x7FC4
lis r3, g_dComIfG_gameInfo@ha
b 0x1B50
.close
5 changes: 4 additions & 1 deletion asm/patching_notes
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,7 @@
804801ec 38 84 6b 4c addi r4,r4,0x6b4c


; -5BF0 is 803FA110
; -5BF0 is 803FA110

We can hijack `fopAcM_createItemForPresentDemo()`'s `argflag` in order to inject a world ID.
That should be setting a value to a register currently being set to 0 in most of the DOLs.
31 changes: 31 additions & 0 deletions tweaks.py
Original file line number Diff line number Diff line change
Expand Up @@ -2318,6 +2318,37 @@ def add_custom_actor_rels(randomizer: 'Randomizer'):
section_index_of_actor_profile=2,
offset_of_actor_profile=0,
)
elf_path = os.path.join(ASM_PATH, "d_a_demo_item.plf")
rel_path = "files/rels/d_a_demo_item.rel"
randomizer.replace_rel


def replace_rel_from_elf(randomizer: 'Randomizer', linked_elf_path, rel_path, actor_profile_name):
orig_rel = randomizer.get_rel(rel_path)
rel_id = orig_rel.id
main_symbols = randomizer.get_symbol_map("files/maps/framework.map")
new_rel, profile_section_index, profile_address = elf2rel.convert_elf_to_rel(linked_elf_path, rel_id, main_symbols,
actor_profile_name)

randomizer.rels_by_path[rel_path] = new_rel

# If this REL is in RELS.arc, we also need to update the file entry to know that it's associated with a different REL now.
rel_name = os.path.basename(rel_path)
rels_arc = randomizer.get_arc("files/RELS.arc")
rel_file_entry = rels_arc.get_file_entry(rel_name)
if rel_file_entry:
rel_file_entry.data = new_rel.data

# We need to update the pointer to the REL's profile in the profile list.
profile_list = randomizer.get_rel("files/rels/f_pc_profile_lst.rel")
if rel_id not in profile_list.relocation_entries_for_module:
raise Exception("Tried to replace a REL that was not already in the profile list.")

profile_relocation = profile_list.relocation_entries_for_module[new_rel.id][0]
profile_relocation.section_num_to_relocate_against = profile_section_index
profile_relocation.symbol_address = profile_address

profile_list.save_changes(preserve_section_data_offsets=True)


def fix_message_closing_sound_on_quest_status_screen(randomizer: 'Randomizer'):
Expand Down

0 comments on commit 931d0fe

Please sign in to comment.