From 931d0fecfc4d26949ed7c31837478204f10a07cb Mon Sep 17 00:00:00 2001 From: Crain-32 <25422785+Crain-32@users.noreply.github.com> Date: Wed, 3 Apr 2024 13:55:44 -0600 Subject: [PATCH] eh --- asm/d_a_demo_item.plf | Bin 0 -> 16304 bytes asm/elf2rel.py | 144 ++++++++++++++++++++ asm/linker.ld | 2 + asm/patch_diffs/multiworld_scripts_diff.txt | 10 +- asm/patches/multiworld_scripts.asm | 16 ++- asm/patching_notes | 5 +- tweaks.py | 31 +++++ 7 files changed, 200 insertions(+), 8 deletions(-) create mode 100644 asm/d_a_demo_item.plf create mode 100644 asm/elf2rel.py diff --git a/asm/d_a_demo_item.plf b/asm/d_a_demo_item.plf new file mode 100644 index 0000000000000000000000000000000000000000..818133d8eee5355b9aac0bdb2833d5e00c5634df GIT binary patch literal 16304 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 OdzU0_T77cA#(x8_7TDPU literal 0 HcmV?d00001 diff --git a/asm/elf2rel.py b/asm/elf2rel.py new file mode 100644 index 000000000..6d9a0a84f --- /dev/null +++ b/asm/elf2rel.py @@ -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 \ No newline at end of file diff --git a/asm/linker.ld b/asm/linker.ld index 77bcf8de3..2c1b01f7f 100644 --- a/asm/linker.ld +++ b/asm/linker.ld @@ -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; diff --git a/asm/patch_diffs/multiworld_scripts_diff.txt b/asm/patch_diffs/multiworld_scripts_diff.txt index cfb9c996f..f666599dc 100644 --- a/asm/patch_diffs/multiworld_scripts_diff.txt +++ b/asm/patch_diffs/multiworld_scripts_diff.txt @@ -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] @@ -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}] diff --git a/asm/patches/multiworld_scripts.asm b/asm/patches/multiworld_scripts.asm index f387733f8..5dfa85862 100644 --- a/asm/patches/multiworld_scripts.asm +++ b/asm/patches/multiworld_scripts.asm @@ -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 @@ -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 @@ -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 @@ -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 \ No newline at end of file diff --git a/asm/patching_notes b/asm/patching_notes index 5508cdfcc..4c92da500 100644 --- a/asm/patching_notes +++ b/asm/patching_notes @@ -19,4 +19,7 @@ 804801ec 38 84 6b 4c addi r4,r4,0x6b4c -; -5BF0 is 803FA110 \ No newline at end of file +; -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. \ No newline at end of file diff --git a/tweaks.py b/tweaks.py index bdd2e828f..05f33c9c1 100644 --- a/tweaks.py +++ b/tweaks.py @@ -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'):