summaryrefslogtreecommitdiff
path: root/src/core/loader/nso.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/loader/nso.cpp')
-rw-r--r--src/core/loader/nso.cpp68
1 files changed, 18 insertions, 50 deletions
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 @@
22 22
23namespace Loader { 23namespace Loader {
24 24
25struct NsoSegmentHeader { 25struct MODHeader {
26 u32_le offset;
27 u32_le location;
28 u32_le size;
29 union {
30 u32_le alignment;
31 u32_le bss_size;
32 };
33};
34static_assert(sizeof(NsoSegmentHeader) == 0x10, "NsoSegmentHeader has incorrect size.");
35
36struct NsoHeader {
37 using SHA256Hash = std::array<u8, 0x20>;
38
39 struct RODataRelativeExtent {
40 u32 data_offset;
41 u32 size;
42 };
43
44 u32_le magic;
45 u32_le version;
46 u32 reserved;
47 u32_le flags;
48 std::array<NsoSegmentHeader, 3> segments; // Text, RoData, Data (in that order)
49 std::array<u8, 0x20> build_id;
50 std::array<u32_le, 3> segments_compressed_size;
51 std::array<u8, 0x1C> padding;
52 RODataRelativeExtent api_info_extent;
53 RODataRelativeExtent dynstr_extent;
54 RODataRelativeExtent dynsyn_extent;
55 std::array<SHA256Hash, 3> segment_hashes;
56
57 bool IsSegmentCompressed(size_t segment_num) const {
58 ASSERT_MSG(segment_num < 3, "Invalid segment {}", segment_num);
59 return ((flags >> segment_num) & 1);
60 }
61};
62static_assert(sizeof(NsoHeader) == 0x100, "NsoHeader has incorrect size.");
63static_assert(std::is_trivially_copyable_v<NsoHeader>, "NsoHeader isn't trivially copyable.");
64
65struct ModHeader {
66 u32_le magic; 26 u32_le magic;
67 u32_le dynamic_offset; 27 u32_le dynamic_offset;
68 u32_le bss_start_offset; 28 u32_le bss_start_offset;
@@ -71,7 +31,12 @@ struct ModHeader {
71 u32_le eh_frame_hdr_end_offset; 31 u32_le eh_frame_hdr_end_offset;
72 u32_le module_offset; // Offset to runtime-generated module object. typically equal to .bss base 32 u32_le module_offset; // Offset to runtime-generated module object. typically equal to .bss base
73}; 33};
74static_assert(sizeof(ModHeader) == 0x1c, "ModHeader has incorrect size."); 34static_assert(sizeof(MODHeader) == 0x1c, "MODHeader has incorrect size.");
35
36bool NSOHeader::IsSegmentCompressed(size_t segment_num) const {
37 ASSERT_MSG(segment_num < 3, "Invalid segment {}", segment_num);
38 return ((flags >> segment_num) & 1) != 0;
39}
75 40
76AppLoader_NSO::AppLoader_NSO(FileSys::VirtualFile file) : AppLoader(std::move(file)) {} 41AppLoader_NSO::AppLoader_NSO(FileSys::VirtualFile file) : AppLoader(std::move(file)) {}
77 42
@@ -89,7 +54,7 @@ FileType AppLoader_NSO::IdentifyType(const FileSys::VirtualFile& file) {
89} 54}
90 55
91static std::vector<u8> DecompressSegment(const std::vector<u8>& compressed_data, 56static std::vector<u8> DecompressSegment(const std::vector<u8>& compressed_data,
92 const NsoSegmentHeader& header) { 57 const NSOSegmentHeader& header) {
93 std::vector<u8> uncompressed_data(header.size); 58 std::vector<u8> uncompressed_data(header.size);
94 const int bytes_uncompressed = 59 const int bytes_uncompressed =
95 LZ4_decompress_safe(reinterpret_cast<const char*>(compressed_data.data()), 60 LZ4_decompress_safe(reinterpret_cast<const char*>(compressed_data.data()),
@@ -111,15 +76,18 @@ std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::Process& process,
111 const FileSys::VfsFile& file, VAddr load_base, 76 const FileSys::VfsFile& file, VAddr load_base,
112 bool should_pass_arguments, 77 bool should_pass_arguments,
113 std::optional<FileSys::PatchManager> pm) { 78 std::optional<FileSys::PatchManager> pm) {
114 if (file.GetSize() < sizeof(NsoHeader)) 79 if (file.GetSize() < sizeof(NSOHeader)) {
115 return {}; 80 return {};
81 }
116 82
117 NsoHeader nso_header{}; 83 NSOHeader nso_header{};
118 if (sizeof(NsoHeader) != file.ReadObject(&nso_header)) 84 if (sizeof(NSOHeader) != file.ReadObject(&nso_header)) {
119 return {}; 85 return {};
86 }
120 87
121 if (nso_header.magic != Common::MakeMagic('N', 'S', 'O', '0')) 88 if (nso_header.magic != Common::MakeMagic('N', 'S', 'O', '0')) {
122 return {}; 89 return {};
90 }
123 91
124 // Build program image 92 // Build program image
125 Kernel::CodeSet codeset; 93 Kernel::CodeSet codeset;
@@ -155,10 +123,10 @@ std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::Process& process,
155 std::memcpy(&module_offset, program_image.data() + 4, sizeof(u32)); 123 std::memcpy(&module_offset, program_image.data() + 4, sizeof(u32));
156 124
157 // Read MOD header 125 // Read MOD header
158 ModHeader mod_header{}; 126 MODHeader mod_header{};
159 // Default .bss to size in segment header if MOD0 section doesn't exist 127 // Default .bss to size in segment header if MOD0 section doesn't exist
160 u32 bss_size{PageAlignSize(nso_header.segments[2].bss_size)}; 128 u32 bss_size{PageAlignSize(nso_header.segments[2].bss_size)};
161 std::memcpy(&mod_header, program_image.data() + module_offset, sizeof(ModHeader)); 129 std::memcpy(&mod_header, program_image.data() + module_offset, sizeof(MODHeader));
162 const bool has_mod_header{mod_header.magic == Common::MakeMagic('M', 'O', 'D', '0')}; 130 const bool has_mod_header{mod_header.magic == Common::MakeMagic('M', 'O', 'D', '0')};
163 if (has_mod_header) { 131 if (has_mod_header) {
164 // Resize program image to include .bss section and page align each section 132 // 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,
171 // Apply patches if necessary 139 // Apply patches if necessary
172 if (pm && (pm->HasNSOPatch(nso_header.build_id) || Settings::values.dump_nso)) { 140 if (pm && (pm->HasNSOPatch(nso_header.build_id) || Settings::values.dump_nso)) {
173 std::vector<u8> pi_header(program_image.size() + 0x100); 141 std::vector<u8> pi_header(program_image.size() + 0x100);
174 std::memcpy(pi_header.data(), &nso_header, sizeof(NsoHeader)); 142 std::memcpy(pi_header.data(), &nso_header, sizeof(NSOHeader));
175 std::memcpy(pi_header.data() + 0x100, program_image.data(), program_image.size()); 143 std::memcpy(pi_header.data() + 0x100, program_image.data(), program_image.size());
176 144
177 pi_header = pm->PatchNSO(pi_header); 145 pi_header = pm->PatchNSO(pi_header);