diff --git a/source/ElfUtils.cpp b/source/ElfUtils.cpp index 1dfed91..5cc5c41 100644 --- a/source/ElfUtils.cpp +++ b/source/ElfUtils.cpp @@ -8,16 +8,16 @@ #include "ElfUtils.h" #include "elfio/elfio.hpp" -bool ElfUtils::doRelocation(std::vector> &relocData, relocation_trampoline_entry_t *tramp_data, uint32_t tramp_length) { +bool ElfUtils::doRelocation(const std::vector> &relocData, relocation_trampoline_entry_t *tramp_data, uint32_t tramp_length) { for (auto const &curReloc : relocData) { std::string functionName = curReloc->getName(); - std::string rplName = curReloc->getImportRPLInformation()->getName(); + std::string rplName = curReloc->getImportRPLInformation()->getRPLName(); int32_t isData = curReloc->getImportRPLInformation()->isData(); OSDynLoad_Module rplHandle = nullptr; auto err = OSDynLoad_IsModuleLoaded(rplName.c_str(), &rplHandle); - if (err != OS_DYNLOAD_OK || rplHandle == 0) { + if (err != OS_DYNLOAD_OK || rplHandle == nullptr) { // only acquire if not already loaded. OSDynLoad_Acquire(rplName.c_str(), &rplHandle); } @@ -41,15 +41,15 @@ bool ElfUtils::doRelocation(std::vector> &relocD } // See https://github.com/decaf-emu/decaf-emu/blob/43366a34e7b55ab9d19b2444aeb0ccd46ac77dea/src/libdecaf/src/cafe/loader/cafe_loader_reloc.cpp#L144 -bool ElfUtils::elfLinkOne(char type, size_t offset, int32_t addend, uint32_t destination, uint32_t symbol_addr, relocation_trampoline_entry_t *trampolin_data, uint32_t trampolin_data_length, +bool ElfUtils::elfLinkOne(char type, size_t offset, int32_t addend, uint32_t destination, uint32_t symbol_addr, relocation_trampoline_entry_t *trampoline_data, uint32_t trampoline_data_length, RelocationType reloc_type) { if (type == R_PPC_NONE) { return true; } + auto target = destination + offset; auto value = symbol_addr + addend; - auto relValue = value - static_cast(target); switch (type) { @@ -68,7 +68,7 @@ bool ElfUtils::elfLinkOne(char type, size_t offset, int32_t addend, uint32_t des *((uint16_t *) (target)) = static_cast((value + 0x8000) >> 16); break; case R_PPC_DTPMOD32: - DEBUG_FUNCTION_LINE_ERR("################IMPLEMENT ME\n"); + DEBUG_FUNCTION_LINE_ERR("################IMPLEMENT ME"); //*((int32_t *)(target)) = tlsModuleIndex; break; case R_PPC_DTPREL32: @@ -111,33 +111,40 @@ bool ElfUtils::elfLinkOne(char type, size_t offset, int32_t addend, uint32_t des // } auto distance = static_cast(value) - static_cast(target); if (distance > 0x1FFFFFC || distance < -0x1FFFFFC) { - if (trampolin_data == nullptr) { - DEBUG_FUNCTION_LINE_ERR("***24-bit relative branch cannot hit target. Trampoline isn't provided\n"); - DEBUG_FUNCTION_LINE_ERR("***value %08X - target %08X = distance %08X\n", value, target, distance); + if (trampoline_data == nullptr) { + DEBUG_FUNCTION_LINE_ERR("***24-bit relative branch cannot hit target. Trampoline isn't provided"); + DEBUG_FUNCTION_LINE_ERR("***value %08X - target %08X = distance %08X", value, target, distance); return false; } else { relocation_trampoline_entry_t *freeSlot = nullptr; - for (uint32_t i = 0; i < trampolin_data_length; i++) { + for (uint32_t i = 0; i < trampoline_data_length; i++) { // We want to override "old" relocations of imports // Pending relocations have the status RELOC_TRAMP_IMPORT_IN_PROGRESS. // When all relocations are done successfully, they will be turned into RELOC_TRAMP_IMPORT_DONE // so they can be overridden/updated/reused on the next application launch. // // Relocations that won't change will have the status RELOC_TRAMP_FIXED and are set to free when the module is unloaded. - if (trampolin_data[i].status == RELOC_TRAMP_FREE || - trampolin_data[i].status == RELOC_TRAMP_IMPORT_DONE) { - freeSlot = &(trampolin_data[i]); + if (trampoline_data[i].status == RELOC_TRAMP_FREE || + trampoline_data[i].status == RELOC_TRAMP_IMPORT_DONE) { + freeSlot = &(trampoline_data[i]); break; } } if (freeSlot == nullptr) { - DEBUG_FUNCTION_LINE_ERR("***24-bit relative branch cannot hit target. Trampoline data list is full\n"); - DEBUG_FUNCTION_LINE_ERR("***value %08X - target %08X = distance %08X\n", value, target, (target - (uint32_t) & (freeSlot->trampoline[0]))); + DEBUG_FUNCTION_LINE_ERR("***24-bit relative branch cannot hit target. Trampoline data list is full"); + DEBUG_FUNCTION_LINE_ERR("***value %08X - target %08X = distance %08X", value, target, target - (uint32_t) & (freeSlot->trampoline[0])); return false; } - if (target - (uint32_t) & (freeSlot->trampoline[0]) > 0x1FFFFFC) { + auto symbolValue = (uint32_t) & (freeSlot->trampoline[0]); + auto newValue = symbolValue + addend; + auto newDistance = static_cast(newValue) - static_cast(target); + if (newDistance > 0x1FFFFFC || newDistance < -0x1FFFFFC) { DEBUG_FUNCTION_LINE_ERR("**Cannot link 24-bit jump (too far to tramp buffer)."); - DEBUG_FUNCTION_LINE_ERR("***value %08X - target %08X = distance %08X\n", value, target, (target - (uint32_t) & (freeSlot->trampoline[0]))); + if (newDistance < 0) { + DEBUG_FUNCTION_LINE_ERR("***value %08X - target %08X = distance -%08X", newValue, target, abs(newDistance)); + } else { + DEBUG_FUNCTION_LINE_ERR("***value %08X - target %08X = distance %08X", newValue, target, newDistance); + } return false; } @@ -154,9 +161,7 @@ bool ElfUtils::elfLinkOne(char type, size_t offset, int32_t addend, uint32_t des // Relocations for the imports may be overridden freeSlot->status = RELOC_TRAMP_IMPORT_DONE; } - auto symbolValue = (uint32_t) & (freeSlot->trampoline[0]); - value = symbolValue + addend; - distance = static_cast(value) - static_cast(target); + distance = newDistance; } } @@ -182,5 +187,7 @@ bool ElfUtils::elfLinkOne(char type, size_t offset, int32_t addend, uint32_t des DEBUG_FUNCTION_LINE_ERR("***ERROR: Unsupported Relocation_Add Type (%08X):", type); return false; } + ICInvalidateRange(reinterpret_cast(target), 4); + DCFlushRange(reinterpret_cast(target), 4); return true; -} +} \ No newline at end of file diff --git a/source/ElfUtils.h b/source/ElfUtils.h index 1b616d2..c544f28 100644 --- a/source/ElfUtils.h +++ b/source/ElfUtils.h @@ -50,5 +50,5 @@ public: RelocationType reloc_type); - static bool doRelocation(std::vector> &relocData, relocation_trampoline_entry_t *tramp_data, uint32_t tramp_length); + static bool doRelocation(const std::vector> &relocData, relocation_trampoline_entry_t *tramp_data, uint32_t tramp_length); }; diff --git a/source/main.cpp b/source/main.cpp index 8e4ba9a..3441e09 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -184,13 +184,13 @@ int main(int argc, char **argv) { DYN_LINK_TRAMPOLIN_LIST_LENGTH); if (!moduleData) { DEBUG_FUNCTION_LINE_ERR("Failed to load %s", setupModules.GetFilepath(i)); + OSFatal("EnvironmentLoader: Failed to load module"); continue; } DEBUG_FUNCTION_LINE("Loaded module data"); - auto relocData = moduleData.value()->getRelocationDataList(); - if (!ElfUtils::doRelocation(relocData, gModuleData->trampolines, DYN_LINK_TRAMPOLIN_LIST_LENGTH)) { + if (!ElfUtils::doRelocation(moduleData.value()->getRelocationDataList(), gModuleData->trampolines, DYN_LINK_TRAMPOLIN_LIST_LENGTH)) { DEBUG_FUNCTION_LINE_ERR("Relocations failed"); - OSFatal("Relocations failed"); + OSFatal("EnvironmentLoader: Relocations failed"); } else { DEBUG_FUNCTION_LINE("Relocation done"); } diff --git a/source/module/ImportRPLInformation.h b/source/module/ImportRPLInformation.h index 4e3c42f..1188d76 100644 --- a/source/module/ImportRPLInformation.h +++ b/source/module/ImportRPLInformation.h @@ -1,23 +1,24 @@ /**************************************************************************** - * Copyright (C) 2018 Maschell - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - ****************************************************************************/ +* Copyright (C) 2018 Maschell +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +****************************************************************************/ #pragma once #include "utils/logger.h" +#include #include #include #include @@ -26,44 +27,27 @@ class ImportRPLInformation { public: - explicit ImportRPLInformation(std::string name, bool isData = false) { - this->name = std::move(name); - this->_isData = isData; + explicit ImportRPLInformation(std::string rawSectionName) { + this->name = std::move(rawSectionName); } ~ImportRPLInformation() = default; - static std::optional> createImportRPLInformation(std::string rawSectionName) { - std::string fimport = ".fimport_"; - std::string dimport = ".dimport_"; - - bool data = false; - - std::string rplName; - - if (rawSectionName.size() < fimport.size()) { - return std::nullopt; - } else if (std::equal(fimport.begin(), fimport.end(), rawSectionName.begin())) { - rplName = rawSectionName.substr(fimport.size()); - } else if (std::equal(dimport.begin(), dimport.end(), rawSectionName.begin())) { - rplName = rawSectionName.substr(dimport.size()); - data = true; - } else { - DEBUG_FUNCTION_LINE("invalid section name\n"); - return std::nullopt; - } - return std::make_shared(rplName, data); - } - - [[nodiscard]] std::string getName() const { + [[nodiscard]] const std::string &getName() const { return name; } + [[nodiscard]] const char *getRPLName() const { + if (name.max_size() < strlen("._import_") + 1) { + OSFatal("Invalid RPLName, is too short to be valid"); + } + return name.c_str() + strlen("._import_"); + } + [[nodiscard]] bool isData() const { - return _isData; + return name.starts_with(".dimport_"); } private: std::string name; - bool _isData = false; }; diff --git a/source/module/ModuleData.h b/source/module/ModuleData.h index 82ad360..335b0ff 100644 --- a/source/module/ModuleData.h +++ b/source/module/ModuleData.h @@ -29,15 +29,15 @@ public: ~ModuleData() = default; - void setEntrypoint(uint32_t addr) { - this->entrypoint = addr; + void setEntrypoint(uint32_t address) { + this->entrypoint = address; } - void addRelocationData(const std::shared_ptr &relocation_data) { - relocation_data_list.push_back(relocation_data); + void addRelocationData(std::unique_ptr relocation_data) { + relocation_data_list.push_back(std::move(relocation_data)); } - [[nodiscard]] const std::vector> &getRelocationDataList() const { + [[nodiscard]] const std::vector> &getRelocationDataList() const { return relocation_data_list; } @@ -45,12 +45,12 @@ public: return entrypoint; } - void setStartAddress(uint32_t addr) { - this->startAddress = addr; + void setStartAddress(uint32_t address) { + this->startAddress = address; } - void setEndAddress(uint32_t _endAddress) { - this->endAddress = _endAddress; + void setEndAddress(uint32_t address) { + this->endAddress = address; } [[nodiscard]] uint32_t getStartAddress() const { @@ -62,7 +62,7 @@ public: } private: - std::vector> relocation_data_list; + std::vector> relocation_data_list; uint32_t entrypoint = 0; uint32_t startAddress = 0; uint32_t endAddress = 0; diff --git a/source/module/ModuleDataFactory.cpp b/source/module/ModuleDataFactory.cpp index a895c90..1275536 100644 --- a/source/module/ModuleDataFactory.cpp +++ b/source/module/ModuleDataFactory.cpp @@ -18,17 +18,21 @@ #include "ModuleDataFactory.h" #include "../utils/FileUtils.h" #include "ElfUtils.h" +#include "utils/OnLeavingScope.h" +#include "utils/utils.h" #include #include #include #include -using namespace ELFIO; - -std::optional> +std::optional> ModuleDataFactory::load(const std::string &path, uint32_t destination_address_end, uint32_t maximum_size, relocation_trampoline_entry_t *trampoline_data, uint32_t trampoline_data_length) { - elfio reader; - std::shared_ptr moduleData = std::make_shared(); + ELFIO::elfio reader; + auto moduleData = make_unique_nothrow(); + if (!moduleData) { + DEBUG_FUNCTION_LINE_ERR("Failed to allocate ModuleData"); + return {}; + } uint8_t *buffer = nullptr; uint32_t fsize = 0; @@ -44,12 +48,19 @@ ModuleDataFactory::load(const std::string &path, uint32_t destination_address_en return {}; } - uint32_t sec_num = reader.sections.size(); - auto **destinations = (uint8_t **) malloc(sizeof(uint8_t *) * sec_num); + auto cleanupBuffer = onLeavingScope([buffer]() { free(buffer); }); + + uint32_t sec_num = reader.sections.size(); + + auto destinations = make_unique_nothrow(sec_num); + if (!destinations) { + DEBUG_FUNCTION_LINE_ERR("Failed alloc memory for destinations array"); + return {}; + } uint32_t sizeOfModule = 0; for (uint32_t i = 0; i < sec_num; ++i) { - section *psec = reader.sections[i]; + ELFIO::section *psec = reader.sections[i]; if (psec->get_type() == 0x80000002) { continue; } @@ -61,8 +72,6 @@ ModuleDataFactory::load(const std::string &path, uint32_t destination_address_en if (sizeOfModule > maximum_size) { DEBUG_FUNCTION_LINE_ERR("Module is too big."); - free(destinations); - free(buffer); return {}; } @@ -78,8 +87,8 @@ ModuleDataFactory::load(const std::string &path, uint32_t destination_address_en uint32_t endAddress = 0; for (uint32_t i = 0; i < sec_num; ++i) { - section *psec = reader.sections[i]; - if (psec->get_type() == 0x80000002) { + ELFIO::section *psec = reader.sections[i]; + if (psec->get_type() == 0x80000002 || psec->get_name() == ".wut_load_bounds") { continue; } @@ -89,8 +98,6 @@ ModuleDataFactory::load(const std::string &path, uint32_t destination_address_en totalSize += sectionSize; if (totalSize > maximum_size) { DEBUG_FUNCTION_LINE_ERR("Couldn't load setup module because it's too big."); - free(destinations); - free(buffer); return {}; } @@ -108,17 +115,20 @@ ModuleDataFactory::load(const std::string &path, uint32_t destination_address_en destination -= 0x10000000; destinations[psec->get_index()] -= 0x10000000; } else if (address >= 0xC0000000) { - destination -= 0xC0000000; - destinations[psec->get_index()] -= 0xC0000000; + DEBUG_FUNCTION_LINE_ERR("Loading section from 0xC0000000 is NOT supported"); + return std::nullopt; } else { DEBUG_FUNCTION_LINE_ERR("Unhandled case"); - free(destinations); - free(buffer); return std::nullopt; } const char *p = reader.sections[i]->get_data(); + if (destination + sectionSize > (uint32_t) destination_address_end) { + DEBUG_FUNCTION_LINE_ERR("Tried to overflow buffer. %08X > %08X", destination + sectionSize, destination_address_end); + OSFatal("EnvironmentLoader: Tried to overflow buffer"); + } + if (psec->get_type() == SHT_NOBITS) { DEBUG_FUNCTION_LINE("memset section %s %08X to 0 (%d bytes)", psec->get_name().c_str(), destination, sectionSize); memset((void *) destination, 0, sectionSize); @@ -143,29 +153,20 @@ ModuleDataFactory::load(const std::string &path, uint32_t destination_address_en } for (uint32_t i = 0; i < sec_num; ++i) { - section *psec = reader.sections[i]; + ELFIO::section *psec = reader.sections[i]; if ((psec->get_type() == SHT_PROGBITS || psec->get_type() == SHT_NOBITS) && (psec->get_flags() & SHF_ALLOC)) { DEBUG_FUNCTION_LINE("Linking (%d)... %s", i, psec->get_name().c_str()); if (!linkSection(reader, psec->get_index(), (uint32_t) destinations[psec->get_index()], offset_text, offset_data, trampoline_data, trampoline_data_length)) { DEBUG_FUNCTION_LINE_ERR("elfLink failed"); - free(destinations); - free(buffer); return std::nullopt; } } } - auto relocationData = getImportRelocationData(reader, destinations); - - for (auto const &reloc : relocationData) { - moduleData->addRelocationData(reloc); - } + getImportRelocationData(moduleData, reader, destinations.get()); DCFlushRange((void *) baseOffset, totalSize); ICInvalidateRange((void *) baseOffset, totalSize); - free(destinations); - free(buffer); - moduleData->setStartAddress(startAddress); moduleData->setEndAddress(endAddress); moduleData->setEntrypoint(entrypoint); @@ -174,79 +175,91 @@ ModuleDataFactory::load(const std::string &path, uint32_t destination_address_en return moduleData; } -std::vector> ModuleDataFactory::getImportRelocationData(elfio &reader, uint8_t **destinations) { - std::vector> result; - std::map infoMap; +bool ModuleDataFactory::getImportRelocationData(std::unique_ptr &moduleData, ELFIO::elfio &reader, uint8_t **destinations) { + std::map> infoMap; uint32_t sec_num = reader.sections.size(); for (uint32_t i = 0; i < sec_num; ++i) { - section *psec = reader.sections[i]; + auto *psec = reader.sections[i]; if (psec->get_type() == 0x80000002) { - infoMap[i] = psec->get_name(); + auto info = make_shared_nothrow(psec->get_name()); + if (!info) { + DEBUG_FUNCTION_LINE_ERR("Failed too allocate ImportRPLInformation"); + return false; + } + infoMap[i] = std::move(info); } } for (uint32_t i = 0; i < sec_num; ++i) { - section *psec = reader.sections[i]; + ELFIO::section *psec = reader.sections[i]; if (psec->get_type() == SHT_RELA || psec->get_type() == SHT_REL) { - DEBUG_FUNCTION_LINE_VERBOSE("Found relocation section %s", psec->get_name().c_str()); - relocation_section_accessor rel(reader, psec); + ELFIO::relocation_section_accessor rel(reader, psec); for (uint32_t j = 0; j < (uint32_t) rel.get_entries_num(); ++j) { - Elf64_Addr offset; - Elf_Word type; - Elf_Sxword addend; + ELFIO::Elf64_Addr offset; + ELFIO::Elf_Word type; + ELFIO::Elf_Sxword addend; std::string sym_name; - Elf64_Addr sym_value; - Elf_Half sym_section_index; + ELFIO::Elf64_Addr sym_value; + ELFIO::Elf_Half sym_section_index; if (!rel.get_entry(j, offset, sym_value, sym_name, type, addend, sym_section_index)) { DEBUG_FUNCTION_LINE_ERR("Failed to get relocation"); + OSFatal("Failed to get relocation"); break; } - // uint32_t adjusted_sym_value = (uint32_t) sym_value; - if (infoMap.count(sym_section_index) == 0) { + auto adjusted_sym_value = (uint32_t) sym_value; + if (adjusted_sym_value < 0xC0000000) { continue; } - auto rplInfo = ImportRPLInformation::createImportRPLInformation(infoMap[sym_section_index]); - if (!rplInfo) { - DEBUG_FUNCTION_LINE_ERR("Failed to create import information"); - break; - } uint32_t section_index = psec->get_info(); + if (!infoMap.contains(sym_section_index)) { + DEBUG_FUNCTION_LINE_ERR("Relocation is referencing a unknown section. %d destination: %08X sym_name %s", section_index, destinations[section_index], sym_name.c_str()); + OSFatal("Relocation is referencing a unknown section."); + } - // When these relocations are performed, we don't need the 0xC0000000 offset anymore. - auto relocationData = std::make_shared(type, offset - 0x02000000, addend, (void *) (destinations[section_index] + 0x02000000), sym_name, rplInfo.value()); - //relocationData->printInformation(); - result.push_back(relocationData); + auto relocationData = make_unique_nothrow(type, + offset - 0x02000000, + addend, + (void *) (destinations[section_index] + 0x02000000), + sym_name, + infoMap[sym_section_index]); + + if (!relocationData) { + DEBUG_FUNCTION_LINE_ERR("Failed to alloc relocation data"); + return false; + } + + moduleData->addRelocationData(std::move(relocationData)); } } } - return result; + return true; } -bool ModuleDataFactory::linkSection(elfio &reader, uint32_t section_index, uint32_t destination, uint32_t base_text, uint32_t base_data, relocation_trampoline_entry_t *trampoline_data, +bool ModuleDataFactory::linkSection(ELFIO::elfio &reader, uint32_t section_index, uint32_t destination, uint32_t base_text, uint32_t base_data, relocation_trampoline_entry_t *trampoline_data, uint32_t trampoline_data_length) { uint32_t sec_num = reader.sections.size(); for (uint32_t i = 0; i < sec_num; ++i) { - section *psec = reader.sections[i]; + ELFIO::section *psec = reader.sections[i]; if (psec->get_info() == section_index) { DEBUG_FUNCTION_LINE_VERBOSE("Found relocation section %s", psec->get_name().c_str()); - relocation_section_accessor rel(reader, psec); + ELFIO::relocation_section_accessor rel(reader, psec); for (uint32_t j = 0; j < (uint32_t) rel.get_entries_num(); ++j) { - Elf64_Addr offset; - Elf_Word type; - Elf_Sxword addend; + ELFIO::Elf64_Addr offset; + ELFIO::Elf_Word type; + ELFIO::Elf_Sxword addend; std::string sym_name; - Elf64_Addr sym_value; - Elf_Half sym_section_index; + ELFIO::Elf64_Addr sym_value; + ELFIO::Elf_Half sym_section_index; if (!rel.get_entry(j, offset, sym_value, sym_name, type, addend, sym_section_index)) { DEBUG_FUNCTION_LINE_ERR("Failed to get relocation"); - break; + return false; } auto adjusted_sym_value = (uint32_t) sym_value; @@ -272,13 +285,11 @@ bool ModuleDataFactory::linkSection(elfio &reader, uint32_t section_index, uint3 DEBUG_FUNCTION_LINE_ERR("NOT IMPLEMENTED: %04X", sym_section_index); return false; } - if (!ElfUtils::elfLinkOne(type, offset, addend, destination, adjusted_sym_value, trampoline_data, trampoline_data_length, RELOC_TYPE_FIXED)) { DEBUG_FUNCTION_LINE_ERR("Link failed"); return false; } } - DEBUG_FUNCTION_LINE_VERBOSE("done"); } } return true; diff --git a/source/module/ModuleDataFactory.h b/source/module/ModuleDataFactory.h index f636c57..a37bcc4 100644 --- a/source/module/ModuleDataFactory.h +++ b/source/module/ModuleDataFactory.h @@ -26,11 +26,11 @@ class ModuleDataFactory { public: - static std::optional> + static std::optional> load(const std::string &path, uint32_t destination_address_end, uint32_t maximum_size, relocation_trampoline_entry_t *trampoline_data, uint32_t trampoline_data_length); static bool linkSection(ELFIO::elfio &reader, uint32_t section_index, uint32_t destination, uint32_t base_text, uint32_t base_data, relocation_trampoline_entry_t *trampoline_data, uint32_t trampoline_data_length); - static std::vector> getImportRelocationData(ELFIO::elfio &reader, uint8_t **destinations); + static bool getImportRelocationData(std::unique_ptr &moduleData, ELFIO::elfio &reader, uint8_t **destinations); }; diff --git a/source/utils/OnLeavingScope.h b/source/utils/OnLeavingScope.h new file mode 100644 index 0000000..e92e6ca --- /dev/null +++ b/source/utils/OnLeavingScope.h @@ -0,0 +1,113 @@ +/** +* The contents of this file are based on the article posted at the +* following location: +* +* http://crascit.com/2015/06/03/on-leaving-scope-part-2/ +* +* The material in that article has some commonality with the code made +* available as part of Facebook's folly library at: +* +* https://github.com/facebook/folly/blob/master/folly/ScopeGuard.h +* +* Furthermore, similar material is currently part of a draft proposal +* to the C++ standards committee, referencing the same work by Andrei +* Alexandresu that led to the folly implementation. The draft proposal +* can be found at: +* +* http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4189.pdf +* +* With the above in mind, the content below is made available under +* the same license terms as folly to minimize any legal concerns. +* Should there be ambiguity over copyright ownership between Facebook +* and myself for any material included in this file, it should be +* interpreted that Facebook is the copyright owner for the ambiguous +* section of code concerned. +* +* Craig Scott +* 3rd June 2015 +* +* ---------------------------------------------------------------------- +* +* Copyright 2015 Craig Scott +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#ifndef CRASCIT_ONLEAVINGSCOPE_H +#define CRASCIT_ONLEAVINGSCOPE_H + +#include +#include + + +/** +* This class is intended to be used only to create a local object on the +* stack. It accepts a function object in its constructor and will invoke +* that function object in its destructor. The class provides a move +* constructor so it can be used with the onLeavingScope factory function, +* but it cannot be copied. +* +* Do no use this function directly, use the onLeavingScope() factory +* function instead. +*/ +template +class OnLeavingScope { +public: + // Prevent copying + OnLeavingScope(const OnLeavingScope &) = delete; + OnLeavingScope &operator=(const OnLeavingScope &) = delete; + + // Allow moving + OnLeavingScope(OnLeavingScope &&other) : m_func(std::move(other.m_func)), + m_owner(other.m_owner) { + other.m_owner = false; + } + + OnLeavingScope(const Func &f) : m_func(f), + m_owner(true) { + } + OnLeavingScope(Func &&f) : m_func(std::move(f)), + m_owner(true) { + } + ~OnLeavingScope() { + if (m_owner) + m_func(); + } + +private: + Func m_func; + bool m_owner; +}; + + +/** +* Factory function for creating an OnLeavingScope object. It is intended +* to be used like so: +* +* auto cleanup = onLeavingScope(...); +* +* where the ... could be a lambda function, function object or pointer to +* a free function to be invoked when the cleanup object goes out of scope. +* The function object must take no function arguments, but can return any +* type (the return value is ignored). +* +* The \a Func template parameter would rarely, if ever, be manually +* specified. Normally, it would be deduced automatically by the compiler +* from the object passed as the function argument. +*/ +template +OnLeavingScope::type> onLeavingScope(Func &&f) { + return OnLeavingScope::type>(std::forward(f)); +} + +#endif // CRASCIT_ONLEAVINGSCOPE_H diff --git a/source/utils/utils.h b/source/utils/utils.h new file mode 100644 index 0000000..a71f4f9 --- /dev/null +++ b/source/utils/utils.h @@ -0,0 +1,17 @@ +#pragma once +#include + +template +std::unique_ptr make_unique_nothrow(Args &&...args) noexcept(noexcept(T(std::forward(args)...))) { + return std::unique_ptr(new (std::nothrow) T(std::forward(args)...)); +} + +template +inline typename std::_MakeUniq::__array make_unique_nothrow(size_t num) noexcept { + return std::unique_ptr(new (std::nothrow) std::remove_extent_t[num]()); +} + +template +std::shared_ptr make_shared_nothrow(Args &&...args) noexcept(noexcept(T(std::forward(args)...))) { + return std::shared_ptr(new (std::nothrow) T(std::forward(args)...)); +}