diff options
author | Lioncash <mathew1800@gmail.com> | 2019-03-22 18:04:41 +0100 |
---|---|---|
committer | Lioncash <mathew1800@gmail.com> | 2019-03-22 19:39:10 +0100 |
commit | 1cf90f45704373cd61d274d1e3c4dc6e5be87eaa (patch) | |
tree | 7654dab9069c34d32cd14f2ae3a025b7eaeff7b2 | |
parent | loader/nso: Fix definition of the NSO header struct (diff) | |
download | yuzu-1cf90f45704373cd61d274d1e3c4dc6e5be87eaa.tar yuzu-1cf90f45704373cd61d274d1e3c4dc6e5be87eaa.tar.gz yuzu-1cf90f45704373cd61d274d1e3c4dc6e5be87eaa.tar.bz2 yuzu-1cf90f45704373cd61d274d1e3c4dc6e5be87eaa.tar.lz yuzu-1cf90f45704373cd61d274d1e3c4dc6e5be87eaa.tar.xz yuzu-1cf90f45704373cd61d274d1e3c4dc6e5be87eaa.tar.zst yuzu-1cf90f45704373cd61d274d1e3c4dc6e5be87eaa.zip |
-rw-r--r-- | src/core/file_sys/patch_manager.cpp | 22 | ||||
-rw-r--r-- | src/core/loader/nso.cpp | 68 | ||||
-rw-r--r-- | src/core/loader/nso.h | 39 |
3 files changed, 65 insertions, 64 deletions
diff --git a/src/core/file_sys/patch_manager.cpp b/src/core/file_sys/patch_manager.cpp index efc572c72..fd21d3ad1 100644 --- a/src/core/file_sys/patch_manager.cpp +++ b/src/core/file_sys/patch_manager.cpp @@ -20,6 +20,7 @@ #include "core/file_sys/vfs_vector.h" #include "core/hle/service/filesystem/filesystem.h" #include "core/loader/loader.h" +#include "core/loader/nso.h" #include "core/settings.h" namespace FileSys { @@ -32,14 +33,6 @@ constexpr std::array<const char*, 14> EXEFS_FILE_NAMES{ "subsdk3", "subsdk4", "subsdk5", "subsdk6", "subsdk7", "subsdk8", "subsdk9", }; -struct NSOBuildHeader { - u32_le magic; - INSERT_PADDING_BYTES(0x3C); - std::array<u8, 0x20> build_id; - INSERT_PADDING_BYTES(0xA0); -}; -static_assert(sizeof(NSOBuildHeader) == 0x100, "NSOBuildHeader has incorrect size."); - std::string FormatTitleVersion(u32 version, TitleVersionFormat format) { std::array<u8, sizeof(u32)> bytes{}; bytes[0] = version % SINGLE_BYTE_MODULUS; @@ -163,15 +156,16 @@ std::vector<VirtualFile> PatchManager::CollectPatches(const std::vector<VirtualD } std::vector<u8> PatchManager::PatchNSO(const std::vector<u8>& nso) const { - if (nso.size() < sizeof(NSOBuildHeader)) { + if (nso.size() < sizeof(Loader::NSOHeader)) { return nso; } - NSOBuildHeader header; - std::memcpy(&header, nso.data(), sizeof(NSOBuildHeader)); + Loader::NSOHeader header; + std::memcpy(&header, nso.data(), sizeof(header)); - if (header.magic != Common::MakeMagic('N', 'S', 'O', '0')) + if (header.magic != Common::MakeMagic('N', 'S', 'O', '0')) { return nso; + } const auto build_id_raw = Common::HexArrayToString(header.build_id); const auto build_id = build_id_raw.substr(0, build_id_raw.find_last_not_of('0') + 1); @@ -214,11 +208,11 @@ std::vector<u8> PatchManager::PatchNSO(const std::vector<u8>& nso) const { } } - if (out.size() < sizeof(NSOBuildHeader)) { + if (out.size() < sizeof(Loader::NSOHeader)) { return nso; } - std::memcpy(out.data(), &header, sizeof(NSOBuildHeader)); + std::memcpy(out.data(), &header, sizeof(header)); return out; } diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp index a52104792..262eaeaee 100644 --- a/src/core/loader/nso.cpp +++ b/src/core/loader/nso.cpp @@ -22,47 +22,7 @@ namespace Loader { -struct NsoSegmentHeader { - u32_le offset; - u32_le location; - u32_le size; - union { - u32_le alignment; - u32_le bss_size; - }; -}; -static_assert(sizeof(NsoSegmentHeader) == 0x10, "NsoSegmentHeader has incorrect size."); - -struct NsoHeader { - using SHA256Hash = std::array<u8, 0x20>; - - struct RODataRelativeExtent { - u32 data_offset; - u32 size; - }; - - u32_le magic; - u32_le version; - u32 reserved; - u32_le flags; - std::array<NsoSegmentHeader, 3> segments; // Text, RoData, Data (in that order) - std::array<u8, 0x20> build_id; - std::array<u32_le, 3> segments_compressed_size; - std::array<u8, 0x1C> padding; - RODataRelativeExtent api_info_extent; - RODataRelativeExtent dynstr_extent; - RODataRelativeExtent dynsyn_extent; - std::array<SHA256Hash, 3> segment_hashes; - - bool IsSegmentCompressed(size_t segment_num) const { - ASSERT_MSG(segment_num < 3, "Invalid segment {}", segment_num); - return ((flags >> segment_num) & 1); - } -}; -static_assert(sizeof(NsoHeader) == 0x100, "NsoHeader has incorrect size."); -static_assert(std::is_trivially_copyable_v<NsoHeader>, "NsoHeader isn't trivially copyable."); - -struct ModHeader { +struct MODHeader { u32_le magic; u32_le dynamic_offset; u32_le bss_start_offset; @@ -71,7 +31,12 @@ struct ModHeader { u32_le eh_frame_hdr_end_offset; u32_le module_offset; // Offset to runtime-generated module object. typically equal to .bss base }; -static_assert(sizeof(ModHeader) == 0x1c, "ModHeader has incorrect size."); +static_assert(sizeof(MODHeader) == 0x1c, "MODHeader has incorrect size."); + +bool NSOHeader::IsSegmentCompressed(size_t segment_num) const { + ASSERT_MSG(segment_num < 3, "Invalid segment {}", segment_num); + return ((flags >> segment_num) & 1) != 0; +} AppLoader_NSO::AppLoader_NSO(FileSys::VirtualFile file) : AppLoader(std::move(file)) {} @@ -89,7 +54,7 @@ FileType AppLoader_NSO::IdentifyType(const FileSys::VirtualFile& file) { } static std::vector<u8> DecompressSegment(const std::vector<u8>& compressed_data, - const NsoSegmentHeader& header) { + const NSOSegmentHeader& header) { std::vector<u8> uncompressed_data(header.size); const int bytes_uncompressed = LZ4_decompress_safe(reinterpret_cast<const char*>(compressed_data.data()), @@ -111,15 +76,18 @@ std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::Process& process, const FileSys::VfsFile& file, VAddr load_base, bool should_pass_arguments, std::optional<FileSys::PatchManager> pm) { - if (file.GetSize() < sizeof(NsoHeader)) + if (file.GetSize() < sizeof(NSOHeader)) { return {}; + } - NsoHeader nso_header{}; - if (sizeof(NsoHeader) != file.ReadObject(&nso_header)) + NSOHeader nso_header{}; + if (sizeof(NSOHeader) != file.ReadObject(&nso_header)) { return {}; + } - if (nso_header.magic != Common::MakeMagic('N', 'S', 'O', '0')) + if (nso_header.magic != Common::MakeMagic('N', 'S', 'O', '0')) { return {}; + } // Build program image Kernel::CodeSet codeset; @@ -155,10 +123,10 @@ std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::Process& process, std::memcpy(&module_offset, program_image.data() + 4, sizeof(u32)); // Read MOD header - ModHeader mod_header{}; + MODHeader mod_header{}; // Default .bss to size in segment header if MOD0 section doesn't exist u32 bss_size{PageAlignSize(nso_header.segments[2].bss_size)}; - std::memcpy(&mod_header, program_image.data() + module_offset, sizeof(ModHeader)); + std::memcpy(&mod_header, program_image.data() + module_offset, sizeof(MODHeader)); const bool has_mod_header{mod_header.magic == Common::MakeMagic('M', 'O', 'D', '0')}; if (has_mod_header) { // Resize program image to include .bss section and page align each section @@ -171,7 +139,7 @@ std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::Process& process, // Apply patches if necessary if (pm && (pm->HasNSOPatch(nso_header.build_id) || Settings::values.dump_nso)) { std::vector<u8> pi_header(program_image.size() + 0x100); - std::memcpy(pi_header.data(), &nso_header, sizeof(NsoHeader)); + std::memcpy(pi_header.data(), &nso_header, sizeof(NSOHeader)); std::memcpy(pi_header.data() + 0x100, program_image.data(), program_image.size()); pi_header = pm->PatchNSO(pi_header); diff --git a/src/core/loader/nso.h b/src/core/loader/nso.h index 167c8a694..4674c3724 100644 --- a/src/core/loader/nso.h +++ b/src/core/loader/nso.h @@ -4,7 +4,9 @@ #pragma once +#include <array> #include <optional> +#include <type_traits> #include "common/common_types.h" #include "common/swap.h" #include "core/file_sys/patch_manager.h" @@ -16,6 +18,43 @@ class Process; namespace Loader { +struct NSOSegmentHeader { + u32_le offset; + u32_le location; + u32_le size; + union { + u32_le alignment; + u32_le bss_size; + }; +}; +static_assert(sizeof(NSOSegmentHeader) == 0x10, "NsoSegmentHeader has incorrect size."); + +struct NSOHeader { + using SHA256Hash = std::array<u8, 0x20>; + + struct RODataRelativeExtent { + u32_le data_offset; + u32_le size; + }; + + u32_le magic; + u32_le version; + u32 reserved; + u32_le flags; + std::array<NSOSegmentHeader, 3> segments; // Text, RoData, Data (in that order) + std::array<u8, 0x20> build_id; + std::array<u32_le, 3> segments_compressed_size; + std::array<u8, 0x1C> padding; + RODataRelativeExtent api_info_extent; + RODataRelativeExtent dynstr_extent; + RODataRelativeExtent dynsyn_extent; + std::array<SHA256Hash, 3> segment_hashes; + + bool IsSegmentCompressed(size_t segment_num) const; +}; +static_assert(sizeof(NSOHeader) == 0x100, "NSOHeader has incorrect size."); +static_assert(std::is_trivially_copyable_v<NSOHeader>, "NSOHeader must be trivially copyable."); + constexpr u64 NSO_ARGUMENT_DATA_ALLOCATION_SIZE = 0x9000; struct NSOArgumentHeader { |