| 95 | using Kernel::CodeSet; |
| 96 | |
| 97 | static THREEDSX_Error Load3DSXFile(Core::System& system, FileUtil::IOFile& file, u32 base_addr, |
| 98 | std::shared_ptr<CodeSet>* out_codeset) { |
| 99 | if (!file.IsOpen()) |
| 100 | return ERROR_FILE; |
| 101 | |
| 102 | // Reset read pointer in case this file has been read before. |
| 103 | file.Seek(0, SEEK_SET); |
| 104 | |
| 105 | THREEDSX_Header hdr; |
| 106 | if (file.ReadBytes(&hdr, sizeof(hdr)) != sizeof(hdr)) |
| 107 | return ERROR_READ; |
| 108 | |
| 109 | THREEloadinfo loadinfo; |
| 110 | // loadinfo segments must be a multiple of 0x1000 |
| 111 | loadinfo.seg_sizes[0] = (hdr.code_seg_size + 0xFFF) & ~0xFFF; |
| 112 | loadinfo.seg_sizes[1] = (hdr.rodata_seg_size + 0xFFF) & ~0xFFF; |
| 113 | loadinfo.seg_sizes[2] = (hdr.data_seg_size + 0xFFF) & ~0xFFF; |
| 114 | // prevent integer overflow leading to heap-buffer-overflow |
| 115 | if (loadinfo.seg_sizes[0] < hdr.code_seg_size || loadinfo.seg_sizes[1] < hdr.rodata_seg_size || |
| 116 | loadinfo.seg_sizes[2] < hdr.data_seg_size) { |
| 117 | return ERROR_READ; |
| 118 | } |
| 119 | u32 offsets[2] = {loadinfo.seg_sizes[0], loadinfo.seg_sizes[0] + loadinfo.seg_sizes[1]}; |
| 120 | u32 n_reloc_tables = hdr.reloc_hdr_size / sizeof(u32); |
| 121 | std::vector<u8> program_image(loadinfo.seg_sizes[0] + loadinfo.seg_sizes[1] + |
| 122 | loadinfo.seg_sizes[2]); |
| 123 | |
| 124 | loadinfo.seg_addrs[0] = base_addr; |
| 125 | loadinfo.seg_addrs[1] = loadinfo.seg_addrs[0] + loadinfo.seg_sizes[0]; |
| 126 | loadinfo.seg_addrs[2] = loadinfo.seg_addrs[1] + loadinfo.seg_sizes[1]; |
| 127 | loadinfo.seg_ptrs[0] = program_image.data(); |
| 128 | loadinfo.seg_ptrs[1] = loadinfo.seg_ptrs[0] + loadinfo.seg_sizes[0]; |
| 129 | loadinfo.seg_ptrs[2] = loadinfo.seg_ptrs[1] + loadinfo.seg_sizes[1]; |
| 130 | |
| 131 | // Skip header for future compatibility |
| 132 | file.Seek(hdr.header_size, SEEK_SET); |
| 133 | |
| 134 | // Read the relocation headers |
| 135 | std::vector<u32> relocs(n_reloc_tables * NUM_SEGMENTS); |
| 136 | for (unsigned int current_segment = 0; current_segment < NUM_SEGMENTS; ++current_segment) { |
| 137 | std::size_t size = n_reloc_tables * sizeof(u32); |
| 138 | if (file.ReadBytes(&relocs[current_segment * n_reloc_tables], size) != size) |
| 139 | return ERROR_READ; |
| 140 | } |
| 141 | |
| 142 | // Read the segments |
| 143 | if (file.ReadBytes(loadinfo.seg_ptrs[0], hdr.code_seg_size) != hdr.code_seg_size) |
| 144 | return ERROR_READ; |
| 145 | if (file.ReadBytes(loadinfo.seg_ptrs[1], hdr.rodata_seg_size) != hdr.rodata_seg_size) |
| 146 | return ERROR_READ; |
| 147 | if (file.ReadBytes(loadinfo.seg_ptrs[2], hdr.data_seg_size - hdr.bss_size) != |
| 148 | hdr.data_seg_size - hdr.bss_size) |
| 149 | return ERROR_READ; |
| 150 | |
| 151 | // BSS clear |
| 152 | std::memset((char*)loadinfo.seg_ptrs[2] + hdr.data_seg_size - hdr.bss_size, 0, hdr.bss_size); |
| 153 | |
| 154 | // Relocate the segments |
no test coverage detected