diff options
| author | 2015-01-20 12:55:28 -0500 | |
|---|---|---|
| committer | 2015-01-20 12:55:28 -0500 | |
| commit | 205170fa623efdd5eafb0c957d728babe4836f45 (patch) | |
| tree | 26dd9e4c7ae9cc7a3bb09f42c942c4e47c9cc06f /src/core/loader/3dsx.cpp | |
| parent | Merge pull request #496 from lioncash/warn (diff) | |
| parent | Loader: Clean up the ELF AppLoader. (diff) | |
| download | yuzu-205170fa623efdd5eafb0c957d728babe4836f45.tar.gz yuzu-205170fa623efdd5eafb0c957d728babe4836f45.tar.xz yuzu-205170fa623efdd5eafb0c957d728babe4836f45.zip | |
Merge pull request #241 from linkmauve/better-loader
Improve the loader a bit
Diffstat (limited to 'src/core/loader/3dsx.cpp')
| -rw-r--r-- | src/core/loader/3dsx.cpp | 109 |
1 files changed, 56 insertions, 53 deletions
diff --git a/src/core/loader/3dsx.cpp b/src/core/loader/3dsx.cpp index 4d072871a..958dd03e8 100644 --- a/src/core/loader/3dsx.cpp +++ b/src/core/loader/3dsx.cpp | |||
| @@ -13,11 +13,9 @@ | |||
| 13 | 13 | ||
| 14 | #include "3dsx.h" | 14 | #include "3dsx.h" |
| 15 | 15 | ||
| 16 | |||
| 17 | namespace Loader { | 16 | namespace Loader { |
| 18 | 17 | ||
| 19 | 18 | /** | |
| 20 | /** | ||
| 21 | * File layout: | 19 | * File layout: |
| 22 | * - File header | 20 | * - File header |
| 23 | * - Code, rodata and data relocation table headers | 21 | * - Code, rodata and data relocation table headers |
| @@ -46,7 +44,6 @@ enum THREEDSX_Error { | |||
| 46 | static const u32 RELOCBUFSIZE = 512; | 44 | static const u32 RELOCBUFSIZE = 512; |
| 47 | 45 | ||
| 48 | // File header | 46 | // File header |
| 49 | static const u32 THREEDSX_MAGIC = 0x58534433; // '3DSX' | ||
| 50 | #pragma pack(1) | 47 | #pragma pack(1) |
| 51 | struct THREEDSX_Header | 48 | struct THREEDSX_Header |
| 52 | { | 49 | { |
| @@ -64,9 +61,9 @@ struct THREEDSX_Header | |||
| 64 | struct THREEDSX_RelocHdr | 61 | struct THREEDSX_RelocHdr |
| 65 | { | 62 | { |
| 66 | // # of absolute relocations (that is, fix address to post-relocation memory layout) | 63 | // # of absolute relocations (that is, fix address to post-relocation memory layout) |
| 67 | u32 cross_segment_absolute; | 64 | u32 cross_segment_absolute; |
| 68 | // # of cross-segment relative relocations (that is, 32bit signed offsets that need to be patched) | 65 | // # of cross-segment relative relocations (that is, 32bit signed offsets that need to be patched) |
| 69 | u32 cross_segment_relative; | 66 | u32 cross_segment_relative; |
| 70 | // more? | 67 | // more? |
| 71 | 68 | ||
| 72 | // Relocations are written in this order: | 69 | // Relocations are written in this order: |
| @@ -88,12 +85,7 @@ struct THREEloadinfo | |||
| 88 | u32 seg_sizes[3]; | 85 | u32 seg_sizes[3]; |
| 89 | }; | 86 | }; |
| 90 | 87 | ||
| 91 | class THREEDSXReader { | 88 | static u32 TranslateAddr(u32 addr, const THREEloadinfo *loadinfo, u32* offsets) |
| 92 | public: | ||
| 93 | static int Load3DSXFile(const std::string& filename, u32 base_addr); | ||
| 94 | }; | ||
| 95 | |||
| 96 | static u32 TranslateAddr(u32 addr, THREEloadinfo *loadinfo, u32* offsets) | ||
| 97 | { | 89 | { |
| 98 | if (addr < offsets[0]) | 90 | if (addr < offsets[0]) |
| 99 | return loadinfo->seg_addrs[0] + addr; | 91 | return loadinfo->seg_addrs[0] + addr; |
| @@ -102,12 +94,14 @@ static u32 TranslateAddr(u32 addr, THREEloadinfo *loadinfo, u32* offsets) | |||
| 102 | return loadinfo->seg_addrs[2] + addr - offsets[1]; | 94 | return loadinfo->seg_addrs[2] + addr - offsets[1]; |
| 103 | } | 95 | } |
| 104 | 96 | ||
| 105 | int THREEDSXReader::Load3DSXFile(const std::string& filename, u32 base_addr) | 97 | static THREEDSX_Error Load3DSXFile(FileUtil::IOFile& file, u32 base_addr) |
| 106 | { | 98 | { |
| 107 | FileUtil::IOFile file(filename, "rb"); | 99 | if (!file.IsOpen()) |
| 108 | if (!file.IsOpen()) { | ||
| 109 | return ERROR_FILE; | 100 | return ERROR_FILE; |
| 110 | } | 101 | |
| 102 | // Reset read pointer in case this file has been read before. | ||
| 103 | file.Seek(0, SEEK_SET); | ||
| 104 | |||
| 111 | THREEDSX_Header hdr; | 105 | THREEDSX_Header hdr; |
| 112 | if (file.ReadBytes(&hdr, sizeof(hdr)) != sizeof(hdr)) | 106 | if (file.ReadBytes(&hdr, sizeof(hdr)) != sizeof(hdr)) |
| 113 | return ERROR_READ; | 107 | return ERROR_READ; |
| @@ -136,8 +130,9 @@ int THREEDSXReader::Load3DSXFile(const std::string& filename, u32 base_addr) | |||
| 136 | // Read the relocation headers | 130 | // Read the relocation headers |
| 137 | u32* relocs = (u32*)(loadinfo.seg_ptrs[2] + hdr.data_seg_size); | 131 | u32* relocs = (u32*)(loadinfo.seg_ptrs[2] + hdr.data_seg_size); |
| 138 | 132 | ||
| 139 | for (u32 current_segment = 0; current_segment < 3; current_segment++) { | 133 | for (unsigned current_segment : {0, 1, 2}) { |
| 140 | if (file.ReadBytes(&relocs[current_segment*n_reloc_tables], n_reloc_tables * 4) != n_reloc_tables * 4) | 134 | size_t size = n_reloc_tables * 4; |
| 135 | if (file.ReadBytes(&relocs[current_segment * n_reloc_tables], size) != size) | ||
| 141 | return ERROR_READ; | 136 | return ERROR_READ; |
| 142 | } | 137 | } |
| 143 | 138 | ||
| @@ -153,9 +148,9 @@ int THREEDSXReader::Load3DSXFile(const std::string& filename, u32 base_addr) | |||
| 153 | memset((char*)loadinfo.seg_ptrs[2] + hdr.data_seg_size - hdr.bss_size, 0, hdr.bss_size); | 148 | memset((char*)loadinfo.seg_ptrs[2] + hdr.data_seg_size - hdr.bss_size, 0, hdr.bss_size); |
| 154 | 149 | ||
| 155 | // Relocate the segments | 150 | // Relocate the segments |
| 156 | for (u32 current_segment = 0; current_segment < 3; current_segment++) { | 151 | for (unsigned current_segment : {0, 1, 2}) { |
| 157 | for (u32 current_segment_reloc_table = 0; current_segment_reloc_table < n_reloc_tables; current_segment_reloc_table++) { | 152 | for (unsigned current_segment_reloc_table = 0; current_segment_reloc_table < n_reloc_tables; current_segment_reloc_table++) { |
| 158 | u32 n_relocs = relocs[current_segment*n_reloc_tables + current_segment_reloc_table]; | 153 | u32 n_relocs = relocs[current_segment * n_reloc_tables + current_segment_reloc_table]; |
| 159 | if (current_segment_reloc_table >= 2) { | 154 | if (current_segment_reloc_table >= 2) { |
| 160 | // We are not using this table - ignore it because we don't know what it dose | 155 | // We are not using this table - ignore it because we don't know what it dose |
| 161 | file.Seek(n_relocs*sizeof(THREEDSX_Reloc), SEEK_CUR); | 156 | file.Seek(n_relocs*sizeof(THREEDSX_Reloc), SEEK_CUR); |
| @@ -164,29 +159,35 @@ int THREEDSXReader::Load3DSXFile(const std::string& filename, u32 base_addr) | |||
| 164 | static THREEDSX_Reloc reloc_table[RELOCBUFSIZE]; | 159 | static THREEDSX_Reloc reloc_table[RELOCBUFSIZE]; |
| 165 | 160 | ||
| 166 | u32* pos = (u32*)loadinfo.seg_ptrs[current_segment]; | 161 | u32* pos = (u32*)loadinfo.seg_ptrs[current_segment]; |
| 167 | u32* end_pos = pos + (loadinfo.seg_sizes[current_segment] / 4); | 162 | const u32* end_pos = pos + (loadinfo.seg_sizes[current_segment] / 4); |
| 168 | 163 | ||
| 169 | while (n_relocs) { | 164 | while (n_relocs) { |
| 170 | u32 remaining = std::min(RELOCBUFSIZE, n_relocs); | 165 | u32 remaining = std::min(RELOCBUFSIZE, n_relocs); |
| 171 | n_relocs -= remaining; | 166 | n_relocs -= remaining; |
| 172 | 167 | ||
| 173 | if (file.ReadBytes(reloc_table, remaining*sizeof(THREEDSX_Reloc)) != remaining*sizeof(THREEDSX_Reloc)) | 168 | if (file.ReadBytes(reloc_table, remaining * sizeof(THREEDSX_Reloc)) != remaining * sizeof(THREEDSX_Reloc)) |
| 174 | return ERROR_READ; | 169 | return ERROR_READ; |
| 175 | 170 | ||
| 176 | for (u32 current_inprogress = 0; current_inprogress < remaining && pos < end_pos; current_inprogress++) { | 171 | for (unsigned current_inprogress = 0; current_inprogress < remaining && pos < end_pos; current_inprogress++) { |
| 177 | LOG_TRACE(Loader, "(t=%d,skip=%u,patch=%u)\n", | 172 | const auto& table = reloc_table[current_inprogress]; |
| 178 | current_segment_reloc_table, (u32)reloc_table[current_inprogress].skip, (u32)reloc_table[current_inprogress].patch); | 173 | LOG_TRACE(Loader, "(t=%d,skip=%u,patch=%u)\n", current_segment_reloc_table, |
| 179 | pos += reloc_table[current_inprogress].skip; | 174 | (u32)table.skip, (u32)table.patch); |
| 180 | s32 num_patches = reloc_table[current_inprogress].patch; | 175 | pos += table.skip; |
| 176 | s32 num_patches = table.patch; | ||
| 181 | while (0 < num_patches && pos < end_pos) { | 177 | while (0 < num_patches && pos < end_pos) { |
| 182 | u32 in_addr = (char*)pos - (char*)&all_mem[0]; | 178 | u32 in_addr = (char*)pos - (char*)&all_mem[0]; |
| 183 | u32 addr = TranslateAddr(*pos, &loadinfo, offsets); | 179 | u32 addr = TranslateAddr(*pos, &loadinfo, offsets); |
| 184 | LOG_TRACE(Loader, "Patching %08X <-- rel(%08X,%d) (%08X)\n", | 180 | LOG_TRACE(Loader, "Patching %08X <-- rel(%08X,%d) (%08X)\n", |
| 185 | base_addr + in_addr, addr, current_segment_reloc_table, *pos); | 181 | base_addr + in_addr, addr, current_segment_reloc_table, *pos); |
| 186 | switch (current_segment_reloc_table) { | 182 | switch (current_segment_reloc_table) { |
| 187 | case 0: *pos = (addr); break; | 183 | case 0: |
| 188 | case 1: *pos = (addr - in_addr); break; | 184 | *pos = (addr); |
| 189 | default: break; //this should never happen | 185 | break; |
| 186 | case 1: | ||
| 187 | *pos = (addr - in_addr); | ||
| 188 | break; | ||
| 189 | default: | ||
| 190 | break; //this should never happen | ||
| 190 | } | 191 | } |
| 191 | pos++; | 192 | pos++; |
| 192 | num_patches--; | 193 | num_patches--; |
| @@ -207,28 +208,30 @@ int THREEDSXReader::Load3DSXFile(const std::string& filename, u32 base_addr) | |||
| 207 | return ERROR_NONE; | 208 | return ERROR_NONE; |
| 208 | } | 209 | } |
| 209 | 210 | ||
| 210 | /// AppLoader_DSX constructor | 211 | FileType AppLoader_THREEDSX::IdentifyType(FileUtil::IOFile& file) { |
| 211 | AppLoader_THREEDSX::AppLoader_THREEDSX(const std::string& filename) : filename(filename) { | 212 | u32 magic; |
| 212 | } | 213 | file.Seek(0, SEEK_SET); |
| 214 | if (1 != file.ReadArray<u32>(&magic, 1)) | ||
| 215 | return FileType::Error; | ||
| 213 | 216 | ||
| 214 | /// AppLoader_DSX destructor | 217 | if (MakeMagic('3', 'D', 'S', 'X') == magic) |
| 215 | AppLoader_THREEDSX::~AppLoader_THREEDSX() { | 218 | return FileType::THREEDSX; |
| 216 | } | ||
| 217 | 219 | ||
| 218 | /** | 220 | return FileType::Error; |
| 219 | * Loads a 3DSX file | 221 | } |
| 220 | * @return Success on success, otherwise Error | 222 | |
| 221 | */ | 223 | ResultStatus AppLoader_THREEDSX::Load() { |
| 222 | ResultStatus AppLoader_THREEDSX::Load() { | 224 | if (is_loaded) |
| 223 | LOG_INFO(Loader, "Loading 3DSX file %s...", filename.c_str()); | 225 | return ResultStatus::ErrorAlreadyLoaded; |
| 224 | FileUtil::IOFile file(filename, "rb"); | 226 | |
| 225 | if (file.IsOpen()) { | 227 | if (!file->IsOpen()) |
| 226 | THREEDSXReader::Load3DSXFile(filename, 0x00100000); | 228 | return ResultStatus::Error; |
| 227 | Kernel::LoadExec(0x00100000); | 229 | |
| 228 | } else { | 230 | Load3DSXFile(*file, 0x00100000); |
| 229 | return ResultStatus::Error; | 231 | Kernel::LoadExec(0x00100000); |
| 230 | } | 232 | |
| 231 | return ResultStatus::Success; | 233 | is_loaded = true; |
| 232 | } | 234 | return ResultStatus::Success; |
| 235 | } | ||
| 233 | 236 | ||
| 234 | } // namespace Loader | 237 | } // namespace Loader |