From 1cf90f45704373cd61d274d1e3c4dc6e5be87eaa Mon Sep 17 00:00:00 2001 From: Lioncash Date: Fri, 22 Mar 2019 13:04:41 -0400 Subject: [PATCH] file_sys/patch_manager: Deduplicate NSO header This source file was utilizing its own version of the NSO header. Instead of keeping this around, we can have the patch manager also use the version of the header that we have defined in loader/nso.h --- src/core/file_sys/patch_manager.cpp | 22 ++++------ src/core/loader/nso.cpp | 68 ++++++++--------------------- 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 EXEFS_FILE_NAMES{ "subsdk3", "subsdk4", "subsdk5", "subsdk6", "subsdk7", "subsdk8", "subsdk9", }; -struct NSOBuildHeader { - u32_le magic; - INSERT_PADDING_BYTES(0x3C); - std::array build_id; - INSERT_PADDING_BYTES(0xA0); -}; -static_assert(sizeof(NSOBuildHeader) == 0x100, "NSOBuildHeader has incorrect size."); - std::string FormatTitleVersion(u32 version, TitleVersionFormat format) { std::array bytes{}; bytes[0] = version % SINGLE_BYTE_MODULUS; @@ -163,15 +156,16 @@ std::vector PatchManager::CollectPatches(const std::vector PatchManager::PatchNSO(const std::vector& 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 PatchManager::PatchNSO(const std::vector& 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; - - struct RODataRelativeExtent { - u32 data_offset; - u32 size; - }; - - u32_le magic; - u32_le version; - u32 reserved; - u32_le flags; - std::array segments; // Text, RoData, Data (in that order) - std::array build_id; - std::array segments_compressed_size; - std::array padding; - RODataRelativeExtent api_info_extent; - RODataRelativeExtent dynstr_extent; - RODataRelativeExtent dynsyn_extent; - std::array 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 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 DecompressSegment(const std::vector& compressed_data, - const NsoSegmentHeader& header) { + const NSOSegmentHeader& header) { std::vector uncompressed_data(header.size); const int bytes_uncompressed = LZ4_decompress_safe(reinterpret_cast(compressed_data.data()), @@ -111,15 +76,18 @@ std::optional AppLoader_NSO::LoadModule(Kernel::Process& process, const FileSys::VfsFile& file, VAddr load_base, bool should_pass_arguments, std::optional 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 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 AppLoader_NSO::LoadModule(Kernel::Process& process, // Apply patches if necessary if (pm && (pm->HasNSOPatch(nso_header.build_id) || Settings::values.dump_nso)) { std::vector 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 #include +#include #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; + + struct RODataRelativeExtent { + u32_le data_offset; + u32_le size; + }; + + u32_le magic; + u32_le version; + u32 reserved; + u32_le flags; + std::array segments; // Text, RoData, Data (in that order) + std::array build_id; + std::array segments_compressed_size; + std::array padding; + RODataRelativeExtent api_info_extent; + RODataRelativeExtent dynstr_extent; + RODataRelativeExtent dynsyn_extent; + std::array 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 must be trivially copyable."); + constexpr u64 NSO_ARGUMENT_DATA_ALLOCATION_SIZE = 0x9000; struct NSOArgumentHeader {