diff options
| author | 2017-10-03 18:30:02 -0400 | |
|---|---|---|
| committer | 2017-10-03 18:30:02 -0400 | |
| commit | d454364bca3d86f9cd32285ee0c27d80617425df (patch) | |
| tree | 241933955272cf8084fb9c458f10fedba401c159 /src | |
| parent | arm_interface: Set TLS address for dynarmic core. (diff) | |
| download | yuzu-d454364bca3d86f9cd32285ee0c27d80617425df.tar.gz yuzu-d454364bca3d86f9cd32285ee0c27d80617425df.tar.xz yuzu-d454364bca3d86f9cd32285ee0c27d80617425df.zip | |
nso: Fixes to support homebrew NSOs without a MOD header.
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/loader/nso.cpp | 38 | ||||
| -rw-r--r-- | src/core/loader/nso.h | 2 |
2 files changed, 23 insertions, 17 deletions
diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp index f5083d122..0155dec82 100644 --- a/src/core/loader/nso.cpp +++ b/src/core/loader/nso.cpp | |||
| @@ -190,14 +190,14 @@ void AppLoader_NSO::Relocate(VAddr load_base, VAddr dynamic_section_addr) { | |||
| 190 | } | 190 | } |
| 191 | } | 191 | } |
| 192 | 192 | ||
| 193 | VAddr AppLoader_NSO::GetEntryPoint() const { | 193 | VAddr AppLoader_NSO::GetEntryPoint(VAddr load_base) const { |
| 194 | // Find nnMain function, set entrypoint to that address | 194 | // Find nnMain function, set entrypoint to that address |
| 195 | const auto& search = exports.find("nnMain"); | 195 | const auto& search = exports.find("nnMain"); |
| 196 | if (search != exports.end()) { | 196 | if (search != exports.end()) { |
| 197 | return search->second; | 197 | return search->second; |
| 198 | } | 198 | } |
| 199 | ASSERT_MSG(false, "Unable to find entrypoint"); | 199 | LOG_ERROR(Loader, "Unable to find entrypoint, defaulting to: 0x%llx", load_base); |
| 200 | return {}; | 200 | return load_base; |
| 201 | } | 201 | } |
| 202 | 202 | ||
| 203 | static constexpr u32 PageAlignSize(u32 size) { | 203 | static constexpr u32 PageAlignSize(u32 size) { |
| @@ -230,29 +230,31 @@ bool AppLoader_NSO::LoadNso(const std::string& path, VAddr load_base) { | |||
| 230 | program_image.insert(program_image.end(), data.begin(), data.end()); | 230 | program_image.insert(program_image.end(), data.begin(), data.end()); |
| 231 | codeset->segments[i].addr = nso_header.segments[i].location; | 231 | codeset->segments[i].addr = nso_header.segments[i].location; |
| 232 | codeset->segments[i].offset = nso_header.segments[i].location; | 232 | codeset->segments[i].offset = nso_header.segments[i].location; |
| 233 | codeset->segments[i].size = static_cast<u32>(data.size()); | 233 | codeset->segments[i].size = PageAlignSize(static_cast<u32>(data.size())); |
| 234 | } | 234 | } |
| 235 | 235 | ||
| 236 | // Read MOD header | 236 | // Read MOD header |
| 237 | ModHeader mod_header{}; | 237 | ModHeader mod_header{}; |
| 238 | u32 bss_size{Memory::PAGE_SIZE}; // Default .bss to page size if MOD0 section doesn't exist | ||
| 238 | std::memcpy(&mod_header, program_image.data(), sizeof(ModHeader)); | 239 | std::memcpy(&mod_header, program_image.data(), sizeof(ModHeader)); |
| 239 | if (mod_header.magic != MakeMagic('M', 'O', 'D', '0')) { | 240 | const bool has_mod_header{mod_header.magic == MakeMagic('M', 'O', 'D', '0')}; |
| 240 | return {}; | 241 | if (has_mod_header) { |
| 242 | // Resize program image to include .bss section and page align each section | ||
| 243 | bss_size = PageAlignSize(mod_header.bss_end_offset - mod_header.bss_start_offset); | ||
| 244 | codeset->data.size += bss_size; | ||
| 241 | } | 245 | } |
| 242 | |||
| 243 | // Resize program image to include .bss section and page align each section | ||
| 244 | const u32 bss_size = mod_header.bss_end_offset - mod_header.bss_start_offset; | ||
| 245 | codeset->code.size = PageAlignSize(codeset->code.size); | ||
| 246 | codeset->rodata.size = PageAlignSize(codeset->rodata.size); | ||
| 247 | codeset->data.size = PageAlignSize(codeset->data.size + bss_size); | ||
| 248 | program_image.resize(PageAlignSize(static_cast<u32>(program_image.size()) + bss_size)); | 246 | program_image.resize(PageAlignSize(static_cast<u32>(program_image.size()) + bss_size)); |
| 249 | 247 | ||
| 250 | // Load codeset for current process | 248 | // Load codeset for current process |
| 251 | codeset->name = path; | 249 | codeset->name = path; |
| 252 | codeset->memory = std::make_shared<std::vector<u8>>(std::move(program_image)); | 250 | codeset->memory = std::make_shared<std::vector<u8>>(std::move(program_image)); |
| 253 | Kernel::g_current_process->LoadModule(codeset, load_base); | 251 | Kernel::g_current_process->LoadModule(codeset, load_base); |
| 254 | Relocate(load_base, load_base + mod_header.offset_to_start + mod_header.dynamic_offset); | ||
| 255 | 252 | ||
| 253 | // Relocate symbols if there was a proper MOD header - This must happen after the image has been | ||
| 254 | // loaded into memory | ||
| 255 | if (has_mod_header) { | ||
| 256 | Relocate(load_base, load_base + mod_header.offset_to_start + mod_header.dynamic_offset); | ||
| 257 | } | ||
| 256 | return true; | 258 | return true; |
| 257 | } | 259 | } |
| 258 | 260 | ||
| @@ -265,17 +267,21 @@ ResultStatus AppLoader_NSO::Load() { | |||
| 265 | } | 267 | } |
| 266 | 268 | ||
| 267 | // Load and relocate "main" and "sdk" NSO | 269 | // Load and relocate "main" and "sdk" NSO |
| 268 | const std::string sdkpath = filepath.substr(0, filepath.find_last_of("/\\")) + "/sdk"; | 270 | static constexpr VAddr main_base{0x10000000}; |
| 269 | Kernel::g_current_process = Kernel::Process::Create("main"); | 271 | Kernel::g_current_process = Kernel::Process::Create("main"); |
| 270 | if (!LoadNso(filepath, 0x10000000) || !LoadNso(sdkpath, 0x20000000)) { | 272 | if (!LoadNso(filepath, main_base)) { |
| 271 | return ResultStatus::ErrorInvalidFormat; | 273 | return ResultStatus::ErrorInvalidFormat; |
| 272 | } | 274 | } |
| 275 | const std::string sdkpath = filepath.substr(0, filepath.find_last_of("/\\")) + "/sdk"; | ||
| 276 | if (!LoadNso(sdkpath, 0x20000000)) { | ||
| 277 | LOG_WARNING(Loader, "failed to find SDK NSO"); | ||
| 278 | } | ||
| 273 | 279 | ||
| 274 | Kernel::g_current_process->svc_access_mask.set(); | 280 | Kernel::g_current_process->svc_access_mask.set(); |
| 275 | Kernel::g_current_process->address_mappings = default_address_mappings; | 281 | Kernel::g_current_process->address_mappings = default_address_mappings; |
| 276 | Kernel::g_current_process->resource_limit = | 282 | Kernel::g_current_process->resource_limit = |
| 277 | Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION); | 283 | Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION); |
| 278 | Kernel::g_current_process->Run(GetEntryPoint(), 48, Kernel::DEFAULT_STACK_SIZE); | 284 | Kernel::g_current_process->Run(GetEntryPoint(main_base), 48, Kernel::DEFAULT_STACK_SIZE); |
| 279 | 285 | ||
| 280 | // Resolve imports | 286 | // Resolve imports |
| 281 | for (const auto& import : imports) { | 287 | for (const auto& import : imports) { |
diff --git a/src/core/loader/nso.h b/src/core/loader/nso.h index 2d9e60ad7..16b41b6dc 100644 --- a/src/core/loader/nso.h +++ b/src/core/loader/nso.h | |||
| @@ -47,7 +47,7 @@ private: | |||
| 47 | 47 | ||
| 48 | void WriteRelocations(const std::vector<Symbol>& symbols, VAddr load_base, | 48 | void WriteRelocations(const std::vector<Symbol>& symbols, VAddr load_base, |
| 49 | u64 relocation_offset, u64 size, bool is_jump_relocation); | 49 | u64 relocation_offset, u64 size, bool is_jump_relocation); |
| 50 | VAddr GetEntryPoint() const; | 50 | VAddr GetEntryPoint(VAddr load_base) const; |
| 51 | bool LoadNso(const std::string& path, VAddr load_base); | 51 | bool LoadNso(const std::string& path, VAddr load_base); |
| 52 | void Relocate(VAddr load_base, VAddr dynamic_section_addr); | 52 | void Relocate(VAddr load_base, VAddr dynamic_section_addr); |
| 53 | 53 | ||