diff options
Diffstat (limited to 'le/le_parse_util.cpp')
| -rw-r--r-- | le/le_parse_util.cpp | 99 |
1 files changed, 99 insertions, 0 deletions
diff --git a/le/le_parse_util.cpp b/le/le_parse_util.cpp new file mode 100644 index 0000000..ab2d70d --- /dev/null +++ b/le/le_parse_util.cpp @@ -0,0 +1,99 @@ +#include "le_parse_util.hpp" + +#include "parse.hpp" + +std::vector<uint8_t> read_file_part(std::istream& is, std::streamsize offset, size_t length) { + is.clear(); + is.seekg(0, std::ios::beg); + + is.ignore(offset); + + std::vector<uint8_t> vec; + vec.reserve(length); + + std::copy_n(std::istream_iterator<uint8_t>(is), length, std::back_inserter(vec)); + return vec; +} + +std::vector<uint8_t> read_object(std::istream& is, le::File file, binparse::Value32 object_id) { + auto object = file.object_table.entries[object_id]; + auto index = object.page_table_index; + + return read_file_part(is, file.le_header.data_page_offset, file.le_header.page_size * (object.nr_page_table_entries -(index -1))); +} + +le::File parse_file(std::istream& is) +{ + is.clear(); + is.seekg(0, std::ios::beg); + + auto file = le::parse_file(is); + + return file; +} + +void relocate(std::vector<le::FixupRecordTable::Entry> fixups, std::vector<uint8_t>& binary, binparse::Value32 page_nr, le::File const& file) { + binparse::Offset32 page_offset; + for(auto&& object : file.object_table.entries) { + if(page_nr >= object.second.page_table_index && page_nr < object.second.page_table_index + object.second.nr_page_table_entries) { + page_offset = object.second.reloc_base_address; + page_offset += ((page_nr - 1) - object.second.page_table_index) * file.le_header.page_size; + break; + } + } + + for(auto&& fixup : fixups) { + auto internal = boost::get<le::FixupRecordTable::Entry::Internal>(fixup.data); + + auto source_offset = boost::get<binparse::Offset16>(fixup.source_offset_or_source_list_count); + + auto target_object = boost::get<binparse::Value8>(internal.object_number); + + auto binary_offset = page_offset + (int32_t) source_offset; + + binparse::Offset32 dest_offset; + if(bit(4, fixup.target_flags)) { + dest_offset = boost::get<binparse::Offset32>(internal.target_offset); + } else { + dest_offset = binparse::Offset32(boost::get<binparse::Offset16>(internal.target_offset)); + } + dest_offset += file.object_table.entries.at(target_object).reloc_base_address; + for(int i = 0; i < 4; ++i) { + uint8_t& byte = *(binary.data() + binary_offset + i); + byte = ((dest_offset >> (i * 8)) & 255); + } + } +} + +std::vector<uint8_t> load_binary(le::File file) +{ + size_t binary_size = 0; + + for(auto&& object : file.object_table.entries) { + auto furthest_object_point = object.second.reloc_base_address + (object.second.nr_page_table_entries * file.le_header.page_size); + if (furthest_object_point > binary_size) { + binary_size = furthest_object_point; + } + } + + std::vector<uint8_t> binary(binary_size, 0x90); + + for(auto&& entry : file.object_table.entries) { + auto&& object = entry.second; + auto index = object.page_table_index; + for(binparse::Value32 i = index ; i < index + object.nr_page_table_entries; ++i) { + auto page = file.pages.map[i]; + + binparse::Offset32 dest_offset = binparse::Offset32(object.reloc_base_address + (i-index) * file.le_header.page_size); + + std::copy(page.begin(), page.end(), binary.data() + dest_offset); + } + } + + for(auto&& entry : file.fixup_record_table.entries) { + auto&& relocation = entry.second; + relocate(relocation, binary, entry.first, file); + } + + return binary; +} |
