diff --git a/Source/Tools/CommonTools/CMakeLists.txt b/Source/Tools/CommonTools/CMakeLists.txt index 85abded1dc..451f0a5b45 100644 --- a/Source/Tools/CommonTools/CMakeLists.txt +++ b/Source/Tools/CommonTools/CMakeLists.txt @@ -6,7 +6,6 @@ set(SRCS if (NOT MINGW_BUILD) list(APPEND SRCS Linux/Utils/ELFContainer.cpp - Linux/Utils/ELFSymbolDatabase.cpp ) endif() diff --git a/Source/Tools/CommonTools/Linux/Utils/ELFSymbolDatabase.cpp b/Source/Tools/CommonTools/Linux/Utils/ELFSymbolDatabase.cpp deleted file mode 100644 index 5d8d8dcdb0..0000000000 --- a/Source/Tools/CommonTools/Linux/Utils/ELFSymbolDatabase.cpp +++ /dev/null @@ -1,361 +0,0 @@ -// SPDX-License-Identifier: MIT -/* -$info$ -tags: glue|elf-parsing -desc: Part of our now defunct ld-linux replacement, keeps tracks of all symbols, loads elfs, handles relocations. Small parts of this are -used. $end_info$ -*/ - -#include "Linux/Utils/ELFSymbolDatabase.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -namespace ELFLoader { -void ELFSymbolDatabase::FillLibrarySearchPaths() { - // XXX: Open /etc/ld.so.conf and parse the paths in that file - // For now I'm just filling with regular search paths - if (File->GetMode() == ELFContainer::MODE_64BIT) { - LibrarySearchPaths.emplace_back("/usr/local/lib/x86_64-linux-gnu"); - LibrarySearchPaths.emplace_back("/lib/x86_64-linux-gnu"); - LibrarySearchPaths.emplace_back("/usr/lib/x86_64-linux-gnu"); - } else { - LibrarySearchPaths.emplace_back("/usr/local/lib/i386-linux-gnu"); - LibrarySearchPaths.emplace_back("/lib/i386-linux-gnu"); - LibrarySearchPaths.emplace_back("/usr/lib/i386-linux-gnu"); - } - - // At least we can scan LD_LIBRARY_PATH - auto EnvVar = getenv("LD_LIBRARY_PATH"); - if (EnvVar) { - fextl::string Env = EnvVar; - fextl::stringstream EnvStream(Env); - fextl::string Token; - while (std::getline(EnvStream, Token, ';')) { - LibrarySearchPaths.emplace_back(Token); - } - } -} - -bool ELFSymbolDatabase::FindLibraryFile(fextl::string* Result, const char* Library) { - for (auto& Path : LibrarySearchPaths) { - const fextl::string TmpPath = fextl::fmt::format("{}/{}", Path, Library); - if (FHU::Filesystem::Exists(TmpPath)) { - *Result = TmpPath; - return true; - } - } - return false; -} - -ELFSymbolDatabase::ELFSymbolDatabase(::ELFLoader::ELFContainer* file) - : File {file} { - FillLibrarySearchPaths(); - - // Don't try to load the file if it was invalid - if (!File->WasLoaded()) { - return; - } - - fextl::vector UnfilledDependencies; - fextl::vector NewLibraries; - - auto FillDependencies = [&UnfilledDependencies, this](ELFInfo* ELF) { - for (auto& Lib : *ELF->Container->GetNecessaryLibs()) { - if (NameToELF.find(Lib) == NameToELF.end()) { - UnfilledDependencies.emplace_back(Lib); - } - } - }; - - auto LoadDependencies = [&UnfilledDependencies, &NewLibraries, this]() { - for (auto& Lib : UnfilledDependencies) { - if (NameToELF.find(Lib) == NameToELF.end()) { - fextl::string LibraryPath; -#if defined(ASSERTIONS_ENABLED) && ASSERTIONS_ENABLED - bool Found = -#endif - FindLibraryFile(&LibraryPath, Lib.c_str()); - LOGMAN_THROW_A_FMT(Found, "Couldn't find library '{}'", Lib); - auto Info = DynamicELFInfo.emplace_back(new ELFInfo {}); - Info->Name = Lib; - Info->Container = new ::ELFLoader::ELFContainer(LibraryPath, {}, true); - NewLibraries.emplace_back(Info); - NameToELF[Lib] = Info; - } - } - }; - - LocalInfo.Container = File; - LocalInfo.Name = "/proc/self/exe"; - NewLibraries.emplace_back(&LocalInfo); - - do { - fextl::vector PreviousLibs; - PreviousLibs.swap(NewLibraries); - for (auto ELF : PreviousLibs) { - FillDependencies(ELF); - LoadDependencies(); - } - } while (!UnfilledDependencies.empty() && !NewLibraries.empty()); - - FillMemoryLayouts(0); - FillInitializationOrder(); - FillSymbols(); - - if (LocalInfo.Container->WasDynamic() && File->GetMode() == ELFContainer::MODE_64BIT) { - ELFBase = FEXCore::Allocator::mmap(nullptr, ELFMemorySize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - FillMemoryLayouts(reinterpret_cast(ELFBase)); - FillInitializationOrder(); - FillSymbols(); - - FixedNoReplace = false; - } -} - -ELFSymbolDatabase::~ELFSymbolDatabase() { - if (ELFBase) { - FEXCore::Allocator::munmap(ELFBase, ELFMemorySize); - ELFBase = nullptr; - } -} - -void ELFSymbolDatabase::FillMemoryLayouts(uint64_t DefinedBase) { - uint64_t ELFBases = DefinedBase; - ELFMemorySize = 0; - if (!DefinedBase) { - if (File->GetMode() == ELFContainer::MODE_64BIT) { - ELFBases = 0x1'0000'0000; - } else { - // 32bit we will just load at the lowest memory address we can - // Which on Linux is at 0x1'0000 - ELFBases = 0x1'0000; - } - } - // We can only relocate the passed in ELF if it is dynamic - // If it is EXEC then it HAS to end up in the base offset it chose - if (LocalInfo.Container->WasDynamic()) { - LocalInfo.CustomLayout = File->GetLayout(); - uint64_t CurrentELFBase = std::get<0>(LocalInfo.CustomLayout); - uint64_t CurrentELFEnd = std::get<1>(LocalInfo.CustomLayout); - uint64_t CurrentELFAlignedSize = FEXCore::AlignUp(std::get<2>(LocalInfo.CustomLayout), 4096); - - CurrentELFBase += ELFBases; - CurrentELFEnd += ELFBases; - - std::get<0>(LocalInfo.CustomLayout) = CurrentELFBase; - std::get<1>(LocalInfo.CustomLayout) = CurrentELFEnd; - std::get<2>(LocalInfo.CustomLayout) = CurrentELFAlignedSize; - LocalInfo.GuestBase = ELFBases; - - ELFBases += CurrentELFAlignedSize; - ELFMemorySize += CurrentELFAlignedSize; - } else { - LocalInfo.CustomLayout = File->GetLayout(); - uint64_t CurrentELFBase = std::get<0>(LocalInfo.CustomLayout); - uint64_t CurrentELFAlignedSize = FEXCore::AlignUp(std::get<2>(LocalInfo.CustomLayout), 4096); - if (CurrentELFBase < 0x10000) { - // We can't allocate memory in the first 16KB, Hopefully no elfs require this. - LOGMAN_MSG_A_FMT("Elf requires memory mapped in the first 16kb"); - } - - std::get<2>(LocalInfo.CustomLayout) = CurrentELFAlignedSize; - LocalInfo.GuestBase = 0; - ELFMemorySize += CurrentELFAlignedSize; - } - - for (size_t i = 0; i < DynamicELFInfo.size(); ++i) { - auto ELF = DynamicELFInfo[i]->Container; - auto Layout = ELF->GetLayout(); - - uint64_t CurrentELFBase = std::get<0>(Layout); - uint64_t CurrentELFEnd = std::get<1>(Layout); - uint64_t CurrentELFAlignedSize = FEXCore::AlignUp(std::get<2>(Layout), 4096); - - CurrentELFBase += ELFBases; - CurrentELFEnd += ELFBases; - - std::get<0>(Layout) = CurrentELFBase; - std::get<1>(Layout) = CurrentELFEnd; - std::get<2>(Layout) = CurrentELFAlignedSize; - DynamicELFInfo[i]->CustomLayout = Layout; - DynamicELFInfo[i]->GuestBase = ELFBases; - - ELFBases += CurrentELFAlignedSize; - ELFMemorySize += CurrentELFAlignedSize; - } -} - -void ELFSymbolDatabase::FillInitializationOrder() { - std::set AlreadyInList; - - while (true) { - if (InitializationOrder.size() == DynamicELFInfo.size()) { - break; - } - - for (auto& ELF : DynamicELFInfo) { - // If this ELF is already in the list then skip it - if (AlreadyInList.find(ELF->Name) != AlreadyInList.end()) { - continue; - } - - bool AllLibsLoaded = true; - for (auto& Lib : *ELF->Container->GetNecessaryLibs()) { - if (AlreadyInList.find(Lib) == AlreadyInList.end()) { - AllLibsLoaded = false; - break; - } - } - - if (AllLibsLoaded) { - InitializationOrder.emplace_back(ELF); - AlreadyInList.insert(ELF->Name); - } - } - } -} - -void ELFSymbolDatabase::FillSymbols() { - auto LocalSymbolFiller = [this](ELFLoader::ELFSymbol* Symbol) { - Symbols.emplace_back(Symbol); - Symbol->Address += LocalInfo.GuestBase; - SymbolMap[Symbol->Name] = Symbol; - SymbolMapByAddress[Symbol->Address] = Symbol; - if (Symbol->Bind == STB_GLOBAL) { - SymbolMapGlobalOnly[Symbol->Name] = Symbol; - } - if (Symbol->Bind != STB_WEAK) { - SymbolMapNoWeak[Symbol->Name] = Symbol; - } - }; - - LocalInfo.Container->AddSymbols(LocalSymbolFiller); - - // Let us fill symbols based on initialization order - for (auto ELF : InitializationOrder) { - auto SymbolFiller = [this, &ELF](ELFLoader::ELFSymbol* Symbol) { - Symbols.emplace_back(Symbol); - // Offset the address by the guest base - Symbol->Address += ELF->GuestBase; - SymbolMap[Symbol->Name] = Symbol; - SymbolMapNoMain[Symbol->Name] = Symbol; - SymbolMapByAddress[Symbol->Address] = Symbol; - if (Symbol->Bind == STB_GLOBAL) { - SymbolMapGlobalOnly[Symbol->Name] = Symbol; - } - if (Symbol->Bind != STB_WEAK) { - SymbolMapNoWeak[Symbol->Name] = Symbol; - SymbolMapNoMainNoWeak[Symbol->Name] = Symbol; - } - }; - - ELF->Container->AddSymbols(SymbolFiller); - } -} - -void ELFSymbolDatabase::MapMemoryRegions(std::function Mapper) { - auto Map = [&](ELFInfo& ELF) { - uint64_t ELFBase = std::get<0>(ELF.CustomLayout); - uint64_t ELFSize = std::get<2>(ELF.CustomLayout); - uint64_t OffsetFromBase = ELFBase - ELF.GuestBase; - ELF.ELFBase = static_cast(Mapper(ELFBase, ELFSize, FixedNoReplace)) - OffsetFromBase; - }; - - Map(LocalInfo); - for (auto* ELF : DynamicELFInfo) { - Map(*ELF); - } -} - -void ELFSymbolDatabase::WriteLoadableSections(::ELFLoader::ELFContainer::MemoryWriter Writer) { - File->WriteLoadableSections(Writer, LocalInfo.GuestBase); - - for (size_t i = 0; i < DynamicELFInfo.size(); ++i) { - auto ELF = DynamicELFInfo[i]->Container; - - ELF->WriteLoadableSections(Writer, DynamicELFInfo[i]->GuestBase); - } - - HandleRelocations(); -} - -void ELFSymbolDatabase::HandleRelocations() { - auto SymbolGetter = [this](const char* SymbolName, uint8_t Table) -> ELFLoader::ELFSymbol* { - SymbolTableType& TablePtr = SymbolMap; - if (Table == 0) { - TablePtr = SymbolMap; - } else if (Table == 1) { // Global - TablePtr = SymbolMapGlobalOnly; - } else if (Table == 2) { // NoWeak - TablePtr = SymbolMapNoWeak; - } else if (Table == 3) { // No Main - TablePtr = SymbolMapNoMain; - } else if (Table == 4) { // No Main No Weak - TablePtr = SymbolMapNoMainNoWeak; - } - - auto Sym = TablePtr.find(SymbolName); - if (Sym == TablePtr.end()) { - return nullptr; - } - return Sym->second; - }; - - for (auto ELF : InitializationOrder) { - ELF->Container->FixupRelocations(ELF->ELFBase, ELF->GuestBase, SymbolGetter); - } - - LocalInfo.Container->FixupRelocations(LocalInfo.ELFBase, LocalInfo.GuestBase, SymbolGetter); -} - -uint64_t ELFSymbolDatabase::GetElfBase() const { - return LocalInfo.GuestBase; -} - -uint64_t ELFSymbolDatabase::DefaultRIP() const { - return File->GetEntryPoint() + LocalInfo.GuestBase; -} - -const ELFSymbol* ELFSymbolDatabase::GetSymbolInRange(RangeType Address) { - auto Sym = SymbolMapByAddress.upper_bound(Address.first); - if (Sym != SymbolMapByAddress.begin()) { - --Sym; - } - if (Sym == SymbolMapByAddress.end()) { - return nullptr; - } - - if ((Sym->second->Address + Sym->second->Size) < Address.first) { - return nullptr; - } - - if (Sym->second->Address > Address.first) { - return nullptr; - } - - return Sym->second; -} - -void ELFSymbolDatabase::GetInitLocations(fextl::vector* Locations) { - // Walk the initialization order and fill the locations for initializations - for (auto ELF : InitializationOrder) { - ELF->Container->GetInitLocations(ELF->GuestBase, Locations); - } -} - -} // namespace ELFLoader diff --git a/Source/Tools/CommonTools/Linux/Utils/ELFSymbolDatabase.h b/Source/Tools/CommonTools/Linux/Utils/ELFSymbolDatabase.h deleted file mode 100644 index 17b001ac19..0000000000 --- a/Source/Tools/CommonTools/Linux/Utils/ELFSymbolDatabase.h +++ /dev/null @@ -1,76 +0,0 @@ -// SPDX-License-Identifier: MIT -#pragma once - -#include -#include -#include -#include - -#include "Linux/Utils/ELFContainer.h" - -#include -#include -#include - -namespace ELFLoader { -class ELFSymbolDatabase final { -public: - ELFSymbolDatabase(::ELFLoader::ELFContainer* file); - ~ELFSymbolDatabase(); - - uint64_t GetElfBase() const; - - void MapMemoryRegions(std::function Mapper); - void WriteLoadableSections(::ELFLoader::ELFContainer::MemoryWriter Writer); - - uint64_t DefaultRIP() const; - - using RangeType = std::pair; - const ::ELFLoader::ELFSymbol* GetSymbolInRange(RangeType Address); - const ::ELFLoader::ELFSymbol* GetGlobalSymbolInRange(RangeType Address); - const ::ELFLoader::ELFSymbol* GetNoWeakSymbolInRange(RangeType Address); - - void GetInitLocations(fextl::vector* Locations); - -private: - ::ELFLoader::ELFContainer* File; - - struct ELFInfo { - fextl::string Name; - ::ELFLoader::ELFContainer* Container; - ::ELFLoader::ELFContainer::MemoryLayout CustomLayout; - void* ELFBase; - uint64_t GuestBase; - }; - - ELFInfo LocalInfo; - fextl::vector DynamicELFInfo; - fextl::vector InitializationOrder; - uint64_t ELFMemorySize {}; - bool FixedNoReplace {true}; - void* ELFBase {}; - - fextl::unordered_map NameToELF; - fextl::vector LibrarySearchPaths; - - // Symbols - fextl::vector Symbols; - using SymbolTableType = fextl::unordered_map; - SymbolTableType SymbolMap; - SymbolTableType SymbolMapGlobalOnly; - SymbolTableType SymbolMapNoWeak; - SymbolTableType SymbolMapNoMain; - SymbolTableType SymbolMapNoMainNoWeak; - fextl::map SymbolMapByAddress; - - bool FindLibraryFile(fextl::string* Result, const char* Library); - void FillLibrarySearchPaths(); - void FillMemoryLayouts(uint64_t DefinedBase); - void FillInitializationOrder(); - void FillSymbols(); - - void HandleRelocations(); - - const ::ELFLoader::ELFSymbol* GetSymbolFromTable(RangeType Address, fextl::unordered_map& Table); -}; -} // namespace ELFLoader diff --git a/Source/Tools/FEXLoader/ELFCodeLoader.h b/Source/Tools/FEXLoader/ELFCodeLoader.h index 99a782c547..b1417e6721 100644 --- a/Source/Tools/FEXLoader/ELFCodeLoader.h +++ b/Source/Tools/FEXLoader/ELFCodeLoader.h @@ -4,19 +4,13 @@ #include "ArchHelpers/UContext.h" #include "CodeLoader.h" -#include "Common/Config.h" #include "Common/FDUtils.h" #include "FEXCore/Utils/Allocator.h" #include "LinuxSyscalls/Syscalls.h" #include "VDSO_Emulation.h" #include "Linux/Utils/ELFParser.h" -#include "Linux/Utils/ELFSymbolDatabase.h" -#include -#include -#include #include -#include #include #include