diff --git a/CMakeLists.txt b/CMakeLists.txt index ac78bcb..e479064 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,6 +19,7 @@ set(CAPSTONE_ARCHITECTURE_DEFAULT OFF) set(CAPSTONE_PPC_SUPPORT ON) add_subdirectory(external/capstone) -add_executable(weee main.cpp core/mem.cpp) +add_executable(weee main.cpp core/mem.cpp core/loaders/elf.cpp + core/loaders/dol.cpp) target_link_libraries(weee PUBLIC capstone) target_include_directories(weee PUBLIC core) \ No newline at end of file diff --git a/README.md b/README.md index 2904ae4..624978a 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # weee - [x] ELF -- [ ] DOL +- [x] DOL - [ ] panda.dol - [ ] libogc simple examples \ No newline at end of file diff --git a/core/broadway.hpp b/core/broadway.hpp new file mode 100644 index 0000000..dcdc05a --- /dev/null +++ b/core/broadway.hpp @@ -0,0 +1,7 @@ +#pragma once + +namespace weee::core { +struct broadway { + +}; +} // namespace weee::core diff --git a/core/loaders/dol.cpp b/core/loaders/dol.cpp new file mode 100644 index 0000000..7bfc34d --- /dev/null +++ b/core/loaders/dol.cpp @@ -0,0 +1,63 @@ +#include +#include +#include +#include +#include +#include + +namespace weee::core { +bool load_dol(const std::string &path, mem &mem) { + auto bin = ircolib::read_file_binary(path); + if (bin.size() <= 0) + return false; + + struct header { + struct section { + ircolib::u32 offset, addr, size; + }; + std::array text; + std::array data; + ircolib::u32 bss_address, bss_size, entry_point; + } hdr; + + for (size_t bin_index = 0; bin_index < 0xD8; bin_index += 4) { + if (ircolib::is_inside_range_ext(bin_index, 0, 0x1c)) // text file offsets + hdr.text[bin_index / 4].offset = std::byteswap(ircolib::read_access(bin, bin_index)); + + if (ircolib::is_inside_range_ext(bin_index, 0x1c, 0x48)) // data file offsets + hdr.data[(bin_index - 0x1c) / 4].offset = std::byteswap(ircolib::read_access(bin, bin_index)); + + if (ircolib::is_inside_range_ext(bin_index, 0x48, 0x64)) // text loading addresses + hdr.text[(bin_index - 0x48) / 4].addr = std::byteswap(ircolib::read_access(bin, bin_index)); + + if (ircolib::is_inside_range_ext(bin_index, 0x64, 0x90)) // data loading addresses + hdr.data[(bin_index - 0x64) / 4].addr = std::byteswap(ircolib::read_access(bin, bin_index)); + + if (ircolib::is_inside_range_ext(bin_index, 0x90, 0xac)) // text sizes + hdr.text[(bin_index - 0x90) / 4].size = std::byteswap(ircolib::read_access(bin, bin_index)); + + if (ircolib::is_inside_range_ext(bin_index, 0xac, 0xd8)) // data sizes + hdr.data[(bin_index - 0xac) / 4].size = std::byteswap(ircolib::read_access(bin, bin_index)); + } + + hdr.bss_address = std::byteswap(ircolib::read_access(bin, 0xD8)); + hdr.bss_size = std::byteswap(ircolib::read_access(bin, 0xDC)); + mem.set(0, hdr.bss_size, hdr.bss_address & 0x0FFFFFFF); + + hdr.entry_point = std::byteswap(ircolib::read_access(bin, 0xE0)); + + for (const auto §ion : hdr.text) { + if (section.offset == 0) + continue; + mem.copy(&bin[section.offset], section.size, section.addr & 0x0FFFFFFF); + } + + for (const auto §ion : hdr.data) { + if (section.offset == 0) + continue; + mem.copy(&bin[section.offset], section.size, section.addr & 0x0FFFFFFF); + } + + return true; +} +} // namespace weee::core diff --git a/core/loaders/dol.hpp b/core/loaders/dol.hpp new file mode 100644 index 0000000..80048b0 --- /dev/null +++ b/core/loaders/dol.hpp @@ -0,0 +1,9 @@ +#pragma once +#include +#include + +namespace weee::core { +struct mem; + +bool load_dol(const std::string &, mem &); +} // namespace weee::core diff --git a/core/loaders/elf.cpp b/core/loaders/elf.cpp new file mode 100644 index 0000000..3ed81c8 --- /dev/null +++ b/core/loaders/elf.cpp @@ -0,0 +1,48 @@ +#include +#include +#include +#include + +namespace weee::core { +bool load_elf(const std::string &path, mem &mem) { + ELFIO::elfio reader; + if (!reader.load(path)) + return false; + + size_t sanity_bss_check_count = 0; + + for (const auto &segment : reader.segments) { + const auto segment_type = segment->get_type(); + if (segment_type != ELFIO::PT_LOAD && segment_type != ELFIO::PT_TLS && segment_type != ELFIO::PT_NOTE) + continue; + + if (segment->get_memory_size() == 0) + continue; + + const bool exc = segment->get_flags() & ELFIO::PF_X; + const bool rd = segment->get_flags() & ELFIO::PF_R; + const bool wr = segment->get_flags() & ELFIO::PF_W; + + std::println("Segment {} {}{}{} @ 0x{:08X} -> 0x{:08X}", segment->get_index(), rd ? 'R' : '_', wr ? 'W' : '_', + exc ? 'X' : '_', segment->get_virtual_address(), + segment->get_virtual_address() + segment->get_memory_size() - 1); + + if (segment->get_file_size() == 0) { + sanity_bss_check_count++; + if (sanity_bss_check_count > 1) { + std::println("weee does not support multiple .bss segments"); + return -2; + } + + // .bss we zero out + mem.set(0, segment->get_memory_size(), segment->get_virtual_address() & 0x0FFFFFFF); + continue; + } + + mem.copy((const ircolib::u8 *)segment->get_data(), segment->get_file_size(), + segment->get_virtual_address() & 0x0FFFFFFF); + } + + return true; +} +} // namespace weee::core diff --git a/core/loaders/elf.hpp b/core/loaders/elf.hpp new file mode 100644 index 0000000..7ebb71f --- /dev/null +++ b/core/loaders/elf.hpp @@ -0,0 +1,9 @@ +#pragma once +#include +#include + +namespace weee::core { +struct mem; + +bool load_elf(const std::string &, mem &); +} // namespace weee::core diff --git a/external/ircolib/mem_access.hpp b/external/ircolib/mem_access.hpp index c4e0822..51f1c11 100644 --- a/external/ircolib/mem_access.hpp +++ b/external/ircolib/mem_access.hpp @@ -30,6 +30,11 @@ static inline constexpr bool is_inside_range(const std::integral auto &addr, con return addr >= start && addr <= end; } +static inline constexpr bool is_inside_range_ext(const std::integral auto &addr, const std::integral auto &start, + const std::integral auto &end) { + return addr >= start && addr < end; +} + template static constexpr inline T read_access(const u8 *data, const u32 index); template diff --git a/main.cpp b/main.cpp index 12907d1..c6e4e8f 100644 --- a/main.cpp +++ b/main.cpp @@ -1,53 +1,32 @@ -#include -#include #include #include -#include "mem.hpp" +#include +#include +#include +#include int main(int argc, char **argv) { - ELFIO::elfio reader; - weee::core::mem mem; cflags::cflags flags; - flags.add_string_callback('\0', "elf", [&](const std::string &v) { reader.load(v); }, "ELF binary to load"); + flags.add_string_callback( + '\0', "elf", + [&](const std::string &v) { + if (!weee::core::load_elf(v, mem)) + ircolib::panic("Could not load '{}'", v); + }, + "ELF binary to load"); + + flags.add_string_callback( + '\0', "dol", + [&](const std::string &v) { + if (!weee::core::load_dol(v, mem)) + ircolib::panic("Could not load '{}'", v); + }, + "DOL binary to load"); if (!flags.parse(argc, argv)) return -1; - size_t sanity_bss_check_count = 0; - - for (const auto &segment : reader.segments) { - const auto segment_type = segment->get_type(); - if (segment_type != ELFIO::PT_LOAD && segment_type != ELFIO::PT_TLS && segment_type != ELFIO::PT_NOTE) - continue; - - if (segment->get_memory_size() == 0) - continue; - - const bool exc = segment->get_flags() & ELFIO::PF_X; - const bool rd = segment->get_flags() & ELFIO::PF_R; - const bool wr = segment->get_flags() & ELFIO::PF_W; - - std::println("Segment {} {}{}{} @ 0x{:08X} -> 0x{:08X}", segment->get_index(), rd ? 'R' : '_', wr ? 'W' : '_', - exc ? 'X' : '_', segment->get_virtual_address(), - segment->get_virtual_address() + segment->get_memory_size() - 1); - - if (segment->get_file_size() == 0) { - sanity_bss_check_count++; - if (sanity_bss_check_count > 1) { - std::println("weee does not support multiple .bss segments"); - return -2; - } - - // .bss we zero out - mem.set(0, segment->get_memory_size(), segment->get_virtual_address() & 0x0FFFFFFF); - continue; - } - - mem.copy((const ircolib::u8 *)segment->get_data(), segment->get_file_size(), - segment->get_virtual_address() & 0x0FFFFFFF); - } - return 0; }