diff options
Diffstat (limited to '')
-rw-r--r-- | src/core/hle/service/ldr_ro/cro_helper.h | 714 |
1 files changed, 0 insertions, 714 deletions
diff --git a/src/core/hle/service/ldr_ro/cro_helper.h b/src/core/hle/service/ldr_ro/cro_helper.h deleted file mode 100644 index 57b4fb6df..000000000 --- a/src/core/hle/service/ldr_ro/cro_helper.h +++ /dev/null @@ -1,714 +0,0 @@ -// Copyright 2016 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include <array> -#include <tuple> -#include "common/common_types.h" -#include "common/swap.h" -#include "core/hle/result.h" -#include "core/memory.h" - -namespace Service { -namespace LDR { - -// GCC versions < 5.0 do not implement std::is_trivially_copyable. -// Excluding MSVC because it has weird behaviour for std::is_trivially_copyable. -#if (__GNUC__ >= 5) || defined(__clang__) -#define ASSERT_CRO_STRUCT(name, size) \ - static_assert(std::is_standard_layout<name>::value, \ - "CRO structure " #name " doesn't use standard layout"); \ - static_assert(std::is_trivially_copyable<name>::value, \ - "CRO structure " #name " isn't trivially copyable"); \ - static_assert(sizeof(name) == (size), "Unexpected struct size for CRO structure " #name) -#else -#define ASSERT_CRO_STRUCT(name, size) \ - static_assert(std::is_standard_layout<name>::value, \ - "CRO structure " #name " doesn't use standard layout"); \ - static_assert(sizeof(name) == (size), "Unexpected struct size for CRO structure " #name) -#endif - -static constexpr u32 CRO_HEADER_SIZE = 0x138; -static constexpr u32 CRO_HASH_SIZE = 0x80; - -/// Represents a loaded module (CRO) with interfaces manipulating it. -class CROHelper final { -public: - explicit CROHelper(VAddr cro_address) : module_address(cro_address) {} - - std::string ModuleName() const { - return Memory::ReadCString(GetField(ModuleNameOffset), GetField(ModuleNameSize)); - } - - u32 GetFileSize() const { - return GetField(FileSize); - } - - /** - * Rebases the module according to its address. - * @param crs_address the virtual address of the static module - * @param cro_size the size of the CRO file - * @param data_segment_address buffer address for .data segment - * @param data_segment_size the buffer size for .data segment - * @param bss_segment_address the buffer address for .bss segment - * @param bss_segment_size the buffer size for .bss segment - * @param is_crs true if the module itself is the static module - * @returns ResultCode RESULT_SUCCESS on success, otherwise error code. - */ - ResultCode Rebase(VAddr crs_address, u32 cro_size, VAddr data_segment_address, - u32 data_segment_size, VAddr bss_segment_address, u32 bss_segment_size, - bool is_crs); - - /** - * Unrebases the module. - * @param is_crs true if the module itself is the static module - */ - void Unrebase(bool is_crs); - - /** - * Verifies module hash by CRR. - * @param cro_size the size of the CRO - * @param crr the virtual address of the CRR - * @returns ResultCode RESULT_SUCCESS on success, otherwise error code. - */ - ResultCode VerifyHash(u32 cro_size, VAddr crr) const; - - /** - * Links this module with all registered auto-link module. - * @param crs_address the virtual address of the static module - * @param link_on_load_bug_fix true if links when loading and fixes the bug - * @returns ResultCode RESULT_SUCCESS on success, otherwise error code. - */ - ResultCode Link(VAddr crs_address, bool link_on_load_bug_fix); - - /** - * Unlinks this module with other modules. - * @param crs_address the virtual address of the static module - * @returns ResultCode RESULT_SUCCESS on success, otherwise error code. - */ - ResultCode Unlink(VAddr crs_address); - - /** - * Clears all relocations to zero. - * @returns ResultCode RESULT_SUCCESS on success, otherwise error code. - */ - ResultCode ClearRelocations(); - - /// Initialize this module as the static module (CRS) - void InitCRS(); - - /** - * Registers this module and adds it to the module list. - * @param crs_address the virtual address of the static module - * @param auto_link whether to register as an auto link module - */ - void Register(VAddr crs_address, bool auto_link); - - /** - * Unregisters this module and removes from the module list. - * @param crs_address the virtual address of the static module - */ - void Unregister(VAddr crs_address); - - /** - * Gets the end of reserved data according to the fix level. - * @param fix_level fix level from 0 to 3 - * @returns the end of reserved data. - */ - u32 GetFixEnd(u32 fix_level) const; - - /** - * Zeros offsets to cropped data according to the fix level and marks as fixed. - * @param fix_level fix level from 0 to 3 - * @returns page-aligned size of the module after fixing. - */ - u32 Fix(u32 fix_level); - - bool IsFixed() const { - return GetField(Magic) == MAGIC_FIXD; - } - - u32 GetFixedSize() const { - return GetField(FixedSize); - } - - bool IsLoaded() const; - - /** - * Gets the page address and size of the code segment. - * @returns a tuple of (address, size); (0, 0) if the code segment doesn't exist. - */ - std::tuple<VAddr, u32> GetExecutablePages() const; - -private: - const VAddr module_address; ///< the virtual address of this module - - /** - * Each item in this enum represents a u32 field in the header begin from address+0x80, - * successively. We don't directly use a struct here, to avoid GetPointer, reinterpret_cast, or - * Read/WriteBlock repeatedly. - */ - enum HeaderField { - Magic = 0, - NameOffset, - NextCRO, - PreviousCRO, - FileSize, - BssSize, - FixedSize, - UnknownZero, - UnkSegmentTag, - OnLoadSegmentTag, - OnExitSegmentTag, - OnUnresolvedSegmentTag, - - CodeOffset, - CodeSize, - DataOffset, - DataSize, - ModuleNameOffset, - ModuleNameSize, - SegmentTableOffset, - SegmentNum, - - ExportNamedSymbolTableOffset, - ExportNamedSymbolNum, - ExportIndexedSymbolTableOffset, - ExportIndexedSymbolNum, - ExportStringsOffset, - ExportStringsSize, - ExportTreeTableOffset, - ExportTreeNum, - - ImportModuleTableOffset, - ImportModuleNum, - ExternalRelocationTableOffset, - ExternalRelocationNum, - ImportNamedSymbolTableOffset, - ImportNamedSymbolNum, - ImportIndexedSymbolTableOffset, - ImportIndexedSymbolNum, - ImportAnonymousSymbolTableOffset, - ImportAnonymousSymbolNum, - ImportStringsOffset, - ImportStringsSize, - - StaticAnonymousSymbolTableOffset, - StaticAnonymousSymbolNum, - InternalRelocationTableOffset, - InternalRelocationNum, - StaticRelocationTableOffset, - StaticRelocationNum, - Fix0Barrier, - - Fix3Barrier = ExportNamedSymbolTableOffset, - Fix2Barrier = ImportModuleTableOffset, - Fix1Barrier = StaticAnonymousSymbolTableOffset, - }; - static_assert(Fix0Barrier == (CRO_HEADER_SIZE - CRO_HASH_SIZE) / 4, - "CRO Header fields are wrong!"); - - enum class SegmentType : u32 { - Code = 0, - ROData = 1, - Data = 2, - BSS = 3, - }; - - /** - * Identifies a program location inside of a segment. - * Required to refer to program locations because individual segments may be relocated - * independently of each other. - */ - union SegmentTag { - u32_le raw; - BitField<0, 4, u32_le> segment_index; - BitField<4, 28, u32_le> offset_into_segment; - - SegmentTag() = default; - explicit SegmentTag(u32 raw_) : raw(raw_) {} - }; - - /// Information of a segment in this module. - struct SegmentEntry { - u32_le offset; - u32_le size; - SegmentType type; - - static constexpr HeaderField TABLE_OFFSET_FIELD = SegmentTableOffset; - }; - ASSERT_CRO_STRUCT(SegmentEntry, 12); - - /// Identifies a named symbol exported from this module. - struct ExportNamedSymbolEntry { - u32_le name_offset; // pointing to a substring in ExportStrings - SegmentTag symbol_position; // to self's segment - - static constexpr HeaderField TABLE_OFFSET_FIELD = ExportNamedSymbolTableOffset; - }; - ASSERT_CRO_STRUCT(ExportNamedSymbolEntry, 8); - - /// Identifies an indexed symbol exported from this module. - struct ExportIndexedSymbolEntry { - SegmentTag symbol_position; // to self's segment - - static constexpr HeaderField TABLE_OFFSET_FIELD = ExportIndexedSymbolTableOffset; - }; - ASSERT_CRO_STRUCT(ExportIndexedSymbolEntry, 4); - - /// A tree node in the symbol lookup tree. - struct ExportTreeEntry { - u16_le test_bit; // bit address into the name to test - union Child { - u16_le raw; - BitField<0, 15, u16_le> next_index; - BitField<15, 1, u16_le> is_end; - } left, right; - u16_le export_table_index; // index of an ExportNamedSymbolEntry - - static constexpr HeaderField TABLE_OFFSET_FIELD = ExportTreeTableOffset; - }; - ASSERT_CRO_STRUCT(ExportTreeEntry, 8); - - /// Identifies a named symbol imported from another module. - struct ImportNamedSymbolEntry { - u32_le name_offset; // pointing to a substring in ImportStrings - u32_le relocation_batch_offset; // pointing to a relocation batch in ExternalRelocationTable - - static constexpr HeaderField TABLE_OFFSET_FIELD = ImportNamedSymbolTableOffset; - }; - ASSERT_CRO_STRUCT(ImportNamedSymbolEntry, 8); - - /// Identifies an indexed symbol imported from another module. - struct ImportIndexedSymbolEntry { - u32_le index; // index of an ExportIndexedSymbolEntry in the exporting module - u32_le relocation_batch_offset; // pointing to a relocation batch in ExternalRelocationTable - - static constexpr HeaderField TABLE_OFFSET_FIELD = ImportIndexedSymbolTableOffset; - }; - ASSERT_CRO_STRUCT(ImportIndexedSymbolEntry, 8); - - /// Identifies an anonymous symbol imported from another module. - struct ImportAnonymousSymbolEntry { - SegmentTag symbol_position; // in the exporting segment - u32_le relocation_batch_offset; // pointing to a relocation batch in ExternalRelocationTable - - static constexpr HeaderField TABLE_OFFSET_FIELD = ImportAnonymousSymbolTableOffset; - }; - ASSERT_CRO_STRUCT(ImportAnonymousSymbolEntry, 8); - - /// Information of a imported module and symbols imported from it. - struct ImportModuleEntry { - u32_le name_offset; // pointing to a substring in ImportStrings - u32_le import_indexed_symbol_table_offset; // pointing to a subtable in - // ImportIndexedSymbolTable - u32_le import_indexed_symbol_num; - u32_le import_anonymous_symbol_table_offset; // pointing to a subtable in - // ImportAnonymousSymbolTable - u32_le import_anonymous_symbol_num; - - static constexpr HeaderField TABLE_OFFSET_FIELD = ImportModuleTableOffset; - - void GetImportIndexedSymbolEntry(u32 index, ImportIndexedSymbolEntry& entry) { - Memory::ReadBlock(import_indexed_symbol_table_offset + - index * sizeof(ImportIndexedSymbolEntry), - &entry, sizeof(ImportIndexedSymbolEntry)); - } - - void GetImportAnonymousSymbolEntry(u32 index, ImportAnonymousSymbolEntry& entry) { - Memory::ReadBlock(import_anonymous_symbol_table_offset + - index * sizeof(ImportAnonymousSymbolEntry), - &entry, sizeof(ImportAnonymousSymbolEntry)); - } - }; - ASSERT_CRO_STRUCT(ImportModuleEntry, 20); - - enum class RelocationType : u8 { - Nothing = 0, - AbsoluteAddress = 2, - RelativeAddress = 3, - ThumbBranch = 10, - ArmBranch = 28, - ModifyArmBranch = 29, - AbsoluteAddress2 = 38, - AlignedRelativeAddress = 42, - }; - - struct RelocationEntry { - SegmentTag target_position; // to self's segment as an ExternalRelocationEntry; to static - // module segment as a StaticRelocationEntry - RelocationType type; - u8 is_batch_end; - u8 is_batch_resolved; // set at a batch beginning if the batch is resolved - INSERT_PADDING_BYTES(1); - u32_le addend; - }; - - /// Identifies a normal cross-module relocation. - struct ExternalRelocationEntry : RelocationEntry { - static constexpr HeaderField TABLE_OFFSET_FIELD = ExternalRelocationTableOffset; - }; - ASSERT_CRO_STRUCT(ExternalRelocationEntry, 12); - - /// Identifies a special static relocation (no game is known using this). - struct StaticRelocationEntry : RelocationEntry { - static constexpr HeaderField TABLE_OFFSET_FIELD = StaticRelocationTableOffset; - }; - ASSERT_CRO_STRUCT(StaticRelocationEntry, 12); - - /// Identifies a in-module relocation. - struct InternalRelocationEntry { - SegmentTag target_position; // to self's segment - RelocationType type; - u8 symbol_segment; - INSERT_PADDING_BYTES(2); - u32_le addend; - - static constexpr HeaderField TABLE_OFFSET_FIELD = InternalRelocationTableOffset; - }; - ASSERT_CRO_STRUCT(InternalRelocationEntry, 12); - - /// Identifies a special static anonymous symbol (no game is known using this). - struct StaticAnonymousSymbolEntry { - SegmentTag symbol_position; // to self's segment - u32_le relocation_batch_offset; // pointing to a relocation batch in StaticRelocationTable - - static constexpr HeaderField TABLE_OFFSET_FIELD = StaticAnonymousSymbolTableOffset; - }; - ASSERT_CRO_STRUCT(StaticAnonymousSymbolEntry, 8); - - /** - * Entry size of each table, from Code to StaticRelocationTable. - * Byte string contents (such as Code) are treated with entries of size 1. - * This is used for verifying the size of each table and calculating the fix end. - */ - static const std::array<int, 17> ENTRY_SIZE; - - /// The offset field of the table where to crop for each fix level - static const std::array<HeaderField, 4> FIX_BARRIERS; - - static constexpr u32 MAGIC_CRO0 = 0x304F5243; - static constexpr u32 MAGIC_FIXD = 0x44584946; - - VAddr Field(HeaderField field) const { - return module_address + CRO_HASH_SIZE + field * 4; - } - - u32 GetField(HeaderField field) const { - return Memory::Read32(Field(field)); - } - - void SetField(HeaderField field, u32 value) { - Memory::Write32(Field(field), value); - } - - /** - * Reads an entry in one of module tables. - * @param index index of the entry - * @param data where to put the read entry - * @note the entry type must have the static member TABLE_OFFSET_FIELD - * indicating which table the entry is in. - */ - template <typename T> - void GetEntry(std::size_t index, T& data) const { - Memory::ReadBlock(GetField(T::TABLE_OFFSET_FIELD) + static_cast<u32>(index * sizeof(T)), - &data, sizeof(T)); - } - - /** - * Writes an entry to one of module tables. - * @param index index of the entry - * @param data the entry data to write - * @note the entry type must have the static member TABLE_OFFSET_FIELD - * indicating which table the entry is in. - */ - template <typename T> - void SetEntry(std::size_t index, const T& data) { - Memory::WriteBlock(GetField(T::TABLE_OFFSET_FIELD) + static_cast<u32>(index * sizeof(T)), - &data, sizeof(T)); - } - - /** - * Converts a segment tag to virtual address in this module. - * @param segment_tag the segment tag to convert - * @returns VAddr the virtual address the segment tag points to; 0 if invalid. - */ - VAddr SegmentTagToAddress(SegmentTag segment_tag) const; - - VAddr NextModule() const { - return GetField(NextCRO); - } - - VAddr PreviousModule() const { - return GetField(PreviousCRO); - } - - void SetNextModule(VAddr next) { - SetField(NextCRO, next); - } - - void SetPreviousModule(VAddr previous) { - SetField(PreviousCRO, previous); - } - - /** - * A helper function iterating over all registered auto-link modules, including the static - * module. - * @param crs_address the virtual address of the static module - * @param func a function object to operate on a module. It accepts one parameter - * CROHelper and returns ResultVal<bool>. It should return true to continue the - * iteration, - * false to stop the iteration, or an error code (which will also stop the iteration). - * @returns ResultCode indicating the result of the operation, RESULT_SUCCESS if all iteration - * success, - * otherwise error code of the last iteration. - */ - template <typename FunctionObject> - static ResultCode ForEachAutoLinkCRO(VAddr crs_address, FunctionObject func) { - VAddr current = crs_address; - while (current != 0) { - CROHelper cro(current); - CASCADE_RESULT(bool next, func(cro)); - if (!next) - break; - current = cro.NextModule(); - } - return RESULT_SUCCESS; - } - - /** - * Applies a relocation - * @param target_address where to apply the relocation - * @param relocation_type the type of the relocation - * @param addend address addend applied to the relocated symbol - * @param symbol_address the symbol address to be relocated with - * @param target_future_address the future address of the target. - * Usually equals to target_address, but will be different for a target in .data segment - * @returns ResultCode RESULT_SUCCESS on success, otherwise error code. - */ - ResultCode ApplyRelocation(VAddr target_address, RelocationType relocation_type, u32 addend, - u32 symbol_address, u32 target_future_address); - - /** - * Clears a relocation to zero - * @param target_address where to apply the relocation - * @param relocation_type the type of the relocation - * @returns ResultCode RESULT_SUCCESS on success, otherwise error code. - */ - ResultCode ClearRelocation(VAddr target_address, RelocationType relocation_type); - - /** - * Applies or resets a batch of relocations - * @param batch the virtual address of the first relocation in the batch - * @param symbol_address the symbol address to be relocated with - * @param reset false to set the batch to resolved state, true to reset the batch to unresolved - * state - * @returns ResultCode RESULT_SUCCESS on success, otherwise error code. - */ - ResultCode ApplyRelocationBatch(VAddr batch, u32 symbol_address, bool reset = false); - - /** - * Finds an exported named symbol in this module. - * @param name the name of the symbol to find - * @return VAddr the virtual address of the symbol; 0 if not found. - */ - VAddr FindExportNamedSymbol(const std::string& name) const; - - /** - * Rebases offsets in module header according to module address. - * @param cro_size the size of the CRO file - * @returns ResultCode RESULT_SUCCESS if all offsets are verified as valid, otherwise error - * code. - */ - ResultCode RebaseHeader(u32 cro_size); - - /** - * Rebases offsets in segment table according to module address. - * @param cro_size the size of the CRO file - * @param data_segment_address the buffer address for .data segment - * @param data_segment_size the buffer size for .data segment - * @param bss_segment_address the buffer address for .bss segment - * @param bss_segment_size the buffer size for .bss segment - * @returns ResultVal<VAddr> with the virtual address of .data segment in CRO. - */ - ResultVal<VAddr> RebaseSegmentTable(u32 cro_size, VAddr data_segment_address, - u32 data_segment_size, VAddr bss_segment_address, - u32 bss_segment_size); - - /** - * Rebases offsets in exported named symbol table according to module address. - * @returns ResultCode RESULT_SUCCESS if all offsets are verified as valid, otherwise error - * code. - */ - ResultCode RebaseExportNamedSymbolTable(); - - /** - * Verifies indices in export tree table. - * @returns ResultCode RESULT_SUCCESS if all indices are verified as valid, otherwise error - * code. - */ - ResultCode VerifyExportTreeTable() const; - - /** - * Rebases offsets in exported module table according to module address. - * @returns ResultCode RESULT_SUCCESS if all offsets are verified as valid, otherwise error - * code. - */ - ResultCode RebaseImportModuleTable(); - - /** - * Rebases offsets in imported named symbol table according to module address. - * @returns ResultCode RESULT_SUCCESS if all offsets are verified as valid, otherwise error - * code. - */ - ResultCode RebaseImportNamedSymbolTable(); - - /** - * Rebases offsets in imported indexed symbol table according to module address. - * @returns ResultCode RESULT_SUCCESS if all offsets are verified as valid, otherwise error - * code. - */ - ResultCode RebaseImportIndexedSymbolTable(); - - /** - * Rebases offsets in imported anonymous symbol table according to module address. - * @returns ResultCode RESULT_SUCCESS if all offsets are verified as valid, otherwise error - * code. - */ - ResultCode RebaseImportAnonymousSymbolTable(); - - /** - * Gets the address of OnUnresolved function in this module. - * Used as the applied symbol for reset relocation. - * @returns the virtual address of OnUnresolved. 0 if not provided. - */ - VAddr GetOnUnresolvedAddress(); - - /** - * Resets all external relocations to unresolved state. - * @returns ResultCode RESULT_SUCCESS on success, otherwise error code. - */ - ResultCode ResetExternalRelocations(); - - /** - * Clears all external relocations to zero. - * @returns ResultCode RESULT_SUCCESS on success, otherwise error code. - */ - ResultCode ClearExternalRelocations(); - - /** - * Applies all static anonymous symbol to the static module. - * @param crs_address the virtual address of the static module - * @returns ResultCode RESULT_SUCCESS on success, otherwise error code. - */ - ResultCode ApplyStaticAnonymousSymbolToCRS(VAddr crs_address); - - /** - * Applies all internal relocations to the module itself. - * @param old_data_segment_address the virtual address of data segment in CRO buffer - * @returns ResultCode RESULT_SUCCESS on success, otherwise error code. - */ - ResultCode ApplyInternalRelocations(u32 old_data_segment_address); - - /** - * Clears all internal relocations to zero. - * @returns ResultCode RESULT_SUCCESS on success, otherwise error code. - */ - ResultCode ClearInternalRelocations(); - - /// Unrebases offsets in imported anonymous symbol table - void UnrebaseImportAnonymousSymbolTable(); - - /// Unrebases offsets in imported indexed symbol table - void UnrebaseImportIndexedSymbolTable(); - - /// Unrebases offsets in imported named symbol table - void UnrebaseImportNamedSymbolTable(); - - /// Unrebases offsets in imported module table - void UnrebaseImportModuleTable(); - - /// Unrebases offsets in exported named symbol table - void UnrebaseExportNamedSymbolTable(); - - /// Unrebases offsets in segment table - void UnrebaseSegmentTable(); - - /// Unrebases offsets in module header - void UnrebaseHeader(); - - /** - * Looks up all imported named symbols of this module in all registered auto-link modules, and - * resolves them if found. - * @param crs_address the virtual address of the static module - * @returns ResultCode RESULT_SUCCESS on success, otherwise error code. - */ - ResultCode ApplyImportNamedSymbol(VAddr crs_address); - - /** - * Resets all imported named symbols of this module to unresolved state. - * @returns ResultCode RESULT_SUCCESS on success, otherwise error code. - */ - ResultCode ResetImportNamedSymbol(); - - /** - * Resets all imported indexed symbols of this module to unresolved state. - * @returns ResultCode RESULT_SUCCESS on success, otherwise error code. - */ - ResultCode ResetImportIndexedSymbol(); - - /** - * Resets all imported anonymous symbols of this module to unresolved state. - * @returns ResultCode RESULT_SUCCESS on success, otherwise error code. - */ - ResultCode ResetImportAnonymousSymbol(); - - /** - * Finds registered auto-link modules that this module imports, and resolves indexed and - * anonymous symbols exported by them. - * @param crs_address the virtual address of the static module - * @returns ResultCode RESULT_SUCCESS on success, otherwise error code. - */ - ResultCode ApplyModuleImport(VAddr crs_address); - - /** - * Resolves target module's imported named symbols that exported by this module. - * @param target the module to resolve. - * @returns ResultCode RESULT_SUCCESS on success, otherwise error code. - */ - ResultCode ApplyExportNamedSymbol(CROHelper target); - - /** - * Resets target's named symbols imported from this module to unresolved state. - * @param target the module to reset. - * @returns ResultCode RESULT_SUCCESS on success, otherwise error code. - */ - ResultCode ResetExportNamedSymbol(CROHelper target); - - /** - * Resolves imported indexed and anonymous symbols in the target module which imports this - * module. - * @param target the module to resolve. - * @returns ResultCode RESULT_SUCCESS on success, otherwise error code. - */ - ResultCode ApplyModuleExport(CROHelper target); - - /** - * Resets target's indexed and anonymous symbol imported from this module to unresolved state. - * @param target the module to reset. - * @returns ResultCode RESULT_SUCCESS on success, otherwise error code. - */ - ResultCode ResetModuleExport(CROHelper target); - - /** - * Resolves the exit function in this module - * @param crs_address the virtual address of the static module. - * @returns ResultCode RESULT_SUCCESS on success, otherwise error code. - */ - ResultCode ApplyExitRelocations(VAddr crs_address); -}; - -} // namespace LDR -} // namespace Service |