diff options
author | orivej <orivej@yandex-team.ru> | 2022-02-10 16:45:01 +0300 |
---|---|---|
committer | Daniil Cherednik <dcherednik@yandex-team.ru> | 2022-02-10 16:45:01 +0300 |
commit | 2d37894b1b037cf24231090eda8589bbb44fb6fc (patch) | |
tree | be835aa92c6248212e705f25388ebafcf84bc7a1 /contrib/libs/llvm12/lib/ExecutionEngine | |
parent | 718c552901d703c502ccbefdfc3c9028d608b947 (diff) | |
download | ydb-2d37894b1b037cf24231090eda8589bbb44fb6fc.tar.gz |
Restoring authorship annotation for <orivej@yandex-team.ru>. Commit 2 of 2.
Diffstat (limited to 'contrib/libs/llvm12/lib/ExecutionEngine')
34 files changed, 13352 insertions, 13352 deletions
diff --git a/contrib/libs/llvm12/lib/ExecutionEngine/ExecutionEngine.cpp b/contrib/libs/llvm12/lib/ExecutionEngine/ExecutionEngine.cpp index 803a90b5a2..c8bbf0bcdf 100644 --- a/contrib/libs/llvm12/lib/ExecutionEngine/ExecutionEngine.cpp +++ b/contrib/libs/llvm12/lib/ExecutionEngine/ExecutionEngine.cpp @@ -1,1309 +1,1309 @@ -//===-- ExecutionEngine.cpp - Common Implementation shared by EEs ---------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file defines the common interface used by the various execution engine -// subclasses. -// -// FIXME: This file needs to be updated to support scalable vectors -// -//===----------------------------------------------------------------------===// - -#include "llvm/ExecutionEngine/ExecutionEngine.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/SmallString.h" -#include "llvm/ADT/Statistic.h" -#include "llvm/ExecutionEngine/GenericValue.h" -#include "llvm/ExecutionEngine/JITEventListener.h" -#include "llvm/ExecutionEngine/ObjectCache.h" -#include "llvm/ExecutionEngine/RTDyldMemoryManager.h" -#include "llvm/IR/Constants.h" -#include "llvm/IR/DataLayout.h" -#include "llvm/IR/DerivedTypes.h" -#include "llvm/IR/Mangler.h" -#include "llvm/IR/Module.h" -#include "llvm/IR/Operator.h" -#include "llvm/IR/ValueHandle.h" -#include "llvm/Object/Archive.h" -#include "llvm/Object/ObjectFile.h" -#include "llvm/Support/Debug.h" -#include "llvm/Support/DynamicLibrary.h" -#include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/Host.h" -#include "llvm/Support/TargetRegistry.h" -#include "llvm/Support/raw_ostream.h" -#include "llvm/Target/TargetMachine.h" -#include <cmath> -#include <cstring> -#include <mutex> -using namespace llvm; - -#define DEBUG_TYPE "jit" - -STATISTIC(NumInitBytes, "Number of bytes of global vars initialized"); -STATISTIC(NumGlobals , "Number of global vars initialized"); - -ExecutionEngine *(*ExecutionEngine::MCJITCtor)( - std::unique_ptr<Module> M, std::string *ErrorStr, - std::shared_ptr<MCJITMemoryManager> MemMgr, - std::shared_ptr<LegacyJITSymbolResolver> Resolver, - std::unique_ptr<TargetMachine> TM) = nullptr; - -ExecutionEngine *(*ExecutionEngine::InterpCtor)(std::unique_ptr<Module> M, - std::string *ErrorStr) =nullptr; - -void JITEventListener::anchor() {} - -void ObjectCache::anchor() {} - -void ExecutionEngine::Init(std::unique_ptr<Module> M) { - CompilingLazily = false; - GVCompilationDisabled = false; - SymbolSearchingDisabled = false; - - // IR module verification is enabled by default in debug builds, and disabled - // by default in release builds. -#ifndef NDEBUG - VerifyModules = true; -#else - VerifyModules = false; -#endif - - assert(M && "Module is null?"); - Modules.push_back(std::move(M)); -} - -ExecutionEngine::ExecutionEngine(std::unique_ptr<Module> M) - : DL(M->getDataLayout()), LazyFunctionCreator(nullptr) { - Init(std::move(M)); -} - -ExecutionEngine::ExecutionEngine(DataLayout DL, std::unique_ptr<Module> M) - : DL(std::move(DL)), LazyFunctionCreator(nullptr) { - Init(std::move(M)); -} - -ExecutionEngine::~ExecutionEngine() { - clearAllGlobalMappings(); -} - -namespace { -/// Helper class which uses a value handler to automatically deletes the -/// memory block when the GlobalVariable is destroyed. -class GVMemoryBlock final : public CallbackVH { - GVMemoryBlock(const GlobalVariable *GV) - : CallbackVH(const_cast<GlobalVariable*>(GV)) {} - -public: - /// Returns the address the GlobalVariable should be written into. The - /// GVMemoryBlock object prefixes that. - static char *Create(const GlobalVariable *GV, const DataLayout& TD) { - Type *ElTy = GV->getValueType(); - size_t GVSize = (size_t)TD.getTypeAllocSize(ElTy); - void *RawMemory = ::operator new( - alignTo(sizeof(GVMemoryBlock), TD.getPreferredAlign(GV)) + GVSize); - new(RawMemory) GVMemoryBlock(GV); - return static_cast<char*>(RawMemory) + sizeof(GVMemoryBlock); - } - - void deleted() override { - // We allocated with operator new and with some extra memory hanging off the - // end, so don't just delete this. I'm not sure if this is actually - // required. - this->~GVMemoryBlock(); - ::operator delete(this); - } -}; -} // anonymous namespace - -char *ExecutionEngine::getMemoryForGV(const GlobalVariable *GV) { - return GVMemoryBlock::Create(GV, getDataLayout()); -} - -void ExecutionEngine::addObjectFile(std::unique_ptr<object::ObjectFile> O) { - llvm_unreachable("ExecutionEngine subclass doesn't implement addObjectFile."); -} - -void -ExecutionEngine::addObjectFile(object::OwningBinary<object::ObjectFile> O) { - llvm_unreachable("ExecutionEngine subclass doesn't implement addObjectFile."); -} - -void ExecutionEngine::addArchive(object::OwningBinary<object::Archive> A) { - llvm_unreachable("ExecutionEngine subclass doesn't implement addArchive."); -} - -bool ExecutionEngine::removeModule(Module *M) { - for (auto I = Modules.begin(), E = Modules.end(); I != E; ++I) { - Module *Found = I->get(); - if (Found == M) { - I->release(); - Modules.erase(I); - clearGlobalMappingsFromModule(M); - return true; - } - } - return false; -} - -Function *ExecutionEngine::FindFunctionNamed(StringRef FnName) { - for (unsigned i = 0, e = Modules.size(); i != e; ++i) { - Function *F = Modules[i]->getFunction(FnName); - if (F && !F->isDeclaration()) - return F; - } - return nullptr; -} - -GlobalVariable *ExecutionEngine::FindGlobalVariableNamed(StringRef Name, bool AllowInternal) { - for (unsigned i = 0, e = Modules.size(); i != e; ++i) { - GlobalVariable *GV = Modules[i]->getGlobalVariable(Name,AllowInternal); - if (GV && !GV->isDeclaration()) - return GV; - } - return nullptr; -} - -uint64_t ExecutionEngineState::RemoveMapping(StringRef Name) { - GlobalAddressMapTy::iterator I = GlobalAddressMap.find(Name); - uint64_t OldVal; - - // FIXME: This is silly, we shouldn't end up with a mapping -> 0 in the - // GlobalAddressMap. - if (I == GlobalAddressMap.end()) - OldVal = 0; - else { - GlobalAddressReverseMap.erase(I->second); - OldVal = I->second; - GlobalAddressMap.erase(I); - } - - return OldVal; -} - -std::string ExecutionEngine::getMangledName(const GlobalValue *GV) { - assert(GV->hasName() && "Global must have name."); - - std::lock_guard<sys::Mutex> locked(lock); - SmallString<128> FullName; - - const DataLayout &DL = - GV->getParent()->getDataLayout().isDefault() - ? getDataLayout() - : GV->getParent()->getDataLayout(); - - Mangler::getNameWithPrefix(FullName, GV->getName(), DL); - return std::string(FullName.str()); -} - -void ExecutionEngine::addGlobalMapping(const GlobalValue *GV, void *Addr) { - std::lock_guard<sys::Mutex> locked(lock); - addGlobalMapping(getMangledName(GV), (uint64_t) Addr); -} - -void ExecutionEngine::addGlobalMapping(StringRef Name, uint64_t Addr) { - std::lock_guard<sys::Mutex> locked(lock); - - assert(!Name.empty() && "Empty GlobalMapping symbol name!"); - - LLVM_DEBUG(dbgs() << "JIT: Map \'" << Name << "\' to [" << Addr << "]\n";); - uint64_t &CurVal = EEState.getGlobalAddressMap()[Name]; - assert((!CurVal || !Addr) && "GlobalMapping already established!"); - CurVal = Addr; - - // If we are using the reverse mapping, add it too. - if (!EEState.getGlobalAddressReverseMap().empty()) { - std::string &V = EEState.getGlobalAddressReverseMap()[CurVal]; - assert((!V.empty() || !Name.empty()) && - "GlobalMapping already established!"); - V = std::string(Name); - } -} - -void ExecutionEngine::clearAllGlobalMappings() { - std::lock_guard<sys::Mutex> locked(lock); - - EEState.getGlobalAddressMap().clear(); - EEState.getGlobalAddressReverseMap().clear(); -} - -void ExecutionEngine::clearGlobalMappingsFromModule(Module *M) { - std::lock_guard<sys::Mutex> locked(lock); - - for (GlobalObject &GO : M->global_objects()) - EEState.RemoveMapping(getMangledName(&GO)); -} - -uint64_t ExecutionEngine::updateGlobalMapping(const GlobalValue *GV, - void *Addr) { - std::lock_guard<sys::Mutex> locked(lock); - return updateGlobalMapping(getMangledName(GV), (uint64_t) Addr); -} - -uint64_t ExecutionEngine::updateGlobalMapping(StringRef Name, uint64_t Addr) { - std::lock_guard<sys::Mutex> locked(lock); - - ExecutionEngineState::GlobalAddressMapTy &Map = - EEState.getGlobalAddressMap(); - - // Deleting from the mapping? - if (!Addr) - return EEState.RemoveMapping(Name); - - uint64_t &CurVal = Map[Name]; - uint64_t OldVal = CurVal; - - if (CurVal && !EEState.getGlobalAddressReverseMap().empty()) - EEState.getGlobalAddressReverseMap().erase(CurVal); - CurVal = Addr; - - // If we are using the reverse mapping, add it too. - if (!EEState.getGlobalAddressReverseMap().empty()) { - std::string &V = EEState.getGlobalAddressReverseMap()[CurVal]; - assert((!V.empty() || !Name.empty()) && - "GlobalMapping already established!"); - V = std::string(Name); - } - return OldVal; -} - -uint64_t ExecutionEngine::getAddressToGlobalIfAvailable(StringRef S) { - std::lock_guard<sys::Mutex> locked(lock); - uint64_t Address = 0; - ExecutionEngineState::GlobalAddressMapTy::iterator I = - EEState.getGlobalAddressMap().find(S); - if (I != EEState.getGlobalAddressMap().end()) - Address = I->second; - return Address; -} - - -void *ExecutionEngine::getPointerToGlobalIfAvailable(StringRef S) { - std::lock_guard<sys::Mutex> locked(lock); - if (void* Address = (void *) getAddressToGlobalIfAvailable(S)) - return Address; - return nullptr; -} - -void *ExecutionEngine::getPointerToGlobalIfAvailable(const GlobalValue *GV) { - std::lock_guard<sys::Mutex> locked(lock); - return getPointerToGlobalIfAvailable(getMangledName(GV)); -} - -const GlobalValue *ExecutionEngine::getGlobalValueAtAddress(void *Addr) { - std::lock_guard<sys::Mutex> locked(lock); - - // If we haven't computed the reverse mapping yet, do so first. - if (EEState.getGlobalAddressReverseMap().empty()) { - for (ExecutionEngineState::GlobalAddressMapTy::iterator - I = EEState.getGlobalAddressMap().begin(), - E = EEState.getGlobalAddressMap().end(); I != E; ++I) { - StringRef Name = I->first(); - uint64_t Addr = I->second; - EEState.getGlobalAddressReverseMap().insert( - std::make_pair(Addr, std::string(Name))); - } - } - - std::map<uint64_t, std::string>::iterator I = - EEState.getGlobalAddressReverseMap().find((uint64_t) Addr); - - if (I != EEState.getGlobalAddressReverseMap().end()) { - StringRef Name = I->second; - for (unsigned i = 0, e = Modules.size(); i != e; ++i) - if (GlobalValue *GV = Modules[i]->getNamedValue(Name)) - return GV; - } - return nullptr; -} - -namespace { -class ArgvArray { - std::unique_ptr<char[]> Array; - std::vector<std::unique_ptr<char[]>> Values; -public: - /// Turn a vector of strings into a nice argv style array of pointers to null - /// terminated strings. - void *reset(LLVMContext &C, ExecutionEngine *EE, - const std::vector<std::string> &InputArgv); -}; -} // anonymous namespace -void *ArgvArray::reset(LLVMContext &C, ExecutionEngine *EE, - const std::vector<std::string> &InputArgv) { - Values.clear(); // Free the old contents. - Values.reserve(InputArgv.size()); - unsigned PtrSize = EE->getDataLayout().getPointerSize(); - Array = std::make_unique<char[]>((InputArgv.size()+1)*PtrSize); - - LLVM_DEBUG(dbgs() << "JIT: ARGV = " << (void *)Array.get() << "\n"); - Type *SBytePtr = Type::getInt8PtrTy(C); - - for (unsigned i = 0; i != InputArgv.size(); ++i) { - unsigned Size = InputArgv[i].size()+1; - auto Dest = std::make_unique<char[]>(Size); - LLVM_DEBUG(dbgs() << "JIT: ARGV[" << i << "] = " << (void *)Dest.get() - << "\n"); - - std::copy(InputArgv[i].begin(), InputArgv[i].end(), Dest.get()); - Dest[Size-1] = 0; - - // Endian safe: Array[i] = (PointerTy)Dest; - EE->StoreValueToMemory(PTOGV(Dest.get()), - (GenericValue*)(&Array[i*PtrSize]), SBytePtr); - Values.push_back(std::move(Dest)); - } - - // Null terminate it - EE->StoreValueToMemory(PTOGV(nullptr), - (GenericValue*)(&Array[InputArgv.size()*PtrSize]), - SBytePtr); - return Array.get(); -} - -void ExecutionEngine::runStaticConstructorsDestructors(Module &module, - bool isDtors) { - StringRef Name(isDtors ? "llvm.global_dtors" : "llvm.global_ctors"); - GlobalVariable *GV = module.getNamedGlobal(Name); - - // If this global has internal linkage, or if it has a use, then it must be - // an old-style (llvmgcc3) static ctor with __main linked in and in use. If - // this is the case, don't execute any of the global ctors, __main will do - // it. - if (!GV || GV->isDeclaration() || GV->hasLocalLinkage()) return; - - // Should be an array of '{ i32, void ()* }' structs. The first value is - // the init priority, which we ignore. - ConstantArray *InitList = dyn_cast<ConstantArray>(GV->getInitializer()); - if (!InitList) - return; - for (unsigned i = 0, e = InitList->getNumOperands(); i != e; ++i) { - ConstantStruct *CS = dyn_cast<ConstantStruct>(InitList->getOperand(i)); - if (!CS) continue; - - Constant *FP = CS->getOperand(1); - if (FP->isNullValue()) - continue; // Found a sentinal value, ignore. - - // Strip off constant expression casts. - if (ConstantExpr *CE = dyn_cast<ConstantExpr>(FP)) - if (CE->isCast()) - FP = CE->getOperand(0); - - // Execute the ctor/dtor function! - if (Function *F = dyn_cast<Function>(FP)) - runFunction(F, None); - - // FIXME: It is marginally lame that we just do nothing here if we see an - // entry we don't recognize. It might not be unreasonable for the verifier - // to not even allow this and just assert here. - } -} - -void ExecutionEngine::runStaticConstructorsDestructors(bool isDtors) { - // Execute global ctors/dtors for each module in the program. - for (std::unique_ptr<Module> &M : Modules) - runStaticConstructorsDestructors(*M, isDtors); -} - -#ifndef NDEBUG -/// isTargetNullPtr - Return whether the target pointer stored at Loc is null. -static bool isTargetNullPtr(ExecutionEngine *EE, void *Loc) { - unsigned PtrSize = EE->getDataLayout().getPointerSize(); - for (unsigned i = 0; i < PtrSize; ++i) - if (*(i + (uint8_t*)Loc)) - return false; - return true; -} -#endif - -int ExecutionEngine::runFunctionAsMain(Function *Fn, - const std::vector<std::string> &argv, - const char * const * envp) { - std::vector<GenericValue> GVArgs; - GenericValue GVArgc; - GVArgc.IntVal = APInt(32, argv.size()); - - // Check main() type - unsigned NumArgs = Fn->getFunctionType()->getNumParams(); - FunctionType *FTy = Fn->getFunctionType(); - Type* PPInt8Ty = Type::getInt8PtrTy(Fn->getContext())->getPointerTo(); - - // Check the argument types. - if (NumArgs > 3) - report_fatal_error("Invalid number of arguments of main() supplied"); - if (NumArgs >= 3 && FTy->getParamType(2) != PPInt8Ty) - report_fatal_error("Invalid type for third argument of main() supplied"); - if (NumArgs >= 2 && FTy->getParamType(1) != PPInt8Ty) - report_fatal_error("Invalid type for second argument of main() supplied"); - if (NumArgs >= 1 && !FTy->getParamType(0)->isIntegerTy(32)) - report_fatal_error("Invalid type for first argument of main() supplied"); - if (!FTy->getReturnType()->isIntegerTy() && - !FTy->getReturnType()->isVoidTy()) - report_fatal_error("Invalid return type of main() supplied"); - - ArgvArray CArgv; - ArgvArray CEnv; - if (NumArgs) { - GVArgs.push_back(GVArgc); // Arg #0 = argc. - if (NumArgs > 1) { - // Arg #1 = argv. - GVArgs.push_back(PTOGV(CArgv.reset(Fn->getContext(), this, argv))); - assert(!isTargetNullPtr(this, GVTOP(GVArgs[1])) && - "argv[0] was null after CreateArgv"); - if (NumArgs > 2) { - std::vector<std::string> EnvVars; - for (unsigned i = 0; envp[i]; ++i) - EnvVars.emplace_back(envp[i]); - // Arg #2 = envp. - GVArgs.push_back(PTOGV(CEnv.reset(Fn->getContext(), this, EnvVars))); - } - } - } - - return runFunction(Fn, GVArgs).IntVal.getZExtValue(); -} - -EngineBuilder::EngineBuilder() : EngineBuilder(nullptr) {} - -EngineBuilder::EngineBuilder(std::unique_ptr<Module> M) - : M(std::move(M)), WhichEngine(EngineKind::Either), ErrorStr(nullptr), +//===-- ExecutionEngine.cpp - Common Implementation shared by EEs ---------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines the common interface used by the various execution engine +// subclasses. +// +// FIXME: This file needs to be updated to support scalable vectors +// +//===----------------------------------------------------------------------===// + +#include "llvm/ExecutionEngine/ExecutionEngine.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/Statistic.h" +#include "llvm/ExecutionEngine/GenericValue.h" +#include "llvm/ExecutionEngine/JITEventListener.h" +#include "llvm/ExecutionEngine/ObjectCache.h" +#include "llvm/ExecutionEngine/RTDyldMemoryManager.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/DataLayout.h" +#include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/Mangler.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/Operator.h" +#include "llvm/IR/ValueHandle.h" +#include "llvm/Object/Archive.h" +#include "llvm/Object/ObjectFile.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/DynamicLibrary.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/Host.h" +#include "llvm/Support/TargetRegistry.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Target/TargetMachine.h" +#include <cmath> +#include <cstring> +#include <mutex> +using namespace llvm; + +#define DEBUG_TYPE "jit" + +STATISTIC(NumInitBytes, "Number of bytes of global vars initialized"); +STATISTIC(NumGlobals , "Number of global vars initialized"); + +ExecutionEngine *(*ExecutionEngine::MCJITCtor)( + std::unique_ptr<Module> M, std::string *ErrorStr, + std::shared_ptr<MCJITMemoryManager> MemMgr, + std::shared_ptr<LegacyJITSymbolResolver> Resolver, + std::unique_ptr<TargetMachine> TM) = nullptr; + +ExecutionEngine *(*ExecutionEngine::InterpCtor)(std::unique_ptr<Module> M, + std::string *ErrorStr) =nullptr; + +void JITEventListener::anchor() {} + +void ObjectCache::anchor() {} + +void ExecutionEngine::Init(std::unique_ptr<Module> M) { + CompilingLazily = false; + GVCompilationDisabled = false; + SymbolSearchingDisabled = false; + + // IR module verification is enabled by default in debug builds, and disabled + // by default in release builds. +#ifndef NDEBUG + VerifyModules = true; +#else + VerifyModules = false; +#endif + + assert(M && "Module is null?"); + Modules.push_back(std::move(M)); +} + +ExecutionEngine::ExecutionEngine(std::unique_ptr<Module> M) + : DL(M->getDataLayout()), LazyFunctionCreator(nullptr) { + Init(std::move(M)); +} + +ExecutionEngine::ExecutionEngine(DataLayout DL, std::unique_ptr<Module> M) + : DL(std::move(DL)), LazyFunctionCreator(nullptr) { + Init(std::move(M)); +} + +ExecutionEngine::~ExecutionEngine() { + clearAllGlobalMappings(); +} + +namespace { +/// Helper class which uses a value handler to automatically deletes the +/// memory block when the GlobalVariable is destroyed. +class GVMemoryBlock final : public CallbackVH { + GVMemoryBlock(const GlobalVariable *GV) + : CallbackVH(const_cast<GlobalVariable*>(GV)) {} + +public: + /// Returns the address the GlobalVariable should be written into. The + /// GVMemoryBlock object prefixes that. + static char *Create(const GlobalVariable *GV, const DataLayout& TD) { + Type *ElTy = GV->getValueType(); + size_t GVSize = (size_t)TD.getTypeAllocSize(ElTy); + void *RawMemory = ::operator new( + alignTo(sizeof(GVMemoryBlock), TD.getPreferredAlign(GV)) + GVSize); + new(RawMemory) GVMemoryBlock(GV); + return static_cast<char*>(RawMemory) + sizeof(GVMemoryBlock); + } + + void deleted() override { + // We allocated with operator new and with some extra memory hanging off the + // end, so don't just delete this. I'm not sure if this is actually + // required. + this->~GVMemoryBlock(); + ::operator delete(this); + } +}; +} // anonymous namespace + +char *ExecutionEngine::getMemoryForGV(const GlobalVariable *GV) { + return GVMemoryBlock::Create(GV, getDataLayout()); +} + +void ExecutionEngine::addObjectFile(std::unique_ptr<object::ObjectFile> O) { + llvm_unreachable("ExecutionEngine subclass doesn't implement addObjectFile."); +} + +void +ExecutionEngine::addObjectFile(object::OwningBinary<object::ObjectFile> O) { + llvm_unreachable("ExecutionEngine subclass doesn't implement addObjectFile."); +} + +void ExecutionEngine::addArchive(object::OwningBinary<object::Archive> A) { + llvm_unreachable("ExecutionEngine subclass doesn't implement addArchive."); +} + +bool ExecutionEngine::removeModule(Module *M) { + for (auto I = Modules.begin(), E = Modules.end(); I != E; ++I) { + Module *Found = I->get(); + if (Found == M) { + I->release(); + Modules.erase(I); + clearGlobalMappingsFromModule(M); + return true; + } + } + return false; +} + +Function *ExecutionEngine::FindFunctionNamed(StringRef FnName) { + for (unsigned i = 0, e = Modules.size(); i != e; ++i) { + Function *F = Modules[i]->getFunction(FnName); + if (F && !F->isDeclaration()) + return F; + } + return nullptr; +} + +GlobalVariable *ExecutionEngine::FindGlobalVariableNamed(StringRef Name, bool AllowInternal) { + for (unsigned i = 0, e = Modules.size(); i != e; ++i) { + GlobalVariable *GV = Modules[i]->getGlobalVariable(Name,AllowInternal); + if (GV && !GV->isDeclaration()) + return GV; + } + return nullptr; +} + +uint64_t ExecutionEngineState::RemoveMapping(StringRef Name) { + GlobalAddressMapTy::iterator I = GlobalAddressMap.find(Name); + uint64_t OldVal; + + // FIXME: This is silly, we shouldn't end up with a mapping -> 0 in the + // GlobalAddressMap. + if (I == GlobalAddressMap.end()) + OldVal = 0; + else { + GlobalAddressReverseMap.erase(I->second); + OldVal = I->second; + GlobalAddressMap.erase(I); + } + + return OldVal; +} + +std::string ExecutionEngine::getMangledName(const GlobalValue *GV) { + assert(GV->hasName() && "Global must have name."); + + std::lock_guard<sys::Mutex> locked(lock); + SmallString<128> FullName; + + const DataLayout &DL = + GV->getParent()->getDataLayout().isDefault() + ? getDataLayout() + : GV->getParent()->getDataLayout(); + + Mangler::getNameWithPrefix(FullName, GV->getName(), DL); + return std::string(FullName.str()); +} + +void ExecutionEngine::addGlobalMapping(const GlobalValue *GV, void *Addr) { + std::lock_guard<sys::Mutex> locked(lock); + addGlobalMapping(getMangledName(GV), (uint64_t) Addr); +} + +void ExecutionEngine::addGlobalMapping(StringRef Name, uint64_t Addr) { + std::lock_guard<sys::Mutex> locked(lock); + + assert(!Name.empty() && "Empty GlobalMapping symbol name!"); + + LLVM_DEBUG(dbgs() << "JIT: Map \'" << Name << "\' to [" << Addr << "]\n";); + uint64_t &CurVal = EEState.getGlobalAddressMap()[Name]; + assert((!CurVal || !Addr) && "GlobalMapping already established!"); + CurVal = Addr; + + // If we are using the reverse mapping, add it too. + if (!EEState.getGlobalAddressReverseMap().empty()) { + std::string &V = EEState.getGlobalAddressReverseMap()[CurVal]; + assert((!V.empty() || !Name.empty()) && + "GlobalMapping already established!"); + V = std::string(Name); + } +} + +void ExecutionEngine::clearAllGlobalMappings() { + std::lock_guard<sys::Mutex> locked(lock); + + EEState.getGlobalAddressMap().clear(); + EEState.getGlobalAddressReverseMap().clear(); +} + +void ExecutionEngine::clearGlobalMappingsFromModule(Module *M) { + std::lock_guard<sys::Mutex> locked(lock); + + for (GlobalObject &GO : M->global_objects()) + EEState.RemoveMapping(getMangledName(&GO)); +} + +uint64_t ExecutionEngine::updateGlobalMapping(const GlobalValue *GV, + void *Addr) { + std::lock_guard<sys::Mutex> locked(lock); + return updateGlobalMapping(getMangledName(GV), (uint64_t) Addr); +} + +uint64_t ExecutionEngine::updateGlobalMapping(StringRef Name, uint64_t Addr) { + std::lock_guard<sys::Mutex> locked(lock); + + ExecutionEngineState::GlobalAddressMapTy &Map = + EEState.getGlobalAddressMap(); + + // Deleting from the mapping? + if (!Addr) + return EEState.RemoveMapping(Name); + + uint64_t &CurVal = Map[Name]; + uint64_t OldVal = CurVal; + + if (CurVal && !EEState.getGlobalAddressReverseMap().empty()) + EEState.getGlobalAddressReverseMap().erase(CurVal); + CurVal = Addr; + + // If we are using the reverse mapping, add it too. + if (!EEState.getGlobalAddressReverseMap().empty()) { + std::string &V = EEState.getGlobalAddressReverseMap()[CurVal]; + assert((!V.empty() || !Name.empty()) && + "GlobalMapping already established!"); + V = std::string(Name); + } + return OldVal; +} + +uint64_t ExecutionEngine::getAddressToGlobalIfAvailable(StringRef S) { + std::lock_guard<sys::Mutex> locked(lock); + uint64_t Address = 0; + ExecutionEngineState::GlobalAddressMapTy::iterator I = + EEState.getGlobalAddressMap().find(S); + if (I != EEState.getGlobalAddressMap().end()) + Address = I->second; + return Address; +} + + +void *ExecutionEngine::getPointerToGlobalIfAvailable(StringRef S) { + std::lock_guard<sys::Mutex> locked(lock); + if (void* Address = (void *) getAddressToGlobalIfAvailable(S)) + return Address; + return nullptr; +} + +void *ExecutionEngine::getPointerToGlobalIfAvailable(const GlobalValue *GV) { + std::lock_guard<sys::Mutex> locked(lock); + return getPointerToGlobalIfAvailable(getMangledName(GV)); +} + +const GlobalValue *ExecutionEngine::getGlobalValueAtAddress(void *Addr) { + std::lock_guard<sys::Mutex> locked(lock); + + // If we haven't computed the reverse mapping yet, do so first. + if (EEState.getGlobalAddressReverseMap().empty()) { + for (ExecutionEngineState::GlobalAddressMapTy::iterator + I = EEState.getGlobalAddressMap().begin(), + E = EEState.getGlobalAddressMap().end(); I != E; ++I) { + StringRef Name = I->first(); + uint64_t Addr = I->second; + EEState.getGlobalAddressReverseMap().insert( + std::make_pair(Addr, std::string(Name))); + } + } + + std::map<uint64_t, std::string>::iterator I = + EEState.getGlobalAddressReverseMap().find((uint64_t) Addr); + + if (I != EEState.getGlobalAddressReverseMap().end()) { + StringRef Name = I->second; + for (unsigned i = 0, e = Modules.size(); i != e; ++i) + if (GlobalValue *GV = Modules[i]->getNamedValue(Name)) + return GV; + } + return nullptr; +} + +namespace { +class ArgvArray { + std::unique_ptr<char[]> Array; + std::vector<std::unique_ptr<char[]>> Values; +public: + /// Turn a vector of strings into a nice argv style array of pointers to null + /// terminated strings. + void *reset(LLVMContext &C, ExecutionEngine *EE, + const std::vector<std::string> &InputArgv); +}; +} // anonymous namespace +void *ArgvArray::reset(LLVMContext &C, ExecutionEngine *EE, + const std::vector<std::string> &InputArgv) { + Values.clear(); // Free the old contents. + Values.reserve(InputArgv.size()); + unsigned PtrSize = EE->getDataLayout().getPointerSize(); + Array = std::make_unique<char[]>((InputArgv.size()+1)*PtrSize); + + LLVM_DEBUG(dbgs() << "JIT: ARGV = " << (void *)Array.get() << "\n"); + Type *SBytePtr = Type::getInt8PtrTy(C); + + for (unsigned i = 0; i != InputArgv.size(); ++i) { + unsigned Size = InputArgv[i].size()+1; + auto Dest = std::make_unique<char[]>(Size); + LLVM_DEBUG(dbgs() << "JIT: ARGV[" << i << "] = " << (void *)Dest.get() + << "\n"); + + std::copy(InputArgv[i].begin(), InputArgv[i].end(), Dest.get()); + Dest[Size-1] = 0; + + // Endian safe: Array[i] = (PointerTy)Dest; + EE->StoreValueToMemory(PTOGV(Dest.get()), + (GenericValue*)(&Array[i*PtrSize]), SBytePtr); + Values.push_back(std::move(Dest)); + } + + // Null terminate it + EE->StoreValueToMemory(PTOGV(nullptr), + (GenericValue*)(&Array[InputArgv.size()*PtrSize]), + SBytePtr); + return Array.get(); +} + +void ExecutionEngine::runStaticConstructorsDestructors(Module &module, + bool isDtors) { + StringRef Name(isDtors ? "llvm.global_dtors" : "llvm.global_ctors"); + GlobalVariable *GV = module.getNamedGlobal(Name); + + // If this global has internal linkage, or if it has a use, then it must be + // an old-style (llvmgcc3) static ctor with __main linked in and in use. If + // this is the case, don't execute any of the global ctors, __main will do + // it. + if (!GV || GV->isDeclaration() || GV->hasLocalLinkage()) return; + + // Should be an array of '{ i32, void ()* }' structs. The first value is + // the init priority, which we ignore. + ConstantArray *InitList = dyn_cast<ConstantArray>(GV->getInitializer()); + if (!InitList) + return; + for (unsigned i = 0, e = InitList->getNumOperands(); i != e; ++i) { + ConstantStruct *CS = dyn_cast<ConstantStruct>(InitList->getOperand(i)); + if (!CS) continue; + + Constant *FP = CS->getOperand(1); + if (FP->isNullValue()) + continue; // Found a sentinal value, ignore. + + // Strip off constant expression casts. + if (ConstantExpr *CE = dyn_cast<ConstantExpr>(FP)) + if (CE->isCast()) + FP = CE->getOperand(0); + + // Execute the ctor/dtor function! + if (Function *F = dyn_cast<Function>(FP)) + runFunction(F, None); + + // FIXME: It is marginally lame that we just do nothing here if we see an + // entry we don't recognize. It might not be unreasonable for the verifier + // to not even allow this and just assert here. + } +} + +void ExecutionEngine::runStaticConstructorsDestructors(bool isDtors) { + // Execute global ctors/dtors for each module in the program. + for (std::unique_ptr<Module> &M : Modules) + runStaticConstructorsDestructors(*M, isDtors); +} + +#ifndef NDEBUG +/// isTargetNullPtr - Return whether the target pointer stored at Loc is null. +static bool isTargetNullPtr(ExecutionEngine *EE, void *Loc) { + unsigned PtrSize = EE->getDataLayout().getPointerSize(); + for (unsigned i = 0; i < PtrSize; ++i) + if (*(i + (uint8_t*)Loc)) + return false; + return true; +} +#endif + +int ExecutionEngine::runFunctionAsMain(Function *Fn, + const std::vector<std::string> &argv, + const char * const * envp) { + std::vector<GenericValue> GVArgs; + GenericValue GVArgc; + GVArgc.IntVal = APInt(32, argv.size()); + + // Check main() type + unsigned NumArgs = Fn->getFunctionType()->getNumParams(); + FunctionType *FTy = Fn->getFunctionType(); + Type* PPInt8Ty = Type::getInt8PtrTy(Fn->getContext())->getPointerTo(); + + // Check the argument types. + if (NumArgs > 3) + report_fatal_error("Invalid number of arguments of main() supplied"); + if (NumArgs >= 3 && FTy->getParamType(2) != PPInt8Ty) + report_fatal_error("Invalid type for third argument of main() supplied"); + if (NumArgs >= 2 && FTy->getParamType(1) != PPInt8Ty) + report_fatal_error("Invalid type for second argument of main() supplied"); + if (NumArgs >= 1 && !FTy->getParamType(0)->isIntegerTy(32)) + report_fatal_error("Invalid type for first argument of main() supplied"); + if (!FTy->getReturnType()->isIntegerTy() && + !FTy->getReturnType()->isVoidTy()) + report_fatal_error("Invalid return type of main() supplied"); + + ArgvArray CArgv; + ArgvArray CEnv; + if (NumArgs) { + GVArgs.push_back(GVArgc); // Arg #0 = argc. + if (NumArgs > 1) { + // Arg #1 = argv. + GVArgs.push_back(PTOGV(CArgv.reset(Fn->getContext(), this, argv))); + assert(!isTargetNullPtr(this, GVTOP(GVArgs[1])) && + "argv[0] was null after CreateArgv"); + if (NumArgs > 2) { + std::vector<std::string> EnvVars; + for (unsigned i = 0; envp[i]; ++i) + EnvVars.emplace_back(envp[i]); + // Arg #2 = envp. + GVArgs.push_back(PTOGV(CEnv.reset(Fn->getContext(), this, EnvVars))); + } + } + } + + return runFunction(Fn, GVArgs).IntVal.getZExtValue(); +} + +EngineBuilder::EngineBuilder() : EngineBuilder(nullptr) {} + +EngineBuilder::EngineBuilder(std::unique_ptr<Module> M) + : M(std::move(M)), WhichEngine(EngineKind::Either), ErrorStr(nullptr), OptLevel(CodeGenOpt::Default), MemMgr(nullptr), Resolver(nullptr) { -// IR module verification is enabled by default in debug builds, and disabled -// by default in release builds. -#ifndef NDEBUG - VerifyModules = true; -#else - VerifyModules = false; -#endif -} - -EngineBuilder::~EngineBuilder() = default; - -EngineBuilder &EngineBuilder::setMCJITMemoryManager( - std::unique_ptr<RTDyldMemoryManager> mcjmm) { - auto SharedMM = std::shared_ptr<RTDyldMemoryManager>(std::move(mcjmm)); - MemMgr = SharedMM; - Resolver = SharedMM; - return *this; -} - -EngineBuilder& -EngineBuilder::setMemoryManager(std::unique_ptr<MCJITMemoryManager> MM) { - MemMgr = std::shared_ptr<MCJITMemoryManager>(std::move(MM)); - return *this; -} - -EngineBuilder & -EngineBuilder::setSymbolResolver(std::unique_ptr<LegacyJITSymbolResolver> SR) { - Resolver = std::shared_ptr<LegacyJITSymbolResolver>(std::move(SR)); - return *this; -} - -ExecutionEngine *EngineBuilder::create(TargetMachine *TM) { - std::unique_ptr<TargetMachine> TheTM(TM); // Take ownership. - - // Make sure we can resolve symbols in the program as well. The zero arg - // to the function tells DynamicLibrary to load the program, not a library. - if (sys::DynamicLibrary::LoadLibraryPermanently(nullptr, ErrorStr)) - return nullptr; - - // If the user specified a memory manager but didn't specify which engine to - // create, we assume they only want the JIT, and we fail if they only want - // the interpreter. - if (MemMgr) { - if (WhichEngine & EngineKind::JIT) - WhichEngine = EngineKind::JIT; - else { - if (ErrorStr) - *ErrorStr = "Cannot create an interpreter with a memory manager."; - return nullptr; - } - } - - // Unless the interpreter was explicitly selected or the JIT is not linked, - // try making a JIT. - if ((WhichEngine & EngineKind::JIT) && TheTM) { - if (!TM->getTarget().hasJIT()) { - errs() << "WARNING: This target JIT is not designed for the host" - << " you are running. If bad things happen, please choose" - << " a different -march switch.\n"; - } - - ExecutionEngine *EE = nullptr; +// IR module verification is enabled by default in debug builds, and disabled +// by default in release builds. +#ifndef NDEBUG + VerifyModules = true; +#else + VerifyModules = false; +#endif +} + +EngineBuilder::~EngineBuilder() = default; + +EngineBuilder &EngineBuilder::setMCJITMemoryManager( + std::unique_ptr<RTDyldMemoryManager> mcjmm) { + auto SharedMM = std::shared_ptr<RTDyldMemoryManager>(std::move(mcjmm)); + MemMgr = SharedMM; + Resolver = SharedMM; + return *this; +} + +EngineBuilder& +EngineBuilder::setMemoryManager(std::unique_ptr<MCJITMemoryManager> MM) { + MemMgr = std::shared_ptr<MCJITMemoryManager>(std::move(MM)); + return *this; +} + +EngineBuilder & +EngineBuilder::setSymbolResolver(std::unique_ptr<LegacyJITSymbolResolver> SR) { + Resolver = std::shared_ptr<LegacyJITSymbolResolver>(std::move(SR)); + return *this; +} + +ExecutionEngine *EngineBuilder::create(TargetMachine *TM) { + std::unique_ptr<TargetMachine> TheTM(TM); // Take ownership. + + // Make sure we can resolve symbols in the program as well. The zero arg + // to the function tells DynamicLibrary to load the program, not a library. + if (sys::DynamicLibrary::LoadLibraryPermanently(nullptr, ErrorStr)) + return nullptr; + + // If the user specified a memory manager but didn't specify which engine to + // create, we assume they only want the JIT, and we fail if they only want + // the interpreter. + if (MemMgr) { + if (WhichEngine & EngineKind::JIT) + WhichEngine = EngineKind::JIT; + else { + if (ErrorStr) + *ErrorStr = "Cannot create an interpreter with a memory manager."; + return nullptr; + } + } + + // Unless the interpreter was explicitly selected or the JIT is not linked, + // try making a JIT. + if ((WhichEngine & EngineKind::JIT) && TheTM) { + if (!TM->getTarget().hasJIT()) { + errs() << "WARNING: This target JIT is not designed for the host" + << " you are running. If bad things happen, please choose" + << " a different -march switch.\n"; + } + + ExecutionEngine *EE = nullptr; if (ExecutionEngine::MCJITCtor) - EE = ExecutionEngine::MCJITCtor(std::move(M), ErrorStr, std::move(MemMgr), - std::move(Resolver), std::move(TheTM)); - - if (EE) { - EE->setVerifyModules(VerifyModules); - return EE; - } - } - - // If we can't make a JIT and we didn't request one specifically, try making - // an interpreter instead. - if (WhichEngine & EngineKind::Interpreter) { - if (ExecutionEngine::InterpCtor) - return ExecutionEngine::InterpCtor(std::move(M), ErrorStr); - if (ErrorStr) - *ErrorStr = "Interpreter has not been linked in."; - return nullptr; - } - - if ((WhichEngine & EngineKind::JIT) && !ExecutionEngine::MCJITCtor) { - if (ErrorStr) - *ErrorStr = "JIT has not been linked in."; - } - - return nullptr; -} - -void *ExecutionEngine::getPointerToGlobal(const GlobalValue *GV) { - if (Function *F = const_cast<Function*>(dyn_cast<Function>(GV))) - return getPointerToFunction(F); - - std::lock_guard<sys::Mutex> locked(lock); - if (void* P = getPointerToGlobalIfAvailable(GV)) - return P; - - // Global variable might have been added since interpreter started. - if (GlobalVariable *GVar = - const_cast<GlobalVariable *>(dyn_cast<GlobalVariable>(GV))) - emitGlobalVariable(GVar); - else - llvm_unreachable("Global hasn't had an address allocated yet!"); - - return getPointerToGlobalIfAvailable(GV); -} - -/// Converts a Constant* into a GenericValue, including handling of -/// ConstantExpr values. -GenericValue ExecutionEngine::getConstantValue(const Constant *C) { - // If its undefined, return the garbage. - if (isa<UndefValue>(C)) { - GenericValue Result; - switch (C->getType()->getTypeID()) { - default: - break; - case Type::IntegerTyID: - case Type::X86_FP80TyID: - case Type::FP128TyID: - case Type::PPC_FP128TyID: - // Although the value is undefined, we still have to construct an APInt - // with the correct bit width. - Result.IntVal = APInt(C->getType()->getPrimitiveSizeInBits(), 0); - break; - case Type::StructTyID: { - // if the whole struct is 'undef' just reserve memory for the value. - if(StructType *STy = dyn_cast<StructType>(C->getType())) { - unsigned int elemNum = STy->getNumElements(); - Result.AggregateVal.resize(elemNum); - for (unsigned int i = 0; i < elemNum; ++i) { - Type *ElemTy = STy->getElementType(i); - if (ElemTy->isIntegerTy()) - Result.AggregateVal[i].IntVal = - APInt(ElemTy->getPrimitiveSizeInBits(), 0); - else if (ElemTy->isAggregateType()) { - const Constant *ElemUndef = UndefValue::get(ElemTy); - Result.AggregateVal[i] = getConstantValue(ElemUndef); - } - } - } - } - break; - case Type::ScalableVectorTyID: - report_fatal_error( - "Scalable vector support not yet implemented in ExecutionEngine"); - case Type::FixedVectorTyID: - // if the whole vector is 'undef' just reserve memory for the value. - auto *VTy = cast<FixedVectorType>(C->getType()); - Type *ElemTy = VTy->getElementType(); - unsigned int elemNum = VTy->getNumElements(); - Result.AggregateVal.resize(elemNum); - if (ElemTy->isIntegerTy()) - for (unsigned int i = 0; i < elemNum; ++i) - Result.AggregateVal[i].IntVal = - APInt(ElemTy->getPrimitiveSizeInBits(), 0); - break; - } - return Result; - } - - // Otherwise, if the value is a ConstantExpr... - if (const ConstantExpr *CE = dyn_cast<ConstantExpr>(C)) { - Constant *Op0 = CE->getOperand(0); - switch (CE->getOpcode()) { - case Instruction::GetElementPtr: { - // Compute the index - GenericValue Result = getConstantValue(Op0); - APInt Offset(DL.getPointerSizeInBits(), 0); - cast<GEPOperator>(CE)->accumulateConstantOffset(DL, Offset); - - char* tmp = (char*) Result.PointerVal; - Result = PTOGV(tmp + Offset.getSExtValue()); - return Result; - } - case Instruction::Trunc: { - GenericValue GV = getConstantValue(Op0); - uint32_t BitWidth = cast<IntegerType>(CE->getType())->getBitWidth(); - GV.IntVal = GV.IntVal.trunc(BitWidth); - return GV; - } - case Instruction::ZExt: { - GenericValue GV = getConstantValue(Op0); - uint32_t BitWidth = cast<IntegerType>(CE->getType())->getBitWidth(); - GV.IntVal = GV.IntVal.zext(BitWidth); - return GV; - } - case Instruction::SExt: { - GenericValue GV = getConstantValue(Op0); - uint32_t BitWidth = cast<IntegerType>(CE->getType())->getBitWidth(); - GV.IntVal = GV.IntVal.sext(BitWidth); - return GV; - } - case Instruction::FPTrunc: { - // FIXME long double - GenericValue GV = getConstantValue(Op0); - GV.FloatVal = float(GV.DoubleVal); - return GV; - } - case Instruction::FPExt:{ - // FIXME long double - GenericValue GV = getConstantValue(Op0); - GV.DoubleVal = double(GV.FloatVal); - return GV; - } - case Instruction::UIToFP: { - GenericValue GV = getConstantValue(Op0); - if (CE->getType()->isFloatTy()) - GV.FloatVal = float(GV.IntVal.roundToDouble()); - else if (CE->getType()->isDoubleTy()) - GV.DoubleVal = GV.IntVal.roundToDouble(); - else if (CE->getType()->isX86_FP80Ty()) { - APFloat apf = APFloat::getZero(APFloat::x87DoubleExtended()); - (void)apf.convertFromAPInt(GV.IntVal, - false, - APFloat::rmNearestTiesToEven); - GV.IntVal = apf.bitcastToAPInt(); - } - return GV; - } - case Instruction::SIToFP: { - GenericValue GV = getConstantValue(Op0); - if (CE->getType()->isFloatTy()) - GV.FloatVal = float(GV.IntVal.signedRoundToDouble()); - else if (CE->getType()->isDoubleTy()) - GV.DoubleVal = GV.IntVal.signedRoundToDouble(); - else if (CE->getType()->isX86_FP80Ty()) { - APFloat apf = APFloat::getZero(APFloat::x87DoubleExtended()); - (void)apf.convertFromAPInt(GV.IntVal, - true, - APFloat::rmNearestTiesToEven); - GV.IntVal = apf.bitcastToAPInt(); - } - return GV; - } - case Instruction::FPToUI: // double->APInt conversion handles sign - case Instruction::FPToSI: { - GenericValue GV = getConstantValue(Op0); - uint32_t BitWidth = cast<IntegerType>(CE->getType())->getBitWidth(); - if (Op0->getType()->isFloatTy()) - GV.IntVal = APIntOps::RoundFloatToAPInt(GV.FloatVal, BitWidth); - else if (Op0->getType()->isDoubleTy()) - GV.IntVal = APIntOps::RoundDoubleToAPInt(GV.DoubleVal, BitWidth); - else if (Op0->getType()->isX86_FP80Ty()) { - APFloat apf = APFloat(APFloat::x87DoubleExtended(), GV.IntVal); - uint64_t v; - bool ignored; - (void)apf.convertToInteger(makeMutableArrayRef(v), BitWidth, - CE->getOpcode()==Instruction::FPToSI, - APFloat::rmTowardZero, &ignored); - GV.IntVal = v; // endian? - } - return GV; - } - case Instruction::PtrToInt: { - GenericValue GV = getConstantValue(Op0); - uint32_t PtrWidth = DL.getTypeSizeInBits(Op0->getType()); - assert(PtrWidth <= 64 && "Bad pointer width"); - GV.IntVal = APInt(PtrWidth, uintptr_t(GV.PointerVal)); - uint32_t IntWidth = DL.getTypeSizeInBits(CE->getType()); - GV.IntVal = GV.IntVal.zextOrTrunc(IntWidth); - return GV; - } - case Instruction::IntToPtr: { - GenericValue GV = getConstantValue(Op0); - uint32_t PtrWidth = DL.getTypeSizeInBits(CE->getType()); - GV.IntVal = GV.IntVal.zextOrTrunc(PtrWidth); - assert(GV.IntVal.getBitWidth() <= 64 && "Bad pointer width"); - GV.PointerVal = PointerTy(uintptr_t(GV.IntVal.getZExtValue())); - return GV; - } - case Instruction::BitCast: { - GenericValue GV = getConstantValue(Op0); - Type* DestTy = CE->getType(); - switch (Op0->getType()->getTypeID()) { - default: llvm_unreachable("Invalid bitcast operand"); - case Type::IntegerTyID: - assert(DestTy->isFloatingPointTy() && "invalid bitcast"); - if (DestTy->isFloatTy()) - GV.FloatVal = GV.IntVal.bitsToFloat(); - else if (DestTy->isDoubleTy()) - GV.DoubleVal = GV.IntVal.bitsToDouble(); - break; - case Type::FloatTyID: - assert(DestTy->isIntegerTy(32) && "Invalid bitcast"); - GV.IntVal = APInt::floatToBits(GV.FloatVal); - break; - case Type::DoubleTyID: - assert(DestTy->isIntegerTy(64) && "Invalid bitcast"); - GV.IntVal = APInt::doubleToBits(GV.DoubleVal); - break; - case Type::PointerTyID: - assert(DestTy->isPointerTy() && "Invalid bitcast"); - break; // getConstantValue(Op0) above already converted it - } - return GV; - } - case Instruction::Add: - case Instruction::FAdd: - case Instruction::Sub: - case Instruction::FSub: - case Instruction::Mul: - case Instruction::FMul: - case Instruction::UDiv: - case Instruction::SDiv: - case Instruction::URem: - case Instruction::SRem: - case Instruction::And: - case Instruction::Or: - case Instruction::Xor: { - GenericValue LHS = getConstantValue(Op0); - GenericValue RHS = getConstantValue(CE->getOperand(1)); - GenericValue GV; - switch (CE->getOperand(0)->getType()->getTypeID()) { - default: llvm_unreachable("Bad add type!"); - case Type::IntegerTyID: - switch (CE->getOpcode()) { - default: llvm_unreachable("Invalid integer opcode"); - case Instruction::Add: GV.IntVal = LHS.IntVal + RHS.IntVal; break; - case Instruction::Sub: GV.IntVal = LHS.IntVal - RHS.IntVal; break; - case Instruction::Mul: GV.IntVal = LHS.IntVal * RHS.IntVal; break; - case Instruction::UDiv:GV.IntVal = LHS.IntVal.udiv(RHS.IntVal); break; - case Instruction::SDiv:GV.IntVal = LHS.IntVal.sdiv(RHS.IntVal); break; - case Instruction::URem:GV.IntVal = LHS.IntVal.urem(RHS.IntVal); break; - case Instruction::SRem:GV.IntVal = LHS.IntVal.srem(RHS.IntVal); break; - case Instruction::And: GV.IntVal = LHS.IntVal & RHS.IntVal; break; - case Instruction::Or: GV.IntVal = LHS.IntVal | RHS.IntVal; break; - case Instruction::Xor: GV.IntVal = LHS.IntVal ^ RHS.IntVal; break; - } - break; - case Type::FloatTyID: - switch (CE->getOpcode()) { - default: llvm_unreachable("Invalid float opcode"); - case Instruction::FAdd: - GV.FloatVal = LHS.FloatVal + RHS.FloatVal; break; - case Instruction::FSub: - GV.FloatVal = LHS.FloatVal - RHS.FloatVal; break; - case Instruction::FMul: - GV.FloatVal = LHS.FloatVal * RHS.FloatVal; break; - case Instruction::FDiv: - GV.FloatVal = LHS.FloatVal / RHS.FloatVal; break; - case Instruction::FRem: - GV.FloatVal = std::fmod(LHS.FloatVal,RHS.FloatVal); break; - } - break; - case Type::DoubleTyID: - switch (CE->getOpcode()) { - default: llvm_unreachable("Invalid double opcode"); - case Instruction::FAdd: - GV.DoubleVal = LHS.DoubleVal + RHS.DoubleVal; break; - case Instruction::FSub: - GV.DoubleVal = LHS.DoubleVal - RHS.DoubleVal; break; - case Instruction::FMul: - GV.DoubleVal = LHS.DoubleVal * RHS.DoubleVal; break; - case Instruction::FDiv: - GV.DoubleVal = LHS.DoubleVal / RHS.DoubleVal; break; - case Instruction::FRem: - GV.DoubleVal = std::fmod(LHS.DoubleVal,RHS.DoubleVal); break; - } - break; - case Type::X86_FP80TyID: - case Type::PPC_FP128TyID: - case Type::FP128TyID: { - const fltSemantics &Sem = CE->getOperand(0)->getType()->getFltSemantics(); - APFloat apfLHS = APFloat(Sem, LHS.IntVal); - switch (CE->getOpcode()) { - default: llvm_unreachable("Invalid long double opcode"); - case Instruction::FAdd: - apfLHS.add(APFloat(Sem, RHS.IntVal), APFloat::rmNearestTiesToEven); - GV.IntVal = apfLHS.bitcastToAPInt(); - break; - case Instruction::FSub: - apfLHS.subtract(APFloat(Sem, RHS.IntVal), - APFloat::rmNearestTiesToEven); - GV.IntVal = apfLHS.bitcastToAPInt(); - break; - case Instruction::FMul: - apfLHS.multiply(APFloat(Sem, RHS.IntVal), - APFloat::rmNearestTiesToEven); - GV.IntVal = apfLHS.bitcastToAPInt(); - break; - case Instruction::FDiv: - apfLHS.divide(APFloat(Sem, RHS.IntVal), - APFloat::rmNearestTiesToEven); - GV.IntVal = apfLHS.bitcastToAPInt(); - break; - case Instruction::FRem: - apfLHS.mod(APFloat(Sem, RHS.IntVal)); - GV.IntVal = apfLHS.bitcastToAPInt(); - break; - } - } - break; - } - return GV; - } - default: - break; - } - - SmallString<256> Msg; - raw_svector_ostream OS(Msg); - OS << "ConstantExpr not handled: " << *CE; - report_fatal_error(OS.str()); - } - - // Otherwise, we have a simple constant. - GenericValue Result; - switch (C->getType()->getTypeID()) { - case Type::FloatTyID: - Result.FloatVal = cast<ConstantFP>(C)->getValueAPF().convertToFloat(); - break; - case Type::DoubleTyID: - Result.DoubleVal = cast<ConstantFP>(C)->getValueAPF().convertToDouble(); - break; - case Type::X86_FP80TyID: - case Type::FP128TyID: - case Type::PPC_FP128TyID: - Result.IntVal = cast <ConstantFP>(C)->getValueAPF().bitcastToAPInt(); - break; - case Type::IntegerTyID: - Result.IntVal = cast<ConstantInt>(C)->getValue(); - break; - case Type::PointerTyID: - while (auto *A = dyn_cast<GlobalAlias>(C)) { - C = A->getAliasee(); - } - if (isa<ConstantPointerNull>(C)) - Result.PointerVal = nullptr; - else if (const Function *F = dyn_cast<Function>(C)) - Result = PTOGV(getPointerToFunctionOrStub(const_cast<Function*>(F))); - else if (const GlobalVariable *GV = dyn_cast<GlobalVariable>(C)) - Result = PTOGV(getOrEmitGlobalVariable(const_cast<GlobalVariable*>(GV))); - else - llvm_unreachable("Unknown constant pointer type!"); - break; - case Type::ScalableVectorTyID: - report_fatal_error( - "Scalable vector support not yet implemented in ExecutionEngine"); - case Type::FixedVectorTyID: { - unsigned elemNum; - Type* ElemTy; - const ConstantDataVector *CDV = dyn_cast<ConstantDataVector>(C); - const ConstantVector *CV = dyn_cast<ConstantVector>(C); - const ConstantAggregateZero *CAZ = dyn_cast<ConstantAggregateZero>(C); - - if (CDV) { - elemNum = CDV->getNumElements(); - ElemTy = CDV->getElementType(); - } else if (CV || CAZ) { - auto *VTy = cast<FixedVectorType>(C->getType()); - elemNum = VTy->getNumElements(); - ElemTy = VTy->getElementType(); - } else { - llvm_unreachable("Unknown constant vector type!"); - } - - Result.AggregateVal.resize(elemNum); - // Check if vector holds floats. - if(ElemTy->isFloatTy()) { - if (CAZ) { - GenericValue floatZero; - floatZero.FloatVal = 0.f; - std::fill(Result.AggregateVal.begin(), Result.AggregateVal.end(), - floatZero); - break; - } - if(CV) { - for (unsigned i = 0; i < elemNum; ++i) - if (!isa<UndefValue>(CV->getOperand(i))) - Result.AggregateVal[i].FloatVal = cast<ConstantFP>( - CV->getOperand(i))->getValueAPF().convertToFloat(); - break; - } - if(CDV) - for (unsigned i = 0; i < elemNum; ++i) - Result.AggregateVal[i].FloatVal = CDV->getElementAsFloat(i); - - break; - } - // Check if vector holds doubles. - if (ElemTy->isDoubleTy()) { - if (CAZ) { - GenericValue doubleZero; - doubleZero.DoubleVal = 0.0; - std::fill(Result.AggregateVal.begin(), Result.AggregateVal.end(), - doubleZero); - break; - } - if(CV) { - for (unsigned i = 0; i < elemNum; ++i) - if (!isa<UndefValue>(CV->getOperand(i))) - Result.AggregateVal[i].DoubleVal = cast<ConstantFP>( - CV->getOperand(i))->getValueAPF().convertToDouble(); - break; - } - if(CDV) - for (unsigned i = 0; i < elemNum; ++i) - Result.AggregateVal[i].DoubleVal = CDV->getElementAsDouble(i); - - break; - } - // Check if vector holds integers. - if (ElemTy->isIntegerTy()) { - if (CAZ) { - GenericValue intZero; - intZero.IntVal = APInt(ElemTy->getScalarSizeInBits(), 0ull); - std::fill(Result.AggregateVal.begin(), Result.AggregateVal.end(), - intZero); - break; - } - if(CV) { - for (unsigned i = 0; i < elemNum; ++i) - if (!isa<UndefValue>(CV->getOperand(i))) - Result.AggregateVal[i].IntVal = cast<ConstantInt>( - CV->getOperand(i))->getValue(); - else { - Result.AggregateVal[i].IntVal = - APInt(CV->getOperand(i)->getType()->getPrimitiveSizeInBits(), 0); - } - break; - } - if(CDV) - for (unsigned i = 0; i < elemNum; ++i) - Result.AggregateVal[i].IntVal = APInt( - CDV->getElementType()->getPrimitiveSizeInBits(), - CDV->getElementAsInteger(i)); - - break; - } - llvm_unreachable("Unknown constant pointer type!"); - } break; - - default: - SmallString<256> Msg; - raw_svector_ostream OS(Msg); - OS << "ERROR: Constant unimplemented for type: " << *C->getType(); - report_fatal_error(OS.str()); - } - - return Result; -} - -void ExecutionEngine::StoreValueToMemory(const GenericValue &Val, - GenericValue *Ptr, Type *Ty) { - const unsigned StoreBytes = getDataLayout().getTypeStoreSize(Ty); - - switch (Ty->getTypeID()) { - default: - dbgs() << "Cannot store value of type " << *Ty << "!\n"; - break; - case Type::IntegerTyID: - StoreIntToMemory(Val.IntVal, (uint8_t*)Ptr, StoreBytes); - break; - case Type::FloatTyID: - *((float*)Ptr) = Val.FloatVal; - break; - case Type::DoubleTyID: - *((double*)Ptr) = Val.DoubleVal; - break; - case Type::X86_FP80TyID: - memcpy(Ptr, Val.IntVal.getRawData(), 10); - break; - case Type::PointerTyID: - // Ensure 64 bit target pointers are fully initialized on 32 bit hosts. - if (StoreBytes != sizeof(PointerTy)) - memset(&(Ptr->PointerVal), 0, StoreBytes); - - *((PointerTy*)Ptr) = Val.PointerVal; - break; - case Type::FixedVectorTyID: - case Type::ScalableVectorTyID: - for (unsigned i = 0; i < Val.AggregateVal.size(); ++i) { - if (cast<VectorType>(Ty)->getElementType()->isDoubleTy()) - *(((double*)Ptr)+i) = Val.AggregateVal[i].DoubleVal; - if (cast<VectorType>(Ty)->getElementType()->isFloatTy()) - *(((float*)Ptr)+i) = Val.AggregateVal[i].FloatVal; - if (cast<VectorType>(Ty)->getElementType()->isIntegerTy()) { - unsigned numOfBytes =(Val.AggregateVal[i].IntVal.getBitWidth()+7)/8; - StoreIntToMemory(Val.AggregateVal[i].IntVal, - (uint8_t*)Ptr + numOfBytes*i, numOfBytes); - } - } - break; - } - - if (sys::IsLittleEndianHost != getDataLayout().isLittleEndian()) - // Host and target are different endian - reverse the stored bytes. - std::reverse((uint8_t*)Ptr, StoreBytes + (uint8_t*)Ptr); -} - -/// FIXME: document -/// -void ExecutionEngine::LoadValueFromMemory(GenericValue &Result, - GenericValue *Ptr, - Type *Ty) { - const unsigned LoadBytes = getDataLayout().getTypeStoreSize(Ty); - - switch (Ty->getTypeID()) { - case Type::IntegerTyID: - // An APInt with all words initially zero. - Result.IntVal = APInt(cast<IntegerType>(Ty)->getBitWidth(), 0); - LoadIntFromMemory(Result.IntVal, (uint8_t*)Ptr, LoadBytes); - break; - case Type::FloatTyID: - Result.FloatVal = *((float*)Ptr); - break; - case Type::DoubleTyID: - Result.DoubleVal = *((double*)Ptr); - break; - case Type::PointerTyID: - Result.PointerVal = *((PointerTy*)Ptr); - break; - case Type::X86_FP80TyID: { - // This is endian dependent, but it will only work on x86 anyway. - // FIXME: Will not trap if loading a signaling NaN. - uint64_t y[2]; - memcpy(y, Ptr, 10); - Result.IntVal = APInt(80, y); - break; - } - case Type::ScalableVectorTyID: - report_fatal_error( - "Scalable vector support not yet implemented in ExecutionEngine"); - case Type::FixedVectorTyID: { - auto *VT = cast<FixedVectorType>(Ty); - Type *ElemT = VT->getElementType(); - const unsigned numElems = VT->getNumElements(); - if (ElemT->isFloatTy()) { - Result.AggregateVal.resize(numElems); - for (unsigned i = 0; i < numElems; ++i) - Result.AggregateVal[i].FloatVal = *((float*)Ptr+i); - } - if (ElemT->isDoubleTy()) { - Result.AggregateVal.resize(numElems); - for (unsigned i = 0; i < numElems; ++i) - Result.AggregateVal[i].DoubleVal = *((double*)Ptr+i); - } - if (ElemT->isIntegerTy()) { - GenericValue intZero; - const unsigned elemBitWidth = cast<IntegerType>(ElemT)->getBitWidth(); - intZero.IntVal = APInt(elemBitWidth, 0); - Result.AggregateVal.resize(numElems, intZero); - for (unsigned i = 0; i < numElems; ++i) - LoadIntFromMemory(Result.AggregateVal[i].IntVal, - (uint8_t*)Ptr+((elemBitWidth+7)/8)*i, (elemBitWidth+7)/8); - } - break; - } - default: - SmallString<256> Msg; - raw_svector_ostream OS(Msg); - OS << "Cannot load value of type " << *Ty << "!"; - report_fatal_error(OS.str()); - } -} - -void ExecutionEngine::InitializeMemory(const Constant *Init, void *Addr) { - LLVM_DEBUG(dbgs() << "JIT: Initializing " << Addr << " "); - LLVM_DEBUG(Init->dump()); - if (isa<UndefValue>(Init)) - return; - - if (const ConstantVector *CP = dyn_cast<ConstantVector>(Init)) { - unsigned ElementSize = - getDataLayout().getTypeAllocSize(CP->getType()->getElementType()); - for (unsigned i = 0, e = CP->getNumOperands(); i != e; ++i) - InitializeMemory(CP->getOperand(i), (char*)Addr+i*ElementSize); - return; - } - - if (isa<ConstantAggregateZero>(Init)) { - memset(Addr, 0, (size_t)getDataLayout().getTypeAllocSize(Init->getType())); - return; - } - - if (const ConstantArray *CPA = dyn_cast<ConstantArray>(Init)) { - unsigned ElementSize = - getDataLayout().getTypeAllocSize(CPA->getType()->getElementType()); - for (unsigned i = 0, e = CPA->getNumOperands(); i != e; ++i) - InitializeMemory(CPA->getOperand(i), (char*)Addr+i*ElementSize); - return; - } - - if (const ConstantStruct *CPS = dyn_cast<ConstantStruct>(Init)) { - const StructLayout *SL = - getDataLayout().getStructLayout(cast<StructType>(CPS->getType())); - for (unsigned i = 0, e = CPS->getNumOperands(); i != e; ++i) - InitializeMemory(CPS->getOperand(i), (char*)Addr+SL->getElementOffset(i)); - return; - } - - if (const ConstantDataSequential *CDS = - dyn_cast<ConstantDataSequential>(Init)) { - // CDS is already laid out in host memory order. - StringRef Data = CDS->getRawDataValues(); - memcpy(Addr, Data.data(), Data.size()); - return; - } - - if (Init->getType()->isFirstClassType()) { - GenericValue Val = getConstantValue(Init); - StoreValueToMemory(Val, (GenericValue*)Addr, Init->getType()); - return; - } - - LLVM_DEBUG(dbgs() << "Bad Type: " << *Init->getType() << "\n"); - llvm_unreachable("Unknown constant type to initialize memory with!"); -} - -/// EmitGlobals - Emit all of the global variables to memory, storing their -/// addresses into GlobalAddress. This must make sure to copy the contents of -/// their initializers into the memory. -void ExecutionEngine::emitGlobals() { - // Loop over all of the global variables in the program, allocating the memory - // to hold them. If there is more than one module, do a prepass over globals - // to figure out how the different modules should link together. - std::map<std::pair<std::string, Type*>, - const GlobalValue*> LinkedGlobalsMap; - - if (Modules.size() != 1) { - for (unsigned m = 0, e = Modules.size(); m != e; ++m) { - Module &M = *Modules[m]; - for (const auto &GV : M.globals()) { - if (GV.hasLocalLinkage() || GV.isDeclaration() || - GV.hasAppendingLinkage() || !GV.hasName()) - continue;// Ignore external globals and globals with internal linkage. - - const GlobalValue *&GVEntry = LinkedGlobalsMap[std::make_pair( - std::string(GV.getName()), GV.getType())]; - - // If this is the first time we've seen this global, it is the canonical - // version. - if (!GVEntry) { - GVEntry = &GV; - continue; - } - - // If the existing global is strong, never replace it. - if (GVEntry->hasExternalLinkage()) - continue; - - // Otherwise, we know it's linkonce/weak, replace it if this is a strong - // symbol. FIXME is this right for common? - if (GV.hasExternalLinkage() || GVEntry->hasExternalWeakLinkage()) - GVEntry = &GV; - } - } - } - - std::vector<const GlobalValue*> NonCanonicalGlobals; - for (unsigned m = 0, e = Modules.size(); m != e; ++m) { - Module &M = *Modules[m]; - for (const auto &GV : M.globals()) { - // In the multi-module case, see what this global maps to. - if (!LinkedGlobalsMap.empty()) { - if (const GlobalValue *GVEntry = LinkedGlobalsMap[std::make_pair( - std::string(GV.getName()), GV.getType())]) { - // If something else is the canonical global, ignore this one. - if (GVEntry != &GV) { - NonCanonicalGlobals.push_back(&GV); - continue; - } - } - } - - if (!GV.isDeclaration()) { - addGlobalMapping(&GV, getMemoryForGV(&GV)); - } else { - // External variable reference. Try to use the dynamic loader to - // get a pointer to it. - if (void *SymAddr = sys::DynamicLibrary::SearchForAddressOfSymbol( - std::string(GV.getName()))) - addGlobalMapping(&GV, SymAddr); - else { - report_fatal_error("Could not resolve external global address: " - +GV.getName()); - } - } - } - - // If there are multiple modules, map the non-canonical globals to their - // canonical location. - if (!NonCanonicalGlobals.empty()) { - for (unsigned i = 0, e = NonCanonicalGlobals.size(); i != e; ++i) { - const GlobalValue *GV = NonCanonicalGlobals[i]; - const GlobalValue *CGV = LinkedGlobalsMap[std::make_pair( - std::string(GV->getName()), GV->getType())]; - void *Ptr = getPointerToGlobalIfAvailable(CGV); - assert(Ptr && "Canonical global wasn't codegen'd!"); - addGlobalMapping(GV, Ptr); - } - } - - // Now that all of the globals are set up in memory, loop through them all - // and initialize their contents. - for (const auto &GV : M.globals()) { - if (!GV.isDeclaration()) { - if (!LinkedGlobalsMap.empty()) { - if (const GlobalValue *GVEntry = LinkedGlobalsMap[std::make_pair( - std::string(GV.getName()), GV.getType())]) - if (GVEntry != &GV) // Not the canonical variable. - continue; - } - emitGlobalVariable(&GV); - } - } - } -} - -// EmitGlobalVariable - This method emits the specified global variable to the -// address specified in GlobalAddresses, or allocates new memory if it's not -// already in the map. -void ExecutionEngine::emitGlobalVariable(const GlobalVariable *GV) { - void *GA = getPointerToGlobalIfAvailable(GV); - - if (!GA) { - // If it's not already specified, allocate memory for the global. - GA = getMemoryForGV(GV); - - // If we failed to allocate memory for this global, return. - if (!GA) return; - - addGlobalMapping(GV, GA); - } - - // Don't initialize if it's thread local, let the client do it. - if (!GV->isThreadLocal()) - InitializeMemory(GV->getInitializer(), GA); - - Type *ElTy = GV->getValueType(); - size_t GVSize = (size_t)getDataLayout().getTypeAllocSize(ElTy); - NumInitBytes += (unsigned)GVSize; - ++NumGlobals; -} + EE = ExecutionEngine::MCJITCtor(std::move(M), ErrorStr, std::move(MemMgr), + std::move(Resolver), std::move(TheTM)); + + if (EE) { + EE->setVerifyModules(VerifyModules); + return EE; + } + } + + // If we can't make a JIT and we didn't request one specifically, try making + // an interpreter instead. + if (WhichEngine & EngineKind::Interpreter) { + if (ExecutionEngine::InterpCtor) + return ExecutionEngine::InterpCtor(std::move(M), ErrorStr); + if (ErrorStr) + *ErrorStr = "Interpreter has not been linked in."; + return nullptr; + } + + if ((WhichEngine & EngineKind::JIT) && !ExecutionEngine::MCJITCtor) { + if (ErrorStr) + *ErrorStr = "JIT has not been linked in."; + } + + return nullptr; +} + +void *ExecutionEngine::getPointerToGlobal(const GlobalValue *GV) { + if (Function *F = const_cast<Function*>(dyn_cast<Function>(GV))) + return getPointerToFunction(F); + + std::lock_guard<sys::Mutex> locked(lock); + if (void* P = getPointerToGlobalIfAvailable(GV)) + return P; + + // Global variable might have been added since interpreter started. + if (GlobalVariable *GVar = + const_cast<GlobalVariable *>(dyn_cast<GlobalVariable>(GV))) + emitGlobalVariable(GVar); + else + llvm_unreachable("Global hasn't had an address allocated yet!"); + + return getPointerToGlobalIfAvailable(GV); +} + +/// Converts a Constant* into a GenericValue, including handling of +/// ConstantExpr values. +GenericValue ExecutionEngine::getConstantValue(const Constant *C) { + // If its undefined, return the garbage. + if (isa<UndefValue>(C)) { + GenericValue Result; + switch (C->getType()->getTypeID()) { + default: + break; + case Type::IntegerTyID: + case Type::X86_FP80TyID: + case Type::FP128TyID: + case Type::PPC_FP128TyID: + // Although the value is undefined, we still have to construct an APInt + // with the correct bit width. + Result.IntVal = APInt(C->getType()->getPrimitiveSizeInBits(), 0); + break; + case Type::StructTyID: { + // if the whole struct is 'undef' just reserve memory for the value. + if(StructType *STy = dyn_cast<StructType>(C->getType())) { + unsigned int elemNum = STy->getNumElements(); + Result.AggregateVal.resize(elemNum); + for (unsigned int i = 0; i < elemNum; ++i) { + Type *ElemTy = STy->getElementType(i); + if (ElemTy->isIntegerTy()) + Result.AggregateVal[i].IntVal = + APInt(ElemTy->getPrimitiveSizeInBits(), 0); + else if (ElemTy->isAggregateType()) { + const Constant *ElemUndef = UndefValue::get(ElemTy); + Result.AggregateVal[i] = getConstantValue(ElemUndef); + } + } + } + } + break; + case Type::ScalableVectorTyID: + report_fatal_error( + "Scalable vector support not yet implemented in ExecutionEngine"); + case Type::FixedVectorTyID: + // if the whole vector is 'undef' just reserve memory for the value. + auto *VTy = cast<FixedVectorType>(C->getType()); + Type *ElemTy = VTy->getElementType(); + unsigned int elemNum = VTy->getNumElements(); + Result.AggregateVal.resize(elemNum); + if (ElemTy->isIntegerTy()) + for (unsigned int i = 0; i < elemNum; ++i) + Result.AggregateVal[i].IntVal = + APInt(ElemTy->getPrimitiveSizeInBits(), 0); + break; + } + return Result; + } + + // Otherwise, if the value is a ConstantExpr... + if (const ConstantExpr *CE = dyn_cast<ConstantExpr>(C)) { + Constant *Op0 = CE->getOperand(0); + switch (CE->getOpcode()) { + case Instruction::GetElementPtr: { + // Compute the index + GenericValue Result = getConstantValue(Op0); + APInt Offset(DL.getPointerSizeInBits(), 0); + cast<GEPOperator>(CE)->accumulateConstantOffset(DL, Offset); + + char* tmp = (char*) Result.PointerVal; + Result = PTOGV(tmp + Offset.getSExtValue()); + return Result; + } + case Instruction::Trunc: { + GenericValue GV = getConstantValue(Op0); + uint32_t BitWidth = cast<IntegerType>(CE->getType())->getBitWidth(); + GV.IntVal = GV.IntVal.trunc(BitWidth); + return GV; + } + case Instruction::ZExt: { + GenericValue GV = getConstantValue(Op0); + uint32_t BitWidth = cast<IntegerType>(CE->getType())->getBitWidth(); + GV.IntVal = GV.IntVal.zext(BitWidth); + return GV; + } + case Instruction::SExt: { + GenericValue GV = getConstantValue(Op0); + uint32_t BitWidth = cast<IntegerType>(CE->getType())->getBitWidth(); + GV.IntVal = GV.IntVal.sext(BitWidth); + return GV; + } + case Instruction::FPTrunc: { + // FIXME long double + GenericValue GV = getConstantValue(Op0); + GV.FloatVal = float(GV.DoubleVal); + return GV; + } + case Instruction::FPExt:{ + // FIXME long double + GenericValue GV = getConstantValue(Op0); + GV.DoubleVal = double(GV.FloatVal); + return GV; + } + case Instruction::UIToFP: { + GenericValue GV = getConstantValue(Op0); + if (CE->getType()->isFloatTy()) + GV.FloatVal = float(GV.IntVal.roundToDouble()); + else if (CE->getType()->isDoubleTy()) + GV.DoubleVal = GV.IntVal.roundToDouble(); + else if (CE->getType()->isX86_FP80Ty()) { + APFloat apf = APFloat::getZero(APFloat::x87DoubleExtended()); + (void)apf.convertFromAPInt(GV.IntVal, + false, + APFloat::rmNearestTiesToEven); + GV.IntVal = apf.bitcastToAPInt(); + } + return GV; + } + case Instruction::SIToFP: { + GenericValue GV = getConstantValue(Op0); + if (CE->getType()->isFloatTy()) + GV.FloatVal = float(GV.IntVal.signedRoundToDouble()); + else if (CE->getType()->isDoubleTy()) + GV.DoubleVal = GV.IntVal.signedRoundToDouble(); + else if (CE->getType()->isX86_FP80Ty()) { + APFloat apf = APFloat::getZero(APFloat::x87DoubleExtended()); + (void)apf.convertFromAPInt(GV.IntVal, + true, + APFloat::rmNearestTiesToEven); + GV.IntVal = apf.bitcastToAPInt(); + } + return GV; + } + case Instruction::FPToUI: // double->APInt conversion handles sign + case Instruction::FPToSI: { + GenericValue GV = getConstantValue(Op0); + uint32_t BitWidth = cast<IntegerType>(CE->getType())->getBitWidth(); + if (Op0->getType()->isFloatTy()) + GV.IntVal = APIntOps::RoundFloatToAPInt(GV.FloatVal, BitWidth); + else if (Op0->getType()->isDoubleTy()) + GV.IntVal = APIntOps::RoundDoubleToAPInt(GV.DoubleVal, BitWidth); + else if (Op0->getType()->isX86_FP80Ty()) { + APFloat apf = APFloat(APFloat::x87DoubleExtended(), GV.IntVal); + uint64_t v; + bool ignored; + (void)apf.convertToInteger(makeMutableArrayRef(v), BitWidth, + CE->getOpcode()==Instruction::FPToSI, + APFloat::rmTowardZero, &ignored); + GV.IntVal = v; // endian? + } + return GV; + } + case Instruction::PtrToInt: { + GenericValue GV = getConstantValue(Op0); + uint32_t PtrWidth = DL.getTypeSizeInBits(Op0->getType()); + assert(PtrWidth <= 64 && "Bad pointer width"); + GV.IntVal = APInt(PtrWidth, uintptr_t(GV.PointerVal)); + uint32_t IntWidth = DL.getTypeSizeInBits(CE->getType()); + GV.IntVal = GV.IntVal.zextOrTrunc(IntWidth); + return GV; + } + case Instruction::IntToPtr: { + GenericValue GV = getConstantValue(Op0); + uint32_t PtrWidth = DL.getTypeSizeInBits(CE->getType()); + GV.IntVal = GV.IntVal.zextOrTrunc(PtrWidth); + assert(GV.IntVal.getBitWidth() <= 64 && "Bad pointer width"); + GV.PointerVal = PointerTy(uintptr_t(GV.IntVal.getZExtValue())); + return GV; + } + case Instruction::BitCast: { + GenericValue GV = getConstantValue(Op0); + Type* DestTy = CE->getType(); + switch (Op0->getType()->getTypeID()) { + default: llvm_unreachable("Invalid bitcast operand"); + case Type::IntegerTyID: + assert(DestTy->isFloatingPointTy() && "invalid bitcast"); + if (DestTy->isFloatTy()) + GV.FloatVal = GV.IntVal.bitsToFloat(); + else if (DestTy->isDoubleTy()) + GV.DoubleVal = GV.IntVal.bitsToDouble(); + break; + case Type::FloatTyID: + assert(DestTy->isIntegerTy(32) && "Invalid bitcast"); + GV.IntVal = APInt::floatToBits(GV.FloatVal); + break; + case Type::DoubleTyID: + assert(DestTy->isIntegerTy(64) && "Invalid bitcast"); + GV.IntVal = APInt::doubleToBits(GV.DoubleVal); + break; + case Type::PointerTyID: + assert(DestTy->isPointerTy() && "Invalid bitcast"); + break; // getConstantValue(Op0) above already converted it + } + return GV; + } + case Instruction::Add: + case Instruction::FAdd: + case Instruction::Sub: + case Instruction::FSub: + case Instruction::Mul: + case Instruction::FMul: + case Instruction::UDiv: + case Instruction::SDiv: + case Instruction::URem: + case Instruction::SRem: + case Instruction::And: + case Instruction::Or: + case Instruction::Xor: { + GenericValue LHS = getConstantValue(Op0); + GenericValue RHS = getConstantValue(CE->getOperand(1)); + GenericValue GV; + switch (CE->getOperand(0)->getType()->getTypeID()) { + default: llvm_unreachable("Bad add type!"); + case Type::IntegerTyID: + switch (CE->getOpcode()) { + default: llvm_unreachable("Invalid integer opcode"); + case Instruction::Add: GV.IntVal = LHS.IntVal + RHS.IntVal; break; + case Instruction::Sub: GV.IntVal = LHS.IntVal - RHS.IntVal; break; + case Instruction::Mul: GV.IntVal = LHS.IntVal * RHS.IntVal; break; + case Instruction::UDiv:GV.IntVal = LHS.IntVal.udiv(RHS.IntVal); break; + case Instruction::SDiv:GV.IntVal = LHS.IntVal.sdiv(RHS.IntVal); break; + case Instruction::URem:GV.IntVal = LHS.IntVal.urem(RHS.IntVal); break; + case Instruction::SRem:GV.IntVal = LHS.IntVal.srem(RHS.IntVal); break; + case Instruction::And: GV.IntVal = LHS.IntVal & RHS.IntVal; break; + case Instruction::Or: GV.IntVal = LHS.IntVal | RHS.IntVal; break; + case Instruction::Xor: GV.IntVal = LHS.IntVal ^ RHS.IntVal; break; + } + break; + case Type::FloatTyID: + switch (CE->getOpcode()) { + default: llvm_unreachable("Invalid float opcode"); + case Instruction::FAdd: + GV.FloatVal = LHS.FloatVal + RHS.FloatVal; break; + case Instruction::FSub: + GV.FloatVal = LHS.FloatVal - RHS.FloatVal; break; + case Instruction::FMul: + GV.FloatVal = LHS.FloatVal * RHS.FloatVal; break; + case Instruction::FDiv: + GV.FloatVal = LHS.FloatVal / RHS.FloatVal; break; + case Instruction::FRem: + GV.FloatVal = std::fmod(LHS.FloatVal,RHS.FloatVal); break; + } + break; + case Type::DoubleTyID: + switch (CE->getOpcode()) { + default: llvm_unreachable("Invalid double opcode"); + case Instruction::FAdd: + GV.DoubleVal = LHS.DoubleVal + RHS.DoubleVal; break; + case Instruction::FSub: + GV.DoubleVal = LHS.DoubleVal - RHS.DoubleVal; break; + case Instruction::FMul: + GV.DoubleVal = LHS.DoubleVal * RHS.DoubleVal; break; + case Instruction::FDiv: + GV.DoubleVal = LHS.DoubleVal / RHS.DoubleVal; break; + case Instruction::FRem: + GV.DoubleVal = std::fmod(LHS.DoubleVal,RHS.DoubleVal); break; + } + break; + case Type::X86_FP80TyID: + case Type::PPC_FP128TyID: + case Type::FP128TyID: { + const fltSemantics &Sem = CE->getOperand(0)->getType()->getFltSemantics(); + APFloat apfLHS = APFloat(Sem, LHS.IntVal); + switch (CE->getOpcode()) { + default: llvm_unreachable("Invalid long double opcode"); + case Instruction::FAdd: + apfLHS.add(APFloat(Sem, RHS.IntVal), APFloat::rmNearestTiesToEven); + GV.IntVal = apfLHS.bitcastToAPInt(); + break; + case Instruction::FSub: + apfLHS.subtract(APFloat(Sem, RHS.IntVal), + APFloat::rmNearestTiesToEven); + GV.IntVal = apfLHS.bitcastToAPInt(); + break; + case Instruction::FMul: + apfLHS.multiply(APFloat(Sem, RHS.IntVal), + APFloat::rmNearestTiesToEven); + GV.IntVal = apfLHS.bitcastToAPInt(); + break; + case Instruction::FDiv: + apfLHS.divide(APFloat(Sem, RHS.IntVal), + APFloat::rmNearestTiesToEven); + GV.IntVal = apfLHS.bitcastToAPInt(); + break; + case Instruction::FRem: + apfLHS.mod(APFloat(Sem, RHS.IntVal)); + GV.IntVal = apfLHS.bitcastToAPInt(); + break; + } + } + break; + } + return GV; + } + default: + break; + } + + SmallString<256> Msg; + raw_svector_ostream OS(Msg); + OS << "ConstantExpr not handled: " << *CE; + report_fatal_error(OS.str()); + } + + // Otherwise, we have a simple constant. + GenericValue Result; + switch (C->getType()->getTypeID()) { + case Type::FloatTyID: + Result.FloatVal = cast<ConstantFP>(C)->getValueAPF().convertToFloat(); + break; + case Type::DoubleTyID: + Result.DoubleVal = cast<ConstantFP>(C)->getValueAPF().convertToDouble(); + break; + case Type::X86_FP80TyID: + case Type::FP128TyID: + case Type::PPC_FP128TyID: + Result.IntVal = cast <ConstantFP>(C)->getValueAPF().bitcastToAPInt(); + break; + case Type::IntegerTyID: + Result.IntVal = cast<ConstantInt>(C)->getValue(); + break; + case Type::PointerTyID: + while (auto *A = dyn_cast<GlobalAlias>(C)) { + C = A->getAliasee(); + } + if (isa<ConstantPointerNull>(C)) + Result.PointerVal = nullptr; + else if (const Function *F = dyn_cast<Function>(C)) + Result = PTOGV(getPointerToFunctionOrStub(const_cast<Function*>(F))); + else if (const GlobalVariable *GV = dyn_cast<GlobalVariable>(C)) + Result = PTOGV(getOrEmitGlobalVariable(const_cast<GlobalVariable*>(GV))); + else + llvm_unreachable("Unknown constant pointer type!"); + break; + case Type::ScalableVectorTyID: + report_fatal_error( + "Scalable vector support not yet implemented in ExecutionEngine"); + case Type::FixedVectorTyID: { + unsigned elemNum; + Type* ElemTy; + const ConstantDataVector *CDV = dyn_cast<ConstantDataVector>(C); + const ConstantVector *CV = dyn_cast<ConstantVector>(C); + const ConstantAggregateZero *CAZ = dyn_cast<ConstantAggregateZero>(C); + + if (CDV) { + elemNum = CDV->getNumElements(); + ElemTy = CDV->getElementType(); + } else if (CV || CAZ) { + auto *VTy = cast<FixedVectorType>(C->getType()); + elemNum = VTy->getNumElements(); + ElemTy = VTy->getElementType(); + } else { + llvm_unreachable("Unknown constant vector type!"); + } + + Result.AggregateVal.resize(elemNum); + // Check if vector holds floats. + if(ElemTy->isFloatTy()) { + if (CAZ) { + GenericValue floatZero; + floatZero.FloatVal = 0.f; + std::fill(Result.AggregateVal.begin(), Result.AggregateVal.end(), + floatZero); + break; + } + if(CV) { + for (unsigned i = 0; i < elemNum; ++i) + if (!isa<UndefValue>(CV->getOperand(i))) + Result.AggregateVal[i].FloatVal = cast<ConstantFP>( + CV->getOperand(i))->getValueAPF().convertToFloat(); + break; + } + if(CDV) + for (unsigned i = 0; i < elemNum; ++i) + Result.AggregateVal[i].FloatVal = CDV->getElementAsFloat(i); + + break; + } + // Check if vector holds doubles. + if (ElemTy->isDoubleTy()) { + if (CAZ) { + GenericValue doubleZero; + doubleZero.DoubleVal = 0.0; + std::fill(Result.AggregateVal.begin(), Result.AggregateVal.end(), + doubleZero); + break; + } + if(CV) { + for (unsigned i = 0; i < elemNum; ++i) + if (!isa<UndefValue>(CV->getOperand(i))) + Result.AggregateVal[i].DoubleVal = cast<ConstantFP>( + CV->getOperand(i))->getValueAPF().convertToDouble(); + break; + } + if(CDV) + for (unsigned i = 0; i < elemNum; ++i) + Result.AggregateVal[i].DoubleVal = CDV->getElementAsDouble(i); + + break; + } + // Check if vector holds integers. + if (ElemTy->isIntegerTy()) { + if (CAZ) { + GenericValue intZero; + intZero.IntVal = APInt(ElemTy->getScalarSizeInBits(), 0ull); + std::fill(Result.AggregateVal.begin(), Result.AggregateVal.end(), + intZero); + break; + } + if(CV) { + for (unsigned i = 0; i < elemNum; ++i) + if (!isa<UndefValue>(CV->getOperand(i))) + Result.AggregateVal[i].IntVal = cast<ConstantInt>( + CV->getOperand(i))->getValue(); + else { + Result.AggregateVal[i].IntVal = + APInt(CV->getOperand(i)->getType()->getPrimitiveSizeInBits(), 0); + } + break; + } + if(CDV) + for (unsigned i = 0; i < elemNum; ++i) + Result.AggregateVal[i].IntVal = APInt( + CDV->getElementType()->getPrimitiveSizeInBits(), + CDV->getElementAsInteger(i)); + + break; + } + llvm_unreachable("Unknown constant pointer type!"); + } break; + + default: + SmallString<256> Msg; + raw_svector_ostream OS(Msg); + OS << "ERROR: Constant unimplemented for type: " << *C->getType(); + report_fatal_error(OS.str()); + } + + return Result; +} + +void ExecutionEngine::StoreValueToMemory(const GenericValue &Val, + GenericValue *Ptr, Type *Ty) { + const unsigned StoreBytes = getDataLayout().getTypeStoreSize(Ty); + + switch (Ty->getTypeID()) { + default: + dbgs() << "Cannot store value of type " << *Ty << "!\n"; + break; + case Type::IntegerTyID: + StoreIntToMemory(Val.IntVal, (uint8_t*)Ptr, StoreBytes); + break; + case Type::FloatTyID: + *((float*)Ptr) = Val.FloatVal; + break; + case Type::DoubleTyID: + *((double*)Ptr) = Val.DoubleVal; + break; + case Type::X86_FP80TyID: + memcpy(Ptr, Val.IntVal.getRawData(), 10); + break; + case Type::PointerTyID: + // Ensure 64 bit target pointers are fully initialized on 32 bit hosts. + if (StoreBytes != sizeof(PointerTy)) + memset(&(Ptr->PointerVal), 0, StoreBytes); + + *((PointerTy*)Ptr) = Val.PointerVal; + break; + case Type::FixedVectorTyID: + case Type::ScalableVectorTyID: + for (unsigned i = 0; i < Val.AggregateVal.size(); ++i) { + if (cast<VectorType>(Ty)->getElementType()->isDoubleTy()) + *(((double*)Ptr)+i) = Val.AggregateVal[i].DoubleVal; + if (cast<VectorType>(Ty)->getElementType()->isFloatTy()) + *(((float*)Ptr)+i) = Val.AggregateVal[i].FloatVal; + if (cast<VectorType>(Ty)->getElementType()->isIntegerTy()) { + unsigned numOfBytes =(Val.AggregateVal[i].IntVal.getBitWidth()+7)/8; + StoreIntToMemory(Val.AggregateVal[i].IntVal, + (uint8_t*)Ptr + numOfBytes*i, numOfBytes); + } + } + break; + } + + if (sys::IsLittleEndianHost != getDataLayout().isLittleEndian()) + // Host and target are different endian - reverse the stored bytes. + std::reverse((uint8_t*)Ptr, StoreBytes + (uint8_t*)Ptr); +} + +/// FIXME: document +/// +void ExecutionEngine::LoadValueFromMemory(GenericValue &Result, + GenericValue *Ptr, + Type *Ty) { + const unsigned LoadBytes = getDataLayout().getTypeStoreSize(Ty); + + switch (Ty->getTypeID()) { + case Type::IntegerTyID: + // An APInt with all words initially zero. + Result.IntVal = APInt(cast<IntegerType>(Ty)->getBitWidth(), 0); + LoadIntFromMemory(Result.IntVal, (uint8_t*)Ptr, LoadBytes); + break; + case Type::FloatTyID: + Result.FloatVal = *((float*)Ptr); + break; + case Type::DoubleTyID: + Result.DoubleVal = *((double*)Ptr); + break; + case Type::PointerTyID: + Result.PointerVal = *((PointerTy*)Ptr); + break; + case Type::X86_FP80TyID: { + // This is endian dependent, but it will only work on x86 anyway. + // FIXME: Will not trap if loading a signaling NaN. + uint64_t y[2]; + memcpy(y, Ptr, 10); + Result.IntVal = APInt(80, y); + break; + } + case Type::ScalableVectorTyID: + report_fatal_error( + "Scalable vector support not yet implemented in ExecutionEngine"); + case Type::FixedVectorTyID: { + auto *VT = cast<FixedVectorType>(Ty); + Type *ElemT = VT->getElementType(); + const unsigned numElems = VT->getNumElements(); + if (ElemT->isFloatTy()) { + Result.AggregateVal.resize(numElems); + for (unsigned i = 0; i < numElems; ++i) + Result.AggregateVal[i].FloatVal = *((float*)Ptr+i); + } + if (ElemT->isDoubleTy()) { + Result.AggregateVal.resize(numElems); + for (unsigned i = 0; i < numElems; ++i) + Result.AggregateVal[i].DoubleVal = *((double*)Ptr+i); + } + if (ElemT->isIntegerTy()) { + GenericValue intZero; + const unsigned elemBitWidth = cast<IntegerType>(ElemT)->getBitWidth(); + intZero.IntVal = APInt(elemBitWidth, 0); + Result.AggregateVal.resize(numElems, intZero); + for (unsigned i = 0; i < numElems; ++i) + LoadIntFromMemory(Result.AggregateVal[i].IntVal, + (uint8_t*)Ptr+((elemBitWidth+7)/8)*i, (elemBitWidth+7)/8); + } + break; + } + default: + SmallString<256> Msg; + raw_svector_ostream OS(Msg); + OS << "Cannot load value of type " << *Ty << "!"; + report_fatal_error(OS.str()); + } +} + +void ExecutionEngine::InitializeMemory(const Constant *Init, void *Addr) { + LLVM_DEBUG(dbgs() << "JIT: Initializing " << Addr << " "); + LLVM_DEBUG(Init->dump()); + if (isa<UndefValue>(Init)) + return; + + if (const ConstantVector *CP = dyn_cast<ConstantVector>(Init)) { + unsigned ElementSize = + getDataLayout().getTypeAllocSize(CP->getType()->getElementType()); + for (unsigned i = 0, e = CP->getNumOperands(); i != e; ++i) + InitializeMemory(CP->getOperand(i), (char*)Addr+i*ElementSize); + return; + } + + if (isa<ConstantAggregateZero>(Init)) { + memset(Addr, 0, (size_t)getDataLayout().getTypeAllocSize(Init->getType())); + return; + } + + if (const ConstantArray *CPA = dyn_cast<ConstantArray>(Init)) { + unsigned ElementSize = + getDataLayout().getTypeAllocSize(CPA->getType()->getElementType()); + for (unsigned i = 0, e = CPA->getNumOperands(); i != e; ++i) + InitializeMemory(CPA->getOperand(i), (char*)Addr+i*ElementSize); + return; + } + + if (const ConstantStruct *CPS = dyn_cast<ConstantStruct>(Init)) { + const StructLayout *SL = + getDataLayout().getStructLayout(cast<StructType>(CPS->getType())); + for (unsigned i = 0, e = CPS->getNumOperands(); i != e; ++i) + InitializeMemory(CPS->getOperand(i), (char*)Addr+SL->getElementOffset(i)); + return; + } + + if (const ConstantDataSequential *CDS = + dyn_cast<ConstantDataSequential>(Init)) { + // CDS is already laid out in host memory order. + StringRef Data = CDS->getRawDataValues(); + memcpy(Addr, Data.data(), Data.size()); + return; + } + + if (Init->getType()->isFirstClassType()) { + GenericValue Val = getConstantValue(Init); + StoreValueToMemory(Val, (GenericValue*)Addr, Init->getType()); + return; + } + + LLVM_DEBUG(dbgs() << "Bad Type: " << *Init->getType() << "\n"); + llvm_unreachable("Unknown constant type to initialize memory with!"); +} + +/// EmitGlobals - Emit all of the global variables to memory, storing their +/// addresses into GlobalAddress. This must make sure to copy the contents of +/// their initializers into the memory. +void ExecutionEngine::emitGlobals() { + // Loop over all of the global variables in the program, allocating the memory + // to hold them. If there is more than one module, do a prepass over globals + // to figure out how the different modules should link together. + std::map<std::pair<std::string, Type*>, + const GlobalValue*> LinkedGlobalsMap; + + if (Modules.size() != 1) { + for (unsigned m = 0, e = Modules.size(); m != e; ++m) { + Module &M = *Modules[m]; + for (const auto &GV : M.globals()) { + if (GV.hasLocalLinkage() || GV.isDeclaration() || + GV.hasAppendingLinkage() || !GV.hasName()) + continue;// Ignore external globals and globals with internal linkage. + + const GlobalValue *&GVEntry = LinkedGlobalsMap[std::make_pair( + std::string(GV.getName()), GV.getType())]; + + // If this is the first time we've seen this global, it is the canonical + // version. + if (!GVEntry) { + GVEntry = &GV; + continue; + } + + // If the existing global is strong, never replace it. + if (GVEntry->hasExternalLinkage()) + continue; + + // Otherwise, we know it's linkonce/weak, replace it if this is a strong + // symbol. FIXME is this right for common? + if (GV.hasExternalLinkage() || GVEntry->hasExternalWeakLinkage()) + GVEntry = &GV; + } + } + } + + std::vector<const GlobalValue*> NonCanonicalGlobals; + for (unsigned m = 0, e = Modules.size(); m != e; ++m) { + Module &M = *Modules[m]; + for (const auto &GV : M.globals()) { + // In the multi-module case, see what this global maps to. + if (!LinkedGlobalsMap.empty()) { + if (const GlobalValue *GVEntry = LinkedGlobalsMap[std::make_pair( + std::string(GV.getName()), GV.getType())]) { + // If something else is the canonical global, ignore this one. + if (GVEntry != &GV) { + NonCanonicalGlobals.push_back(&GV); + continue; + } + } + } + + if (!GV.isDeclaration()) { + addGlobalMapping(&GV, getMemoryForGV(&GV)); + } else { + // External variable reference. Try to use the dynamic loader to + // get a pointer to it. + if (void *SymAddr = sys::DynamicLibrary::SearchForAddressOfSymbol( + std::string(GV.getName()))) + addGlobalMapping(&GV, SymAddr); + else { + report_fatal_error("Could not resolve external global address: " + +GV.getName()); + } + } + } + + // If there are multiple modules, map the non-canonical globals to their + // canonical location. + if (!NonCanonicalGlobals.empty()) { + for (unsigned i = 0, e = NonCanonicalGlobals.size(); i != e; ++i) { + const GlobalValue *GV = NonCanonicalGlobals[i]; + const GlobalValue *CGV = LinkedGlobalsMap[std::make_pair( + std::string(GV->getName()), GV->getType())]; + void *Ptr = getPointerToGlobalIfAvailable(CGV); + assert(Ptr && "Canonical global wasn't codegen'd!"); + addGlobalMapping(GV, Ptr); + } + } + + // Now that all of the globals are set up in memory, loop through them all + // and initialize their contents. + for (const auto &GV : M.globals()) { + if (!GV.isDeclaration()) { + if (!LinkedGlobalsMap.empty()) { + if (const GlobalValue *GVEntry = LinkedGlobalsMap[std::make_pair( + std::string(GV.getName()), GV.getType())]) + if (GVEntry != &GV) // Not the canonical variable. + continue; + } + emitGlobalVariable(&GV); + } + } + } +} + +// EmitGlobalVariable - This method emits the specified global variable to the +// address specified in GlobalAddresses, or allocates new memory if it's not +// already in the map. +void ExecutionEngine::emitGlobalVariable(const GlobalVariable *GV) { + void *GA = getPointerToGlobalIfAvailable(GV); + + if (!GA) { + // If it's not already specified, allocate memory for the global. + GA = getMemoryForGV(GV); + + // If we failed to allocate memory for this global, return. + if (!GA) return; + + addGlobalMapping(GV, GA); + } + + // Don't initialize if it's thread local, let the client do it. + if (!GV->isThreadLocal()) + InitializeMemory(GV->getInitializer(), GA); + + Type *ElTy = GV->getValueType(); + size_t GVSize = (size_t)getDataLayout().getTypeAllocSize(ElTy); + NumInitBytes += (unsigned)GVSize; + ++NumGlobals; +} diff --git a/contrib/libs/llvm12/lib/ExecutionEngine/ExecutionEngineBindings.cpp b/contrib/libs/llvm12/lib/ExecutionEngine/ExecutionEngineBindings.cpp index 77171bfae4..addec6871f 100644 --- a/contrib/libs/llvm12/lib/ExecutionEngine/ExecutionEngineBindings.cpp +++ b/contrib/libs/llvm12/lib/ExecutionEngine/ExecutionEngineBindings.cpp @@ -1,448 +1,448 @@ -//===-- ExecutionEngineBindings.cpp - C bindings for EEs ------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file defines the C bindings for the ExecutionEngine library. -// -//===----------------------------------------------------------------------===// - -#include "llvm-c/ExecutionEngine.h" -#include "llvm/ExecutionEngine/ExecutionEngine.h" -#include "llvm/ExecutionEngine/GenericValue.h" -#include "llvm/ExecutionEngine/JITEventListener.h" -#include "llvm/ExecutionEngine/RTDyldMemoryManager.h" -#include "llvm/IR/DerivedTypes.h" -#include "llvm/IR/Module.h" -#include "llvm/Support/ErrorHandling.h" -#include "llvm/Target/CodeGenCWrappers.h" -#include "llvm/Target/TargetOptions.h" -#include <cstring> - -using namespace llvm; - -#define DEBUG_TYPE "jit" - -// Wrapping the C bindings types. -DEFINE_SIMPLE_CONVERSION_FUNCTIONS(GenericValue, LLVMGenericValueRef) - - -static LLVMTargetMachineRef wrap(const TargetMachine *P) { - return - reinterpret_cast<LLVMTargetMachineRef>(const_cast<TargetMachine*>(P)); -} - -/*===-- Operations on generic values --------------------------------------===*/ - -LLVMGenericValueRef LLVMCreateGenericValueOfInt(LLVMTypeRef Ty, - unsigned long long N, - LLVMBool IsSigned) { - GenericValue *GenVal = new GenericValue(); - GenVal->IntVal = APInt(unwrap<IntegerType>(Ty)->getBitWidth(), N, IsSigned); - return wrap(GenVal); -} - -LLVMGenericValueRef LLVMCreateGenericValueOfPointer(void *P) { - GenericValue *GenVal = new GenericValue(); - GenVal->PointerVal = P; - return wrap(GenVal); -} - -LLVMGenericValueRef LLVMCreateGenericValueOfFloat(LLVMTypeRef TyRef, double N) { - GenericValue *GenVal = new GenericValue(); - switch (unwrap(TyRef)->getTypeID()) { - case Type::FloatTyID: - GenVal->FloatVal = N; - break; - case Type::DoubleTyID: - GenVal->DoubleVal = N; - break; - default: - llvm_unreachable("LLVMGenericValueToFloat supports only float and double."); - } - return wrap(GenVal); -} - -unsigned LLVMGenericValueIntWidth(LLVMGenericValueRef GenValRef) { - return unwrap(GenValRef)->IntVal.getBitWidth(); -} - -unsigned long long LLVMGenericValueToInt(LLVMGenericValueRef GenValRef, - LLVMBool IsSigned) { - GenericValue *GenVal = unwrap(GenValRef); - if (IsSigned) - return GenVal->IntVal.getSExtValue(); - else - return GenVal->IntVal.getZExtValue(); -} - -void *LLVMGenericValueToPointer(LLVMGenericValueRef GenVal) { - return unwrap(GenVal)->PointerVal; -} - -double LLVMGenericValueToFloat(LLVMTypeRef TyRef, LLVMGenericValueRef GenVal) { - switch (unwrap(TyRef)->getTypeID()) { - case Type::FloatTyID: - return unwrap(GenVal)->FloatVal; - case Type::DoubleTyID: - return unwrap(GenVal)->DoubleVal; - default: - llvm_unreachable("LLVMGenericValueToFloat supports only float and double."); - } -} - -void LLVMDisposeGenericValue(LLVMGenericValueRef GenVal) { - delete unwrap(GenVal); -} - -/*===-- Operations on execution engines -----------------------------------===*/ - -LLVMBool LLVMCreateExecutionEngineForModule(LLVMExecutionEngineRef *OutEE, - LLVMModuleRef M, - char **OutError) { - std::string Error; - EngineBuilder builder(std::unique_ptr<Module>(unwrap(M))); - builder.setEngineKind(EngineKind::Either) - .setErrorStr(&Error); - if (ExecutionEngine *EE = builder.create()){ - *OutEE = wrap(EE); - return 0; - } - *OutError = strdup(Error.c_str()); - return 1; -} - -LLVMBool LLVMCreateInterpreterForModule(LLVMExecutionEngineRef *OutInterp, - LLVMModuleRef M, - char **OutError) { - std::string Error; - EngineBuilder builder(std::unique_ptr<Module>(unwrap(M))); - builder.setEngineKind(EngineKind::Interpreter) - .setErrorStr(&Error); - if (ExecutionEngine *Interp = builder.create()) { - *OutInterp = wrap(Interp); - return 0; - } - *OutError = strdup(Error.c_str()); - return 1; -} - -LLVMBool LLVMCreateJITCompilerForModule(LLVMExecutionEngineRef *OutJIT, - LLVMModuleRef M, - unsigned OptLevel, - char **OutError) { - std::string Error; - EngineBuilder builder(std::unique_ptr<Module>(unwrap(M))); - builder.setEngineKind(EngineKind::JIT) - .setErrorStr(&Error) - .setOptLevel((CodeGenOpt::Level)OptLevel); - if (ExecutionEngine *JIT = builder.create()) { - *OutJIT = wrap(JIT); - return 0; - } - *OutError = strdup(Error.c_str()); - return 1; -} - -void LLVMInitializeMCJITCompilerOptions(LLVMMCJITCompilerOptions *PassedOptions, - size_t SizeOfPassedOptions) { - LLVMMCJITCompilerOptions options; - memset(&options, 0, sizeof(options)); // Most fields are zero by default. - options.CodeModel = LLVMCodeModelJITDefault; - - memcpy(PassedOptions, &options, - std::min(sizeof(options), SizeOfPassedOptions)); -} - -LLVMBool LLVMCreateMCJITCompilerForModule( - LLVMExecutionEngineRef *OutJIT, LLVMModuleRef M, - LLVMMCJITCompilerOptions *PassedOptions, size_t SizeOfPassedOptions, - char **OutError) { - LLVMMCJITCompilerOptions options; - // If the user passed a larger sized options struct, then they were compiled - // against a newer LLVM. Tell them that something is wrong. - if (SizeOfPassedOptions > sizeof(options)) { - *OutError = strdup( - "Refusing to use options struct that is larger than my own; assuming " - "LLVM library mismatch."); - return 1; - } - - // Defend against the user having an old version of the API by ensuring that - // any fields they didn't see are cleared. We must defend against fields being - // set to the bitwise equivalent of zero, and assume that this means "do the - // default" as if that option hadn't been available. - LLVMInitializeMCJITCompilerOptions(&options, sizeof(options)); - memcpy(&options, PassedOptions, SizeOfPassedOptions); - - TargetOptions targetOptions; - targetOptions.EnableFastISel = options.EnableFastISel; - std::unique_ptr<Module> Mod(unwrap(M)); - - if (Mod) - // Set function attribute "frame-pointer" based on - // NoFramePointerElim. - for (auto &F : *Mod) { - auto Attrs = F.getAttributes(); - StringRef Value = options.NoFramePointerElim ? "all" : "none"; - Attrs = Attrs.addAttribute(F.getContext(), AttributeList::FunctionIndex, - "frame-pointer", Value); - F.setAttributes(Attrs); - } - - std::string Error; - EngineBuilder builder(std::move(Mod)); - builder.setEngineKind(EngineKind::JIT) - .setErrorStr(&Error) - .setOptLevel((CodeGenOpt::Level)options.OptLevel) - .setTargetOptions(targetOptions); - bool JIT; - if (Optional<CodeModel::Model> CM = unwrap(options.CodeModel, JIT)) - builder.setCodeModel(*CM); - if (options.MCJMM) - builder.setMCJITMemoryManager( - std::unique_ptr<RTDyldMemoryManager>(unwrap(options.MCJMM))); - if (ExecutionEngine *JIT = builder.create()) { - *OutJIT = wrap(JIT); - return 0; - } - *OutError = strdup(Error.c_str()); - return 1; -} - -void LLVMDisposeExecutionEngine(LLVMExecutionEngineRef EE) { - delete unwrap(EE); -} - -void LLVMRunStaticConstructors(LLVMExecutionEngineRef EE) { - unwrap(EE)->finalizeObject(); - unwrap(EE)->runStaticConstructorsDestructors(false); -} - -void LLVMRunStaticDestructors(LLVMExecutionEngineRef EE) { - unwrap(EE)->finalizeObject(); - unwrap(EE)->runStaticConstructorsDestructors(true); -} - -int LLVMRunFunctionAsMain(LLVMExecutionEngineRef EE, LLVMValueRef F, - unsigned ArgC, const char * const *ArgV, - const char * const *EnvP) { - unwrap(EE)->finalizeObject(); - - std::vector<std::string> ArgVec(ArgV, ArgV + ArgC); - return unwrap(EE)->runFunctionAsMain(unwrap<Function>(F), ArgVec, EnvP); -} - -LLVMGenericValueRef LLVMRunFunction(LLVMExecutionEngineRef EE, LLVMValueRef F, - unsigned NumArgs, - LLVMGenericValueRef *Args) { - unwrap(EE)->finalizeObject(); - - std::vector<GenericValue> ArgVec; - ArgVec.reserve(NumArgs); - for (unsigned I = 0; I != NumArgs; ++I) - ArgVec.push_back(*unwrap(Args[I])); - - GenericValue *Result = new GenericValue(); - *Result = unwrap(EE)->runFunction(unwrap<Function>(F), ArgVec); - return wrap(Result); -} - -void LLVMFreeMachineCodeForFunction(LLVMExecutionEngineRef EE, LLVMValueRef F) { -} - -void LLVMAddModule(LLVMExecutionEngineRef EE, LLVMModuleRef M){ - unwrap(EE)->addModule(std::unique_ptr<Module>(unwrap(M))); -} - -LLVMBool LLVMRemoveModule(LLVMExecutionEngineRef EE, LLVMModuleRef M, - LLVMModuleRef *OutMod, char **OutError) { - Module *Mod = unwrap(M); - unwrap(EE)->removeModule(Mod); - *OutMod = wrap(Mod); - return 0; -} - -LLVMBool LLVMFindFunction(LLVMExecutionEngineRef EE, const char *Name, - LLVMValueRef *OutFn) { - if (Function *F = unwrap(EE)->FindFunctionNamed(Name)) { - *OutFn = wrap(F); - return 0; - } - return 1; -} - -void *LLVMRecompileAndRelinkFunction(LLVMExecutionEngineRef EE, - LLVMValueRef Fn) { - return nullptr; -} - -LLVMTargetDataRef LLVMGetExecutionEngineTargetData(LLVMExecutionEngineRef EE) { - return wrap(&unwrap(EE)->getDataLayout()); -} - -LLVMTargetMachineRef -LLVMGetExecutionEngineTargetMachine(LLVMExecutionEngineRef EE) { - return wrap(unwrap(EE)->getTargetMachine()); -} - -void LLVMAddGlobalMapping(LLVMExecutionEngineRef EE, LLVMValueRef Global, - void* Addr) { - unwrap(EE)->addGlobalMapping(unwrap<GlobalValue>(Global), Addr); -} - -void *LLVMGetPointerToGlobal(LLVMExecutionEngineRef EE, LLVMValueRef Global) { - unwrap(EE)->finalizeObject(); - - return unwrap(EE)->getPointerToGlobal(unwrap<GlobalValue>(Global)); -} - -uint64_t LLVMGetGlobalValueAddress(LLVMExecutionEngineRef EE, const char *Name) { - return unwrap(EE)->getGlobalValueAddress(Name); -} - -uint64_t LLVMGetFunctionAddress(LLVMExecutionEngineRef EE, const char *Name) { - return unwrap(EE)->getFunctionAddress(Name); -} - -LLVMBool LLVMExecutionEngineGetErrMsg(LLVMExecutionEngineRef EE, - char **OutError) { - assert(OutError && "OutError must be non-null"); - auto *ExecEngine = unwrap(EE); - if (ExecEngine->hasError()) { - *OutError = strdup(ExecEngine->getErrorMessage().c_str()); - ExecEngine->clearErrorMessage(); - return true; - } - return false; -} - -/*===-- Operations on memory managers -------------------------------------===*/ - -namespace { - -struct SimpleBindingMMFunctions { - LLVMMemoryManagerAllocateCodeSectionCallback AllocateCodeSection; - LLVMMemoryManagerAllocateDataSectionCallback AllocateDataSection; - LLVMMemoryManagerFinalizeMemoryCallback FinalizeMemory; - LLVMMemoryManagerDestroyCallback Destroy; -}; - -class SimpleBindingMemoryManager : public RTDyldMemoryManager { -public: - SimpleBindingMemoryManager(const SimpleBindingMMFunctions& Functions, - void *Opaque); - ~SimpleBindingMemoryManager() override; - - uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment, - unsigned SectionID, - StringRef SectionName) override; - - uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment, - unsigned SectionID, StringRef SectionName, - bool isReadOnly) override; - - bool finalizeMemory(std::string *ErrMsg) override; - -private: - SimpleBindingMMFunctions Functions; - void *Opaque; -}; - -SimpleBindingMemoryManager::SimpleBindingMemoryManager( - const SimpleBindingMMFunctions& Functions, - void *Opaque) - : Functions(Functions), Opaque(Opaque) { - assert(Functions.AllocateCodeSection && - "No AllocateCodeSection function provided!"); - assert(Functions.AllocateDataSection && - "No AllocateDataSection function provided!"); - assert(Functions.FinalizeMemory && - "No FinalizeMemory function provided!"); - assert(Functions.Destroy && - "No Destroy function provided!"); -} - -SimpleBindingMemoryManager::~SimpleBindingMemoryManager() { - Functions.Destroy(Opaque); -} - -uint8_t *SimpleBindingMemoryManager::allocateCodeSection( - uintptr_t Size, unsigned Alignment, unsigned SectionID, - StringRef SectionName) { - return Functions.AllocateCodeSection(Opaque, Size, Alignment, SectionID, - SectionName.str().c_str()); -} - -uint8_t *SimpleBindingMemoryManager::allocateDataSection( - uintptr_t Size, unsigned Alignment, unsigned SectionID, - StringRef SectionName, bool isReadOnly) { - return Functions.AllocateDataSection(Opaque, Size, Alignment, SectionID, - SectionName.str().c_str(), - isReadOnly); -} - -bool SimpleBindingMemoryManager::finalizeMemory(std::string *ErrMsg) { - char *errMsgCString = nullptr; - bool result = Functions.FinalizeMemory(Opaque, &errMsgCString); - assert((result || !errMsgCString) && - "Did not expect an error message if FinalizeMemory succeeded"); - if (errMsgCString) { - if (ErrMsg) - *ErrMsg = errMsgCString; - free(errMsgCString); - } - return result; -} - -} // anonymous namespace - -LLVMMCJITMemoryManagerRef LLVMCreateSimpleMCJITMemoryManager( - void *Opaque, - LLVMMemoryManagerAllocateCodeSectionCallback AllocateCodeSection, - LLVMMemoryManagerAllocateDataSectionCallback AllocateDataSection, - LLVMMemoryManagerFinalizeMemoryCallback FinalizeMemory, - LLVMMemoryManagerDestroyCallback Destroy) { - - if (!AllocateCodeSection || !AllocateDataSection || !FinalizeMemory || - !Destroy) - return nullptr; - - SimpleBindingMMFunctions functions; - functions.AllocateCodeSection = AllocateCodeSection; - functions.AllocateDataSection = AllocateDataSection; - functions.FinalizeMemory = FinalizeMemory; - functions.Destroy = Destroy; - return wrap(new SimpleBindingMemoryManager(functions, Opaque)); -} - -void LLVMDisposeMCJITMemoryManager(LLVMMCJITMemoryManagerRef MM) { - delete unwrap(MM); -} - -/*===-- JIT Event Listener functions -------------------------------------===*/ - - -#if !LLVM_USE_INTEL_JITEVENTS -LLVMJITEventListenerRef LLVMCreateIntelJITEventListener(void) -{ - return nullptr; -} -#endif - -#if !LLVM_USE_OPROFILE -LLVMJITEventListenerRef LLVMCreateOProfileJITEventListener(void) -{ - return nullptr; -} -#endif - -#if !LLVM_USE_PERF -LLVMJITEventListenerRef LLVMCreatePerfJITEventListener(void) -{ - return nullptr; -} -#endif +//===-- ExecutionEngineBindings.cpp - C bindings for EEs ------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines the C bindings for the ExecutionEngine library. +// +//===----------------------------------------------------------------------===// + +#include "llvm-c/ExecutionEngine.h" +#include "llvm/ExecutionEngine/ExecutionEngine.h" +#include "llvm/ExecutionEngine/GenericValue.h" +#include "llvm/ExecutionEngine/JITEventListener.h" +#include "llvm/ExecutionEngine/RTDyldMemoryManager.h" +#include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/Module.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Target/CodeGenCWrappers.h" +#include "llvm/Target/TargetOptions.h" +#include <cstring> + +using namespace llvm; + +#define DEBUG_TYPE "jit" + +// Wrapping the C bindings types. +DEFINE_SIMPLE_CONVERSION_FUNCTIONS(GenericValue, LLVMGenericValueRef) + + +static LLVMTargetMachineRef wrap(const TargetMachine *P) { + return + reinterpret_cast<LLVMTargetMachineRef>(const_cast<TargetMachine*>(P)); +} + +/*===-- Operations on generic values --------------------------------------===*/ + +LLVMGenericValueRef LLVMCreateGenericValueOfInt(LLVMTypeRef Ty, + unsigned long long N, + LLVMBool IsSigned) { + GenericValue *GenVal = new GenericValue(); + GenVal->IntVal = APInt(unwrap<IntegerType>(Ty)->getBitWidth(), N, IsSigned); + return wrap(GenVal); +} + +LLVMGenericValueRef LLVMCreateGenericValueOfPointer(void *P) { + GenericValue *GenVal = new GenericValue(); + GenVal->PointerVal = P; + return wrap(GenVal); +} + +LLVMGenericValueRef LLVMCreateGenericValueOfFloat(LLVMTypeRef TyRef, double N) { + GenericValue *GenVal = new GenericValue(); + switch (unwrap(TyRef)->getTypeID()) { + case Type::FloatTyID: + GenVal->FloatVal = N; + break; + case Type::DoubleTyID: + GenVal->DoubleVal = N; + break; + default: + llvm_unreachable("LLVMGenericValueToFloat supports only float and double."); + } + return wrap(GenVal); +} + +unsigned LLVMGenericValueIntWidth(LLVMGenericValueRef GenValRef) { + return unwrap(GenValRef)->IntVal.getBitWidth(); +} + +unsigned long long LLVMGenericValueToInt(LLVMGenericValueRef GenValRef, + LLVMBool IsSigned) { + GenericValue *GenVal = unwrap(GenValRef); + if (IsSigned) + return GenVal->IntVal.getSExtValue(); + else + return GenVal->IntVal.getZExtValue(); +} + +void *LLVMGenericValueToPointer(LLVMGenericValueRef GenVal) { + return unwrap(GenVal)->PointerVal; +} + +double LLVMGenericValueToFloat(LLVMTypeRef TyRef, LLVMGenericValueRef GenVal) { + switch (unwrap(TyRef)->getTypeID()) { + case Type::FloatTyID: + return unwrap(GenVal)->FloatVal; + case Type::DoubleTyID: + return unwrap(GenVal)->DoubleVal; + default: + llvm_unreachable("LLVMGenericValueToFloat supports only float and double."); + } +} + +void LLVMDisposeGenericValue(LLVMGenericValueRef GenVal) { + delete unwrap(GenVal); +} + +/*===-- Operations on execution engines -----------------------------------===*/ + +LLVMBool LLVMCreateExecutionEngineForModule(LLVMExecutionEngineRef *OutEE, + LLVMModuleRef M, + char **OutError) { + std::string Error; + EngineBuilder builder(std::unique_ptr<Module>(unwrap(M))); + builder.setEngineKind(EngineKind::Either) + .setErrorStr(&Error); + if (ExecutionEngine *EE = builder.create()){ + *OutEE = wrap(EE); + return 0; + } + *OutError = strdup(Error.c_str()); + return 1; +} + +LLVMBool LLVMCreateInterpreterForModule(LLVMExecutionEngineRef *OutInterp, + LLVMModuleRef M, + char **OutError) { + std::string Error; + EngineBuilder builder(std::unique_ptr<Module>(unwrap(M))); + builder.setEngineKind(EngineKind::Interpreter) + .setErrorStr(&Error); + if (ExecutionEngine *Interp = builder.create()) { + *OutInterp = wrap(Interp); + return 0; + } + *OutError = strdup(Error.c_str()); + return 1; +} + +LLVMBool LLVMCreateJITCompilerForModule(LLVMExecutionEngineRef *OutJIT, + LLVMModuleRef M, + unsigned OptLevel, + char **OutError) { + std::string Error; + EngineBuilder builder(std::unique_ptr<Module>(unwrap(M))); + builder.setEngineKind(EngineKind::JIT) + .setErrorStr(&Error) + .setOptLevel((CodeGenOpt::Level)OptLevel); + if (ExecutionEngine *JIT = builder.create()) { + *OutJIT = wrap(JIT); + return 0; + } + *OutError = strdup(Error.c_str()); + return 1; +} + +void LLVMInitializeMCJITCompilerOptions(LLVMMCJITCompilerOptions *PassedOptions, + size_t SizeOfPassedOptions) { + LLVMMCJITCompilerOptions options; + memset(&options, 0, sizeof(options)); // Most fields are zero by default. + options.CodeModel = LLVMCodeModelJITDefault; + + memcpy(PassedOptions, &options, + std::min(sizeof(options), SizeOfPassedOptions)); +} + +LLVMBool LLVMCreateMCJITCompilerForModule( + LLVMExecutionEngineRef *OutJIT, LLVMModuleRef M, + LLVMMCJITCompilerOptions *PassedOptions, size_t SizeOfPassedOptions, + char **OutError) { + LLVMMCJITCompilerOptions options; + // If the user passed a larger sized options struct, then they were compiled + // against a newer LLVM. Tell them that something is wrong. + if (SizeOfPassedOptions > sizeof(options)) { + *OutError = strdup( + "Refusing to use options struct that is larger than my own; assuming " + "LLVM library mismatch."); + return 1; + } + + // Defend against the user having an old version of the API by ensuring that + // any fields they didn't see are cleared. We must defend against fields being + // set to the bitwise equivalent of zero, and assume that this means "do the + // default" as if that option hadn't been available. + LLVMInitializeMCJITCompilerOptions(&options, sizeof(options)); + memcpy(&options, PassedOptions, SizeOfPassedOptions); + + TargetOptions targetOptions; + targetOptions.EnableFastISel = options.EnableFastISel; + std::unique_ptr<Module> Mod(unwrap(M)); + + if (Mod) + // Set function attribute "frame-pointer" based on + // NoFramePointerElim. + for (auto &F : *Mod) { + auto Attrs = F.getAttributes(); + StringRef Value = options.NoFramePointerElim ? "all" : "none"; + Attrs = Attrs.addAttribute(F.getContext(), AttributeList::FunctionIndex, + "frame-pointer", Value); + F.setAttributes(Attrs); + } + + std::string Error; + EngineBuilder builder(std::move(Mod)); + builder.setEngineKind(EngineKind::JIT) + .setErrorStr(&Error) + .setOptLevel((CodeGenOpt::Level)options.OptLevel) + .setTargetOptions(targetOptions); + bool JIT; + if (Optional<CodeModel::Model> CM = unwrap(options.CodeModel, JIT)) + builder.setCodeModel(*CM); + if (options.MCJMM) + builder.setMCJITMemoryManager( + std::unique_ptr<RTDyldMemoryManager>(unwrap(options.MCJMM))); + if (ExecutionEngine *JIT = builder.create()) { + *OutJIT = wrap(JIT); + return 0; + } + *OutError = strdup(Error.c_str()); + return 1; +} + +void LLVMDisposeExecutionEngine(LLVMExecutionEngineRef EE) { + delete unwrap(EE); +} + +void LLVMRunStaticConstructors(LLVMExecutionEngineRef EE) { + unwrap(EE)->finalizeObject(); + unwrap(EE)->runStaticConstructorsDestructors(false); +} + +void LLVMRunStaticDestructors(LLVMExecutionEngineRef EE) { + unwrap(EE)->finalizeObject(); + unwrap(EE)->runStaticConstructorsDestructors(true); +} + +int LLVMRunFunctionAsMain(LLVMExecutionEngineRef EE, LLVMValueRef F, + unsigned ArgC, const char * const *ArgV, + const char * const *EnvP) { + unwrap(EE)->finalizeObject(); + + std::vector<std::string> ArgVec(ArgV, ArgV + ArgC); + return unwrap(EE)->runFunctionAsMain(unwrap<Function>(F), ArgVec, EnvP); +} + +LLVMGenericValueRef LLVMRunFunction(LLVMExecutionEngineRef EE, LLVMValueRef F, + unsigned NumArgs, + LLVMGenericValueRef *Args) { + unwrap(EE)->finalizeObject(); + + std::vector<GenericValue> ArgVec; + ArgVec.reserve(NumArgs); + for (unsigned I = 0; I != NumArgs; ++I) + ArgVec.push_back(*unwrap(Args[I])); + + GenericValue *Result = new GenericValue(); + *Result = unwrap(EE)->runFunction(unwrap<Function>(F), ArgVec); + return wrap(Result); +} + +void LLVMFreeMachineCodeForFunction(LLVMExecutionEngineRef EE, LLVMValueRef F) { +} + +void LLVMAddModule(LLVMExecutionEngineRef EE, LLVMModuleRef M){ + unwrap(EE)->addModule(std::unique_ptr<Module>(unwrap(M))); +} + +LLVMBool LLVMRemoveModule(LLVMExecutionEngineRef EE, LLVMModuleRef M, + LLVMModuleRef *OutMod, char **OutError) { + Module *Mod = unwrap(M); + unwrap(EE)->removeModule(Mod); + *OutMod = wrap(Mod); + return 0; +} + +LLVMBool LLVMFindFunction(LLVMExecutionEngineRef EE, const char *Name, + LLVMValueRef *OutFn) { + if (Function *F = unwrap(EE)->FindFunctionNamed(Name)) { + *OutFn = wrap(F); + return 0; + } + return 1; +} + +void *LLVMRecompileAndRelinkFunction(LLVMExecutionEngineRef EE, + LLVMValueRef Fn) { + return nullptr; +} + +LLVMTargetDataRef LLVMGetExecutionEngineTargetData(LLVMExecutionEngineRef EE) { + return wrap(&unwrap(EE)->getDataLayout()); +} + +LLVMTargetMachineRef +LLVMGetExecutionEngineTargetMachine(LLVMExecutionEngineRef EE) { + return wrap(unwrap(EE)->getTargetMachine()); +} + +void LLVMAddGlobalMapping(LLVMExecutionEngineRef EE, LLVMValueRef Global, + void* Addr) { + unwrap(EE)->addGlobalMapping(unwrap<GlobalValue>(Global), Addr); +} + +void *LLVMGetPointerToGlobal(LLVMExecutionEngineRef EE, LLVMValueRef Global) { + unwrap(EE)->finalizeObject(); + + return unwrap(EE)->getPointerToGlobal(unwrap<GlobalValue>(Global)); +} + +uint64_t LLVMGetGlobalValueAddress(LLVMExecutionEngineRef EE, const char *Name) { + return unwrap(EE)->getGlobalValueAddress(Name); +} + +uint64_t LLVMGetFunctionAddress(LLVMExecutionEngineRef EE, const char *Name) { + return unwrap(EE)->getFunctionAddress(Name); +} + +LLVMBool LLVMExecutionEngineGetErrMsg(LLVMExecutionEngineRef EE, + char **OutError) { + assert(OutError && "OutError must be non-null"); + auto *ExecEngine = unwrap(EE); + if (ExecEngine->hasError()) { + *OutError = strdup(ExecEngine->getErrorMessage().c_str()); + ExecEngine->clearErrorMessage(); + return true; + } + return false; +} + +/*===-- Operations on memory managers -------------------------------------===*/ + +namespace { + +struct SimpleBindingMMFunctions { + LLVMMemoryManagerAllocateCodeSectionCallback AllocateCodeSection; + LLVMMemoryManagerAllocateDataSectionCallback AllocateDataSection; + LLVMMemoryManagerFinalizeMemoryCallback FinalizeMemory; + LLVMMemoryManagerDestroyCallback Destroy; +}; + +class SimpleBindingMemoryManager : public RTDyldMemoryManager { +public: + SimpleBindingMemoryManager(const SimpleBindingMMFunctions& Functions, + void *Opaque); + ~SimpleBindingMemoryManager() override; + + uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment, + unsigned SectionID, + StringRef SectionName) override; + + uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment, + unsigned SectionID, StringRef SectionName, + bool isReadOnly) override; + + bool finalizeMemory(std::string *ErrMsg) override; + +private: + SimpleBindingMMFunctions Functions; + void *Opaque; +}; + +SimpleBindingMemoryManager::SimpleBindingMemoryManager( + const SimpleBindingMMFunctions& Functions, + void *Opaque) + : Functions(Functions), Opaque(Opaque) { + assert(Functions.AllocateCodeSection && + "No AllocateCodeSection function provided!"); + assert(Functions.AllocateDataSection && + "No AllocateDataSection function provided!"); + assert(Functions.FinalizeMemory && + "No FinalizeMemory function provided!"); + assert(Functions.Destroy && + "No Destroy function provided!"); +} + +SimpleBindingMemoryManager::~SimpleBindingMemoryManager() { + Functions.Destroy(Opaque); +} + +uint8_t *SimpleBindingMemoryManager::allocateCodeSection( + uintptr_t Size, unsigned Alignment, unsigned SectionID, + StringRef SectionName) { + return Functions.AllocateCodeSection(Opaque, Size, Alignment, SectionID, + SectionName.str().c_str()); +} + +uint8_t *SimpleBindingMemoryManager::allocateDataSection( + uintptr_t Size, unsigned Alignment, unsigned SectionID, + StringRef SectionName, bool isReadOnly) { + return Functions.AllocateDataSection(Opaque, Size, Alignment, SectionID, + SectionName.str().c_str(), + isReadOnly); +} + +bool SimpleBindingMemoryManager::finalizeMemory(std::string *ErrMsg) { + char *errMsgCString = nullptr; + bool result = Functions.FinalizeMemory(Opaque, &errMsgCString); + assert((result || !errMsgCString) && + "Did not expect an error message if FinalizeMemory succeeded"); + if (errMsgCString) { + if (ErrMsg) + *ErrMsg = errMsgCString; + free(errMsgCString); + } + return result; +} + +} // anonymous namespace + +LLVMMCJITMemoryManagerRef LLVMCreateSimpleMCJITMemoryManager( + void *Opaque, + LLVMMemoryManagerAllocateCodeSectionCallback AllocateCodeSection, + LLVMMemoryManagerAllocateDataSectionCallback AllocateDataSection, + LLVMMemoryManagerFinalizeMemoryCallback FinalizeMemory, + LLVMMemoryManagerDestroyCallback Destroy) { + + if (!AllocateCodeSection || !AllocateDataSection || !FinalizeMemory || + !Destroy) + return nullptr; + + SimpleBindingMMFunctions functions; + functions.AllocateCodeSection = AllocateCodeSection; + functions.AllocateDataSection = AllocateDataSection; + functions.FinalizeMemory = FinalizeMemory; + functions.Destroy = Destroy; + return wrap(new SimpleBindingMemoryManager(functions, Opaque)); +} + +void LLVMDisposeMCJITMemoryManager(LLVMMCJITMemoryManagerRef MM) { + delete unwrap(MM); +} + +/*===-- JIT Event Listener functions -------------------------------------===*/ + + +#if !LLVM_USE_INTEL_JITEVENTS +LLVMJITEventListenerRef LLVMCreateIntelJITEventListener(void) +{ + return nullptr; +} +#endif + +#if !LLVM_USE_OPROFILE +LLVMJITEventListenerRef LLVMCreateOProfileJITEventListener(void) +{ + return nullptr; +} +#endif + +#if !LLVM_USE_PERF +LLVMJITEventListenerRef LLVMCreatePerfJITEventListener(void) +{ + return nullptr; +} +#endif diff --git a/contrib/libs/llvm12/lib/ExecutionEngine/GDBRegistrationListener.cpp b/contrib/libs/llvm12/lib/ExecutionEngine/GDBRegistrationListener.cpp index 77853c767d..7ed025fbb4 100644 --- a/contrib/libs/llvm12/lib/ExecutionEngine/GDBRegistrationListener.cpp +++ b/contrib/libs/llvm12/lib/ExecutionEngine/GDBRegistrationListener.cpp @@ -1,238 +1,238 @@ -//===----- GDBRegistrationListener.cpp - Registers objects with GDB -------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm-c/ExecutionEngine.h" -#include "llvm/ADT/DenseMap.h" -#include "llvm/ExecutionEngine/JITEventListener.h" -#include "llvm/Object/ObjectFile.h" -#include "llvm/Support/Compiler.h" -#include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/ManagedStatic.h" -#include "llvm/Support/Mutex.h" -#include <mutex> - -using namespace llvm; -using namespace llvm::object; - -// This must be kept in sync with gdb/gdb/jit.h . -extern "C" { - - typedef enum { - JIT_NOACTION = 0, - JIT_REGISTER_FN, - JIT_UNREGISTER_FN - } jit_actions_t; - - struct jit_code_entry { - struct jit_code_entry *next_entry; - struct jit_code_entry *prev_entry; - const char *symfile_addr; - uint64_t symfile_size; - }; - - struct jit_descriptor { - uint32_t version; - // This should be jit_actions_t, but we want to be specific about the - // bit-width. - uint32_t action_flag; - struct jit_code_entry *relevant_entry; - struct jit_code_entry *first_entry; - }; - - // We put information about the JITed function in this global, which the - // debugger reads. Make sure to specify the version statically, because the - // debugger checks the version before we can set it during runtime. - struct jit_descriptor __jit_debug_descriptor = { 1, 0, nullptr, nullptr }; - - // Debuggers puts a breakpoint in this function. - LLVM_ATTRIBUTE_NOINLINE void __jit_debug_register_code() { - // The noinline and the asm prevent calls to this function from being - // optimized out. -#if !defined(_MSC_VER) - asm volatile("":::"memory"); -#endif - } - -} - -namespace { - -struct RegisteredObjectInfo { - RegisteredObjectInfo() {} - - RegisteredObjectInfo(std::size_t Size, jit_code_entry *Entry, - OwningBinary<ObjectFile> Obj) - : Size(Size), Entry(Entry), Obj(std::move(Obj)) {} - - std::size_t Size; - jit_code_entry *Entry; - OwningBinary<ObjectFile> Obj; -}; - -// Buffer for an in-memory object file in executable memory -typedef llvm::DenseMap<JITEventListener::ObjectKey, RegisteredObjectInfo> - RegisteredObjectBufferMap; - -/// Global access point for the JIT debugging interface designed for use with a -/// singleton toolbox. Handles thread-safe registration and deregistration of -/// object files that are in executable memory managed by the client of this -/// class. -class GDBJITRegistrationListener : public JITEventListener { - /// A map of in-memory object files that have been registered with the - /// JIT interface. - RegisteredObjectBufferMap ObjectBufferMap; - -public: - /// Instantiates the JIT service. - GDBJITRegistrationListener() : ObjectBufferMap() {} - - /// Unregisters each object that was previously registered and releases all - /// internal resources. - ~GDBJITRegistrationListener() override; - - /// Creates an entry in the JIT registry for the buffer @p Object, - /// which must contain an object file in executable memory with any - /// debug information for the debugger. - void notifyObjectLoaded(ObjectKey K, const ObjectFile &Obj, - const RuntimeDyld::LoadedObjectInfo &L) override; - - /// Removes the internal registration of @p Object, and - /// frees associated resources. - /// Returns true if @p Object was found in ObjectBufferMap. - void notifyFreeingObject(ObjectKey K) override; - -private: - /// Deregister the debug info for the given object file from the debugger - /// and delete any temporary copies. This private method does not remove - /// the function from Map so that it can be called while iterating over Map. - void deregisterObjectInternal(RegisteredObjectBufferMap::iterator I); -}; - -/// Lock used to serialize all jit registration events, since they -/// modify global variables. -ManagedStatic<sys::Mutex> JITDebugLock; - -/// Do the registration. -void NotifyDebugger(jit_code_entry* JITCodeEntry) { - __jit_debug_descriptor.action_flag = JIT_REGISTER_FN; - - // Insert this entry at the head of the list. - JITCodeEntry->prev_entry = nullptr; - jit_code_entry* NextEntry = __jit_debug_descriptor.first_entry; - JITCodeEntry->next_entry = NextEntry; - if (NextEntry) { - NextEntry->prev_entry = JITCodeEntry; - } - __jit_debug_descriptor.first_entry = JITCodeEntry; - __jit_debug_descriptor.relevant_entry = JITCodeEntry; - __jit_debug_register_code(); -} - -GDBJITRegistrationListener::~GDBJITRegistrationListener() { - // Free all registered object files. - std::lock_guard<llvm::sys::Mutex> locked(*JITDebugLock); - for (RegisteredObjectBufferMap::iterator I = ObjectBufferMap.begin(), - E = ObjectBufferMap.end(); - I != E; ++I) { - // Call the private method that doesn't update the map so our iterator - // doesn't break. - deregisterObjectInternal(I); - } - ObjectBufferMap.clear(); -} - -void GDBJITRegistrationListener::notifyObjectLoaded( - ObjectKey K, const ObjectFile &Obj, - const RuntimeDyld::LoadedObjectInfo &L) { - - OwningBinary<ObjectFile> DebugObj = L.getObjectForDebug(Obj); - - // Bail out if debug objects aren't supported. - if (!DebugObj.getBinary()) - return; - - const char *Buffer = DebugObj.getBinary()->getMemoryBufferRef().getBufferStart(); - size_t Size = DebugObj.getBinary()->getMemoryBufferRef().getBufferSize(); - - std::lock_guard<llvm::sys::Mutex> locked(*JITDebugLock); - assert(ObjectBufferMap.find(K) == ObjectBufferMap.end() && - "Second attempt to perform debug registration."); - jit_code_entry* JITCodeEntry = new jit_code_entry(); - - if (!JITCodeEntry) { - llvm::report_fatal_error( - "Allocation failed when registering a JIT entry!\n"); - } else { - JITCodeEntry->symfile_addr = Buffer; - JITCodeEntry->symfile_size = Size; - - ObjectBufferMap[K] = - RegisteredObjectInfo(Size, JITCodeEntry, std::move(DebugObj)); - NotifyDebugger(JITCodeEntry); - } -} - -void GDBJITRegistrationListener::notifyFreeingObject(ObjectKey K) { - std::lock_guard<llvm::sys::Mutex> locked(*JITDebugLock); - RegisteredObjectBufferMap::iterator I = ObjectBufferMap.find(K); - - if (I != ObjectBufferMap.end()) { - deregisterObjectInternal(I); - ObjectBufferMap.erase(I); - } -} - -void GDBJITRegistrationListener::deregisterObjectInternal( - RegisteredObjectBufferMap::iterator I) { - - jit_code_entry*& JITCodeEntry = I->second.Entry; - - // Do the unregistration. - { - __jit_debug_descriptor.action_flag = JIT_UNREGISTER_FN; - - // Remove the jit_code_entry from the linked list. - jit_code_entry* PrevEntry = JITCodeEntry->prev_entry; - jit_code_entry* NextEntry = JITCodeEntry->next_entry; - - if (NextEntry) { - NextEntry->prev_entry = PrevEntry; - } - if (PrevEntry) { - PrevEntry->next_entry = NextEntry; - } - else { - assert(__jit_debug_descriptor.first_entry == JITCodeEntry); - __jit_debug_descriptor.first_entry = NextEntry; - } - - // Tell the debugger which entry we removed, and unregister the code. - __jit_debug_descriptor.relevant_entry = JITCodeEntry; - __jit_debug_register_code(); - } - - delete JITCodeEntry; - JITCodeEntry = nullptr; -} - -llvm::ManagedStatic<GDBJITRegistrationListener> GDBRegListener; - -} // end namespace - -namespace llvm { - -JITEventListener* JITEventListener::createGDBRegistrationListener() { - return &*GDBRegListener; -} - -} // namespace llvm - -LLVMJITEventListenerRef LLVMCreateGDBRegistrationListener(void) -{ - return wrap(JITEventListener::createGDBRegistrationListener()); -} +//===----- GDBRegistrationListener.cpp - Registers objects with GDB -------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm-c/ExecutionEngine.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ExecutionEngine/JITEventListener.h" +#include "llvm/Object/ObjectFile.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/ManagedStatic.h" +#include "llvm/Support/Mutex.h" +#include <mutex> + +using namespace llvm; +using namespace llvm::object; + +// This must be kept in sync with gdb/gdb/jit.h . +extern "C" { + + typedef enum { + JIT_NOACTION = 0, + JIT_REGISTER_FN, + JIT_UNREGISTER_FN + } jit_actions_t; + + struct jit_code_entry { + struct jit_code_entry *next_entry; + struct jit_code_entry *prev_entry; + const char *symfile_addr; + uint64_t symfile_size; + }; + + struct jit_descriptor { + uint32_t version; + // This should be jit_actions_t, but we want to be specific about the + // bit-width. + uint32_t action_flag; + struct jit_code_entry *relevant_entry; + struct jit_code_entry *first_entry; + }; + + // We put information about the JITed function in this global, which the + // debugger reads. Make sure to specify the version statically, because the + // debugger checks the version before we can set it during runtime. + struct jit_descriptor __jit_debug_descriptor = { 1, 0, nullptr, nullptr }; + + // Debuggers puts a breakpoint in this function. + LLVM_ATTRIBUTE_NOINLINE void __jit_debug_register_code() { + // The noinline and the asm prevent calls to this function from being + // optimized out. +#if !defined(_MSC_VER) + asm volatile("":::"memory"); +#endif + } + +} + +namespace { + +struct RegisteredObjectInfo { + RegisteredObjectInfo() {} + + RegisteredObjectInfo(std::size_t Size, jit_code_entry *Entry, + OwningBinary<ObjectFile> Obj) + : Size(Size), Entry(Entry), Obj(std::move(Obj)) {} + + std::size_t Size; + jit_code_entry *Entry; + OwningBinary<ObjectFile> Obj; +}; + +// Buffer for an in-memory object file in executable memory +typedef llvm::DenseMap<JITEventListener::ObjectKey, RegisteredObjectInfo> + RegisteredObjectBufferMap; + +/// Global access point for the JIT debugging interface designed for use with a +/// singleton toolbox. Handles thread-safe registration and deregistration of +/// object files that are in executable memory managed by the client of this +/// class. +class GDBJITRegistrationListener : public JITEventListener { + /// A map of in-memory object files that have been registered with the + /// JIT interface. + RegisteredObjectBufferMap ObjectBufferMap; + +public: + /// Instantiates the JIT service. + GDBJITRegistrationListener() : ObjectBufferMap() {} + + /// Unregisters each object that was previously registered and releases all + /// internal resources. + ~GDBJITRegistrationListener() override; + + /// Creates an entry in the JIT registry for the buffer @p Object, + /// which must contain an object file in executable memory with any + /// debug information for the debugger. + void notifyObjectLoaded(ObjectKey K, const ObjectFile &Obj, + const RuntimeDyld::LoadedObjectInfo &L) override; + + /// Removes the internal registration of @p Object, and + /// frees associated resources. + /// Returns true if @p Object was found in ObjectBufferMap. + void notifyFreeingObject(ObjectKey K) override; + +private: + /// Deregister the debug info for the given object file from the debugger + /// and delete any temporary copies. This private method does not remove + /// the function from Map so that it can be called while iterating over Map. + void deregisterObjectInternal(RegisteredObjectBufferMap::iterator I); +}; + +/// Lock used to serialize all jit registration events, since they +/// modify global variables. +ManagedStatic<sys::Mutex> JITDebugLock; + +/// Do the registration. +void NotifyDebugger(jit_code_entry* JITCodeEntry) { + __jit_debug_descriptor.action_flag = JIT_REGISTER_FN; + + // Insert this entry at the head of the list. + JITCodeEntry->prev_entry = nullptr; + jit_code_entry* NextEntry = __jit_debug_descriptor.first_entry; + JITCodeEntry->next_entry = NextEntry; + if (NextEntry) { + NextEntry->prev_entry = JITCodeEntry; + } + __jit_debug_descriptor.first_entry = JITCodeEntry; + __jit_debug_descriptor.relevant_entry = JITCodeEntry; + __jit_debug_register_code(); +} + +GDBJITRegistrationListener::~GDBJITRegistrationListener() { + // Free all registered object files. + std::lock_guard<llvm::sys::Mutex> locked(*JITDebugLock); + for (RegisteredObjectBufferMap::iterator I = ObjectBufferMap.begin(), + E = ObjectBufferMap.end(); + I != E; ++I) { + // Call the private method that doesn't update the map so our iterator + // doesn't break. + deregisterObjectInternal(I); + } + ObjectBufferMap.clear(); +} + +void GDBJITRegistrationListener::notifyObjectLoaded( + ObjectKey K, const ObjectFile &Obj, + const RuntimeDyld::LoadedObjectInfo &L) { + + OwningBinary<ObjectFile> DebugObj = L.getObjectForDebug(Obj); + + // Bail out if debug objects aren't supported. + if (!DebugObj.getBinary()) + return; + + const char *Buffer = DebugObj.getBinary()->getMemoryBufferRef().getBufferStart(); + size_t Size = DebugObj.getBinary()->getMemoryBufferRef().getBufferSize(); + + std::lock_guard<llvm::sys::Mutex> locked(*JITDebugLock); + assert(ObjectBufferMap.find(K) == ObjectBufferMap.end() && + "Second attempt to perform debug registration."); + jit_code_entry* JITCodeEntry = new jit_code_entry(); + + if (!JITCodeEntry) { + llvm::report_fatal_error( + "Allocation failed when registering a JIT entry!\n"); + } else { + JITCodeEntry->symfile_addr = Buffer; + JITCodeEntry->symfile_size = Size; + + ObjectBufferMap[K] = + RegisteredObjectInfo(Size, JITCodeEntry, std::move(DebugObj)); + NotifyDebugger(JITCodeEntry); + } +} + +void GDBJITRegistrationListener::notifyFreeingObject(ObjectKey K) { + std::lock_guard<llvm::sys::Mutex> locked(*JITDebugLock); + RegisteredObjectBufferMap::iterator I = ObjectBufferMap.find(K); + + if (I != ObjectBufferMap.end()) { + deregisterObjectInternal(I); + ObjectBufferMap.erase(I); + } +} + +void GDBJITRegistrationListener::deregisterObjectInternal( + RegisteredObjectBufferMap::iterator I) { + + jit_code_entry*& JITCodeEntry = I->second.Entry; + + // Do the unregistration. + { + __jit_debug_descriptor.action_flag = JIT_UNREGISTER_FN; + + // Remove the jit_code_entry from the linked list. + jit_code_entry* PrevEntry = JITCodeEntry->prev_entry; + jit_code_entry* NextEntry = JITCodeEntry->next_entry; + + if (NextEntry) { + NextEntry->prev_entry = PrevEntry; + } + if (PrevEntry) { + PrevEntry->next_entry = NextEntry; + } + else { + assert(__jit_debug_descriptor.first_entry == JITCodeEntry); + __jit_debug_descriptor.first_entry = NextEntry; + } + + // Tell the debugger which entry we removed, and unregister the code. + __jit_debug_descriptor.relevant_entry = JITCodeEntry; + __jit_debug_register_code(); + } + + delete JITCodeEntry; + JITCodeEntry = nullptr; +} + +llvm::ManagedStatic<GDBJITRegistrationListener> GDBRegListener; + +} // end namespace + +namespace llvm { + +JITEventListener* JITEventListener::createGDBRegistrationListener() { + return &*GDBRegListener; +} + +} // namespace llvm + +LLVMJITEventListenerRef LLVMCreateGDBRegistrationListener(void) +{ + return wrap(JITEventListener::createGDBRegistrationListener()); +} diff --git a/contrib/libs/llvm12/lib/ExecutionEngine/MCJIT/MCJIT.cpp b/contrib/libs/llvm12/lib/ExecutionEngine/MCJIT/MCJIT.cpp index fee385de80..144329aa8b 100644 --- a/contrib/libs/llvm12/lib/ExecutionEngine/MCJIT/MCJIT.cpp +++ b/contrib/libs/llvm12/lib/ExecutionEngine/MCJIT/MCJIT.cpp @@ -1,685 +1,685 @@ -//===-- MCJIT.cpp - MC-based Just-in-Time Compiler ------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "MCJIT.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/ExecutionEngine/GenericValue.h" -#include "llvm/ExecutionEngine/JITEventListener.h" -#include "llvm/ExecutionEngine/MCJIT.h" -#include "llvm/ExecutionEngine/ObjectCache.h" -#include "llvm/ExecutionEngine/SectionMemoryManager.h" -#include "llvm/IR/DataLayout.h" -#include "llvm/IR/DerivedTypes.h" -#include "llvm/IR/Function.h" -#include "llvm/IR/LegacyPassManager.h" -#include "llvm/IR/Mangler.h" -#include "llvm/IR/Module.h" -#include "llvm/Object/Archive.h" -#include "llvm/Object/ObjectFile.h" -#include "llvm/Support/DynamicLibrary.h" -#include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/SmallVectorMemoryBuffer.h" -#include <mutex> - -using namespace llvm; - -namespace { - -static struct RegisterJIT { - RegisterJIT() { MCJIT::Register(); } -} JITRegistrator; - -} - -extern "C" void LLVMLinkInMCJIT() { -} - -ExecutionEngine * -MCJIT::createJIT(std::unique_ptr<Module> M, std::string *ErrorStr, - std::shared_ptr<MCJITMemoryManager> MemMgr, - std::shared_ptr<LegacyJITSymbolResolver> Resolver, - std::unique_ptr<TargetMachine> TM) { - // Try to register the program as a source of symbols to resolve against. - // - // FIXME: Don't do this here. - sys::DynamicLibrary::LoadLibraryPermanently(nullptr, nullptr); - - if (!MemMgr || !Resolver) { - auto RTDyldMM = std::make_shared<SectionMemoryManager>(); - if (!MemMgr) - MemMgr = RTDyldMM; - if (!Resolver) - Resolver = RTDyldMM; - } - - return new MCJIT(std::move(M), std::move(TM), std::move(MemMgr), - std::move(Resolver)); -} - -MCJIT::MCJIT(std::unique_ptr<Module> M, std::unique_ptr<TargetMachine> TM, - std::shared_ptr<MCJITMemoryManager> MemMgr, - std::shared_ptr<LegacyJITSymbolResolver> Resolver) - : ExecutionEngine(TM->createDataLayout(), std::move(M)), TM(std::move(TM)), - Ctx(nullptr), MemMgr(std::move(MemMgr)), - Resolver(*this, std::move(Resolver)), Dyld(*this->MemMgr, this->Resolver), - ObjCache(nullptr) { - // FIXME: We are managing our modules, so we do not want the base class - // ExecutionEngine to manage them as well. To avoid double destruction - // of the first (and only) module added in ExecutionEngine constructor - // we remove it from EE and will destruct it ourselves. - // - // It may make sense to move our module manager (based on SmallStPtr) back - // into EE if the JIT and Interpreter can live with it. - // If so, additional functions: addModule, removeModule, FindFunctionNamed, - // runStaticConstructorsDestructors could be moved back to EE as well. - // - std::unique_ptr<Module> First = std::move(Modules[0]); - Modules.clear(); - - if (First->getDataLayout().isDefault()) - First->setDataLayout(getDataLayout()); - - OwnedModules.addModule(std::move(First)); - RegisterJITEventListener(JITEventListener::createGDBRegistrationListener()); -} - -MCJIT::~MCJIT() { - std::lock_guard<sys::Mutex> locked(lock); - - Dyld.deregisterEHFrames(); - - for (auto &Obj : LoadedObjects) - if (Obj) - notifyFreeingObject(*Obj); - - Archives.clear(); -} - -void MCJIT::addModule(std::unique_ptr<Module> M) { - std::lock_guard<sys::Mutex> locked(lock); - - if (M->getDataLayout().isDefault()) - M->setDataLayout(getDataLayout()); - - OwnedModules.addModule(std::move(M)); -} - -bool MCJIT::removeModule(Module *M) { - std::lock_guard<sys::Mutex> locked(lock); - return OwnedModules.removeModule(M); -} - -void MCJIT::addObjectFile(std::unique_ptr<object::ObjectFile> Obj) { - std::unique_ptr<RuntimeDyld::LoadedObjectInfo> L = Dyld.loadObject(*Obj); - if (Dyld.hasError()) - report_fatal_error(Dyld.getErrorString()); - - notifyObjectLoaded(*Obj, *L); - - LoadedObjects.push_back(std::move(Obj)); -} - -void MCJIT::addObjectFile(object::OwningBinary<object::ObjectFile> Obj) { - std::unique_ptr<object::ObjectFile> ObjFile; - std::unique_ptr<MemoryBuffer> MemBuf; - std::tie(ObjFile, MemBuf) = Obj.takeBinary(); - addObjectFile(std::move(ObjFile)); - Buffers.push_back(std::move(MemBuf)); -} - -void MCJIT::addArchive(object::OwningBinary<object::Archive> A) { - Archives.push_back(std::move(A)); -} - -void MCJIT::setObjectCache(ObjectCache* NewCache) { - std::lock_guard<sys::Mutex> locked(lock); - ObjCache = NewCache; -} - -std::unique_ptr<MemoryBuffer> MCJIT::emitObject(Module *M) { - assert(M && "Can not emit a null module"); - - std::lock_guard<sys::Mutex> locked(lock); - - // Materialize all globals in the module if they have not been - // materialized already. - cantFail(M->materializeAll()); - - // This must be a module which has already been added but not loaded to this - // MCJIT instance, since these conditions are tested by our caller, - // generateCodeForModule. - - legacy::PassManager PM; - - // The RuntimeDyld will take ownership of this shortly - SmallVector<char, 4096> ObjBufferSV; - raw_svector_ostream ObjStream(ObjBufferSV); - - // Turn the machine code intermediate representation into bytes in memory - // that may be executed. - if (TM->addPassesToEmitMC(PM, Ctx, ObjStream, !getVerifyModules())) - report_fatal_error("Target does not support MC emission!"); - - // Initialize passes. - PM.run(*M); - // Flush the output buffer to get the generated code into memory - - std::unique_ptr<MemoryBuffer> CompiledObjBuffer( - new SmallVectorMemoryBuffer(std::move(ObjBufferSV))); - - // If we have an object cache, tell it about the new object. - // Note that we're using the compiled image, not the loaded image (as below). - if (ObjCache) { - // MemoryBuffer is a thin wrapper around the actual memory, so it's OK - // to create a temporary object here and delete it after the call. - MemoryBufferRef MB = CompiledObjBuffer->getMemBufferRef(); - ObjCache->notifyObjectCompiled(M, MB); - } - - return CompiledObjBuffer; -} - -void MCJIT::generateCodeForModule(Module *M) { - // Get a thread lock to make sure we aren't trying to load multiple times - std::lock_guard<sys::Mutex> locked(lock); - - // This must be a module which has already been added to this MCJIT instance. - assert(OwnedModules.ownsModule(M) && - "MCJIT::generateCodeForModule: Unknown module."); - - // Re-compilation is not supported - if (OwnedModules.hasModuleBeenLoaded(M)) - return; - - std::unique_ptr<MemoryBuffer> ObjectToLoad; - // Try to load the pre-compiled object from cache if possible - if (ObjCache) - ObjectToLoad = ObjCache->getObject(M); - - assert(M->getDataLayout() == getDataLayout() && "DataLayout Mismatch"); - - // If the cache did not contain a suitable object, compile the object - if (!ObjectToLoad) { - ObjectToLoad = emitObject(M); - assert(ObjectToLoad && "Compilation did not produce an object."); - } - - // Load the object into the dynamic linker. - // MCJIT now owns the ObjectImage pointer (via its LoadedObjects list). - Expected<std::unique_ptr<object::ObjectFile>> LoadedObject = - object::ObjectFile::createObjectFile(ObjectToLoad->getMemBufferRef()); - if (!LoadedObject) { - std::string Buf; - raw_string_ostream OS(Buf); - logAllUnhandledErrors(LoadedObject.takeError(), OS); - OS.flush(); - report_fatal_error(Buf); - } - std::unique_ptr<RuntimeDyld::LoadedObjectInfo> L = - Dyld.loadObject(*LoadedObject.get()); - - if (Dyld.hasError()) - report_fatal_error(Dyld.getErrorString()); - - notifyObjectLoaded(*LoadedObject.get(), *L); - - Buffers.push_back(std::move(ObjectToLoad)); - LoadedObjects.push_back(std::move(*LoadedObject)); - - OwnedModules.markModuleAsLoaded(M); -} - -void MCJIT::finalizeLoadedModules() { - std::lock_guard<sys::Mutex> locked(lock); - - // Resolve any outstanding relocations. - Dyld.resolveRelocations(); - - // Check for Dyld error. - if (Dyld.hasError()) - ErrMsg = Dyld.getErrorString().str(); - - OwnedModules.markAllLoadedModulesAsFinalized(); - - // Register EH frame data for any module we own which has been loaded - Dyld.registerEHFrames(); - - // Set page permissions. - MemMgr->finalizeMemory(); -} - -// FIXME: Rename this. -void MCJIT::finalizeObject() { - std::lock_guard<sys::Mutex> locked(lock); - - // Generate code for module is going to move objects out of the 'added' list, - // so we need to copy that out before using it: - SmallVector<Module*, 16> ModsToAdd; - for (auto M : OwnedModules.added()) - ModsToAdd.push_back(M); - - for (auto M : ModsToAdd) - generateCodeForModule(M); - - finalizeLoadedModules(); -} - -void MCJIT::finalizeModule(Module *M) { - std::lock_guard<sys::Mutex> locked(lock); - - // This must be a module which has already been added to this MCJIT instance. - assert(OwnedModules.ownsModule(M) && "MCJIT::finalizeModule: Unknown module."); - - // If the module hasn't been compiled, just do that. - if (!OwnedModules.hasModuleBeenLoaded(M)) - generateCodeForModule(M); - - finalizeLoadedModules(); -} - -JITSymbol MCJIT::findExistingSymbol(const std::string &Name) { - if (void *Addr = getPointerToGlobalIfAvailable(Name)) - return JITSymbol(static_cast<uint64_t>( - reinterpret_cast<uintptr_t>(Addr)), - JITSymbolFlags::Exported); - - return Dyld.getSymbol(Name); -} - -Module *MCJIT::findModuleForSymbol(const std::string &Name, - bool CheckFunctionsOnly) { - StringRef DemangledName = Name; - if (DemangledName[0] == getDataLayout().getGlobalPrefix()) - DemangledName = DemangledName.substr(1); - - std::lock_guard<sys::Mutex> locked(lock); - - // If it hasn't already been generated, see if it's in one of our modules. - for (ModulePtrSet::iterator I = OwnedModules.begin_added(), - E = OwnedModules.end_added(); - I != E; ++I) { - Module *M = *I; - Function *F = M->getFunction(DemangledName); - if (F && !F->isDeclaration()) - return M; - if (!CheckFunctionsOnly) { - GlobalVariable *G = M->getGlobalVariable(DemangledName); - if (G && !G->isDeclaration()) - return M; - // FIXME: Do we need to worry about global aliases? - } - } - // We didn't find the symbol in any of our modules. - return nullptr; -} - -uint64_t MCJIT::getSymbolAddress(const std::string &Name, - bool CheckFunctionsOnly) { - std::string MangledName; - { - raw_string_ostream MangledNameStream(MangledName); - Mangler::getNameWithPrefix(MangledNameStream, Name, getDataLayout()); - } - if (auto Sym = findSymbol(MangledName, CheckFunctionsOnly)) { - if (auto AddrOrErr = Sym.getAddress()) - return *AddrOrErr; - else - report_fatal_error(AddrOrErr.takeError()); - } else if (auto Err = Sym.takeError()) - report_fatal_error(Sym.takeError()); - return 0; -} - -JITSymbol MCJIT::findSymbol(const std::string &Name, - bool CheckFunctionsOnly) { - std::lock_guard<sys::Mutex> locked(lock); - - // First, check to see if we already have this symbol. - if (auto Sym = findExistingSymbol(Name)) - return Sym; - - for (object::OwningBinary<object::Archive> &OB : Archives) { - object::Archive *A = OB.getBinary(); - // Look for our symbols in each Archive - auto OptionalChildOrErr = A->findSym(Name); - if (!OptionalChildOrErr) - report_fatal_error(OptionalChildOrErr.takeError()); - auto &OptionalChild = *OptionalChildOrErr; - if (OptionalChild) { - // FIXME: Support nested archives? - Expected<std::unique_ptr<object::Binary>> ChildBinOrErr = - OptionalChild->getAsBinary(); - if (!ChildBinOrErr) { - // TODO: Actually report errors helpfully. - consumeError(ChildBinOrErr.takeError()); - continue; - } - std::unique_ptr<object::Binary> &ChildBin = ChildBinOrErr.get(); - if (ChildBin->isObject()) { - std::unique_ptr<object::ObjectFile> OF( - static_cast<object::ObjectFile *>(ChildBin.release())); - // This causes the object file to be loaded. - addObjectFile(std::move(OF)); - // The address should be here now. - if (auto Sym = findExistingSymbol(Name)) - return Sym; - } - } - } - - // If it hasn't already been generated, see if it's in one of our modules. - Module *M = findModuleForSymbol(Name, CheckFunctionsOnly); - if (M) { - generateCodeForModule(M); - - // Check the RuntimeDyld table again, it should be there now. - return findExistingSymbol(Name); - } - - // If a LazyFunctionCreator is installed, use it to get/create the function. - // FIXME: Should we instead have a LazySymbolCreator callback? - if (LazyFunctionCreator) { - auto Addr = static_cast<uint64_t>( - reinterpret_cast<uintptr_t>(LazyFunctionCreator(Name))); - return JITSymbol(Addr, JITSymbolFlags::Exported); - } - - return nullptr; -} - -uint64_t MCJIT::getGlobalValueAddress(const std::string &Name) { - std::lock_guard<sys::Mutex> locked(lock); - uint64_t Result = getSymbolAddress(Name, false); - if (Result != 0) - finalizeLoadedModules(); - return Result; -} - -uint64_t MCJIT::getFunctionAddress(const std::string &Name) { - std::lock_guard<sys::Mutex> locked(lock); - uint64_t Result = getSymbolAddress(Name, true); - if (Result != 0) - finalizeLoadedModules(); - return Result; -} - -// Deprecated. Use getFunctionAddress instead. -void *MCJIT::getPointerToFunction(Function *F) { - std::lock_guard<sys::Mutex> locked(lock); - - Mangler Mang; - SmallString<128> Name; - TM->getNameWithPrefix(Name, F, Mang); - - if (F->isDeclaration() || F->hasAvailableExternallyLinkage()) { - bool AbortOnFailure = !F->hasExternalWeakLinkage(); - void *Addr = getPointerToNamedFunction(Name, AbortOnFailure); - updateGlobalMapping(F, Addr); - return Addr; - } - - Module *M = F->getParent(); - bool HasBeenAddedButNotLoaded = OwnedModules.hasModuleBeenAddedButNotLoaded(M); - - // Make sure the relevant module has been compiled and loaded. - if (HasBeenAddedButNotLoaded) - generateCodeForModule(M); - else if (!OwnedModules.hasModuleBeenLoaded(M)) { - // If this function doesn't belong to one of our modules, we're done. - // FIXME: Asking for the pointer to a function that hasn't been registered, - // and isn't a declaration (which is handled above) should probably - // be an assertion. - return nullptr; - } - - // FIXME: Should the Dyld be retaining module information? Probably not. - // - // This is the accessor for the target address, so make sure to check the - // load address of the symbol, not the local address. - return (void*)Dyld.getSymbol(Name).getAddress(); -} - -void MCJIT::runStaticConstructorsDestructorsInModulePtrSet( - bool isDtors, ModulePtrSet::iterator I, ModulePtrSet::iterator E) { - for (; I != E; ++I) { - ExecutionEngine::runStaticConstructorsDestructors(**I, isDtors); - } -} - -void MCJIT::runStaticConstructorsDestructors(bool isDtors) { - // Execute global ctors/dtors for each module in the program. - runStaticConstructorsDestructorsInModulePtrSet( - isDtors, OwnedModules.begin_added(), OwnedModules.end_added()); - runStaticConstructorsDestructorsInModulePtrSet( - isDtors, OwnedModules.begin_loaded(), OwnedModules.end_loaded()); - runStaticConstructorsDestructorsInModulePtrSet( - isDtors, OwnedModules.begin_finalized(), OwnedModules.end_finalized()); -} - -Function *MCJIT::FindFunctionNamedInModulePtrSet(StringRef FnName, - ModulePtrSet::iterator I, - ModulePtrSet::iterator E) { - for (; I != E; ++I) { - Function *F = (*I)->getFunction(FnName); - if (F && !F->isDeclaration()) - return F; - } - return nullptr; -} - -GlobalVariable *MCJIT::FindGlobalVariableNamedInModulePtrSet(StringRef Name, - bool AllowInternal, - ModulePtrSet::iterator I, - ModulePtrSet::iterator E) { - for (; I != E; ++I) { - GlobalVariable *GV = (*I)->getGlobalVariable(Name, AllowInternal); - if (GV && !GV->isDeclaration()) - return GV; - } - return nullptr; -} - - -Function *MCJIT::FindFunctionNamed(StringRef FnName) { - Function *F = FindFunctionNamedInModulePtrSet( - FnName, OwnedModules.begin_added(), OwnedModules.end_added()); - if (!F) - F = FindFunctionNamedInModulePtrSet(FnName, OwnedModules.begin_loaded(), - OwnedModules.end_loaded()); - if (!F) - F = FindFunctionNamedInModulePtrSet(FnName, OwnedModules.begin_finalized(), - OwnedModules.end_finalized()); - return F; -} - -GlobalVariable *MCJIT::FindGlobalVariableNamed(StringRef Name, bool AllowInternal) { - GlobalVariable *GV = FindGlobalVariableNamedInModulePtrSet( - Name, AllowInternal, OwnedModules.begin_added(), OwnedModules.end_added()); - if (!GV) - GV = FindGlobalVariableNamedInModulePtrSet(Name, AllowInternal, OwnedModules.begin_loaded(), - OwnedModules.end_loaded()); - if (!GV) - GV = FindGlobalVariableNamedInModulePtrSet(Name, AllowInternal, OwnedModules.begin_finalized(), - OwnedModules.end_finalized()); - return GV; -} - -GenericValue MCJIT::runFunction(Function *F, ArrayRef<GenericValue> ArgValues) { - assert(F && "Function *F was null at entry to run()"); - - void *FPtr = getPointerToFunction(F); - finalizeModule(F->getParent()); - assert(FPtr && "Pointer to fn's code was null after getPointerToFunction"); - FunctionType *FTy = F->getFunctionType(); - Type *RetTy = FTy->getReturnType(); - - assert((FTy->getNumParams() == ArgValues.size() || - (FTy->isVarArg() && FTy->getNumParams() <= ArgValues.size())) && - "Wrong number of arguments passed into function!"); - assert(FTy->getNumParams() == ArgValues.size() && - "This doesn't support passing arguments through varargs (yet)!"); - - // Handle some common cases first. These cases correspond to common `main' - // prototypes. - if (RetTy->isIntegerTy(32) || RetTy->isVoidTy()) { - switch (ArgValues.size()) { - case 3: - if (FTy->getParamType(0)->isIntegerTy(32) && - FTy->getParamType(1)->isPointerTy() && - FTy->getParamType(2)->isPointerTy()) { - int (*PF)(int, char **, const char **) = - (int(*)(int, char **, const char **))(intptr_t)FPtr; - - // Call the function. - GenericValue rv; - rv.IntVal = APInt(32, PF(ArgValues[0].IntVal.getZExtValue(), - (char **)GVTOP(ArgValues[1]), - (const char **)GVTOP(ArgValues[2]))); - return rv; - } - break; - case 2: - if (FTy->getParamType(0)->isIntegerTy(32) && - FTy->getParamType(1)->isPointerTy()) { - int (*PF)(int, char **) = (int(*)(int, char **))(intptr_t)FPtr; - - // Call the function. - GenericValue rv; - rv.IntVal = APInt(32, PF(ArgValues[0].IntVal.getZExtValue(), - (char **)GVTOP(ArgValues[1]))); - return rv; - } - break; - case 1: - if (FTy->getNumParams() == 1 && - FTy->getParamType(0)->isIntegerTy(32)) { - GenericValue rv; - int (*PF)(int) = (int(*)(int))(intptr_t)FPtr; - rv.IntVal = APInt(32, PF(ArgValues[0].IntVal.getZExtValue())); - return rv; - } - break; - } - } - - // Handle cases where no arguments are passed first. - if (ArgValues.empty()) { - GenericValue rv; - switch (RetTy->getTypeID()) { - default: llvm_unreachable("Unknown return type for function call!"); - case Type::IntegerTyID: { - unsigned BitWidth = cast<IntegerType>(RetTy)->getBitWidth(); - if (BitWidth == 1) - rv.IntVal = APInt(BitWidth, ((bool(*)())(intptr_t)FPtr)()); - else if (BitWidth <= 8) - rv.IntVal = APInt(BitWidth, ((char(*)())(intptr_t)FPtr)()); - else if (BitWidth <= 16) - rv.IntVal = APInt(BitWidth, ((short(*)())(intptr_t)FPtr)()); - else if (BitWidth <= 32) - rv.IntVal = APInt(BitWidth, ((int(*)())(intptr_t)FPtr)()); - else if (BitWidth <= 64) - rv.IntVal = APInt(BitWidth, ((int64_t(*)())(intptr_t)FPtr)()); - else - llvm_unreachable("Integer types > 64 bits not supported"); - return rv; - } - case Type::VoidTyID: - rv.IntVal = APInt(32, ((int(*)())(intptr_t)FPtr)()); - return rv; - case Type::FloatTyID: - rv.FloatVal = ((float(*)())(intptr_t)FPtr)(); - return rv; - case Type::DoubleTyID: - rv.DoubleVal = ((double(*)())(intptr_t)FPtr)(); - return rv; - case Type::X86_FP80TyID: - case Type::FP128TyID: - case Type::PPC_FP128TyID: - llvm_unreachable("long double not supported yet"); - case Type::PointerTyID: - return PTOGV(((void*(*)())(intptr_t)FPtr)()); - } - } - - report_fatal_error("MCJIT::runFunction does not support full-featured " - "argument passing. Please use " - "ExecutionEngine::getFunctionAddress and cast the result " - "to the desired function pointer type."); -} - -void *MCJIT::getPointerToNamedFunction(StringRef Name, bool AbortOnFailure) { - if (!isSymbolSearchingDisabled()) { - if (auto Sym = Resolver.findSymbol(std::string(Name))) { - if (auto AddrOrErr = Sym.getAddress()) - return reinterpret_cast<void*>( - static_cast<uintptr_t>(*AddrOrErr)); - } else if (auto Err = Sym.takeError()) - report_fatal_error(std::move(Err)); - } - - /// If a LazyFunctionCreator is installed, use it to get/create the function. - if (LazyFunctionCreator) - if (void *RP = LazyFunctionCreator(std::string(Name))) - return RP; - - if (AbortOnFailure) { - report_fatal_error("Program used external function '"+Name+ - "' which could not be resolved!"); - } - return nullptr; -} - -void MCJIT::RegisterJITEventListener(JITEventListener *L) { - if (!L) - return; - std::lock_guard<sys::Mutex> locked(lock); - EventListeners.push_back(L); -} - -void MCJIT::UnregisterJITEventListener(JITEventListener *L) { - if (!L) - return; - std::lock_guard<sys::Mutex> locked(lock); - auto I = find(reverse(EventListeners), L); - if (I != EventListeners.rend()) { - std::swap(*I, EventListeners.back()); - EventListeners.pop_back(); - } -} - -void MCJIT::notifyObjectLoaded(const object::ObjectFile &Obj, - const RuntimeDyld::LoadedObjectInfo &L) { - uint64_t Key = - static_cast<uint64_t>(reinterpret_cast<uintptr_t>(Obj.getData().data())); - std::lock_guard<sys::Mutex> locked(lock); - MemMgr->notifyObjectLoaded(this, Obj); - for (unsigned I = 0, S = EventListeners.size(); I < S; ++I) { - EventListeners[I]->notifyObjectLoaded(Key, Obj, L); - } -} - -void MCJIT::notifyFreeingObject(const object::ObjectFile &Obj) { - uint64_t Key = - static_cast<uint64_t>(reinterpret_cast<uintptr_t>(Obj.getData().data())); - std::lock_guard<sys::Mutex> locked(lock); - for (JITEventListener *L : EventListeners) - L->notifyFreeingObject(Key); -} - -JITSymbol -LinkingSymbolResolver::findSymbol(const std::string &Name) { - auto Result = ParentEngine.findSymbol(Name, false); - if (Result) - return Result; - if (ParentEngine.isSymbolSearchingDisabled()) - return nullptr; - return ClientResolver->findSymbol(Name); -} - -void LinkingSymbolResolver::anchor() {} +//===-- MCJIT.cpp - MC-based Just-in-Time Compiler ------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "MCJIT.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ExecutionEngine/GenericValue.h" +#include "llvm/ExecutionEngine/JITEventListener.h" +#include "llvm/ExecutionEngine/MCJIT.h" +#include "llvm/ExecutionEngine/ObjectCache.h" +#include "llvm/ExecutionEngine/SectionMemoryManager.h" +#include "llvm/IR/DataLayout.h" +#include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/LegacyPassManager.h" +#include "llvm/IR/Mangler.h" +#include "llvm/IR/Module.h" +#include "llvm/Object/Archive.h" +#include "llvm/Object/ObjectFile.h" +#include "llvm/Support/DynamicLibrary.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/SmallVectorMemoryBuffer.h" +#include <mutex> + +using namespace llvm; + +namespace { + +static struct RegisterJIT { + RegisterJIT() { MCJIT::Register(); } +} JITRegistrator; + +} + +extern "C" void LLVMLinkInMCJIT() { +} + +ExecutionEngine * +MCJIT::createJIT(std::unique_ptr<Module> M, std::string *ErrorStr, + std::shared_ptr<MCJITMemoryManager> MemMgr, + std::shared_ptr<LegacyJITSymbolResolver> Resolver, + std::unique_ptr<TargetMachine> TM) { + // Try to register the program as a source of symbols to resolve against. + // + // FIXME: Don't do this here. + sys::DynamicLibrary::LoadLibraryPermanently(nullptr, nullptr); + + if (!MemMgr || !Resolver) { + auto RTDyldMM = std::make_shared<SectionMemoryManager>(); + if (!MemMgr) + MemMgr = RTDyldMM; + if (!Resolver) + Resolver = RTDyldMM; + } + + return new MCJIT(std::move(M), std::move(TM), std::move(MemMgr), + std::move(Resolver)); +} + +MCJIT::MCJIT(std::unique_ptr<Module> M, std::unique_ptr<TargetMachine> TM, + std::shared_ptr<MCJITMemoryManager> MemMgr, + std::shared_ptr<LegacyJITSymbolResolver> Resolver) + : ExecutionEngine(TM->createDataLayout(), std::move(M)), TM(std::move(TM)), + Ctx(nullptr), MemMgr(std::move(MemMgr)), + Resolver(*this, std::move(Resolver)), Dyld(*this->MemMgr, this->Resolver), + ObjCache(nullptr) { + // FIXME: We are managing our modules, so we do not want the base class + // ExecutionEngine to manage them as well. To avoid double destruction + // of the first (and only) module added in ExecutionEngine constructor + // we remove it from EE and will destruct it ourselves. + // + // It may make sense to move our module manager (based on SmallStPtr) back + // into EE if the JIT and Interpreter can live with it. + // If so, additional functions: addModule, removeModule, FindFunctionNamed, + // runStaticConstructorsDestructors could be moved back to EE as well. + // + std::unique_ptr<Module> First = std::move(Modules[0]); + Modules.clear(); + + if (First->getDataLayout().isDefault()) + First->setDataLayout(getDataLayout()); + + OwnedModules.addModule(std::move(First)); + RegisterJITEventListener(JITEventListener::createGDBRegistrationListener()); +} + +MCJIT::~MCJIT() { + std::lock_guard<sys::Mutex> locked(lock); + + Dyld.deregisterEHFrames(); + + for (auto &Obj : LoadedObjects) + if (Obj) + notifyFreeingObject(*Obj); + + Archives.clear(); +} + +void MCJIT::addModule(std::unique_ptr<Module> M) { + std::lock_guard<sys::Mutex> locked(lock); + + if (M->getDataLayout().isDefault()) + M->setDataLayout(getDataLayout()); + + OwnedModules.addModule(std::move(M)); +} + +bool MCJIT::removeModule(Module *M) { + std::lock_guard<sys::Mutex> locked(lock); + return OwnedModules.removeModule(M); +} + +void MCJIT::addObjectFile(std::unique_ptr<object::ObjectFile> Obj) { + std::unique_ptr<RuntimeDyld::LoadedObjectInfo> L = Dyld.loadObject(*Obj); + if (Dyld.hasError()) + report_fatal_error(Dyld.getErrorString()); + + notifyObjectLoaded(*Obj, *L); + + LoadedObjects.push_back(std::move(Obj)); +} + +void MCJIT::addObjectFile(object::OwningBinary<object::ObjectFile> Obj) { + std::unique_ptr<object::ObjectFile> ObjFile; + std::unique_ptr<MemoryBuffer> MemBuf; + std::tie(ObjFile, MemBuf) = Obj.takeBinary(); + addObjectFile(std::move(ObjFile)); + Buffers.push_back(std::move(MemBuf)); +} + +void MCJIT::addArchive(object::OwningBinary<object::Archive> A) { + Archives.push_back(std::move(A)); +} + +void MCJIT::setObjectCache(ObjectCache* NewCache) { + std::lock_guard<sys::Mutex> locked(lock); + ObjCache = NewCache; +} + +std::unique_ptr<MemoryBuffer> MCJIT::emitObject(Module *M) { + assert(M && "Can not emit a null module"); + + std::lock_guard<sys::Mutex> locked(lock); + + // Materialize all globals in the module if they have not been + // materialized already. + cantFail(M->materializeAll()); + + // This must be a module which has already been added but not loaded to this + // MCJIT instance, since these conditions are tested by our caller, + // generateCodeForModule. + + legacy::PassManager PM; + + // The RuntimeDyld will take ownership of this shortly + SmallVector<char, 4096> ObjBufferSV; + raw_svector_ostream ObjStream(ObjBufferSV); + + // Turn the machine code intermediate representation into bytes in memory + // that may be executed. + if (TM->addPassesToEmitMC(PM, Ctx, ObjStream, !getVerifyModules())) + report_fatal_error("Target does not support MC emission!"); + + // Initialize passes. + PM.run(*M); + // Flush the output buffer to get the generated code into memory + + std::unique_ptr<MemoryBuffer> CompiledObjBuffer( + new SmallVectorMemoryBuffer(std::move(ObjBufferSV))); + + // If we have an object cache, tell it about the new object. + // Note that we're using the compiled image, not the loaded image (as below). + if (ObjCache) { + // MemoryBuffer is a thin wrapper around the actual memory, so it's OK + // to create a temporary object here and delete it after the call. + MemoryBufferRef MB = CompiledObjBuffer->getMemBufferRef(); + ObjCache->notifyObjectCompiled(M, MB); + } + + return CompiledObjBuffer; +} + +void MCJIT::generateCodeForModule(Module *M) { + // Get a thread lock to make sure we aren't trying to load multiple times + std::lock_guard<sys::Mutex> locked(lock); + + // This must be a module which has already been added to this MCJIT instance. + assert(OwnedModules.ownsModule(M) && + "MCJIT::generateCodeForModule: Unknown module."); + + // Re-compilation is not supported + if (OwnedModules.hasModuleBeenLoaded(M)) + return; + + std::unique_ptr<MemoryBuffer> ObjectToLoad; + // Try to load the pre-compiled object from cache if possible + if (ObjCache) + ObjectToLoad = ObjCache->getObject(M); + + assert(M->getDataLayout() == getDataLayout() && "DataLayout Mismatch"); + + // If the cache did not contain a suitable object, compile the object + if (!ObjectToLoad) { + ObjectToLoad = emitObject(M); + assert(ObjectToLoad && "Compilation did not produce an object."); + } + + // Load the object into the dynamic linker. + // MCJIT now owns the ObjectImage pointer (via its LoadedObjects list). + Expected<std::unique_ptr<object::ObjectFile>> LoadedObject = + object::ObjectFile::createObjectFile(ObjectToLoad->getMemBufferRef()); + if (!LoadedObject) { + std::string Buf; + raw_string_ostream OS(Buf); + logAllUnhandledErrors(LoadedObject.takeError(), OS); + OS.flush(); + report_fatal_error(Buf); + } + std::unique_ptr<RuntimeDyld::LoadedObjectInfo> L = + Dyld.loadObject(*LoadedObject.get()); + + if (Dyld.hasError()) + report_fatal_error(Dyld.getErrorString()); + + notifyObjectLoaded(*LoadedObject.get(), *L); + + Buffers.push_back(std::move(ObjectToLoad)); + LoadedObjects.push_back(std::move(*LoadedObject)); + + OwnedModules.markModuleAsLoaded(M); +} + +void MCJIT::finalizeLoadedModules() { + std::lock_guard<sys::Mutex> locked(lock); + + // Resolve any outstanding relocations. + Dyld.resolveRelocations(); + + // Check for Dyld error. + if (Dyld.hasError()) + ErrMsg = Dyld.getErrorString().str(); + + OwnedModules.markAllLoadedModulesAsFinalized(); + + // Register EH frame data for any module we own which has been loaded + Dyld.registerEHFrames(); + + // Set page permissions. + MemMgr->finalizeMemory(); +} + +// FIXME: Rename this. +void MCJIT::finalizeObject() { + std::lock_guard<sys::Mutex> locked(lock); + + // Generate code for module is going to move objects out of the 'added' list, + // so we need to copy that out before using it: + SmallVector<Module*, 16> ModsToAdd; + for (auto M : OwnedModules.added()) + ModsToAdd.push_back(M); + + for (auto M : ModsToAdd) + generateCodeForModule(M); + + finalizeLoadedModules(); +} + +void MCJIT::finalizeModule(Module *M) { + std::lock_guard<sys::Mutex> locked(lock); + + // This must be a module which has already been added to this MCJIT instance. + assert(OwnedModules.ownsModule(M) && "MCJIT::finalizeModule: Unknown module."); + + // If the module hasn't been compiled, just do that. + if (!OwnedModules.hasModuleBeenLoaded(M)) + generateCodeForModule(M); + + finalizeLoadedModules(); +} + +JITSymbol MCJIT::findExistingSymbol(const std::string &Name) { + if (void *Addr = getPointerToGlobalIfAvailable(Name)) + return JITSymbol(static_cast<uint64_t>( + reinterpret_cast<uintptr_t>(Addr)), + JITSymbolFlags::Exported); + + return Dyld.getSymbol(Name); +} + +Module *MCJIT::findModuleForSymbol(const std::string &Name, + bool CheckFunctionsOnly) { + StringRef DemangledName = Name; + if (DemangledName[0] == getDataLayout().getGlobalPrefix()) + DemangledName = DemangledName.substr(1); + + std::lock_guard<sys::Mutex> locked(lock); + + // If it hasn't already been generated, see if it's in one of our modules. + for (ModulePtrSet::iterator I = OwnedModules.begin_added(), + E = OwnedModules.end_added(); + I != E; ++I) { + Module *M = *I; + Function *F = M->getFunction(DemangledName); + if (F && !F->isDeclaration()) + return M; + if (!CheckFunctionsOnly) { + GlobalVariable *G = M->getGlobalVariable(DemangledName); + if (G && !G->isDeclaration()) + return M; + // FIXME: Do we need to worry about global aliases? + } + } + // We didn't find the symbol in any of our modules. + return nullptr; +} + +uint64_t MCJIT::getSymbolAddress(const std::string &Name, + bool CheckFunctionsOnly) { + std::string MangledName; + { + raw_string_ostream MangledNameStream(MangledName); + Mangler::getNameWithPrefix(MangledNameStream, Name, getDataLayout()); + } + if (auto Sym = findSymbol(MangledName, CheckFunctionsOnly)) { + if (auto AddrOrErr = Sym.getAddress()) + return *AddrOrErr; + else + report_fatal_error(AddrOrErr.takeError()); + } else if (auto Err = Sym.takeError()) + report_fatal_error(Sym.takeError()); + return 0; +} + +JITSymbol MCJIT::findSymbol(const std::string &Name, + bool CheckFunctionsOnly) { + std::lock_guard<sys::Mutex> locked(lock); + + // First, check to see if we already have this symbol. + if (auto Sym = findExistingSymbol(Name)) + return Sym; + + for (object::OwningBinary<object::Archive> &OB : Archives) { + object::Archive *A = OB.getBinary(); + // Look for our symbols in each Archive + auto OptionalChildOrErr = A->findSym(Name); + if (!OptionalChildOrErr) + report_fatal_error(OptionalChildOrErr.takeError()); + auto &OptionalChild = *OptionalChildOrErr; + if (OptionalChild) { + // FIXME: Support nested archives? + Expected<std::unique_ptr<object::Binary>> ChildBinOrErr = + OptionalChild->getAsBinary(); + if (!ChildBinOrErr) { + // TODO: Actually report errors helpfully. + consumeError(ChildBinOrErr.takeError()); + continue; + } + std::unique_ptr<object::Binary> &ChildBin = ChildBinOrErr.get(); + if (ChildBin->isObject()) { + std::unique_ptr<object::ObjectFile> OF( + static_cast<object::ObjectFile *>(ChildBin.release())); + // This causes the object file to be loaded. + addObjectFile(std::move(OF)); + // The address should be here now. + if (auto Sym = findExistingSymbol(Name)) + return Sym; + } + } + } + + // If it hasn't already been generated, see if it's in one of our modules. + Module *M = findModuleForSymbol(Name, CheckFunctionsOnly); + if (M) { + generateCodeForModule(M); + + // Check the RuntimeDyld table again, it should be there now. + return findExistingSymbol(Name); + } + + // If a LazyFunctionCreator is installed, use it to get/create the function. + // FIXME: Should we instead have a LazySymbolCreator callback? + if (LazyFunctionCreator) { + auto Addr = static_cast<uint64_t>( + reinterpret_cast<uintptr_t>(LazyFunctionCreator(Name))); + return JITSymbol(Addr, JITSymbolFlags::Exported); + } + + return nullptr; +} + +uint64_t MCJIT::getGlobalValueAddress(const std::string &Name) { + std::lock_guard<sys::Mutex> locked(lock); + uint64_t Result = getSymbolAddress(Name, false); + if (Result != 0) + finalizeLoadedModules(); + return Result; +} + +uint64_t MCJIT::getFunctionAddress(const std::string &Name) { + std::lock_guard<sys::Mutex> locked(lock); + uint64_t Result = getSymbolAddress(Name, true); + if (Result != 0) + finalizeLoadedModules(); + return Result; +} + +// Deprecated. Use getFunctionAddress instead. +void *MCJIT::getPointerToFunction(Function *F) { + std::lock_guard<sys::Mutex> locked(lock); + + Mangler Mang; + SmallString<128> Name; + TM->getNameWithPrefix(Name, F, Mang); + + if (F->isDeclaration() || F->hasAvailableExternallyLinkage()) { + bool AbortOnFailure = !F->hasExternalWeakLinkage(); + void *Addr = getPointerToNamedFunction(Name, AbortOnFailure); + updateGlobalMapping(F, Addr); + return Addr; + } + + Module *M = F->getParent(); + bool HasBeenAddedButNotLoaded = OwnedModules.hasModuleBeenAddedButNotLoaded(M); + + // Make sure the relevant module has been compiled and loaded. + if (HasBeenAddedButNotLoaded) + generateCodeForModule(M); + else if (!OwnedModules.hasModuleBeenLoaded(M)) { + // If this function doesn't belong to one of our modules, we're done. + // FIXME: Asking for the pointer to a function that hasn't been registered, + // and isn't a declaration (which is handled above) should probably + // be an assertion. + return nullptr; + } + + // FIXME: Should the Dyld be retaining module information? Probably not. + // + // This is the accessor for the target address, so make sure to check the + // load address of the symbol, not the local address. + return (void*)Dyld.getSymbol(Name).getAddress(); +} + +void MCJIT::runStaticConstructorsDestructorsInModulePtrSet( + bool isDtors, ModulePtrSet::iterator I, ModulePtrSet::iterator E) { + for (; I != E; ++I) { + ExecutionEngine::runStaticConstructorsDestructors(**I, isDtors); + } +} + +void MCJIT::runStaticConstructorsDestructors(bool isDtors) { + // Execute global ctors/dtors for each module in the program. + runStaticConstructorsDestructorsInModulePtrSet( + isDtors, OwnedModules.begin_added(), OwnedModules.end_added()); + runStaticConstructorsDestructorsInModulePtrSet( + isDtors, OwnedModules.begin_loaded(), OwnedModules.end_loaded()); + runStaticConstructorsDestructorsInModulePtrSet( + isDtors, OwnedModules.begin_finalized(), OwnedModules.end_finalized()); +} + +Function *MCJIT::FindFunctionNamedInModulePtrSet(StringRef FnName, + ModulePtrSet::iterator I, + ModulePtrSet::iterator E) { + for (; I != E; ++I) { + Function *F = (*I)->getFunction(FnName); + if (F && !F->isDeclaration()) + return F; + } + return nullptr; +} + +GlobalVariable *MCJIT::FindGlobalVariableNamedInModulePtrSet(StringRef Name, + bool AllowInternal, + ModulePtrSet::iterator I, + ModulePtrSet::iterator E) { + for (; I != E; ++I) { + GlobalVariable *GV = (*I)->getGlobalVariable(Name, AllowInternal); + if (GV && !GV->isDeclaration()) + return GV; + } + return nullptr; +} + + +Function *MCJIT::FindFunctionNamed(StringRef FnName) { + Function *F = FindFunctionNamedInModulePtrSet( + FnName, OwnedModules.begin_added(), OwnedModules.end_added()); + if (!F) + F = FindFunctionNamedInModulePtrSet(FnName, OwnedModules.begin_loaded(), + OwnedModules.end_loaded()); + if (!F) + F = FindFunctionNamedInModulePtrSet(FnName, OwnedModules.begin_finalized(), + OwnedModules.end_finalized()); + return F; +} + +GlobalVariable *MCJIT::FindGlobalVariableNamed(StringRef Name, bool AllowInternal) { + GlobalVariable *GV = FindGlobalVariableNamedInModulePtrSet( + Name, AllowInternal, OwnedModules.begin_added(), OwnedModules.end_added()); + if (!GV) + GV = FindGlobalVariableNamedInModulePtrSet(Name, AllowInternal, OwnedModules.begin_loaded(), + OwnedModules.end_loaded()); + if (!GV) + GV = FindGlobalVariableNamedInModulePtrSet(Name, AllowInternal, OwnedModules.begin_finalized(), + OwnedModules.end_finalized()); + return GV; +} + +GenericValue MCJIT::runFunction(Function *F, ArrayRef<GenericValue> ArgValues) { + assert(F && "Function *F was null at entry to run()"); + + void *FPtr = getPointerToFunction(F); + finalizeModule(F->getParent()); + assert(FPtr && "Pointer to fn's code was null after getPointerToFunction"); + FunctionType *FTy = F->getFunctionType(); + Type *RetTy = FTy->getReturnType(); + + assert((FTy->getNumParams() == ArgValues.size() || + (FTy->isVarArg() && FTy->getNumParams() <= ArgValues.size())) && + "Wrong number of arguments passed into function!"); + assert(FTy->getNumParams() == ArgValues.size() && + "This doesn't support passing arguments through varargs (yet)!"); + + // Handle some common cases first. These cases correspond to common `main' + // prototypes. + if (RetTy->isIntegerTy(32) || RetTy->isVoidTy()) { + switch (ArgValues.size()) { + case 3: + if (FTy->getParamType(0)->isIntegerTy(32) && + FTy->getParamType(1)->isPointerTy() && + FTy->getParamType(2)->isPointerTy()) { + int (*PF)(int, char **, const char **) = + (int(*)(int, char **, const char **))(intptr_t)FPtr; + + // Call the function. + GenericValue rv; + rv.IntVal = APInt(32, PF(ArgValues[0].IntVal.getZExtValue(), + (char **)GVTOP(ArgValues[1]), + (const char **)GVTOP(ArgValues[2]))); + return rv; + } + break; + case 2: + if (FTy->getParamType(0)->isIntegerTy(32) && + FTy->getParamType(1)->isPointerTy()) { + int (*PF)(int, char **) = (int(*)(int, char **))(intptr_t)FPtr; + + // Call the function. + GenericValue rv; + rv.IntVal = APInt(32, PF(ArgValues[0].IntVal.getZExtValue(), + (char **)GVTOP(ArgValues[1]))); + return rv; + } + break; + case 1: + if (FTy->getNumParams() == 1 && + FTy->getParamType(0)->isIntegerTy(32)) { + GenericValue rv; + int (*PF)(int) = (int(*)(int))(intptr_t)FPtr; + rv.IntVal = APInt(32, PF(ArgValues[0].IntVal.getZExtValue())); + return rv; + } + break; + } + } + + // Handle cases where no arguments are passed first. + if (ArgValues.empty()) { + GenericValue rv; + switch (RetTy->getTypeID()) { + default: llvm_unreachable("Unknown return type for function call!"); + case Type::IntegerTyID: { + unsigned BitWidth = cast<IntegerType>(RetTy)->getBitWidth(); + if (BitWidth == 1) + rv.IntVal = APInt(BitWidth, ((bool(*)())(intptr_t)FPtr)()); + else if (BitWidth <= 8) + rv.IntVal = APInt(BitWidth, ((char(*)())(intptr_t)FPtr)()); + else if (BitWidth <= 16) + rv.IntVal = APInt(BitWidth, ((short(*)())(intptr_t)FPtr)()); + else if (BitWidth <= 32) + rv.IntVal = APInt(BitWidth, ((int(*)())(intptr_t)FPtr)()); + else if (BitWidth <= 64) + rv.IntVal = APInt(BitWidth, ((int64_t(*)())(intptr_t)FPtr)()); + else + llvm_unreachable("Integer types > 64 bits not supported"); + return rv; + } + case Type::VoidTyID: + rv.IntVal = APInt(32, ((int(*)())(intptr_t)FPtr)()); + return rv; + case Type::FloatTyID: + rv.FloatVal = ((float(*)())(intptr_t)FPtr)(); + return rv; + case Type::DoubleTyID: + rv.DoubleVal = ((double(*)())(intptr_t)FPtr)(); + return rv; + case Type::X86_FP80TyID: + case Type::FP128TyID: + case Type::PPC_FP128TyID: + llvm_unreachable("long double not supported yet"); + case Type::PointerTyID: + return PTOGV(((void*(*)())(intptr_t)FPtr)()); + } + } + + report_fatal_error("MCJIT::runFunction does not support full-featured " + "argument passing. Please use " + "ExecutionEngine::getFunctionAddress and cast the result " + "to the desired function pointer type."); +} + +void *MCJIT::getPointerToNamedFunction(StringRef Name, bool AbortOnFailure) { + if (!isSymbolSearchingDisabled()) { + if (auto Sym = Resolver.findSymbol(std::string(Name))) { + if (auto AddrOrErr = Sym.getAddress()) + return reinterpret_cast<void*>( + static_cast<uintptr_t>(*AddrOrErr)); + } else if (auto Err = Sym.takeError()) + report_fatal_error(std::move(Err)); + } + + /// If a LazyFunctionCreator is installed, use it to get/create the function. + if (LazyFunctionCreator) + if (void *RP = LazyFunctionCreator(std::string(Name))) + return RP; + + if (AbortOnFailure) { + report_fatal_error("Program used external function '"+Name+ + "' which could not be resolved!"); + } + return nullptr; +} + +void MCJIT::RegisterJITEventListener(JITEventListener *L) { + if (!L) + return; + std::lock_guard<sys::Mutex> locked(lock); + EventListeners.push_back(L); +} + +void MCJIT::UnregisterJITEventListener(JITEventListener *L) { + if (!L) + return; + std::lock_guard<sys::Mutex> locked(lock); + auto I = find(reverse(EventListeners), L); + if (I != EventListeners.rend()) { + std::swap(*I, EventListeners.back()); + EventListeners.pop_back(); + } +} + +void MCJIT::notifyObjectLoaded(const object::ObjectFile &Obj, + const RuntimeDyld::LoadedObjectInfo &L) { + uint64_t Key = + static_cast<uint64_t>(reinterpret_cast<uintptr_t>(Obj.getData().data())); + std::lock_guard<sys::Mutex> locked(lock); + MemMgr->notifyObjectLoaded(this, Obj); + for (unsigned I = 0, S = EventListeners.size(); I < S; ++I) { + EventListeners[I]->notifyObjectLoaded(Key, Obj, L); + } +} + +void MCJIT::notifyFreeingObject(const object::ObjectFile &Obj) { + uint64_t Key = + static_cast<uint64_t>(reinterpret_cast<uintptr_t>(Obj.getData().data())); + std::lock_guard<sys::Mutex> locked(lock); + for (JITEventListener *L : EventListeners) + L->notifyFreeingObject(Key); +} + +JITSymbol +LinkingSymbolResolver::findSymbol(const std::string &Name) { + auto Result = ParentEngine.findSymbol(Name, false); + if (Result) + return Result; + if (ParentEngine.isSymbolSearchingDisabled()) + return nullptr; + return ClientResolver->findSymbol(Name); +} + +void LinkingSymbolResolver::anchor() {} diff --git a/contrib/libs/llvm12/lib/ExecutionEngine/MCJIT/MCJIT.h b/contrib/libs/llvm12/lib/ExecutionEngine/MCJIT/MCJIT.h index 6cbaad6e95..52e7eda903 100644 --- a/contrib/libs/llvm12/lib/ExecutionEngine/MCJIT/MCJIT.h +++ b/contrib/libs/llvm12/lib/ExecutionEngine/MCJIT/MCJIT.h @@ -1,342 +1,342 @@ -//===-- MCJIT.h - Class definition for the MCJIT ----------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_LIB_EXECUTIONENGINE_MCJIT_MCJIT_H -#define LLVM_LIB_EXECUTIONENGINE_MCJIT_MCJIT_H - -#include "llvm/ADT/SmallPtrSet.h" -#include "llvm/ADT/SmallVector.h" -#include "llvm/ExecutionEngine/ExecutionEngine.h" -#include "llvm/ExecutionEngine/RTDyldMemoryManager.h" -#include "llvm/ExecutionEngine/RuntimeDyld.h" - -namespace llvm { -class MCJIT; -class Module; -class ObjectCache; - -// This is a helper class that the MCJIT execution engine uses for linking -// functions across modules that it owns. It aggregates the memory manager -// that is passed in to the MCJIT constructor and defers most functionality -// to that object. -class LinkingSymbolResolver : public LegacyJITSymbolResolver { -public: - LinkingSymbolResolver(MCJIT &Parent, - std::shared_ptr<LegacyJITSymbolResolver> Resolver) - : ParentEngine(Parent), ClientResolver(std::move(Resolver)) {} - - JITSymbol findSymbol(const std::string &Name) override; - - // MCJIT doesn't support logical dylibs. - JITSymbol findSymbolInLogicalDylib(const std::string &Name) override { - return nullptr; - } - -private: - MCJIT &ParentEngine; - std::shared_ptr<LegacyJITSymbolResolver> ClientResolver; - void anchor() override; -}; - -// About Module states: added->loaded->finalized. -// -// The purpose of the "added" state is having modules in standby. (added=known -// but not compiled). The idea is that you can add a module to provide function -// definitions but if nothing in that module is referenced by a module in which -// a function is executed (note the wording here because it's not exactly the -// ideal case) then the module never gets compiled. This is sort of lazy -// compilation. -// -// The purpose of the "loaded" state (loaded=compiled and required sections -// copied into local memory but not yet ready for execution) is to have an -// intermediate state wherein clients can remap the addresses of sections, using -// MCJIT::mapSectionAddress, (in preparation for later copying to a new location -// or an external process) before relocations and page permissions are applied. -// -// It might not be obvious at first glance, but the "remote-mcjit" case in the -// lli tool does this. In that case, the intermediate action is taken by the -// RemoteMemoryManager in response to the notifyObjectLoaded function being -// called. - -class MCJIT : public ExecutionEngine { - MCJIT(std::unique_ptr<Module> M, std::unique_ptr<TargetMachine> tm, - std::shared_ptr<MCJITMemoryManager> MemMgr, - std::shared_ptr<LegacyJITSymbolResolver> Resolver); - - typedef llvm::SmallPtrSet<Module *, 4> ModulePtrSet; - - class OwningModuleContainer { - public: - OwningModuleContainer() { - } - ~OwningModuleContainer() { - freeModulePtrSet(AddedModules); - freeModulePtrSet(LoadedModules); - freeModulePtrSet(FinalizedModules); - } - - ModulePtrSet::iterator begin_added() { return AddedModules.begin(); } - ModulePtrSet::iterator end_added() { return AddedModules.end(); } - iterator_range<ModulePtrSet::iterator> added() { - return make_range(begin_added(), end_added()); - } - - ModulePtrSet::iterator begin_loaded() { return LoadedModules.begin(); } - ModulePtrSet::iterator end_loaded() { return LoadedModules.end(); } - - ModulePtrSet::iterator begin_finalized() { return FinalizedModules.begin(); } - ModulePtrSet::iterator end_finalized() { return FinalizedModules.end(); } - - void addModule(std::unique_ptr<Module> M) { - AddedModules.insert(M.release()); - } - - bool removeModule(Module *M) { - return AddedModules.erase(M) || LoadedModules.erase(M) || - FinalizedModules.erase(M); - } - - bool hasModuleBeenAddedButNotLoaded(Module *M) { +//===-- MCJIT.h - Class definition for the MCJIT ----------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_EXECUTIONENGINE_MCJIT_MCJIT_H +#define LLVM_LIB_EXECUTIONENGINE_MCJIT_MCJIT_H + +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ExecutionEngine/ExecutionEngine.h" +#include "llvm/ExecutionEngine/RTDyldMemoryManager.h" +#include "llvm/ExecutionEngine/RuntimeDyld.h" + +namespace llvm { +class MCJIT; +class Module; +class ObjectCache; + +// This is a helper class that the MCJIT execution engine uses for linking +// functions across modules that it owns. It aggregates the memory manager +// that is passed in to the MCJIT constructor and defers most functionality +// to that object. +class LinkingSymbolResolver : public LegacyJITSymbolResolver { +public: + LinkingSymbolResolver(MCJIT &Parent, + std::shared_ptr<LegacyJITSymbolResolver> Resolver) + : ParentEngine(Parent), ClientResolver(std::move(Resolver)) {} + + JITSymbol findSymbol(const std::string &Name) override; + + // MCJIT doesn't support logical dylibs. + JITSymbol findSymbolInLogicalDylib(const std::string &Name) override { + return nullptr; + } + +private: + MCJIT &ParentEngine; + std::shared_ptr<LegacyJITSymbolResolver> ClientResolver; + void anchor() override; +}; + +// About Module states: added->loaded->finalized. +// +// The purpose of the "added" state is having modules in standby. (added=known +// but not compiled). The idea is that you can add a module to provide function +// definitions but if nothing in that module is referenced by a module in which +// a function is executed (note the wording here because it's not exactly the +// ideal case) then the module never gets compiled. This is sort of lazy +// compilation. +// +// The purpose of the "loaded" state (loaded=compiled and required sections +// copied into local memory but not yet ready for execution) is to have an +// intermediate state wherein clients can remap the addresses of sections, using +// MCJIT::mapSectionAddress, (in preparation for later copying to a new location +// or an external process) before relocations and page permissions are applied. +// +// It might not be obvious at first glance, but the "remote-mcjit" case in the +// lli tool does this. In that case, the intermediate action is taken by the +// RemoteMemoryManager in response to the notifyObjectLoaded function being +// called. + +class MCJIT : public ExecutionEngine { + MCJIT(std::unique_ptr<Module> M, std::unique_ptr<TargetMachine> tm, + std::shared_ptr<MCJITMemoryManager> MemMgr, + std::shared_ptr<LegacyJITSymbolResolver> Resolver); + + typedef llvm::SmallPtrSet<Module *, 4> ModulePtrSet; + + class OwningModuleContainer { + public: + OwningModuleContainer() { + } + ~OwningModuleContainer() { + freeModulePtrSet(AddedModules); + freeModulePtrSet(LoadedModules); + freeModulePtrSet(FinalizedModules); + } + + ModulePtrSet::iterator begin_added() { return AddedModules.begin(); } + ModulePtrSet::iterator end_added() { return AddedModules.end(); } + iterator_range<ModulePtrSet::iterator> added() { + return make_range(begin_added(), end_added()); + } + + ModulePtrSet::iterator begin_loaded() { return LoadedModules.begin(); } + ModulePtrSet::iterator end_loaded() { return LoadedModules.end(); } + + ModulePtrSet::iterator begin_finalized() { return FinalizedModules.begin(); } + ModulePtrSet::iterator end_finalized() { return FinalizedModules.end(); } + + void addModule(std::unique_ptr<Module> M) { + AddedModules.insert(M.release()); + } + + bool removeModule(Module *M) { + return AddedModules.erase(M) || LoadedModules.erase(M) || + FinalizedModules.erase(M); + } + + bool hasModuleBeenAddedButNotLoaded(Module *M) { return AddedModules.contains(M); - } - - bool hasModuleBeenLoaded(Module *M) { - // If the module is in either the "loaded" or "finalized" sections it - // has been loaded. + } + + bool hasModuleBeenLoaded(Module *M) { + // If the module is in either the "loaded" or "finalized" sections it + // has been loaded. return LoadedModules.contains(M) || FinalizedModules.contains(M); - } - - bool hasModuleBeenFinalized(Module *M) { + } + + bool hasModuleBeenFinalized(Module *M) { return FinalizedModules.contains(M); - } - - bool ownsModule(Module* M) { + } + + bool ownsModule(Module* M) { return AddedModules.contains(M) || LoadedModules.contains(M) || FinalizedModules.contains(M); - } - - void markModuleAsLoaded(Module *M) { - // This checks against logic errors in the MCJIT implementation. - // This function should never be called with either a Module that MCJIT - // does not own or a Module that has already been loaded and/or finalized. - assert(AddedModules.count(M) && - "markModuleAsLoaded: Module not found in AddedModules"); - - // Remove the module from the "Added" set. - AddedModules.erase(M); - - // Add the Module to the "Loaded" set. - LoadedModules.insert(M); - } - - void markModuleAsFinalized(Module *M) { - // This checks against logic errors in the MCJIT implementation. - // This function should never be called with either a Module that MCJIT - // does not own, a Module that has not been loaded or a Module that has - // already been finalized. - assert(LoadedModules.count(M) && - "markModuleAsFinalized: Module not found in LoadedModules"); - - // Remove the module from the "Loaded" section of the list. - LoadedModules.erase(M); - - // Add the Module to the "Finalized" section of the list by inserting it - // before the 'end' iterator. - FinalizedModules.insert(M); - } - - void markAllLoadedModulesAsFinalized() { - for (ModulePtrSet::iterator I = LoadedModules.begin(), - E = LoadedModules.end(); - I != E; ++I) { - Module *M = *I; - FinalizedModules.insert(M); - } - LoadedModules.clear(); - } - - private: - ModulePtrSet AddedModules; - ModulePtrSet LoadedModules; - ModulePtrSet FinalizedModules; - - void freeModulePtrSet(ModulePtrSet& MPS) { - // Go through the module set and delete everything. - for (ModulePtrSet::iterator I = MPS.begin(), E = MPS.end(); I != E; ++I) { - Module *M = *I; - delete M; - } - MPS.clear(); - } - }; - - std::unique_ptr<TargetMachine> TM; - MCContext *Ctx; - std::shared_ptr<MCJITMemoryManager> MemMgr; - LinkingSymbolResolver Resolver; - RuntimeDyld Dyld; - std::vector<JITEventListener*> EventListeners; - - OwningModuleContainer OwnedModules; - - SmallVector<object::OwningBinary<object::Archive>, 2> Archives; - SmallVector<std::unique_ptr<MemoryBuffer>, 2> Buffers; - - SmallVector<std::unique_ptr<object::ObjectFile>, 2> LoadedObjects; - - // An optional ObjectCache to be notified of compiled objects and used to - // perform lookup of pre-compiled code to avoid re-compilation. - ObjectCache *ObjCache; - - Function *FindFunctionNamedInModulePtrSet(StringRef FnName, - ModulePtrSet::iterator I, - ModulePtrSet::iterator E); - - GlobalVariable *FindGlobalVariableNamedInModulePtrSet(StringRef Name, - bool AllowInternal, - ModulePtrSet::iterator I, - ModulePtrSet::iterator E); - - void runStaticConstructorsDestructorsInModulePtrSet(bool isDtors, - ModulePtrSet::iterator I, - ModulePtrSet::iterator E); - -public: - ~MCJIT() override; - - /// @name ExecutionEngine interface implementation - /// @{ - void addModule(std::unique_ptr<Module> M) override; - void addObjectFile(std::unique_ptr<object::ObjectFile> O) override; - void addObjectFile(object::OwningBinary<object::ObjectFile> O) override; - void addArchive(object::OwningBinary<object::Archive> O) override; - bool removeModule(Module *M) override; - - /// FindFunctionNamed - Search all of the active modules to find the function that - /// defines FnName. This is very slow operation and shouldn't be used for - /// general code. - Function *FindFunctionNamed(StringRef FnName) override; - - /// FindGlobalVariableNamed - Search all of the active modules to find the - /// global variable that defines Name. This is very slow operation and - /// shouldn't be used for general code. - GlobalVariable *FindGlobalVariableNamed(StringRef Name, - bool AllowInternal = false) override; - - /// Sets the object manager that MCJIT should use to avoid compilation. - void setObjectCache(ObjectCache *manager) override; - - void setProcessAllSections(bool ProcessAllSections) override { - Dyld.setProcessAllSections(ProcessAllSections); - } - - void generateCodeForModule(Module *M) override; - - /// finalizeObject - ensure the module is fully processed and is usable. - /// - /// It is the user-level function for completing the process of making the - /// object usable for execution. It should be called after sections within an - /// object have been relocated using mapSectionAddress. When this method is - /// called the MCJIT execution engine will reapply relocations for a loaded - /// object. - /// Is it OK to finalize a set of modules, add modules and finalize again. - // FIXME: Do we really need both of these? - void finalizeObject() override; - virtual void finalizeModule(Module *); - void finalizeLoadedModules(); - - /// runStaticConstructorsDestructors - This method is used to execute all of - /// the static constructors or destructors for a program. - /// - /// \param isDtors - Run the destructors instead of constructors. - void runStaticConstructorsDestructors(bool isDtors) override; - - void *getPointerToFunction(Function *F) override; - - GenericValue runFunction(Function *F, - ArrayRef<GenericValue> ArgValues) override; - - /// getPointerToNamedFunction - This method returns the address of the - /// specified function by using the dlsym function call. As such it is only - /// useful for resolving library symbols, not code generated symbols. - /// - /// If AbortOnFailure is false and no function with the given name is - /// found, this function silently returns a null pointer. Otherwise, - /// it prints a message to stderr and aborts. - /// - void *getPointerToNamedFunction(StringRef Name, - bool AbortOnFailure = true) override; - - /// mapSectionAddress - map a section to its target address space value. - /// Map the address of a JIT section as returned from the memory manager - /// to the address in the target process as the running code will see it. - /// This is the address which will be used for relocation resolution. - void mapSectionAddress(const void *LocalAddress, - uint64_t TargetAddress) override { - Dyld.mapSectionAddress(LocalAddress, TargetAddress); - } - void RegisterJITEventListener(JITEventListener *L) override; - void UnregisterJITEventListener(JITEventListener *L) override; - - // If successful, these function will implicitly finalize all loaded objects. - // To get a function address within MCJIT without causing a finalize, use - // getSymbolAddress. - uint64_t getGlobalValueAddress(const std::string &Name) override; - uint64_t getFunctionAddress(const std::string &Name) override; - - TargetMachine *getTargetMachine() override { return TM.get(); } - - /// @} - /// @name (Private) Registration Interfaces - /// @{ - - static void Register() { - MCJITCtor = createJIT; - } - - static ExecutionEngine * - createJIT(std::unique_ptr<Module> M, std::string *ErrorStr, - std::shared_ptr<MCJITMemoryManager> MemMgr, - std::shared_ptr<LegacyJITSymbolResolver> Resolver, - std::unique_ptr<TargetMachine> TM); - - // @} - - // Takes a mangled name and returns the corresponding JITSymbol (if a - // definition of that mangled name has been added to the JIT). - JITSymbol findSymbol(const std::string &Name, bool CheckFunctionsOnly); - - // DEPRECATED - Please use findSymbol instead. - // - // This is not directly exposed via the ExecutionEngine API, but it is - // used by the LinkingMemoryManager. - // - // getSymbolAddress takes an unmangled name and returns the corresponding - // JITSymbol if a definition of the name has been added to the JIT. - uint64_t getSymbolAddress(const std::string &Name, - bool CheckFunctionsOnly); - -protected: - /// emitObject -- Generate a JITed object in memory from the specified module - /// Currently, MCJIT only supports a single module and the module passed to - /// this function call is expected to be the contained module. The module - /// is passed as a parameter here to prepare for multiple module support in - /// the future. - std::unique_ptr<MemoryBuffer> emitObject(Module *M); - - void notifyObjectLoaded(const object::ObjectFile &Obj, - const RuntimeDyld::LoadedObjectInfo &L); - void notifyFreeingObject(const object::ObjectFile &Obj); - - JITSymbol findExistingSymbol(const std::string &Name); - Module *findModuleForSymbol(const std::string &Name, bool CheckFunctionsOnly); -}; - -} // end llvm namespace - -#endif // LLVM_LIB_EXECUTIONENGINE_MCJIT_MCJIT_H + } + + void markModuleAsLoaded(Module *M) { + // This checks against logic errors in the MCJIT implementation. + // This function should never be called with either a Module that MCJIT + // does not own or a Module that has already been loaded and/or finalized. + assert(AddedModules.count(M) && + "markModuleAsLoaded: Module not found in AddedModules"); + + // Remove the module from the "Added" set. + AddedModules.erase(M); + + // Add the Module to the "Loaded" set. + LoadedModules.insert(M); + } + + void markModuleAsFinalized(Module *M) { + // This checks against logic errors in the MCJIT implementation. + // This function should never be called with either a Module that MCJIT + // does not own, a Module that has not been loaded or a Module that has + // already been finalized. + assert(LoadedModules.count(M) && + "markModuleAsFinalized: Module not found in LoadedModules"); + + // Remove the module from the "Loaded" section of the list. + LoadedModules.erase(M); + + // Add the Module to the "Finalized" section of the list by inserting it + // before the 'end' iterator. + FinalizedModules.insert(M); + } + + void markAllLoadedModulesAsFinalized() { + for (ModulePtrSet::iterator I = LoadedModules.begin(), + E = LoadedModules.end(); + I != E; ++I) { + Module *M = *I; + FinalizedModules.insert(M); + } + LoadedModules.clear(); + } + + private: + ModulePtrSet AddedModules; + ModulePtrSet LoadedModules; + ModulePtrSet FinalizedModules; + + void freeModulePtrSet(ModulePtrSet& MPS) { + // Go through the module set and delete everything. + for (ModulePtrSet::iterator I = MPS.begin(), E = MPS.end(); I != E; ++I) { + Module *M = *I; + delete M; + } + MPS.clear(); + } + }; + + std::unique_ptr<TargetMachine> TM; + MCContext *Ctx; + std::shared_ptr<MCJITMemoryManager> MemMgr; + LinkingSymbolResolver Resolver; + RuntimeDyld Dyld; + std::vector<JITEventListener*> EventListeners; + + OwningModuleContainer OwnedModules; + + SmallVector<object::OwningBinary<object::Archive>, 2> Archives; + SmallVector<std::unique_ptr<MemoryBuffer>, 2> Buffers; + + SmallVector<std::unique_ptr<object::ObjectFile>, 2> LoadedObjects; + + // An optional ObjectCache to be notified of compiled objects and used to + // perform lookup of pre-compiled code to avoid re-compilation. + ObjectCache *ObjCache; + + Function *FindFunctionNamedInModulePtrSet(StringRef FnName, + ModulePtrSet::iterator I, + ModulePtrSet::iterator E); + + GlobalVariable *FindGlobalVariableNamedInModulePtrSet(StringRef Name, + bool AllowInternal, + ModulePtrSet::iterator I, + ModulePtrSet::iterator E); + + void runStaticConstructorsDestructorsInModulePtrSet(bool isDtors, + ModulePtrSet::iterator I, + ModulePtrSet::iterator E); + +public: + ~MCJIT() override; + + /// @name ExecutionEngine interface implementation + /// @{ + void addModule(std::unique_ptr<Module> M) override; + void addObjectFile(std::unique_ptr<object::ObjectFile> O) override; + void addObjectFile(object::OwningBinary<object::ObjectFile> O) override; + void addArchive(object::OwningBinary<object::Archive> O) override; + bool removeModule(Module *M) override; + + /// FindFunctionNamed - Search all of the active modules to find the function that + /// defines FnName. This is very slow operation and shouldn't be used for + /// general code. + Function *FindFunctionNamed(StringRef FnName) override; + + /// FindGlobalVariableNamed - Search all of the active modules to find the + /// global variable that defines Name. This is very slow operation and + /// shouldn't be used for general code. + GlobalVariable *FindGlobalVariableNamed(StringRef Name, + bool AllowInternal = false) override; + + /// Sets the object manager that MCJIT should use to avoid compilation. + void setObjectCache(ObjectCache *manager) override; + + void setProcessAllSections(bool ProcessAllSections) override { + Dyld.setProcessAllSections(ProcessAllSections); + } + + void generateCodeForModule(Module *M) override; + + /// finalizeObject - ensure the module is fully processed and is usable. + /// + /// It is the user-level function for completing the process of making the + /// object usable for execution. It should be called after sections within an + /// object have been relocated using mapSectionAddress. When this method is + /// called the MCJIT execution engine will reapply relocations for a loaded + /// object. + /// Is it OK to finalize a set of modules, add modules and finalize again. + // FIXME: Do we really need both of these? + void finalizeObject() override; + virtual void finalizeModule(Module *); + void finalizeLoadedModules(); + + /// runStaticConstructorsDestructors - This method is used to execute all of + /// the static constructors or destructors for a program. + /// + /// \param isDtors - Run the destructors instead of constructors. + void runStaticConstructorsDestructors(bool isDtors) override; + + void *getPointerToFunction(Function *F) override; + + GenericValue runFunction(Function *F, + ArrayRef<GenericValue> ArgValues) override; + + /// getPointerToNamedFunction - This method returns the address of the + /// specified function by using the dlsym function call. As such it is only + /// useful for resolving library symbols, not code generated symbols. + /// + /// If AbortOnFailure is false and no function with the given name is + /// found, this function silently returns a null pointer. Otherwise, + /// it prints a message to stderr and aborts. + /// + void *getPointerToNamedFunction(StringRef Name, + bool AbortOnFailure = true) override; + + /// mapSectionAddress - map a section to its target address space value. + /// Map the address of a JIT section as returned from the memory manager + /// to the address in the target process as the running code will see it. + /// This is the address which will be used for relocation resolution. + void mapSectionAddress(const void *LocalAddress, + uint64_t TargetAddress) override { + Dyld.mapSectionAddress(LocalAddress, TargetAddress); + } + void RegisterJITEventListener(JITEventListener *L) override; + void UnregisterJITEventListener(JITEventListener *L) override; + + // If successful, these function will implicitly finalize all loaded objects. + // To get a function address within MCJIT without causing a finalize, use + // getSymbolAddress. + uint64_t getGlobalValueAddress(const std::string &Name) override; + uint64_t getFunctionAddress(const std::string &Name) override; + + TargetMachine *getTargetMachine() override { return TM.get(); } + + /// @} + /// @name (Private) Registration Interfaces + /// @{ + + static void Register() { + MCJITCtor = createJIT; + } + + static ExecutionEngine * + createJIT(std::unique_ptr<Module> M, std::string *ErrorStr, + std::shared_ptr<MCJITMemoryManager> MemMgr, + std::shared_ptr<LegacyJITSymbolResolver> Resolver, + std::unique_ptr<TargetMachine> TM); + + // @} + + // Takes a mangled name and returns the corresponding JITSymbol (if a + // definition of that mangled name has been added to the JIT). + JITSymbol findSymbol(const std::string &Name, bool CheckFunctionsOnly); + + // DEPRECATED - Please use findSymbol instead. + // + // This is not directly exposed via the ExecutionEngine API, but it is + // used by the LinkingMemoryManager. + // + // getSymbolAddress takes an unmangled name and returns the corresponding + // JITSymbol if a definition of the name has been added to the JIT. + uint64_t getSymbolAddress(const std::string &Name, + bool CheckFunctionsOnly); + +protected: + /// emitObject -- Generate a JITed object in memory from the specified module + /// Currently, MCJIT only supports a single module and the module passed to + /// this function call is expected to be the contained module. The module + /// is passed as a parameter here to prepare for multiple module support in + /// the future. + std::unique_ptr<MemoryBuffer> emitObject(Module *M); + + void notifyObjectLoaded(const object::ObjectFile &Obj, + const RuntimeDyld::LoadedObjectInfo &L); + void notifyFreeingObject(const object::ObjectFile &Obj); + + JITSymbol findExistingSymbol(const std::string &Name); + Module *findModuleForSymbol(const std::string &Name, bool CheckFunctionsOnly); +}; + +} // end llvm namespace + +#endif // LLVM_LIB_EXECUTIONENGINE_MCJIT_MCJIT_H diff --git a/contrib/libs/llvm12/lib/ExecutionEngine/MCJIT/ya.make b/contrib/libs/llvm12/lib/ExecutionEngine/MCJIT/ya.make index bfb9867ad7..71377b654c 100644 --- a/contrib/libs/llvm12/lib/ExecutionEngine/MCJIT/ya.make +++ b/contrib/libs/llvm12/lib/ExecutionEngine/MCJIT/ya.make @@ -1,17 +1,17 @@ -# Generated by devtools/yamaker. - -LIBRARY() - +# Generated by devtools/yamaker. + +LIBRARY() + OWNER( orivej g:cpp-contrib ) - + LICENSE(Apache-2.0 WITH LLVM-exception) LICENSE_TEXTS(.yandex_meta/licenses.list.txt) -PEERDIR( +PEERDIR( contrib/libs/llvm12 contrib/libs/llvm12/include contrib/libs/llvm12/lib/ExecutionEngine @@ -20,18 +20,18 @@ PEERDIR( contrib/libs/llvm12/lib/Object contrib/libs/llvm12/lib/Support contrib/libs/llvm12/lib/Target -) - +) + ADDINCL( contrib/libs/llvm12/lib/ExecutionEngine/MCJIT ) - -NO_COMPILER_WARNINGS() - -NO_UTIL() - -SRCS( - MCJIT.cpp -) - -END() + +NO_COMPILER_WARNINGS() + +NO_UTIL() + +SRCS( + MCJIT.cpp +) + +END() diff --git a/contrib/libs/llvm12/lib/ExecutionEngine/PerfJITEvents/PerfJITEventListener.cpp b/contrib/libs/llvm12/lib/ExecutionEngine/PerfJITEvents/PerfJITEventListener.cpp index f47402b0f0..d4c715cc59 100644 --- a/contrib/libs/llvm12/lib/ExecutionEngine/PerfJITEvents/PerfJITEventListener.cpp +++ b/contrib/libs/llvm12/lib/ExecutionEngine/PerfJITEvents/PerfJITEventListener.cpp @@ -1,504 +1,504 @@ -//===-- PerfJITEventListener.cpp - Tell Linux's perf about JITted code ----===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file defines a JITEventListener object that tells perf about JITted -// functions, including source line information. -// -// Documentation for perf jit integration is available at: -// https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/tools/perf/Documentation/jitdump-specification.txt -// https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/tools/perf/Documentation/jit-interface.txt -// -//===----------------------------------------------------------------------===// - -#include "llvm/ADT/Twine.h" -#include "llvm/Config/config.h" -#include "llvm/DebugInfo/DWARF/DWARFContext.h" -#include "llvm/ExecutionEngine/JITEventListener.h" -#include "llvm/Object/ObjectFile.h" -#include "llvm/Object/SymbolSize.h" -#include "llvm/Support/Debug.h" -#include "llvm/Support/Errno.h" -#include "llvm/Support/FileSystem.h" -#include "llvm/Support/ManagedStatic.h" -#include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/Mutex.h" -#include "llvm/Support/Path.h" -#include "llvm/Support/Process.h" -#include "llvm/Support/Threading.h" -#include "llvm/Support/raw_ostream.h" -#include <mutex> - -#include <sys/mman.h> // mmap() -#include <time.h> // clock_gettime(), time(), localtime_r() */ -#include <unistd.h> // for read(), close() - -using namespace llvm; -using namespace llvm::object; -typedef DILineInfoSpecifier::FileLineInfoKind FileLineInfoKind; - -namespace { - -// language identifier (XXX: should we generate something better from debug -// info?) -#define JIT_LANG "llvm-IR" -#define LLVM_PERF_JIT_MAGIC \ - ((uint32_t)'J' << 24 | (uint32_t)'i' << 16 | (uint32_t)'T' << 8 | \ - (uint32_t)'D') -#define LLVM_PERF_JIT_VERSION 1 - -// bit 0: set if the jitdump file is using an architecture-specific timestamp -// clock source -#define JITDUMP_FLAGS_ARCH_TIMESTAMP (1ULL << 0) - -struct LLVMPerfJitHeader; - -class PerfJITEventListener : public JITEventListener { -public: - PerfJITEventListener(); - ~PerfJITEventListener() { - if (MarkerAddr) - CloseMarker(); - } - - void notifyObjectLoaded(ObjectKey K, const ObjectFile &Obj, - const RuntimeDyld::LoadedObjectInfo &L) override; - void notifyFreeingObject(ObjectKey K) override; - -private: - bool InitDebuggingDir(); - bool OpenMarker(); - void CloseMarker(); - static bool FillMachine(LLVMPerfJitHeader &hdr); - - void NotifyCode(Expected<llvm::StringRef> &Symbol, uint64_t CodeAddr, - uint64_t CodeSize); - void NotifyDebug(uint64_t CodeAddr, DILineInfoTable Lines); - - // cache lookups - sys::Process::Pid Pid; - - // base directory for output data - std::string JitPath; - - // output data stream, closed via Dumpstream - int DumpFd = -1; - - // output data stream - std::unique_ptr<raw_fd_ostream> Dumpstream; - - // prevent concurrent dumps from messing up the output file - sys::Mutex Mutex; - - // perf mmap marker - void *MarkerAddr = NULL; - - // perf support ready - bool SuccessfullyInitialized = false; - - // identifier for functions, primarily to identify when moving them around - uint64_t CodeGeneration = 1; -}; - -// The following are POD struct definitions from the perf jit specification - -enum LLVMPerfJitRecordType { - JIT_CODE_LOAD = 0, - JIT_CODE_MOVE = 1, // not emitted, code isn't moved - JIT_CODE_DEBUG_INFO = 2, - JIT_CODE_CLOSE = 3, // not emitted, unnecessary - JIT_CODE_UNWINDING_INFO = 4, // not emitted - - JIT_CODE_MAX -}; - -struct LLVMPerfJitHeader { - uint32_t Magic; // characters "JiTD" - uint32_t Version; // header version - uint32_t TotalSize; // total size of header - uint32_t ElfMach; // elf mach target - uint32_t Pad1; // reserved - uint32_t Pid; - uint64_t Timestamp; // timestamp - uint64_t Flags; // flags -}; - -// record prefix (mandatory in each record) -struct LLVMPerfJitRecordPrefix { - uint32_t Id; // record type identifier - uint32_t TotalSize; - uint64_t Timestamp; -}; - -struct LLVMPerfJitRecordCodeLoad { - LLVMPerfJitRecordPrefix Prefix; - - uint32_t Pid; - uint32_t Tid; - uint64_t Vma; - uint64_t CodeAddr; - uint64_t CodeSize; - uint64_t CodeIndex; -}; - -struct LLVMPerfJitDebugEntry { - uint64_t Addr; - int Lineno; // source line number starting at 1 - int Discrim; // column discriminator, 0 is default - // followed by null terminated filename, \xff\0 if same as previous entry -}; - -struct LLVMPerfJitRecordDebugInfo { - LLVMPerfJitRecordPrefix Prefix; - - uint64_t CodeAddr; - uint64_t NrEntry; - // followed by NrEntry LLVMPerfJitDebugEntry records -}; - -static inline uint64_t timespec_to_ns(const struct timespec *ts) { - const uint64_t NanoSecPerSec = 1000000000; - return ((uint64_t)ts->tv_sec * NanoSecPerSec) + ts->tv_nsec; -} - -static inline uint64_t perf_get_timestamp(void) { - struct timespec ts; - int ret; - - ret = clock_gettime(CLOCK_MONOTONIC, &ts); - if (ret) - return 0; - - return timespec_to_ns(&ts); -} - -PerfJITEventListener::PerfJITEventListener() - : Pid(sys::Process::getProcessId()) { - // check if clock-source is supported - if (!perf_get_timestamp()) { - errs() << "kernel does not support CLOCK_MONOTONIC\n"; - return; - } - - if (!InitDebuggingDir()) { - errs() << "could not initialize debugging directory\n"; - return; - } - - std::string Filename; - raw_string_ostream FilenameBuf(Filename); - FilenameBuf << JitPath << "/jit-" << Pid << ".dump"; - - // Need to open ourselves, because we need to hand the FD to OpenMarker() and - // raw_fd_ostream doesn't expose the FD. - using sys::fs::openFileForWrite; - if (auto EC = - openFileForReadWrite(FilenameBuf.str(), DumpFd, - sys::fs::CD_CreateNew, sys::fs::OF_None)) { - errs() << "could not open JIT dump file " << FilenameBuf.str() << ": " - << EC.message() << "\n"; - return; - } - - Dumpstream = std::make_unique<raw_fd_ostream>(DumpFd, true); - - LLVMPerfJitHeader Header = {0}; - if (!FillMachine(Header)) - return; - - // signal this process emits JIT information - if (!OpenMarker()) - return; - - // emit dumpstream header - Header.Magic = LLVM_PERF_JIT_MAGIC; - Header.Version = LLVM_PERF_JIT_VERSION; - Header.TotalSize = sizeof(Header); - Header.Pid = Pid; - Header.Timestamp = perf_get_timestamp(); - Dumpstream->write(reinterpret_cast<const char *>(&Header), sizeof(Header)); - - // Everything initialized, can do profiling now. - if (!Dumpstream->has_error()) - SuccessfullyInitialized = true; -} - -void PerfJITEventListener::notifyObjectLoaded( - ObjectKey K, const ObjectFile &Obj, - const RuntimeDyld::LoadedObjectInfo &L) { - - if (!SuccessfullyInitialized) - return; - - OwningBinary<ObjectFile> DebugObjOwner = L.getObjectForDebug(Obj); - const ObjectFile &DebugObj = *DebugObjOwner.getBinary(); - - // Get the address of the object image for use as a unique identifier - std::unique_ptr<DIContext> Context = DWARFContext::create(DebugObj); - - // Use symbol info to iterate over functions in the object. - for (const std::pair<SymbolRef, uint64_t> &P : computeSymbolSizes(DebugObj)) { - SymbolRef Sym = P.first; - std::string SourceFileName; - - Expected<SymbolRef::Type> SymTypeOrErr = Sym.getType(); - if (!SymTypeOrErr) { - // There's not much we can with errors here - consumeError(SymTypeOrErr.takeError()); - continue; - } - SymbolRef::Type SymType = *SymTypeOrErr; - if (SymType != SymbolRef::ST_Function) - continue; - - Expected<StringRef> Name = Sym.getName(); - if (!Name) { - consumeError(Name.takeError()); - continue; - } - - Expected<uint64_t> AddrOrErr = Sym.getAddress(); - if (!AddrOrErr) { - consumeError(AddrOrErr.takeError()); - continue; - } - uint64_t Size = P.second; - object::SectionedAddress Address; - Address.Address = *AddrOrErr; - - uint64_t SectionIndex = object::SectionedAddress::UndefSection; - if (auto SectOrErr = Sym.getSection()) - if (*SectOrErr != Obj.section_end()) - SectionIndex = SectOrErr.get()->getIndex(); - - // According to spec debugging info has to come before loading the - // corresonding code load. - DILineInfoTable Lines = Context->getLineInfoForAddressRange( - {*AddrOrErr, SectionIndex}, Size, FileLineInfoKind::AbsoluteFilePath); - - NotifyDebug(*AddrOrErr, Lines); - NotifyCode(Name, *AddrOrErr, Size); - } - - Dumpstream->flush(); -} - -void PerfJITEventListener::notifyFreeingObject(ObjectKey K) { - // perf currently doesn't have an interface for unloading. But munmap()ing the - // code section does, so that's ok. -} - -bool PerfJITEventListener::InitDebuggingDir() { - time_t Time; - struct tm LocalTime; - char TimeBuffer[sizeof("YYYYMMDD")]; - SmallString<64> Path; - - // search for location to dump data to - if (const char *BaseDir = getenv("JITDUMPDIR")) - Path.append(BaseDir); - else if (!sys::path::home_directory(Path)) - Path = "."; - - // create debug directory - Path += "/.debug/jit/"; - if (auto EC = sys::fs::create_directories(Path)) { - errs() << "could not create jit cache directory " << Path << ": " - << EC.message() << "\n"; - return false; - } - - // create unique directory for dump data related to this process - time(&Time); - localtime_r(&Time, &LocalTime); - strftime(TimeBuffer, sizeof(TimeBuffer), "%Y%m%d", &LocalTime); - Path += JIT_LANG "-jit-"; - Path += TimeBuffer; - - SmallString<128> UniqueDebugDir; - - using sys::fs::createUniqueDirectory; - if (auto EC = createUniqueDirectory(Path, UniqueDebugDir)) { - errs() << "could not create unique jit cache directory " << UniqueDebugDir - << ": " << EC.message() << "\n"; - return false; - } - - JitPath = std::string(UniqueDebugDir.str()); - - return true; -} - -bool PerfJITEventListener::OpenMarker() { - // We mmap the jitdump to create an MMAP RECORD in perf.data file. The mmap - // is captured either live (perf record running when we mmap) or in deferred - // mode, via /proc/PID/maps. The MMAP record is used as a marker of a jitdump - // file for more meta data info about the jitted code. Perf report/annotate - // detect this special filename and process the jitdump file. - // - // Mapping must be PROT_EXEC to ensure it is captured by perf record - // even when not using -d option. - MarkerAddr = ::mmap(NULL, sys::Process::getPageSizeEstimate(), - PROT_READ | PROT_EXEC, MAP_PRIVATE, DumpFd, 0); - - if (MarkerAddr == MAP_FAILED) { - errs() << "could not mmap JIT marker\n"; - return false; - } - return true; -} - -void PerfJITEventListener::CloseMarker() { - if (!MarkerAddr) - return; - - munmap(MarkerAddr, sys::Process::getPageSizeEstimate()); - MarkerAddr = nullptr; -} - -bool PerfJITEventListener::FillMachine(LLVMPerfJitHeader &hdr) { - char id[16]; - struct { - uint16_t e_type; - uint16_t e_machine; - } info; - - size_t RequiredMemory = sizeof(id) + sizeof(info); - - ErrorOr<std::unique_ptr<MemoryBuffer>> MB = - MemoryBuffer::getFileSlice("/proc/self/exe", - RequiredMemory, - 0); - - // This'll not guarantee that enough data was actually read from the - // underlying file. Instead the trailing part of the buffer would be - // zeroed. Given the ELF signature check below that seems ok though, - // it's unlikely that the file ends just after that, and the - // consequence would just be that perf wouldn't recognize the - // signature. - if (auto EC = MB.getError()) { - errs() << "could not open /proc/self/exe: " << EC.message() << "\n"; - return false; - } - - memcpy(&id, (*MB)->getBufferStart(), sizeof(id)); - memcpy(&info, (*MB)->getBufferStart() + sizeof(id), sizeof(info)); - - // check ELF signature - if (id[0] != 0x7f || id[1] != 'E' || id[2] != 'L' || id[3] != 'F') { - errs() << "invalid elf signature\n"; - return false; - } - - hdr.ElfMach = info.e_machine; - - return true; -} - -void PerfJITEventListener::NotifyCode(Expected<llvm::StringRef> &Symbol, - uint64_t CodeAddr, uint64_t CodeSize) { - assert(SuccessfullyInitialized); - - // 0 length functions can't have samples. - if (CodeSize == 0) - return; - - LLVMPerfJitRecordCodeLoad rec; - rec.Prefix.Id = JIT_CODE_LOAD; - rec.Prefix.TotalSize = sizeof(rec) + // debug record itself - Symbol->size() + 1 + // symbol name - CodeSize; // and code - rec.Prefix.Timestamp = perf_get_timestamp(); - - rec.CodeSize = CodeSize; - rec.Vma = 0; - rec.CodeAddr = CodeAddr; - rec.Pid = Pid; - rec.Tid = get_threadid(); - - // avoid interspersing output - std::lock_guard<sys::Mutex> Guard(Mutex); - - rec.CodeIndex = CodeGeneration++; // under lock! - - Dumpstream->write(reinterpret_cast<const char *>(&rec), sizeof(rec)); - Dumpstream->write(Symbol->data(), Symbol->size() + 1); - Dumpstream->write(reinterpret_cast<const char *>(CodeAddr), CodeSize); -} - -void PerfJITEventListener::NotifyDebug(uint64_t CodeAddr, - DILineInfoTable Lines) { - assert(SuccessfullyInitialized); - - // Didn't get useful debug info. - if (Lines.empty()) - return; - - LLVMPerfJitRecordDebugInfo rec; - rec.Prefix.Id = JIT_CODE_DEBUG_INFO; - rec.Prefix.TotalSize = sizeof(rec); // will be increased further - rec.Prefix.Timestamp = perf_get_timestamp(); - rec.CodeAddr = CodeAddr; - rec.NrEntry = Lines.size(); - - // compute total size size of record (variable due to filenames) - DILineInfoTable::iterator Begin = Lines.begin(); - DILineInfoTable::iterator End = Lines.end(); - for (DILineInfoTable::iterator It = Begin; It != End; ++It) { - DILineInfo &line = It->second; - rec.Prefix.TotalSize += sizeof(LLVMPerfJitDebugEntry); - rec.Prefix.TotalSize += line.FileName.size() + 1; - } - - // The debug_entry describes the source line information. It is defined as - // follows in order: - // * uint64_t code_addr: address of function for which the debug information - // is generated - // * uint32_t line : source file line number (starting at 1) - // * uint32_t discrim : column discriminator, 0 is default - // * char name[n] : source file name in ASCII, including null termination - - // avoid interspersing output - std::lock_guard<sys::Mutex> Guard(Mutex); - - Dumpstream->write(reinterpret_cast<const char *>(&rec), sizeof(rec)); - - for (DILineInfoTable::iterator It = Begin; It != End; ++It) { - LLVMPerfJitDebugEntry LineInfo; - DILineInfo &Line = It->second; - - LineInfo.Addr = It->first; - // The function re-created by perf is preceded by a elf - // header. Need to adjust for that, otherwise the results are - // wrong. - LineInfo.Addr += 0x40; - LineInfo.Lineno = Line.Line; - LineInfo.Discrim = Line.Discriminator; - - Dumpstream->write(reinterpret_cast<const char *>(&LineInfo), - sizeof(LineInfo)); - Dumpstream->write(Line.FileName.c_str(), Line.FileName.size() + 1); - } -} - -// There should be only a single event listener per process, otherwise perf gets -// confused. -llvm::ManagedStatic<PerfJITEventListener> PerfListener; - -} // end anonymous namespace - -namespace llvm { -JITEventListener *JITEventListener::createPerfJITEventListener() { - return &*PerfListener; -} - -} // namespace llvm - -LLVMJITEventListenerRef LLVMCreatePerfJITEventListener(void) -{ - return wrap(JITEventListener::createPerfJITEventListener()); -} +//===-- PerfJITEventListener.cpp - Tell Linux's perf about JITted code ----===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines a JITEventListener object that tells perf about JITted +// functions, including source line information. +// +// Documentation for perf jit integration is available at: +// https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/tools/perf/Documentation/jitdump-specification.txt +// https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/tools/perf/Documentation/jit-interface.txt +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/Twine.h" +#include "llvm/Config/config.h" +#include "llvm/DebugInfo/DWARF/DWARFContext.h" +#include "llvm/ExecutionEngine/JITEventListener.h" +#include "llvm/Object/ObjectFile.h" +#include "llvm/Object/SymbolSize.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/Errno.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/ManagedStatic.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Mutex.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/Process.h" +#include "llvm/Support/Threading.h" +#include "llvm/Support/raw_ostream.h" +#include <mutex> + +#include <sys/mman.h> // mmap() +#include <time.h> // clock_gettime(), time(), localtime_r() */ +#include <unistd.h> // for read(), close() + +using namespace llvm; +using namespace llvm::object; +typedef DILineInfoSpecifier::FileLineInfoKind FileLineInfoKind; + +namespace { + +// language identifier (XXX: should we generate something better from debug +// info?) +#define JIT_LANG "llvm-IR" +#define LLVM_PERF_JIT_MAGIC \ + ((uint32_t)'J' << 24 | (uint32_t)'i' << 16 | (uint32_t)'T' << 8 | \ + (uint32_t)'D') +#define LLVM_PERF_JIT_VERSION 1 + +// bit 0: set if the jitdump file is using an architecture-specific timestamp +// clock source +#define JITDUMP_FLAGS_ARCH_TIMESTAMP (1ULL << 0) + +struct LLVMPerfJitHeader; + +class PerfJITEventListener : public JITEventListener { +public: + PerfJITEventListener(); + ~PerfJITEventListener() { + if (MarkerAddr) + CloseMarker(); + } + + void notifyObjectLoaded(ObjectKey K, const ObjectFile &Obj, + const RuntimeDyld::LoadedObjectInfo &L) override; + void notifyFreeingObject(ObjectKey K) override; + +private: + bool InitDebuggingDir(); + bool OpenMarker(); + void CloseMarker(); + static bool FillMachine(LLVMPerfJitHeader &hdr); + + void NotifyCode(Expected<llvm::StringRef> &Symbol, uint64_t CodeAddr, + uint64_t CodeSize); + void NotifyDebug(uint64_t CodeAddr, DILineInfoTable Lines); + + // cache lookups + sys::Process::Pid Pid; + + // base directory for output data + std::string JitPath; + + // output data stream, closed via Dumpstream + int DumpFd = -1; + + // output data stream + std::unique_ptr<raw_fd_ostream> Dumpstream; + + // prevent concurrent dumps from messing up the output file + sys::Mutex Mutex; + + // perf mmap marker + void *MarkerAddr = NULL; + + // perf support ready + bool SuccessfullyInitialized = false; + + // identifier for functions, primarily to identify when moving them around + uint64_t CodeGeneration = 1; +}; + +// The following are POD struct definitions from the perf jit specification + +enum LLVMPerfJitRecordType { + JIT_CODE_LOAD = 0, + JIT_CODE_MOVE = 1, // not emitted, code isn't moved + JIT_CODE_DEBUG_INFO = 2, + JIT_CODE_CLOSE = 3, // not emitted, unnecessary + JIT_CODE_UNWINDING_INFO = 4, // not emitted + + JIT_CODE_MAX +}; + +struct LLVMPerfJitHeader { + uint32_t Magic; // characters "JiTD" + uint32_t Version; // header version + uint32_t TotalSize; // total size of header + uint32_t ElfMach; // elf mach target + uint32_t Pad1; // reserved + uint32_t Pid; + uint64_t Timestamp; // timestamp + uint64_t Flags; // flags +}; + +// record prefix (mandatory in each record) +struct LLVMPerfJitRecordPrefix { + uint32_t Id; // record type identifier + uint32_t TotalSize; + uint64_t Timestamp; +}; + +struct LLVMPerfJitRecordCodeLoad { + LLVMPerfJitRecordPrefix Prefix; + + uint32_t Pid; + uint32_t Tid; + uint64_t Vma; + uint64_t CodeAddr; + uint64_t CodeSize; + uint64_t CodeIndex; +}; + +struct LLVMPerfJitDebugEntry { + uint64_t Addr; + int Lineno; // source line number starting at 1 + int Discrim; // column discriminator, 0 is default + // followed by null terminated filename, \xff\0 if same as previous entry +}; + +struct LLVMPerfJitRecordDebugInfo { + LLVMPerfJitRecordPrefix Prefix; + + uint64_t CodeAddr; + uint64_t NrEntry; + // followed by NrEntry LLVMPerfJitDebugEntry records +}; + +static inline uint64_t timespec_to_ns(const struct timespec *ts) { + const uint64_t NanoSecPerSec = 1000000000; + return ((uint64_t)ts->tv_sec * NanoSecPerSec) + ts->tv_nsec; +} + +static inline uint64_t perf_get_timestamp(void) { + struct timespec ts; + int ret; + + ret = clock_gettime(CLOCK_MONOTONIC, &ts); + if (ret) + return 0; + + return timespec_to_ns(&ts); +} + +PerfJITEventListener::PerfJITEventListener() + : Pid(sys::Process::getProcessId()) { + // check if clock-source is supported + if (!perf_get_timestamp()) { + errs() << "kernel does not support CLOCK_MONOTONIC\n"; + return; + } + + if (!InitDebuggingDir()) { + errs() << "could not initialize debugging directory\n"; + return; + } + + std::string Filename; + raw_string_ostream FilenameBuf(Filename); + FilenameBuf << JitPath << "/jit-" << Pid << ".dump"; + + // Need to open ourselves, because we need to hand the FD to OpenMarker() and + // raw_fd_ostream doesn't expose the FD. + using sys::fs::openFileForWrite; + if (auto EC = + openFileForReadWrite(FilenameBuf.str(), DumpFd, + sys::fs::CD_CreateNew, sys::fs::OF_None)) { + errs() << "could not open JIT dump file " << FilenameBuf.str() << ": " + << EC.message() << "\n"; + return; + } + + Dumpstream = std::make_unique<raw_fd_ostream>(DumpFd, true); + + LLVMPerfJitHeader Header = {0}; + if (!FillMachine(Header)) + return; + + // signal this process emits JIT information + if (!OpenMarker()) + return; + + // emit dumpstream header + Header.Magic = LLVM_PERF_JIT_MAGIC; + Header.Version = LLVM_PERF_JIT_VERSION; + Header.TotalSize = sizeof(Header); + Header.Pid = Pid; + Header.Timestamp = perf_get_timestamp(); + Dumpstream->write(reinterpret_cast<const char *>(&Header), sizeof(Header)); + + // Everything initialized, can do profiling now. + if (!Dumpstream->has_error()) + SuccessfullyInitialized = true; +} + +void PerfJITEventListener::notifyObjectLoaded( + ObjectKey K, const ObjectFile &Obj, + const RuntimeDyld::LoadedObjectInfo &L) { + + if (!SuccessfullyInitialized) + return; + + OwningBinary<ObjectFile> DebugObjOwner = L.getObjectForDebug(Obj); + const ObjectFile &DebugObj = *DebugObjOwner.getBinary(); + + // Get the address of the object image for use as a unique identifier + std::unique_ptr<DIContext> Context = DWARFContext::create(DebugObj); + + // Use symbol info to iterate over functions in the object. + for (const std::pair<SymbolRef, uint64_t> &P : computeSymbolSizes(DebugObj)) { + SymbolRef Sym = P.first; + std::string SourceFileName; + + Expected<SymbolRef::Type> SymTypeOrErr = Sym.getType(); + if (!SymTypeOrErr) { + // There's not much we can with errors here + consumeError(SymTypeOrErr.takeError()); + continue; + } + SymbolRef::Type SymType = *SymTypeOrErr; + if (SymType != SymbolRef::ST_Function) + continue; + + Expected<StringRef> Name = Sym.getName(); + if (!Name) { + consumeError(Name.takeError()); + continue; + } + + Expected<uint64_t> AddrOrErr = Sym.getAddress(); + if (!AddrOrErr) { + consumeError(AddrOrErr.takeError()); + continue; + } + uint64_t Size = P.second; + object::SectionedAddress Address; + Address.Address = *AddrOrErr; + + uint64_t SectionIndex = object::SectionedAddress::UndefSection; + if (auto SectOrErr = Sym.getSection()) + if (*SectOrErr != Obj.section_end()) + SectionIndex = SectOrErr.get()->getIndex(); + + // According to spec debugging info has to come before loading the + // corresonding code load. + DILineInfoTable Lines = Context->getLineInfoForAddressRange( + {*AddrOrErr, SectionIndex}, Size, FileLineInfoKind::AbsoluteFilePath); + + NotifyDebug(*AddrOrErr, Lines); + NotifyCode(Name, *AddrOrErr, Size); + } + + Dumpstream->flush(); +} + +void PerfJITEventListener::notifyFreeingObject(ObjectKey K) { + // perf currently doesn't have an interface for unloading. But munmap()ing the + // code section does, so that's ok. +} + +bool PerfJITEventListener::InitDebuggingDir() { + time_t Time; + struct tm LocalTime; + char TimeBuffer[sizeof("YYYYMMDD")]; + SmallString<64> Path; + + // search for location to dump data to + if (const char *BaseDir = getenv("JITDUMPDIR")) + Path.append(BaseDir); + else if (!sys::path::home_directory(Path)) + Path = "."; + + // create debug directory + Path += "/.debug/jit/"; + if (auto EC = sys::fs::create_directories(Path)) { + errs() << "could not create jit cache directory " << Path << ": " + << EC.message() << "\n"; + return false; + } + + // create unique directory for dump data related to this process + time(&Time); + localtime_r(&Time, &LocalTime); + strftime(TimeBuffer, sizeof(TimeBuffer), "%Y%m%d", &LocalTime); + Path += JIT_LANG "-jit-"; + Path += TimeBuffer; + + SmallString<128> UniqueDebugDir; + + using sys::fs::createUniqueDirectory; + if (auto EC = createUniqueDirectory(Path, UniqueDebugDir)) { + errs() << "could not create unique jit cache directory " << UniqueDebugDir + << ": " << EC.message() << "\n"; + return false; + } + + JitPath = std::string(UniqueDebugDir.str()); + + return true; +} + +bool PerfJITEventListener::OpenMarker() { + // We mmap the jitdump to create an MMAP RECORD in perf.data file. The mmap + // is captured either live (perf record running when we mmap) or in deferred + // mode, via /proc/PID/maps. The MMAP record is used as a marker of a jitdump + // file for more meta data info about the jitted code. Perf report/annotate + // detect this special filename and process the jitdump file. + // + // Mapping must be PROT_EXEC to ensure it is captured by perf record + // even when not using -d option. + MarkerAddr = ::mmap(NULL, sys::Process::getPageSizeEstimate(), + PROT_READ | PROT_EXEC, MAP_PRIVATE, DumpFd, 0); + + if (MarkerAddr == MAP_FAILED) { + errs() << "could not mmap JIT marker\n"; + return false; + } + return true; +} + +void PerfJITEventListener::CloseMarker() { + if (!MarkerAddr) + return; + + munmap(MarkerAddr, sys::Process::getPageSizeEstimate()); + MarkerAddr = nullptr; +} + +bool PerfJITEventListener::FillMachine(LLVMPerfJitHeader &hdr) { + char id[16]; + struct { + uint16_t e_type; + uint16_t e_machine; + } info; + + size_t RequiredMemory = sizeof(id) + sizeof(info); + + ErrorOr<std::unique_ptr<MemoryBuffer>> MB = + MemoryBuffer::getFileSlice("/proc/self/exe", + RequiredMemory, + 0); + + // This'll not guarantee that enough data was actually read from the + // underlying file. Instead the trailing part of the buffer would be + // zeroed. Given the ELF signature check below that seems ok though, + // it's unlikely that the file ends just after that, and the + // consequence would just be that perf wouldn't recognize the + // signature. + if (auto EC = MB.getError()) { + errs() << "could not open /proc/self/exe: " << EC.message() << "\n"; + return false; + } + + memcpy(&id, (*MB)->getBufferStart(), sizeof(id)); + memcpy(&info, (*MB)->getBufferStart() + sizeof(id), sizeof(info)); + + // check ELF signature + if (id[0] != 0x7f || id[1] != 'E' || id[2] != 'L' || id[3] != 'F') { + errs() << "invalid elf signature\n"; + return false; + } + + hdr.ElfMach = info.e_machine; + + return true; +} + +void PerfJITEventListener::NotifyCode(Expected<llvm::StringRef> &Symbol, + uint64_t CodeAddr, uint64_t CodeSize) { + assert(SuccessfullyInitialized); + + // 0 length functions can't have samples. + if (CodeSize == 0) + return; + + LLVMPerfJitRecordCodeLoad rec; + rec.Prefix.Id = JIT_CODE_LOAD; + rec.Prefix.TotalSize = sizeof(rec) + // debug record itself + Symbol->size() + 1 + // symbol name + CodeSize; // and code + rec.Prefix.Timestamp = perf_get_timestamp(); + + rec.CodeSize = CodeSize; + rec.Vma = 0; + rec.CodeAddr = CodeAddr; + rec.Pid = Pid; + rec.Tid = get_threadid(); + + // avoid interspersing output + std::lock_guard<sys::Mutex> Guard(Mutex); + + rec.CodeIndex = CodeGeneration++; // under lock! + + Dumpstream->write(reinterpret_cast<const char *>(&rec), sizeof(rec)); + Dumpstream->write(Symbol->data(), Symbol->size() + 1); + Dumpstream->write(reinterpret_cast<const char *>(CodeAddr), CodeSize); +} + +void PerfJITEventListener::NotifyDebug(uint64_t CodeAddr, + DILineInfoTable Lines) { + assert(SuccessfullyInitialized); + + // Didn't get useful debug info. + if (Lines.empty()) + return; + + LLVMPerfJitRecordDebugInfo rec; + rec.Prefix.Id = JIT_CODE_DEBUG_INFO; + rec.Prefix.TotalSize = sizeof(rec); // will be increased further + rec.Prefix.Timestamp = perf_get_timestamp(); + rec.CodeAddr = CodeAddr; + rec.NrEntry = Lines.size(); + + // compute total size size of record (variable due to filenames) + DILineInfoTable::iterator Begin = Lines.begin(); + DILineInfoTable::iterator End = Lines.end(); + for (DILineInfoTable::iterator It = Begin; It != End; ++It) { + DILineInfo &line = It->second; + rec.Prefix.TotalSize += sizeof(LLVMPerfJitDebugEntry); + rec.Prefix.TotalSize += line.FileName.size() + 1; + } + + // The debug_entry describes the source line information. It is defined as + // follows in order: + // * uint64_t code_addr: address of function for which the debug information + // is generated + // * uint32_t line : source file line number (starting at 1) + // * uint32_t discrim : column discriminator, 0 is default + // * char name[n] : source file name in ASCII, including null termination + + // avoid interspersing output + std::lock_guard<sys::Mutex> Guard(Mutex); + + Dumpstream->write(reinterpret_cast<const char *>(&rec), sizeof(rec)); + + for (DILineInfoTable::iterator It = Begin; It != End; ++It) { + LLVMPerfJitDebugEntry LineInfo; + DILineInfo &Line = It->second; + + LineInfo.Addr = It->first; + // The function re-created by perf is preceded by a elf + // header. Need to adjust for that, otherwise the results are + // wrong. + LineInfo.Addr += 0x40; + LineInfo.Lineno = Line.Line; + LineInfo.Discrim = Line.Discriminator; + + Dumpstream->write(reinterpret_cast<const char *>(&LineInfo), + sizeof(LineInfo)); + Dumpstream->write(Line.FileName.c_str(), Line.FileName.size() + 1); + } +} + +// There should be only a single event listener per process, otherwise perf gets +// confused. +llvm::ManagedStatic<PerfJITEventListener> PerfListener; + +} // end anonymous namespace + +namespace llvm { +JITEventListener *JITEventListener::createPerfJITEventListener() { + return &*PerfListener; +} + +} // namespace llvm + +LLVMJITEventListenerRef LLVMCreatePerfJITEventListener(void) +{ + return wrap(JITEventListener::createPerfJITEventListener()); +} diff --git a/contrib/libs/llvm12/lib/ExecutionEngine/PerfJITEvents/ya.make b/contrib/libs/llvm12/lib/ExecutionEngine/PerfJITEvents/ya.make index fc7793f6d6..dc91e6b801 100644 --- a/contrib/libs/llvm12/lib/ExecutionEngine/PerfJITEvents/ya.make +++ b/contrib/libs/llvm12/lib/ExecutionEngine/PerfJITEvents/ya.make @@ -1,17 +1,17 @@ -# Generated by devtools/yamaker. - -LIBRARY() - +# Generated by devtools/yamaker. + +LIBRARY() + OWNER( orivej g:cpp-contrib ) - + LICENSE(Apache-2.0 WITH LLVM-exception) LICENSE_TEXTS(.yandex_meta/licenses.list.txt) -PEERDIR( +PEERDIR( contrib/libs/llvm12 contrib/libs/llvm12/lib/CodeGen contrib/libs/llvm12/lib/DebugInfo/DWARF @@ -20,18 +20,18 @@ PEERDIR( contrib/libs/llvm12/lib/IR contrib/libs/llvm12/lib/Object contrib/libs/llvm12/lib/Support -) - +) + ADDINCL( contrib/libs/llvm12/lib/ExecutionEngine/PerfJITEvents ) - -NO_COMPILER_WARNINGS() - -NO_UTIL() - -SRCS( - PerfJITEventListener.cpp -) - -END() + +NO_COMPILER_WARNINGS() + +NO_UTIL() + +SRCS( + PerfJITEventListener.cpp +) + +END() diff --git a/contrib/libs/llvm12/lib/ExecutionEngine/RuntimeDyld/JITSymbol.cpp b/contrib/libs/llvm12/lib/ExecutionEngine/RuntimeDyld/JITSymbol.cpp index 875aef01c4..0f6f9efe11 100644 --- a/contrib/libs/llvm12/lib/ExecutionEngine/RuntimeDyld/JITSymbol.cpp +++ b/contrib/libs/llvm12/lib/ExecutionEngine/RuntimeDyld/JITSymbol.cpp @@ -1,169 +1,169 @@ -//===----------- JITSymbol.cpp - JITSymbol class implementation -----------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// JITSymbol class implementation plus helper functions. -// -//===----------------------------------------------------------------------===// - -#include "llvm/ExecutionEngine/JITSymbol.h" -#include "llvm/IR/Function.h" -#include "llvm/IR/GlobalAlias.h" -#include "llvm/IR/GlobalValue.h" -#include "llvm/IR/ModuleSummaryIndex.h" -#include "llvm/Object/ObjectFile.h" - -using namespace llvm; - -JITSymbolFlags llvm::JITSymbolFlags::fromGlobalValue(const GlobalValue &GV) { - assert(GV.hasName() && "Can't get flags for anonymous symbol"); - - JITSymbolFlags Flags = JITSymbolFlags::None; - if (GV.hasWeakLinkage() || GV.hasLinkOnceLinkage()) - Flags |= JITSymbolFlags::Weak; - if (GV.hasCommonLinkage()) - Flags |= JITSymbolFlags::Common; - if (!GV.hasLocalLinkage() && !GV.hasHiddenVisibility()) - Flags |= JITSymbolFlags::Exported; - - if (isa<Function>(GV)) - Flags |= JITSymbolFlags::Callable; - else if (isa<GlobalAlias>(GV) && - isa<Function>(cast<GlobalAlias>(GV).getAliasee())) - Flags |= JITSymbolFlags::Callable; - - // Check for a linker-private-global-prefix on the symbol name, in which - // case it must be marked as non-exported. - if (auto *M = GV.getParent()) { - const auto &DL = M->getDataLayout(); - StringRef LPGP = DL.getLinkerPrivateGlobalPrefix(); - if (!LPGP.empty() && GV.getName().front() == '\01' && - GV.getName().substr(1).startswith(LPGP)) - Flags &= ~JITSymbolFlags::Exported; - } - - return Flags; -} - -JITSymbolFlags llvm::JITSymbolFlags::fromSummary(GlobalValueSummary *S) { - JITSymbolFlags Flags = JITSymbolFlags::None; - auto L = S->linkage(); - if (GlobalValue::isWeakLinkage(L) || GlobalValue::isLinkOnceLinkage(L)) - Flags |= JITSymbolFlags::Weak; - if (GlobalValue::isCommonLinkage(L)) - Flags |= JITSymbolFlags::Common; - if (GlobalValue::isExternalLinkage(L) || GlobalValue::isExternalWeakLinkage(L)) - Flags |= JITSymbolFlags::Exported; - - if (isa<FunctionSummary>(S)) - Flags |= JITSymbolFlags::Callable; - - return Flags; -} - -Expected<JITSymbolFlags> -llvm::JITSymbolFlags::fromObjectSymbol(const object::SymbolRef &Symbol) { - Expected<uint32_t> SymbolFlagsOrErr = Symbol.getFlags(); - if (!SymbolFlagsOrErr) - // TODO: Test this error. - return SymbolFlagsOrErr.takeError(); - - JITSymbolFlags Flags = JITSymbolFlags::None; - if (*SymbolFlagsOrErr & object::BasicSymbolRef::SF_Weak) - Flags |= JITSymbolFlags::Weak; - if (*SymbolFlagsOrErr & object::BasicSymbolRef::SF_Common) - Flags |= JITSymbolFlags::Common; - if (*SymbolFlagsOrErr & object::BasicSymbolRef::SF_Exported) - Flags |= JITSymbolFlags::Exported; - - auto SymbolType = Symbol.getType(); - if (!SymbolType) - return SymbolType.takeError(); - - if (*SymbolType & object::SymbolRef::ST_Function) - Flags |= JITSymbolFlags::Callable; - - return Flags; -} - -ARMJITSymbolFlags -llvm::ARMJITSymbolFlags::fromObjectSymbol(const object::SymbolRef &Symbol) { - Expected<uint32_t> SymbolFlagsOrErr = Symbol.getFlags(); - if (!SymbolFlagsOrErr) - // TODO: Actually report errors helpfully. - report_fatal_error(SymbolFlagsOrErr.takeError()); - ARMJITSymbolFlags Flags; - if (*SymbolFlagsOrErr & object::BasicSymbolRef::SF_Thumb) - Flags |= ARMJITSymbolFlags::Thumb; - return Flags; -} - -/// Performs lookup by, for each symbol, first calling -/// findSymbolInLogicalDylib and if that fails calling -/// findSymbol. -void LegacyJITSymbolResolver::lookup(const LookupSet &Symbols, - OnResolvedFunction OnResolved) { - JITSymbolResolver::LookupResult Result; - for (auto &Symbol : Symbols) { - std::string SymName = Symbol.str(); - if (auto Sym = findSymbolInLogicalDylib(SymName)) { - if (auto AddrOrErr = Sym.getAddress()) - Result[Symbol] = JITEvaluatedSymbol(*AddrOrErr, Sym.getFlags()); - else { - OnResolved(AddrOrErr.takeError()); - return; - } - } else if (auto Err = Sym.takeError()) { - OnResolved(std::move(Err)); - return; - } else { - // findSymbolInLogicalDylib failed. Lets try findSymbol. - if (auto Sym = findSymbol(SymName)) { - if (auto AddrOrErr = Sym.getAddress()) - Result[Symbol] = JITEvaluatedSymbol(*AddrOrErr, Sym.getFlags()); - else { - OnResolved(AddrOrErr.takeError()); - return; - } - } else if (auto Err = Sym.takeError()) { - OnResolved(std::move(Err)); - return; - } else { - OnResolved(make_error<StringError>("Symbol not found: " + Symbol, - inconvertibleErrorCode())); - return; - } - } - } - - OnResolved(std::move(Result)); -} - -/// Performs flags lookup by calling findSymbolInLogicalDylib and -/// returning the flags value for that symbol. -Expected<JITSymbolResolver::LookupSet> -LegacyJITSymbolResolver::getResponsibilitySet(const LookupSet &Symbols) { - JITSymbolResolver::LookupSet Result; - - for (auto &Symbol : Symbols) { - std::string SymName = Symbol.str(); - if (auto Sym = findSymbolInLogicalDylib(SymName)) { - // If there's an existing def but it is not strong, then the caller is - // responsible for it. - if (!Sym.getFlags().isStrong()) - Result.insert(Symbol); - } else if (auto Err = Sym.takeError()) - return std::move(Err); - else { - // If there is no existing definition then the caller is responsible for - // it. - Result.insert(Symbol); - } - } - - return std::move(Result); -} +//===----------- JITSymbol.cpp - JITSymbol class implementation -----------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// JITSymbol class implementation plus helper functions. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ExecutionEngine/JITSymbol.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/GlobalAlias.h" +#include "llvm/IR/GlobalValue.h" +#include "llvm/IR/ModuleSummaryIndex.h" +#include "llvm/Object/ObjectFile.h" + +using namespace llvm; + +JITSymbolFlags llvm::JITSymbolFlags::fromGlobalValue(const GlobalValue &GV) { + assert(GV.hasName() && "Can't get flags for anonymous symbol"); + + JITSymbolFlags Flags = JITSymbolFlags::None; + if (GV.hasWeakLinkage() || GV.hasLinkOnceLinkage()) + Flags |= JITSymbolFlags::Weak; + if (GV.hasCommonLinkage()) + Flags |= JITSymbolFlags::Common; + if (!GV.hasLocalLinkage() && !GV.hasHiddenVisibility()) + Flags |= JITSymbolFlags::Exported; + + if (isa<Function>(GV)) + Flags |= JITSymbolFlags::Callable; + else if (isa<GlobalAlias>(GV) && + isa<Function>(cast<GlobalAlias>(GV).getAliasee())) + Flags |= JITSymbolFlags::Callable; + + // Check for a linker-private-global-prefix on the symbol name, in which + // case it must be marked as non-exported. + if (auto *M = GV.getParent()) { + const auto &DL = M->getDataLayout(); + StringRef LPGP = DL.getLinkerPrivateGlobalPrefix(); + if (!LPGP.empty() && GV.getName().front() == '\01' && + GV.getName().substr(1).startswith(LPGP)) + Flags &= ~JITSymbolFlags::Exported; + } + + return Flags; +} + +JITSymbolFlags llvm::JITSymbolFlags::fromSummary(GlobalValueSummary *S) { + JITSymbolFlags Flags = JITSymbolFlags::None; + auto L = S->linkage(); + if (GlobalValue::isWeakLinkage(L) || GlobalValue::isLinkOnceLinkage(L)) + Flags |= JITSymbolFlags::Weak; + if (GlobalValue::isCommonLinkage(L)) + Flags |= JITSymbolFlags::Common; + if (GlobalValue::isExternalLinkage(L) || GlobalValue::isExternalWeakLinkage(L)) + Flags |= JITSymbolFlags::Exported; + + if (isa<FunctionSummary>(S)) + Flags |= JITSymbolFlags::Callable; + + return Flags; +} + +Expected<JITSymbolFlags> +llvm::JITSymbolFlags::fromObjectSymbol(const object::SymbolRef &Symbol) { + Expected<uint32_t> SymbolFlagsOrErr = Symbol.getFlags(); + if (!SymbolFlagsOrErr) + // TODO: Test this error. + return SymbolFlagsOrErr.takeError(); + + JITSymbolFlags Flags = JITSymbolFlags::None; + if (*SymbolFlagsOrErr & object::BasicSymbolRef::SF_Weak) + Flags |= JITSymbolFlags::Weak; + if (*SymbolFlagsOrErr & object::BasicSymbolRef::SF_Common) + Flags |= JITSymbolFlags::Common; + if (*SymbolFlagsOrErr & object::BasicSymbolRef::SF_Exported) + Flags |= JITSymbolFlags::Exported; + + auto SymbolType = Symbol.getType(); + if (!SymbolType) + return SymbolType.takeError(); + + if (*SymbolType & object::SymbolRef::ST_Function) + Flags |= JITSymbolFlags::Callable; + + return Flags; +} + +ARMJITSymbolFlags +llvm::ARMJITSymbolFlags::fromObjectSymbol(const object::SymbolRef &Symbol) { + Expected<uint32_t> SymbolFlagsOrErr = Symbol.getFlags(); + if (!SymbolFlagsOrErr) + // TODO: Actually report errors helpfully. + report_fatal_error(SymbolFlagsOrErr.takeError()); + ARMJITSymbolFlags Flags; + if (*SymbolFlagsOrErr & object::BasicSymbolRef::SF_Thumb) + Flags |= ARMJITSymbolFlags::Thumb; + return Flags; +} + +/// Performs lookup by, for each symbol, first calling +/// findSymbolInLogicalDylib and if that fails calling +/// findSymbol. +void LegacyJITSymbolResolver::lookup(const LookupSet &Symbols, + OnResolvedFunction OnResolved) { + JITSymbolResolver::LookupResult Result; + for (auto &Symbol : Symbols) { + std::string SymName = Symbol.str(); + if (auto Sym = findSymbolInLogicalDylib(SymName)) { + if (auto AddrOrErr = Sym.getAddress()) + Result[Symbol] = JITEvaluatedSymbol(*AddrOrErr, Sym.getFlags()); + else { + OnResolved(AddrOrErr.takeError()); + return; + } + } else if (auto Err = Sym.takeError()) { + OnResolved(std::move(Err)); + return; + } else { + // findSymbolInLogicalDylib failed. Lets try findSymbol. + if (auto Sym = findSymbol(SymName)) { + if (auto AddrOrErr = Sym.getAddress()) + Result[Symbol] = JITEvaluatedSymbol(*AddrOrErr, Sym.getFlags()); + else { + OnResolved(AddrOrErr.takeError()); + return; + } + } else if (auto Err = Sym.takeError()) { + OnResolved(std::move(Err)); + return; + } else { + OnResolved(make_error<StringError>("Symbol not found: " + Symbol, + inconvertibleErrorCode())); + return; + } + } + } + + OnResolved(std::move(Result)); +} + +/// Performs flags lookup by calling findSymbolInLogicalDylib and +/// returning the flags value for that symbol. +Expected<JITSymbolResolver::LookupSet> +LegacyJITSymbolResolver::getResponsibilitySet(const LookupSet &Symbols) { + JITSymbolResolver::LookupSet Result; + + for (auto &Symbol : Symbols) { + std::string SymName = Symbol.str(); + if (auto Sym = findSymbolInLogicalDylib(SymName)) { + // If there's an existing def but it is not strong, then the caller is + // responsible for it. + if (!Sym.getFlags().isStrong()) + Result.insert(Symbol); + } else if (auto Err = Sym.takeError()) + return std::move(Err); + else { + // If there is no existing definition then the caller is responsible for + // it. + Result.insert(Symbol); + } + } + + return std::move(Result); +} diff --git a/contrib/libs/llvm12/lib/ExecutionEngine/RuntimeDyld/RTDyldMemoryManager.cpp b/contrib/libs/llvm12/lib/ExecutionEngine/RuntimeDyld/RTDyldMemoryManager.cpp index 4474aa6d4d..741aa58350 100644 --- a/contrib/libs/llvm12/lib/ExecutionEngine/RuntimeDyld/RTDyldMemoryManager.cpp +++ b/contrib/libs/llvm12/lib/ExecutionEngine/RuntimeDyld/RTDyldMemoryManager.cpp @@ -1,295 +1,295 @@ -//===-- RTDyldMemoryManager.cpp - Memory manager for MC-JIT -----*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// Implementation of the runtime dynamic memory manager base class. -// -//===----------------------------------------------------------------------===// - -#include "llvm/Config/config.h" -#include "llvm/ExecutionEngine/RTDyldMemoryManager.h" -#include "llvm/Support/Compiler.h" -#include "llvm/Support/DynamicLibrary.h" -#include "llvm/Support/ErrorHandling.h" -#include <cstdlib> - -#ifdef __linux__ - // These includes used by RTDyldMemoryManager::getPointerToNamedFunction() - // for Glibc trickery. See comments in this function for more information. - #ifdef HAVE_SYS_STAT_H - #include <sys/stat.h> - #endif - #include <fcntl.h> - #include <unistd.h> -#endif - -namespace llvm { - -RTDyldMemoryManager::~RTDyldMemoryManager() {} - +//===-- RTDyldMemoryManager.cpp - Memory manager for MC-JIT -----*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Implementation of the runtime dynamic memory manager base class. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Config/config.h" +#include "llvm/ExecutionEngine/RTDyldMemoryManager.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/DynamicLibrary.h" +#include "llvm/Support/ErrorHandling.h" +#include <cstdlib> + +#ifdef __linux__ + // These includes used by RTDyldMemoryManager::getPointerToNamedFunction() + // for Glibc trickery. See comments in this function for more information. + #ifdef HAVE_SYS_STAT_H + #include <sys/stat.h> + #endif + #include <fcntl.h> + #include <unistd.h> +#endif + +namespace llvm { + +RTDyldMemoryManager::~RTDyldMemoryManager() {} + #if defined(HAVE_REGISTER_FRAME) && defined(HAVE_DEREGISTER_FRAME) && \ !defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__) -extern "C" void __register_frame(void *); -extern "C" void __deregister_frame(void *); -#else -// The building compiler does not have __(de)register_frame but -// it may be found at runtime in a dynamically-loaded library. -// For example, this happens when building LLVM with Visual C++ -// but using the MingW runtime. -static void __register_frame(void *p) { - static bool Searched = false; - static void((*rf)(void *)) = 0; - - if (!Searched) { - Searched = true; - *(void **)&rf = - llvm::sys::DynamicLibrary::SearchForAddressOfSymbol("__register_frame"); - } - if (rf) - rf(p); -} - -static void __deregister_frame(void *p) { - static bool Searched = false; - static void((*df)(void *)) = 0; - - if (!Searched) { - Searched = true; - *(void **)&df = llvm::sys::DynamicLibrary::SearchForAddressOfSymbol( - "__deregister_frame"); - } - if (df) - df(p); -} -#endif - -#ifdef LLVM_ON_UNIX // Use libunwind - -static const char *processFDE(const char *Entry, bool isDeregister) { - const char *P = Entry; - uint32_t Length = *((const uint32_t *)P); - P += 4; - uint32_t Offset = *((const uint32_t *)P); - if (Offset != 0) { - if (isDeregister) - __deregister_frame(const_cast<char *>(Entry)); - else - __register_frame(const_cast<char *>(Entry)); - } - return P + Length; -} - -// This implementation handles frame registration for local targets. -// Memory managers for remote targets should re-implement this function -// and use the LoadAddr parameter. -void RTDyldMemoryManager::registerEHFramesInProcess(uint8_t *Addr, - size_t Size) { - // On OS X OS X __register_frame takes a single FDE as an argument. - // See http://lists.llvm.org/pipermail/llvm-dev/2013-April/061737.html - // and projects/libunwind/src/UnwindLevel1-gcc-ext.c. - const char *P = (const char *)Addr; - const char *End = P + Size; - do { - P = processFDE(P, false); - } while(P != End); -} - -void RTDyldMemoryManager::deregisterEHFramesInProcess(uint8_t *Addr, - size_t Size) { - const char *P = (const char *)Addr; - const char *End = P + Size; - do { - P = processFDE(P, true); - } while(P != End); -} - -#else - -void RTDyldMemoryManager::registerEHFramesInProcess(uint8_t *Addr, - size_t Size) { - // On Linux __register_frame takes a single argument: - // a pointer to the start of the .eh_frame section. - - // How can it find the end? Because crtendS.o is linked - // in and it has an .eh_frame section with four zero chars. - __register_frame(Addr); -} - -void RTDyldMemoryManager::deregisterEHFramesInProcess(uint8_t *Addr, - size_t Size) { - __deregister_frame(Addr); -} - -#endif - -void RTDyldMemoryManager::registerEHFrames(uint8_t *Addr, uint64_t LoadAddr, - size_t Size) { - registerEHFramesInProcess(Addr, Size); - EHFrames.push_back({Addr, Size}); -} - -void RTDyldMemoryManager::deregisterEHFrames() { - for (auto &Frame : EHFrames) - deregisterEHFramesInProcess(Frame.Addr, Frame.Size); - EHFrames.clear(); -} - -static int jit_noop() { - return 0; -} - -// ARM math functions are statically linked on Android from libgcc.a, but not -// available at runtime for dynamic linking. On Linux these are usually placed -// in libgcc_s.so so can be found by normal dynamic lookup. -#if defined(__BIONIC__) && defined(__arm__) -// List of functions which are statically linked on Android and can be generated -// by LLVM. This is done as a nested macro which is used once to declare the -// imported functions with ARM_MATH_DECL and once to compare them to the -// user-requested symbol in getSymbolAddress with ARM_MATH_CHECK. The test -// assumes that all functions start with __aeabi_ and getSymbolAddress must be -// modified if that changes. -#define ARM_MATH_IMPORTS(PP) \ - PP(__aeabi_d2f) \ - PP(__aeabi_d2iz) \ - PP(__aeabi_d2lz) \ - PP(__aeabi_d2uiz) \ - PP(__aeabi_d2ulz) \ - PP(__aeabi_dadd) \ - PP(__aeabi_dcmpeq) \ - PP(__aeabi_dcmpge) \ - PP(__aeabi_dcmpgt) \ - PP(__aeabi_dcmple) \ - PP(__aeabi_dcmplt) \ - PP(__aeabi_dcmpun) \ - PP(__aeabi_ddiv) \ - PP(__aeabi_dmul) \ - PP(__aeabi_dsub) \ - PP(__aeabi_f2d) \ - PP(__aeabi_f2iz) \ - PP(__aeabi_f2lz) \ - PP(__aeabi_f2uiz) \ - PP(__aeabi_f2ulz) \ - PP(__aeabi_fadd) \ - PP(__aeabi_fcmpeq) \ - PP(__aeabi_fcmpge) \ - PP(__aeabi_fcmpgt) \ - PP(__aeabi_fcmple) \ - PP(__aeabi_fcmplt) \ - PP(__aeabi_fcmpun) \ - PP(__aeabi_fdiv) \ - PP(__aeabi_fmul) \ - PP(__aeabi_fsub) \ - PP(__aeabi_i2d) \ - PP(__aeabi_i2f) \ - PP(__aeabi_idiv) \ - PP(__aeabi_idivmod) \ - PP(__aeabi_l2d) \ - PP(__aeabi_l2f) \ - PP(__aeabi_lasr) \ - PP(__aeabi_ldivmod) \ - PP(__aeabi_llsl) \ - PP(__aeabi_llsr) \ - PP(__aeabi_lmul) \ - PP(__aeabi_ui2d) \ - PP(__aeabi_ui2f) \ - PP(__aeabi_uidiv) \ - PP(__aeabi_uidivmod) \ - PP(__aeabi_ul2d) \ - PP(__aeabi_ul2f) \ - PP(__aeabi_uldivmod) - -// Declare statically linked math functions on ARM. The function declarations -// here do not have the correct prototypes for each function in -// ARM_MATH_IMPORTS, but it doesn't matter because only the symbol addresses are -// needed. In particular the __aeabi_*divmod functions do not have calling -// conventions which match any C prototype. -#define ARM_MATH_DECL(name) extern "C" void name(); -ARM_MATH_IMPORTS(ARM_MATH_DECL) -#undef ARM_MATH_DECL -#endif - -#if defined(__linux__) && defined(__GLIBC__) && \ - (defined(__i386__) || defined(__x86_64__)) -extern "C" LLVM_ATTRIBUTE_WEAK void __morestack(); -#endif - -uint64_t -RTDyldMemoryManager::getSymbolAddressInProcess(const std::string &Name) { - // This implementation assumes that the host program is the target. - // Clients generating code for a remote target should implement their own - // memory manager. -#if defined(__linux__) && defined(__GLIBC__) - //===--------------------------------------------------------------------===// - // Function stubs that are invoked instead of certain library calls - // - // Force the following functions to be linked in to anything that uses the - // JIT. This is a hack designed to work around the all-too-clever Glibc - // strategy of making these functions work differently when inlined vs. when - // not inlined, and hiding their real definitions in a separate archive file - // that the dynamic linker can't see. For more info, search for - // 'libc_nonshared.a' on Google, or read http://llvm.org/PR274. - if (Name == "stat") return (uint64_t)&stat; - if (Name == "fstat") return (uint64_t)&fstat; - if (Name == "lstat") return (uint64_t)&lstat; - if (Name == "stat64") return (uint64_t)&stat64; - if (Name == "fstat64") return (uint64_t)&fstat64; - if (Name == "lstat64") return (uint64_t)&lstat64; - if (Name == "atexit") return (uint64_t)&atexit; - if (Name == "mknod") return (uint64_t)&mknod; - -#if defined(__i386__) || defined(__x86_64__) - // __morestack lives in libgcc, a static library. - if (&__morestack && Name == "__morestack") - return (uint64_t)&__morestack; -#endif -#endif // __linux__ && __GLIBC__ - - // See ARM_MATH_IMPORTS definition for explanation -#if defined(__BIONIC__) && defined(__arm__) - if (Name.compare(0, 8, "__aeabi_") == 0) { - // Check if the user has requested any of the functions listed in - // ARM_MATH_IMPORTS, and if so redirect to the statically linked symbol. -#define ARM_MATH_CHECK(fn) if (Name == #fn) return (uint64_t)&fn; - ARM_MATH_IMPORTS(ARM_MATH_CHECK) -#undef ARM_MATH_CHECK - } -#endif - - // We should not invoke parent's ctors/dtors from generated main()! - // On Mingw and Cygwin, the symbol __main is resolved to - // callee's(eg. tools/lli) one, to invoke wrong duplicated ctors - // (and register wrong callee's dtors with atexit(3)). - // We expect ExecutionEngine::runStaticConstructorsDestructors() - // is called before ExecutionEngine::runFunctionAsMain() is called. - if (Name == "__main") return (uint64_t)&jit_noop; - - const char *NameStr = Name.c_str(); - - // DynamicLibrary::SearchForAddresOfSymbol expects an unmangled 'C' symbol - // name so ff we're on Darwin, strip the leading '_' off. -#ifdef __APPLE__ - if (NameStr[0] == '_') - ++NameStr; -#endif - - return (uint64_t)sys::DynamicLibrary::SearchForAddressOfSymbol(NameStr); -} - -void *RTDyldMemoryManager::getPointerToNamedFunction(const std::string &Name, - bool AbortOnFailure) { - uint64_t Addr = getSymbolAddress(Name); - - if (!Addr && AbortOnFailure) - report_fatal_error("Program used external function '" + Name + - "' which could not be resolved!"); - - return (void*)Addr; -} - -void RTDyldMemoryManager::anchor() {} -void MCJITMemoryManager::anchor() {} -} // namespace llvm +extern "C" void __register_frame(void *); +extern "C" void __deregister_frame(void *); +#else +// The building compiler does not have __(de)register_frame but +// it may be found at runtime in a dynamically-loaded library. +// For example, this happens when building LLVM with Visual C++ +// but using the MingW runtime. +static void __register_frame(void *p) { + static bool Searched = false; + static void((*rf)(void *)) = 0; + + if (!Searched) { + Searched = true; + *(void **)&rf = + llvm::sys::DynamicLibrary::SearchForAddressOfSymbol("__register_frame"); + } + if (rf) + rf(p); +} + +static void __deregister_frame(void *p) { + static bool Searched = false; + static void((*df)(void *)) = 0; + + if (!Searched) { + Searched = true; + *(void **)&df = llvm::sys::DynamicLibrary::SearchForAddressOfSymbol( + "__deregister_frame"); + } + if (df) + df(p); +} +#endif + +#ifdef LLVM_ON_UNIX // Use libunwind + +static const char *processFDE(const char *Entry, bool isDeregister) { + const char *P = Entry; + uint32_t Length = *((const uint32_t *)P); + P += 4; + uint32_t Offset = *((const uint32_t *)P); + if (Offset != 0) { + if (isDeregister) + __deregister_frame(const_cast<char *>(Entry)); + else + __register_frame(const_cast<char *>(Entry)); + } + return P + Length; +} + +// This implementation handles frame registration for local targets. +// Memory managers for remote targets should re-implement this function +// and use the LoadAddr parameter. +void RTDyldMemoryManager::registerEHFramesInProcess(uint8_t *Addr, + size_t Size) { + // On OS X OS X __register_frame takes a single FDE as an argument. + // See http://lists.llvm.org/pipermail/llvm-dev/2013-April/061737.html + // and projects/libunwind/src/UnwindLevel1-gcc-ext.c. + const char *P = (const char *)Addr; + const char *End = P + Size; + do { + P = processFDE(P, false); + } while(P != End); +} + +void RTDyldMemoryManager::deregisterEHFramesInProcess(uint8_t *Addr, + size_t Size) { + const char *P = (const char *)Addr; + const char *End = P + Size; + do { + P = processFDE(P, true); + } while(P != End); +} + +#else + +void RTDyldMemoryManager::registerEHFramesInProcess(uint8_t *Addr, + size_t Size) { + // On Linux __register_frame takes a single argument: + // a pointer to the start of the .eh_frame section. + + // How can it find the end? Because crtendS.o is linked + // in and it has an .eh_frame section with four zero chars. + __register_frame(Addr); +} + +void RTDyldMemoryManager::deregisterEHFramesInProcess(uint8_t *Addr, + size_t Size) { + __deregister_frame(Addr); +} + +#endif + +void RTDyldMemoryManager::registerEHFrames(uint8_t *Addr, uint64_t LoadAddr, + size_t Size) { + registerEHFramesInProcess(Addr, Size); + EHFrames.push_back({Addr, Size}); +} + +void RTDyldMemoryManager::deregisterEHFrames() { + for (auto &Frame : EHFrames) + deregisterEHFramesInProcess(Frame.Addr, Frame.Size); + EHFrames.clear(); +} + +static int jit_noop() { + return 0; +} + +// ARM math functions are statically linked on Android from libgcc.a, but not +// available at runtime for dynamic linking. On Linux these are usually placed +// in libgcc_s.so so can be found by normal dynamic lookup. +#if defined(__BIONIC__) && defined(__arm__) +// List of functions which are statically linked on Android and can be generated +// by LLVM. This is done as a nested macro which is used once to declare the +// imported functions with ARM_MATH_DECL and once to compare them to the +// user-requested symbol in getSymbolAddress with ARM_MATH_CHECK. The test +// assumes that all functions start with __aeabi_ and getSymbolAddress must be +// modified if that changes. +#define ARM_MATH_IMPORTS(PP) \ + PP(__aeabi_d2f) \ + PP(__aeabi_d2iz) \ + PP(__aeabi_d2lz) \ + PP(__aeabi_d2uiz) \ + PP(__aeabi_d2ulz) \ + PP(__aeabi_dadd) \ + PP(__aeabi_dcmpeq) \ + PP(__aeabi_dcmpge) \ + PP(__aeabi_dcmpgt) \ + PP(__aeabi_dcmple) \ + PP(__aeabi_dcmplt) \ + PP(__aeabi_dcmpun) \ + PP(__aeabi_ddiv) \ + PP(__aeabi_dmul) \ + PP(__aeabi_dsub) \ + PP(__aeabi_f2d) \ + PP(__aeabi_f2iz) \ + PP(__aeabi_f2lz) \ + PP(__aeabi_f2uiz) \ + PP(__aeabi_f2ulz) \ + PP(__aeabi_fadd) \ + PP(__aeabi_fcmpeq) \ + PP(__aeabi_fcmpge) \ + PP(__aeabi_fcmpgt) \ + PP(__aeabi_fcmple) \ + PP(__aeabi_fcmplt) \ + PP(__aeabi_fcmpun) \ + PP(__aeabi_fdiv) \ + PP(__aeabi_fmul) \ + PP(__aeabi_fsub) \ + PP(__aeabi_i2d) \ + PP(__aeabi_i2f) \ + PP(__aeabi_idiv) \ + PP(__aeabi_idivmod) \ + PP(__aeabi_l2d) \ + PP(__aeabi_l2f) \ + PP(__aeabi_lasr) \ + PP(__aeabi_ldivmod) \ + PP(__aeabi_llsl) \ + PP(__aeabi_llsr) \ + PP(__aeabi_lmul) \ + PP(__aeabi_ui2d) \ + PP(__aeabi_ui2f) \ + PP(__aeabi_uidiv) \ + PP(__aeabi_uidivmod) \ + PP(__aeabi_ul2d) \ + PP(__aeabi_ul2f) \ + PP(__aeabi_uldivmod) + +// Declare statically linked math functions on ARM. The function declarations +// here do not have the correct prototypes for each function in +// ARM_MATH_IMPORTS, but it doesn't matter because only the symbol addresses are +// needed. In particular the __aeabi_*divmod functions do not have calling +// conventions which match any C prototype. +#define ARM_MATH_DECL(name) extern "C" void name(); +ARM_MATH_IMPORTS(ARM_MATH_DECL) +#undef ARM_MATH_DECL +#endif + +#if defined(__linux__) && defined(__GLIBC__) && \ + (defined(__i386__) || defined(__x86_64__)) +extern "C" LLVM_ATTRIBUTE_WEAK void __morestack(); +#endif + +uint64_t +RTDyldMemoryManager::getSymbolAddressInProcess(const std::string &Name) { + // This implementation assumes that the host program is the target. + // Clients generating code for a remote target should implement their own + // memory manager. +#if defined(__linux__) && defined(__GLIBC__) + //===--------------------------------------------------------------------===// + // Function stubs that are invoked instead of certain library calls + // + // Force the following functions to be linked in to anything that uses the + // JIT. This is a hack designed to work around the all-too-clever Glibc + // strategy of making these functions work differently when inlined vs. when + // not inlined, and hiding their real definitions in a separate archive file + // that the dynamic linker can't see. For more info, search for + // 'libc_nonshared.a' on Google, or read http://llvm.org/PR274. + if (Name == "stat") return (uint64_t)&stat; + if (Name == "fstat") return (uint64_t)&fstat; + if (Name == "lstat") return (uint64_t)&lstat; + if (Name == "stat64") return (uint64_t)&stat64; + if (Name == "fstat64") return (uint64_t)&fstat64; + if (Name == "lstat64") return (uint64_t)&lstat64; + if (Name == "atexit") return (uint64_t)&atexit; + if (Name == "mknod") return (uint64_t)&mknod; + +#if defined(__i386__) || defined(__x86_64__) + // __morestack lives in libgcc, a static library. + if (&__morestack && Name == "__morestack") + return (uint64_t)&__morestack; +#endif +#endif // __linux__ && __GLIBC__ + + // See ARM_MATH_IMPORTS definition for explanation +#if defined(__BIONIC__) && defined(__arm__) + if (Name.compare(0, 8, "__aeabi_") == 0) { + // Check if the user has requested any of the functions listed in + // ARM_MATH_IMPORTS, and if so redirect to the statically linked symbol. +#define ARM_MATH_CHECK(fn) if (Name == #fn) return (uint64_t)&fn; + ARM_MATH_IMPORTS(ARM_MATH_CHECK) +#undef ARM_MATH_CHECK + } +#endif + + // We should not invoke parent's ctors/dtors from generated main()! + // On Mingw and Cygwin, the symbol __main is resolved to + // callee's(eg. tools/lli) one, to invoke wrong duplicated ctors + // (and register wrong callee's dtors with atexit(3)). + // We expect ExecutionEngine::runStaticConstructorsDestructors() + // is called before ExecutionEngine::runFunctionAsMain() is called. + if (Name == "__main") return (uint64_t)&jit_noop; + + const char *NameStr = Name.c_str(); + + // DynamicLibrary::SearchForAddresOfSymbol expects an unmangled 'C' symbol + // name so ff we're on Darwin, strip the leading '_' off. +#ifdef __APPLE__ + if (NameStr[0] == '_') + ++NameStr; +#endif + + return (uint64_t)sys::DynamicLibrary::SearchForAddressOfSymbol(NameStr); +} + +void *RTDyldMemoryManager::getPointerToNamedFunction(const std::string &Name, + bool AbortOnFailure) { + uint64_t Addr = getSymbolAddress(Name); + + if (!Addr && AbortOnFailure) + report_fatal_error("Program used external function '" + Name + + "' which could not be resolved!"); + + return (void*)Addr; +} + +void RTDyldMemoryManager::anchor() {} +void MCJITMemoryManager::anchor() {} +} // namespace llvm diff --git a/contrib/libs/llvm12/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp b/contrib/libs/llvm12/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp index 5477942ab9..e49e6e541f 100644 --- a/contrib/libs/llvm12/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp +++ b/contrib/libs/llvm12/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp @@ -1,1458 +1,1458 @@ -//===-- RuntimeDyld.cpp - Run-time dynamic linker for MC-JIT ----*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// Implementation of the MC-JIT runtime dynamic linker. -// -//===----------------------------------------------------------------------===// - -#include "llvm/ExecutionEngine/RuntimeDyld.h" -#include "RuntimeDyldCOFF.h" -#include "RuntimeDyldELF.h" -#include "RuntimeDyldImpl.h" -#include "RuntimeDyldMachO.h" -#include "llvm/Object/COFF.h" -#include "llvm/Object/ELFObjectFile.h" -#include "llvm/Support/Alignment.h" -#include "llvm/Support/MSVCErrorWorkarounds.h" -#include "llvm/Support/ManagedStatic.h" -#include "llvm/Support/MathExtras.h" -#include <mutex> - -#include <future> - -using namespace llvm; -using namespace llvm::object; - -#define DEBUG_TYPE "dyld" - -namespace { - -enum RuntimeDyldErrorCode { - GenericRTDyldError = 1 -}; - -// FIXME: This class is only here to support the transition to llvm::Error. It -// will be removed once this transition is complete. Clients should prefer to -// deal with the Error value directly, rather than converting to error_code. -class RuntimeDyldErrorCategory : public std::error_category { -public: - const char *name() const noexcept override { return "runtimedyld"; } - - std::string message(int Condition) const override { - switch (static_cast<RuntimeDyldErrorCode>(Condition)) { - case GenericRTDyldError: return "Generic RuntimeDyld error"; - } - llvm_unreachable("Unrecognized RuntimeDyldErrorCode"); - } -}; - -static ManagedStatic<RuntimeDyldErrorCategory> RTDyldErrorCategory; - -} - -char RuntimeDyldError::ID = 0; - -void RuntimeDyldError::log(raw_ostream &OS) const { - OS << ErrMsg << "\n"; -} - -std::error_code RuntimeDyldError::convertToErrorCode() const { - return std::error_code(GenericRTDyldError, *RTDyldErrorCategory); -} - -// Empty out-of-line virtual destructor as the key function. -RuntimeDyldImpl::~RuntimeDyldImpl() {} - -// Pin LoadedObjectInfo's vtables to this file. -void RuntimeDyld::LoadedObjectInfo::anchor() {} - -namespace llvm { - -void RuntimeDyldImpl::registerEHFrames() {} - -void RuntimeDyldImpl::deregisterEHFrames() { - MemMgr.deregisterEHFrames(); -} - -#ifndef NDEBUG -static void dumpSectionMemory(const SectionEntry &S, StringRef State) { - dbgs() << "----- Contents of section " << S.getName() << " " << State - << " -----"; - - if (S.getAddress() == nullptr) { - dbgs() << "\n <section not emitted>\n"; - return; - } - - const unsigned ColsPerRow = 16; - - uint8_t *DataAddr = S.getAddress(); - uint64_t LoadAddr = S.getLoadAddress(); - - unsigned StartPadding = LoadAddr & (ColsPerRow - 1); - unsigned BytesRemaining = S.getSize(); - - if (StartPadding) { - dbgs() << "\n" << format("0x%016" PRIx64, - LoadAddr & ~(uint64_t)(ColsPerRow - 1)) << ":"; - while (StartPadding--) - dbgs() << " "; - } - - while (BytesRemaining > 0) { - if ((LoadAddr & (ColsPerRow - 1)) == 0) - dbgs() << "\n" << format("0x%016" PRIx64, LoadAddr) << ":"; - - dbgs() << " " << format("%02x", *DataAddr); - - ++DataAddr; - ++LoadAddr; - --BytesRemaining; - } - - dbgs() << "\n"; -} -#endif - -// Resolve the relocations for all symbols we currently know about. -void RuntimeDyldImpl::resolveRelocations() { - std::lock_guard<sys::Mutex> locked(lock); - - // Print out the sections prior to relocation. - LLVM_DEBUG(for (int i = 0, e = Sections.size(); i != e; ++i) - dumpSectionMemory(Sections[i], "before relocations");); - - // First, resolve relocations associated with external symbols. - if (auto Err = resolveExternalSymbols()) { - HasError = true; - ErrorStr = toString(std::move(Err)); - } - - resolveLocalRelocations(); - - // Print out sections after relocation. - LLVM_DEBUG(for (int i = 0, e = Sections.size(); i != e; ++i) - dumpSectionMemory(Sections[i], "after relocations");); -} - -void RuntimeDyldImpl::resolveLocalRelocations() { - // Iterate over all outstanding relocations - for (auto it = Relocations.begin(), e = Relocations.end(); it != e; ++it) { - // The Section here (Sections[i]) refers to the section in which the - // symbol for the relocation is located. The SectionID in the relocation - // entry provides the section to which the relocation will be applied. - int Idx = it->first; - uint64_t Addr = Sections[Idx].getLoadAddress(); - LLVM_DEBUG(dbgs() << "Resolving relocations Section #" << Idx << "\t" - << format("%p", (uintptr_t)Addr) << "\n"); - resolveRelocationList(it->second, Addr); - } - Relocations.clear(); -} - -void RuntimeDyldImpl::mapSectionAddress(const void *LocalAddress, - uint64_t TargetAddress) { - std::lock_guard<sys::Mutex> locked(lock); - for (unsigned i = 0, e = Sections.size(); i != e; ++i) { - if (Sections[i].getAddress() == LocalAddress) { - reassignSectionAddress(i, TargetAddress); - return; - } - } - llvm_unreachable("Attempting to remap address of unknown section!"); -} - -static Error getOffset(const SymbolRef &Sym, SectionRef Sec, - uint64_t &Result) { - Expected<uint64_t> AddressOrErr = Sym.getAddress(); - if (!AddressOrErr) - return AddressOrErr.takeError(); - Result = *AddressOrErr - Sec.getAddress(); - return Error::success(); -} - -Expected<RuntimeDyldImpl::ObjSectionToIDMap> -RuntimeDyldImpl::loadObjectImpl(const object::ObjectFile &Obj) { - std::lock_guard<sys::Mutex> locked(lock); - - // Save information about our target - Arch = (Triple::ArchType)Obj.getArch(); - IsTargetLittleEndian = Obj.isLittleEndian(); - setMipsABI(Obj); - - // Compute the memory size required to load all sections to be loaded - // and pass this information to the memory manager - if (MemMgr.needsToReserveAllocationSpace()) { - uint64_t CodeSize = 0, RODataSize = 0, RWDataSize = 0; - uint32_t CodeAlign = 1, RODataAlign = 1, RWDataAlign = 1; - if (auto Err = computeTotalAllocSize(Obj, - CodeSize, CodeAlign, - RODataSize, RODataAlign, - RWDataSize, RWDataAlign)) - return std::move(Err); - MemMgr.reserveAllocationSpace(CodeSize, CodeAlign, RODataSize, RODataAlign, - RWDataSize, RWDataAlign); - } - - // Used sections from the object file - ObjSectionToIDMap LocalSections; - - // Common symbols requiring allocation, with their sizes and alignments - CommonSymbolList CommonSymbolsToAllocate; - - uint64_t CommonSize = 0; - uint32_t CommonAlign = 0; - - // First, collect all weak and common symbols. We need to know if stronger - // definitions occur elsewhere. - JITSymbolResolver::LookupSet ResponsibilitySet; - { - JITSymbolResolver::LookupSet Symbols; - for (auto &Sym : Obj.symbols()) { - Expected<uint32_t> FlagsOrErr = Sym.getFlags(); - if (!FlagsOrErr) - // TODO: Test this error. - return FlagsOrErr.takeError(); - if ((*FlagsOrErr & SymbolRef::SF_Common) || - (*FlagsOrErr & SymbolRef::SF_Weak)) { - // Get symbol name. - if (auto NameOrErr = Sym.getName()) - Symbols.insert(*NameOrErr); - else - return NameOrErr.takeError(); - } - } - - if (auto ResultOrErr = Resolver.getResponsibilitySet(Symbols)) - ResponsibilitySet = std::move(*ResultOrErr); - else - return ResultOrErr.takeError(); - } - - // Parse symbols - LLVM_DEBUG(dbgs() << "Parse symbols:\n"); - for (symbol_iterator I = Obj.symbol_begin(), E = Obj.symbol_end(); I != E; - ++I) { - Expected<uint32_t> FlagsOrErr = I->getFlags(); - if (!FlagsOrErr) - // TODO: Test this error. - return FlagsOrErr.takeError(); - - // Skip undefined symbols. - if (*FlagsOrErr & SymbolRef::SF_Undefined) - continue; - - // Get the symbol type. - object::SymbolRef::Type SymType; - if (auto SymTypeOrErr = I->getType()) - SymType = *SymTypeOrErr; - else - return SymTypeOrErr.takeError(); - - // Get symbol name. - StringRef Name; - if (auto NameOrErr = I->getName()) - Name = *NameOrErr; - else - return NameOrErr.takeError(); - - // Compute JIT symbol flags. - auto JITSymFlags = getJITSymbolFlags(*I); - if (!JITSymFlags) - return JITSymFlags.takeError(); - - // If this is a weak definition, check to see if there's a strong one. - // If there is, skip this symbol (we won't be providing it: the strong - // definition will). If there's no strong definition, make this definition - // strong. - if (JITSymFlags->isWeak() || JITSymFlags->isCommon()) { - // First check whether there's already a definition in this instance. - if (GlobalSymbolTable.count(Name)) - continue; - - // If we're not responsible for this symbol, skip it. - if (!ResponsibilitySet.count(Name)) - continue; - - // Otherwise update the flags on the symbol to make this definition - // strong. - if (JITSymFlags->isWeak()) - *JITSymFlags &= ~JITSymbolFlags::Weak; - if (JITSymFlags->isCommon()) { - *JITSymFlags &= ~JITSymbolFlags::Common; - uint32_t Align = I->getAlignment(); - uint64_t Size = I->getCommonSize(); - if (!CommonAlign) - CommonAlign = Align; - CommonSize = alignTo(CommonSize, Align) + Size; - CommonSymbolsToAllocate.push_back(*I); - } - } - - if (*FlagsOrErr & SymbolRef::SF_Absolute && - SymType != object::SymbolRef::ST_File) { - uint64_t Addr = 0; - if (auto AddrOrErr = I->getAddress()) - Addr = *AddrOrErr; - else - return AddrOrErr.takeError(); - - unsigned SectionID = AbsoluteSymbolSection; - - LLVM_DEBUG(dbgs() << "\tType: " << SymType << " (absolute) Name: " << Name - << " SID: " << SectionID - << " Offset: " << format("%p", (uintptr_t)Addr) - << " flags: " << *FlagsOrErr << "\n"); - if (!Name.empty()) // Skip absolute symbol relocations. - GlobalSymbolTable[Name] = - SymbolTableEntry(SectionID, Addr, *JITSymFlags); - } else if (SymType == object::SymbolRef::ST_Function || - SymType == object::SymbolRef::ST_Data || - SymType == object::SymbolRef::ST_Unknown || - SymType == object::SymbolRef::ST_Other) { - - section_iterator SI = Obj.section_end(); - if (auto SIOrErr = I->getSection()) - SI = *SIOrErr; - else - return SIOrErr.takeError(); - - if (SI == Obj.section_end()) - continue; - - // Get symbol offset. - uint64_t SectOffset; - if (auto Err = getOffset(*I, *SI, SectOffset)) - return std::move(Err); - - bool IsCode = SI->isText(); - unsigned SectionID; - if (auto SectionIDOrErr = - findOrEmitSection(Obj, *SI, IsCode, LocalSections)) - SectionID = *SectionIDOrErr; - else - return SectionIDOrErr.takeError(); - - LLVM_DEBUG(dbgs() << "\tType: " << SymType << " Name: " << Name - << " SID: " << SectionID - << " Offset: " << format("%p", (uintptr_t)SectOffset) - << " flags: " << *FlagsOrErr << "\n"); - if (!Name.empty()) // Skip absolute symbol relocations - GlobalSymbolTable[Name] = - SymbolTableEntry(SectionID, SectOffset, *JITSymFlags); - } - } - - // Allocate common symbols - if (auto Err = emitCommonSymbols(Obj, CommonSymbolsToAllocate, CommonSize, - CommonAlign)) - return std::move(Err); - - // Parse and process relocations - LLVM_DEBUG(dbgs() << "Parse relocations:\n"); - for (section_iterator SI = Obj.section_begin(), SE = Obj.section_end(); - SI != SE; ++SI) { - StubMap Stubs; - - Expected<section_iterator> RelSecOrErr = SI->getRelocatedSection(); - if (!RelSecOrErr) - return RelSecOrErr.takeError(); - - section_iterator RelocatedSection = *RelSecOrErr; - if (RelocatedSection == SE) - continue; - - relocation_iterator I = SI->relocation_begin(); - relocation_iterator E = SI->relocation_end(); - - if (I == E && !ProcessAllSections) - continue; - - bool IsCode = RelocatedSection->isText(); - unsigned SectionID = 0; - if (auto SectionIDOrErr = findOrEmitSection(Obj, *RelocatedSection, IsCode, - LocalSections)) - SectionID = *SectionIDOrErr; - else - return SectionIDOrErr.takeError(); - - LLVM_DEBUG(dbgs() << "\tSectionID: " << SectionID << "\n"); - - for (; I != E;) - if (auto IOrErr = processRelocationRef(SectionID, I, Obj, LocalSections, Stubs)) - I = *IOrErr; - else - return IOrErr.takeError(); - - // If there is a NotifyStubEmitted callback set, call it to register any - // stubs created for this section. - if (NotifyStubEmitted) { - StringRef FileName = Obj.getFileName(); - StringRef SectionName = Sections[SectionID].getName(); - for (auto &KV : Stubs) { - - auto &VR = KV.first; - uint64_t StubAddr = KV.second; - - // If this is a named stub, just call NotifyStubEmitted. - if (VR.SymbolName) { - NotifyStubEmitted(FileName, SectionName, VR.SymbolName, SectionID, - StubAddr); - continue; - } - - // Otherwise we will have to try a reverse lookup on the globla symbol table. - for (auto &GSTMapEntry : GlobalSymbolTable) { - StringRef SymbolName = GSTMapEntry.first(); - auto &GSTEntry = GSTMapEntry.second; - if (GSTEntry.getSectionID() == VR.SectionID && - GSTEntry.getOffset() == VR.Offset) { - NotifyStubEmitted(FileName, SectionName, SymbolName, SectionID, - StubAddr); - break; - } - } - } - } - } - - // Process remaining sections - if (ProcessAllSections) { - LLVM_DEBUG(dbgs() << "Process remaining sections:\n"); - for (section_iterator SI = Obj.section_begin(), SE = Obj.section_end(); - SI != SE; ++SI) { - - /* Ignore already loaded sections */ - if (LocalSections.find(*SI) != LocalSections.end()) - continue; - - bool IsCode = SI->isText(); - if (auto SectionIDOrErr = - findOrEmitSection(Obj, *SI, IsCode, LocalSections)) - LLVM_DEBUG(dbgs() << "\tSectionID: " << (*SectionIDOrErr) << "\n"); - else - return SectionIDOrErr.takeError(); - } - } - - // Give the subclasses a chance to tie-up any loose ends. - if (auto Err = finalizeLoad(Obj, LocalSections)) - return std::move(Err); - -// for (auto E : LocalSections) -// llvm::dbgs() << "Added: " << E.first.getRawDataRefImpl() << " -> " << E.second << "\n"; - - return LocalSections; -} - -// A helper method for computeTotalAllocSize. -// Computes the memory size required to allocate sections with the given sizes, -// assuming that all sections are allocated with the given alignment -static uint64_t -computeAllocationSizeForSections(std::vector<uint64_t> &SectionSizes, - uint64_t Alignment) { - uint64_t TotalSize = 0; - for (size_t Idx = 0, Cnt = SectionSizes.size(); Idx < Cnt; Idx++) { - uint64_t AlignedSize = - (SectionSizes[Idx] + Alignment - 1) / Alignment * Alignment; - TotalSize += AlignedSize; - } - return TotalSize; -} - -static bool isRequiredForExecution(const SectionRef Section) { - const ObjectFile *Obj = Section.getObject(); - if (isa<object::ELFObjectFileBase>(Obj)) - return ELFSectionRef(Section).getFlags() & ELF::SHF_ALLOC; - if (auto *COFFObj = dyn_cast<object::COFFObjectFile>(Obj)) { - const coff_section *CoffSection = COFFObj->getCOFFSection(Section); - // Avoid loading zero-sized COFF sections. - // In PE files, VirtualSize gives the section size, and SizeOfRawData - // may be zero for sections with content. In Obj files, SizeOfRawData - // gives the section size, and VirtualSize is always zero. Hence - // the need to check for both cases below. - bool HasContent = - (CoffSection->VirtualSize > 0) || (CoffSection->SizeOfRawData > 0); - bool IsDiscardable = - CoffSection->Characteristics & - (COFF::IMAGE_SCN_MEM_DISCARDABLE | COFF::IMAGE_SCN_LNK_INFO); - return HasContent && !IsDiscardable; - } - - assert(isa<MachOObjectFile>(Obj)); - return true; -} - -static bool isReadOnlyData(const SectionRef Section) { - const ObjectFile *Obj = Section.getObject(); - if (isa<object::ELFObjectFileBase>(Obj)) - return !(ELFSectionRef(Section).getFlags() & - (ELF::SHF_WRITE | ELF::SHF_EXECINSTR)); - if (auto *COFFObj = dyn_cast<object::COFFObjectFile>(Obj)) - return ((COFFObj->getCOFFSection(Section)->Characteristics & - (COFF::IMAGE_SCN_CNT_INITIALIZED_DATA - | COFF::IMAGE_SCN_MEM_READ - | COFF::IMAGE_SCN_MEM_WRITE)) - == - (COFF::IMAGE_SCN_CNT_INITIALIZED_DATA - | COFF::IMAGE_SCN_MEM_READ)); - - assert(isa<MachOObjectFile>(Obj)); - return false; -} - -static bool isZeroInit(const SectionRef Section) { - const ObjectFile *Obj = Section.getObject(); - if (isa<object::ELFObjectFileBase>(Obj)) - return ELFSectionRef(Section).getType() == ELF::SHT_NOBITS; - if (auto *COFFObj = dyn_cast<object::COFFObjectFile>(Obj)) - return COFFObj->getCOFFSection(Section)->Characteristics & - COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA; - - auto *MachO = cast<MachOObjectFile>(Obj); - unsigned SectionType = MachO->getSectionType(Section); - return SectionType == MachO::S_ZEROFILL || - SectionType == MachO::S_GB_ZEROFILL; -} - -// Compute an upper bound of the memory size that is required to load all -// sections -Error RuntimeDyldImpl::computeTotalAllocSize(const ObjectFile &Obj, - uint64_t &CodeSize, - uint32_t &CodeAlign, - uint64_t &RODataSize, - uint32_t &RODataAlign, - uint64_t &RWDataSize, - uint32_t &RWDataAlign) { - // Compute the size of all sections required for execution - std::vector<uint64_t> CodeSectionSizes; - std::vector<uint64_t> ROSectionSizes; - std::vector<uint64_t> RWSectionSizes; - - // Collect sizes of all sections to be loaded; - // also determine the max alignment of all sections - for (section_iterator SI = Obj.section_begin(), SE = Obj.section_end(); - SI != SE; ++SI) { - const SectionRef &Section = *SI; - - bool IsRequired = isRequiredForExecution(Section) || ProcessAllSections; - - // Consider only the sections that are required to be loaded for execution - if (IsRequired) { - uint64_t DataSize = Section.getSize(); - uint64_t Alignment64 = Section.getAlignment(); - unsigned Alignment = (unsigned)Alignment64 & 0xffffffffL; - bool IsCode = Section.isText(); - bool IsReadOnly = isReadOnlyData(Section); - - Expected<StringRef> NameOrErr = Section.getName(); - if (!NameOrErr) - return NameOrErr.takeError(); - StringRef Name = *NameOrErr; - - uint64_t StubBufSize = computeSectionStubBufSize(Obj, Section); - - uint64_t PaddingSize = 0; - if (Name == ".eh_frame") - PaddingSize += 4; - if (StubBufSize != 0) - PaddingSize += getStubAlignment() - 1; - - uint64_t SectionSize = DataSize + PaddingSize + StubBufSize; - - // The .eh_frame section (at least on Linux) needs an extra four bytes - // padded - // with zeroes added at the end. For MachO objects, this section has a - // slightly different name, so this won't have any effect for MachO - // objects. - if (Name == ".eh_frame") - SectionSize += 4; - - if (!SectionSize) - SectionSize = 1; - - if (IsCode) { - CodeAlign = std::max(CodeAlign, Alignment); - CodeSectionSizes.push_back(SectionSize); - } else if (IsReadOnly) { - RODataAlign = std::max(RODataAlign, Alignment); - ROSectionSizes.push_back(SectionSize); - } else { - RWDataAlign = std::max(RWDataAlign, Alignment); - RWSectionSizes.push_back(SectionSize); - } - } - } - - // Compute Global Offset Table size. If it is not zero we - // also update alignment, which is equal to a size of a - // single GOT entry. - if (unsigned GotSize = computeGOTSize(Obj)) { - RWSectionSizes.push_back(GotSize); - RWDataAlign = std::max<uint32_t>(RWDataAlign, getGOTEntrySize()); - } - - // Compute the size of all common symbols - uint64_t CommonSize = 0; - uint32_t CommonAlign = 1; - for (symbol_iterator I = Obj.symbol_begin(), E = Obj.symbol_end(); I != E; - ++I) { - Expected<uint32_t> FlagsOrErr = I->getFlags(); - if (!FlagsOrErr) - // TODO: Test this error. - return FlagsOrErr.takeError(); - if (*FlagsOrErr & SymbolRef::SF_Common) { - // Add the common symbols to a list. We'll allocate them all below. - uint64_t Size = I->getCommonSize(); - uint32_t Align = I->getAlignment(); - // If this is the first common symbol, use its alignment as the alignment - // for the common symbols section. - if (CommonSize == 0) - CommonAlign = Align; - CommonSize = alignTo(CommonSize, Align) + Size; - } - } - if (CommonSize != 0) { - RWSectionSizes.push_back(CommonSize); - RWDataAlign = std::max(RWDataAlign, CommonAlign); - } - - // Compute the required allocation space for each different type of sections - // (code, read-only data, read-write data) assuming that all sections are - // allocated with the max alignment. Note that we cannot compute with the - // individual alignments of the sections, because then the required size - // depends on the order, in which the sections are allocated. - CodeSize = computeAllocationSizeForSections(CodeSectionSizes, CodeAlign); - RODataSize = computeAllocationSizeForSections(ROSectionSizes, RODataAlign); - RWDataSize = computeAllocationSizeForSections(RWSectionSizes, RWDataAlign); - - return Error::success(); -} - -// compute GOT size -unsigned RuntimeDyldImpl::computeGOTSize(const ObjectFile &Obj) { - size_t GotEntrySize = getGOTEntrySize(); - if (!GotEntrySize) - return 0; - - size_t GotSize = 0; - for (section_iterator SI = Obj.section_begin(), SE = Obj.section_end(); - SI != SE; ++SI) { - - for (const RelocationRef &Reloc : SI->relocations()) - if (relocationNeedsGot(Reloc)) - GotSize += GotEntrySize; - } - - return GotSize; -} - -// compute stub buffer size for the given section -unsigned RuntimeDyldImpl::computeSectionStubBufSize(const ObjectFile &Obj, - const SectionRef &Section) { - unsigned StubSize = getMaxStubSize(); - if (StubSize == 0) { - return 0; - } - // FIXME: this is an inefficient way to handle this. We should computed the - // necessary section allocation size in loadObject by walking all the sections - // once. - unsigned StubBufSize = 0; - for (section_iterator SI = Obj.section_begin(), SE = Obj.section_end(); - SI != SE; ++SI) { - - Expected<section_iterator> RelSecOrErr = SI->getRelocatedSection(); - if (!RelSecOrErr) - report_fatal_error(toString(RelSecOrErr.takeError())); - - section_iterator RelSecI = *RelSecOrErr; - if (!(RelSecI == Section)) - continue; - - for (const RelocationRef &Reloc : SI->relocations()) - if (relocationNeedsStub(Reloc)) - StubBufSize += StubSize; - } - - // Get section data size and alignment - uint64_t DataSize = Section.getSize(); - uint64_t Alignment64 = Section.getAlignment(); - - // Add stubbuf size alignment - unsigned Alignment = (unsigned)Alignment64 & 0xffffffffL; - unsigned StubAlignment = getStubAlignment(); - unsigned EndAlignment = (DataSize | Alignment) & -(DataSize | Alignment); - if (StubAlignment > EndAlignment) - StubBufSize += StubAlignment - EndAlignment; - return StubBufSize; -} - -uint64_t RuntimeDyldImpl::readBytesUnaligned(uint8_t *Src, - unsigned Size) const { - uint64_t Result = 0; - if (IsTargetLittleEndian) { - Src += Size - 1; - while (Size--) - Result = (Result << 8) | *Src--; - } else - while (Size--) - Result = (Result << 8) | *Src++; - - return Result; -} - -void RuntimeDyldImpl::writeBytesUnaligned(uint64_t Value, uint8_t *Dst, - unsigned Size) const { - if (IsTargetLittleEndian) { - while (Size--) { - *Dst++ = Value & 0xFF; - Value >>= 8; - } - } else { - Dst += Size - 1; - while (Size--) { - *Dst-- = Value & 0xFF; - Value >>= 8; - } - } -} - -Expected<JITSymbolFlags> -RuntimeDyldImpl::getJITSymbolFlags(const SymbolRef &SR) { - return JITSymbolFlags::fromObjectSymbol(SR); -} - -Error RuntimeDyldImpl::emitCommonSymbols(const ObjectFile &Obj, - CommonSymbolList &SymbolsToAllocate, - uint64_t CommonSize, - uint32_t CommonAlign) { - if (SymbolsToAllocate.empty()) - return Error::success(); - - // Allocate memory for the section - unsigned SectionID = Sections.size(); - uint8_t *Addr = MemMgr.allocateDataSection(CommonSize, CommonAlign, SectionID, - "<common symbols>", false); - if (!Addr) - report_fatal_error("Unable to allocate memory for common symbols!"); - uint64_t Offset = 0; - Sections.push_back( - SectionEntry("<common symbols>", Addr, CommonSize, CommonSize, 0)); - memset(Addr, 0, CommonSize); - - LLVM_DEBUG(dbgs() << "emitCommonSection SectionID: " << SectionID - << " new addr: " << format("%p", Addr) - << " DataSize: " << CommonSize << "\n"); - - // Assign the address of each symbol - for (auto &Sym : SymbolsToAllocate) { - uint32_t Alignment = Sym.getAlignment(); - uint64_t Size = Sym.getCommonSize(); - StringRef Name; - if (auto NameOrErr = Sym.getName()) - Name = *NameOrErr; - else - return NameOrErr.takeError(); - if (Alignment) { - // This symbol has an alignment requirement. - uint64_t AlignOffset = - offsetToAlignment((uint64_t)Addr, Align(Alignment)); - Addr += AlignOffset; - Offset += AlignOffset; - } - auto JITSymFlags = getJITSymbolFlags(Sym); - - if (!JITSymFlags) - return JITSymFlags.takeError(); - - LLVM_DEBUG(dbgs() << "Allocating common symbol " << Name << " address " - << format("%p", Addr) << "\n"); - if (!Name.empty()) // Skip absolute symbol relocations. - GlobalSymbolTable[Name] = - SymbolTableEntry(SectionID, Offset, std::move(*JITSymFlags)); - Offset += Size; - Addr += Size; - } - - return Error::success(); -} - -Expected<unsigned> -RuntimeDyldImpl::emitSection(const ObjectFile &Obj, - const SectionRef &Section, - bool IsCode) { - StringRef data; - uint64_t Alignment64 = Section.getAlignment(); - - unsigned Alignment = (unsigned)Alignment64 & 0xffffffffL; - unsigned PaddingSize = 0; - unsigned StubBufSize = 0; - bool IsRequired = isRequiredForExecution(Section); - bool IsVirtual = Section.isVirtual(); - bool IsZeroInit = isZeroInit(Section); - bool IsReadOnly = isReadOnlyData(Section); - uint64_t DataSize = Section.getSize(); - - // An alignment of 0 (at least with ELF) is identical to an alignment of 1, - // while being more "polite". Other formats do not support 0-aligned sections - // anyway, so we should guarantee that the alignment is always at least 1. - Alignment = std::max(1u, Alignment); - - Expected<StringRef> NameOrErr = Section.getName(); - if (!NameOrErr) - return NameOrErr.takeError(); - StringRef Name = *NameOrErr; - - StubBufSize = computeSectionStubBufSize(Obj, Section); - - // The .eh_frame section (at least on Linux) needs an extra four bytes padded - // with zeroes added at the end. For MachO objects, this section has a - // slightly different name, so this won't have any effect for MachO objects. - if (Name == ".eh_frame") - PaddingSize = 4; - - uintptr_t Allocate; - unsigned SectionID = Sections.size(); - uint8_t *Addr; - const char *pData = nullptr; - - // If this section contains any bits (i.e. isn't a virtual or bss section), - // grab a reference to them. - if (!IsVirtual && !IsZeroInit) { - // In either case, set the location of the unrelocated section in memory, - // since we still process relocations for it even if we're not applying them. - if (Expected<StringRef> E = Section.getContents()) - data = *E; - else - return E.takeError(); - pData = data.data(); - } - - // If there are any stubs then the section alignment needs to be at least as - // high as stub alignment or padding calculations may by incorrect when the - // section is remapped. - if (StubBufSize != 0) { - Alignment = std::max(Alignment, getStubAlignment()); - PaddingSize += getStubAlignment() - 1; - } - - // Some sections, such as debug info, don't need to be loaded for execution. - // Process those only if explicitly requested. - if (IsRequired || ProcessAllSections) { - Allocate = DataSize + PaddingSize + StubBufSize; - if (!Allocate) - Allocate = 1; - Addr = IsCode ? MemMgr.allocateCodeSection(Allocate, Alignment, SectionID, - Name) - : MemMgr.allocateDataSection(Allocate, Alignment, SectionID, - Name, IsReadOnly); - if (!Addr) - report_fatal_error("Unable to allocate section memory!"); - - // Zero-initialize or copy the data from the image - if (IsZeroInit || IsVirtual) - memset(Addr, 0, DataSize); - else - memcpy(Addr, pData, DataSize); - - // Fill in any extra bytes we allocated for padding - if (PaddingSize != 0) { - memset(Addr + DataSize, 0, PaddingSize); - // Update the DataSize variable to include padding. - DataSize += PaddingSize; - - // Align DataSize to stub alignment if we have any stubs (PaddingSize will - // have been increased above to account for this). - if (StubBufSize > 0) - DataSize &= -(uint64_t)getStubAlignment(); - } - - LLVM_DEBUG(dbgs() << "emitSection SectionID: " << SectionID << " Name: " - << Name << " obj addr: " << format("%p", pData) - << " new addr: " << format("%p", Addr) << " DataSize: " - << DataSize << " StubBufSize: " << StubBufSize - << " Allocate: " << Allocate << "\n"); - } else { - // Even if we didn't load the section, we need to record an entry for it - // to handle later processing (and by 'handle' I mean don't do anything - // with these sections). - Allocate = 0; - Addr = nullptr; - LLVM_DEBUG( - dbgs() << "emitSection SectionID: " << SectionID << " Name: " << Name - << " obj addr: " << format("%p", data.data()) << " new addr: 0" - << " DataSize: " << DataSize << " StubBufSize: " << StubBufSize - << " Allocate: " << Allocate << "\n"); - } - - Sections.push_back( - SectionEntry(Name, Addr, DataSize, Allocate, (uintptr_t)pData)); - - // Debug info sections are linked as if their load address was zero - if (!IsRequired) - Sections.back().setLoadAddress(0); - - return SectionID; -} - -Expected<unsigned> -RuntimeDyldImpl::findOrEmitSection(const ObjectFile &Obj, - const SectionRef &Section, - bool IsCode, - ObjSectionToIDMap &LocalSections) { - - unsigned SectionID = 0; - ObjSectionToIDMap::iterator i = LocalSections.find(Section); - if (i != LocalSections.end()) - SectionID = i->second; - else { - if (auto SectionIDOrErr = emitSection(Obj, Section, IsCode)) - SectionID = *SectionIDOrErr; - else - return SectionIDOrErr.takeError(); - LocalSections[Section] = SectionID; - } - return SectionID; -} - -void RuntimeDyldImpl::addRelocationForSection(const RelocationEntry &RE, - unsigned SectionID) { - Relocations[SectionID].push_back(RE); -} - -void RuntimeDyldImpl::addRelocationForSymbol(const RelocationEntry &RE, - StringRef SymbolName) { - // Relocation by symbol. If the symbol is found in the global symbol table, - // create an appropriate section relocation. Otherwise, add it to - // ExternalSymbolRelocations. - RTDyldSymbolTable::const_iterator Loc = GlobalSymbolTable.find(SymbolName); - if (Loc == GlobalSymbolTable.end()) { - ExternalSymbolRelocations[SymbolName].push_back(RE); - } else { - assert(!SymbolName.empty() && - "Empty symbol should not be in GlobalSymbolTable"); - // Copy the RE since we want to modify its addend. - RelocationEntry RECopy = RE; - const auto &SymInfo = Loc->second; - RECopy.Addend += SymInfo.getOffset(); - Relocations[SymInfo.getSectionID()].push_back(RECopy); - } -} - -uint8_t *RuntimeDyldImpl::createStubFunction(uint8_t *Addr, - unsigned AbiVariant) { - if (Arch == Triple::aarch64 || Arch == Triple::aarch64_be || - Arch == Triple::aarch64_32) { - // This stub has to be able to access the full address space, - // since symbol lookup won't necessarily find a handy, in-range, - // PLT stub for functions which could be anywhere. - // Stub can use ip0 (== x16) to calculate address - writeBytesUnaligned(0xd2e00010, Addr, 4); // movz ip0, #:abs_g3:<addr> - writeBytesUnaligned(0xf2c00010, Addr+4, 4); // movk ip0, #:abs_g2_nc:<addr> - writeBytesUnaligned(0xf2a00010, Addr+8, 4); // movk ip0, #:abs_g1_nc:<addr> - writeBytesUnaligned(0xf2800010, Addr+12, 4); // movk ip0, #:abs_g0_nc:<addr> - writeBytesUnaligned(0xd61f0200, Addr+16, 4); // br ip0 - - return Addr; - } else if (Arch == Triple::arm || Arch == Triple::armeb) { - // TODO: There is only ARM far stub now. We should add the Thumb stub, - // and stubs for branches Thumb - ARM and ARM - Thumb. - writeBytesUnaligned(0xe51ff004, Addr, 4); // ldr pc, [pc, #-4] - return Addr + 4; - } else if (IsMipsO32ABI || IsMipsN32ABI) { - // 0: 3c190000 lui t9,%hi(addr). - // 4: 27390000 addiu t9,t9,%lo(addr). - // 8: 03200008 jr t9. - // c: 00000000 nop. - const unsigned LuiT9Instr = 0x3c190000, AdduiT9Instr = 0x27390000; - const unsigned NopInstr = 0x0; - unsigned JrT9Instr = 0x03200008; - if ((AbiVariant & ELF::EF_MIPS_ARCH) == ELF::EF_MIPS_ARCH_32R6 || - (AbiVariant & ELF::EF_MIPS_ARCH) == ELF::EF_MIPS_ARCH_64R6) - JrT9Instr = 0x03200009; - - writeBytesUnaligned(LuiT9Instr, Addr, 4); - writeBytesUnaligned(AdduiT9Instr, Addr + 4, 4); - writeBytesUnaligned(JrT9Instr, Addr + 8, 4); - writeBytesUnaligned(NopInstr, Addr + 12, 4); - return Addr; - } else if (IsMipsN64ABI) { - // 0: 3c190000 lui t9,%highest(addr). - // 4: 67390000 daddiu t9,t9,%higher(addr). - // 8: 0019CC38 dsll t9,t9,16. - // c: 67390000 daddiu t9,t9,%hi(addr). - // 10: 0019CC38 dsll t9,t9,16. - // 14: 67390000 daddiu t9,t9,%lo(addr). - // 18: 03200008 jr t9. - // 1c: 00000000 nop. - const unsigned LuiT9Instr = 0x3c190000, DaddiuT9Instr = 0x67390000, - DsllT9Instr = 0x19CC38; - const unsigned NopInstr = 0x0; - unsigned JrT9Instr = 0x03200008; - if ((AbiVariant & ELF::EF_MIPS_ARCH) == ELF::EF_MIPS_ARCH_64R6) - JrT9Instr = 0x03200009; - - writeBytesUnaligned(LuiT9Instr, Addr, 4); - writeBytesUnaligned(DaddiuT9Instr, Addr + 4, 4); - writeBytesUnaligned(DsllT9Instr, Addr + 8, 4); - writeBytesUnaligned(DaddiuT9Instr, Addr + 12, 4); - writeBytesUnaligned(DsllT9Instr, Addr + 16, 4); - writeBytesUnaligned(DaddiuT9Instr, Addr + 20, 4); - writeBytesUnaligned(JrT9Instr, Addr + 24, 4); - writeBytesUnaligned(NopInstr, Addr + 28, 4); - return Addr; - } else if (Arch == Triple::ppc64 || Arch == Triple::ppc64le) { - // Depending on which version of the ELF ABI is in use, we need to - // generate one of two variants of the stub. They both start with - // the same sequence to load the target address into r12. - writeInt32BE(Addr, 0x3D800000); // lis r12, highest(addr) - writeInt32BE(Addr+4, 0x618C0000); // ori r12, higher(addr) - writeInt32BE(Addr+8, 0x798C07C6); // sldi r12, r12, 32 - writeInt32BE(Addr+12, 0x658C0000); // oris r12, r12, h(addr) - writeInt32BE(Addr+16, 0x618C0000); // ori r12, r12, l(addr) - if (AbiVariant == 2) { - // PowerPC64 stub ELFv2 ABI: The address points to the function itself. - // The address is already in r12 as required by the ABI. Branch to it. - writeInt32BE(Addr+20, 0xF8410018); // std r2, 24(r1) - writeInt32BE(Addr+24, 0x7D8903A6); // mtctr r12 - writeInt32BE(Addr+28, 0x4E800420); // bctr - } else { - // PowerPC64 stub ELFv1 ABI: The address points to a function descriptor. - // Load the function address on r11 and sets it to control register. Also - // loads the function TOC in r2 and environment pointer to r11. - writeInt32BE(Addr+20, 0xF8410028); // std r2, 40(r1) - writeInt32BE(Addr+24, 0xE96C0000); // ld r11, 0(r12) - writeInt32BE(Addr+28, 0xE84C0008); // ld r2, 0(r12) - writeInt32BE(Addr+32, 0x7D6903A6); // mtctr r11 - writeInt32BE(Addr+36, 0xE96C0010); // ld r11, 16(r2) - writeInt32BE(Addr+40, 0x4E800420); // bctr - } - return Addr; - } else if (Arch == Triple::systemz) { - writeInt16BE(Addr, 0xC418); // lgrl %r1,.+8 - writeInt16BE(Addr+2, 0x0000); - writeInt16BE(Addr+4, 0x0004); - writeInt16BE(Addr+6, 0x07F1); // brc 15,%r1 - // 8-byte address stored at Addr + 8 - return Addr; - } else if (Arch == Triple::x86_64) { - *Addr = 0xFF; // jmp - *(Addr+1) = 0x25; // rip - // 32-bit PC-relative address of the GOT entry will be stored at Addr+2 - } else if (Arch == Triple::x86) { - *Addr = 0xE9; // 32-bit pc-relative jump. - } - return Addr; -} - -// Assign an address to a symbol name and resolve all the relocations -// associated with it. -void RuntimeDyldImpl::reassignSectionAddress(unsigned SectionID, - uint64_t Addr) { - // The address to use for relocation resolution is not - // the address of the local section buffer. We must be doing - // a remote execution environment of some sort. Relocations can't - // be applied until all the sections have been moved. The client must - // trigger this with a call to MCJIT::finalize() or - // RuntimeDyld::resolveRelocations(). - // - // Addr is a uint64_t because we can't assume the pointer width - // of the target is the same as that of the host. Just use a generic - // "big enough" type. - LLVM_DEBUG( - dbgs() << "Reassigning address for section " << SectionID << " (" - << Sections[SectionID].getName() << "): " - << format("0x%016" PRIx64, Sections[SectionID].getLoadAddress()) - << " -> " << format("0x%016" PRIx64, Addr) << "\n"); - Sections[SectionID].setLoadAddress(Addr); -} - -void RuntimeDyldImpl::resolveRelocationList(const RelocationList &Relocs, - uint64_t Value) { - for (unsigned i = 0, e = Relocs.size(); i != e; ++i) { - const RelocationEntry &RE = Relocs[i]; - // Ignore relocations for sections that were not loaded - if (Sections[RE.SectionID].getAddress() == nullptr) - continue; - resolveRelocation(RE, Value); - } -} - -void RuntimeDyldImpl::applyExternalSymbolRelocations( - const StringMap<JITEvaluatedSymbol> ExternalSymbolMap) { - while (!ExternalSymbolRelocations.empty()) { - - StringMap<RelocationList>::iterator i = ExternalSymbolRelocations.begin(); - - StringRef Name = i->first(); - if (Name.size() == 0) { - // This is an absolute symbol, use an address of zero. - LLVM_DEBUG(dbgs() << "Resolving absolute relocations." - << "\n"); - RelocationList &Relocs = i->second; - resolveRelocationList(Relocs, 0); - } else { - uint64_t Addr = 0; - JITSymbolFlags Flags; - RTDyldSymbolTable::const_iterator Loc = GlobalSymbolTable.find(Name); - if (Loc == GlobalSymbolTable.end()) { - auto RRI = ExternalSymbolMap.find(Name); - assert(RRI != ExternalSymbolMap.end() && "No result for symbol"); - Addr = RRI->second.getAddress(); - Flags = RRI->second.getFlags(); - // The call to getSymbolAddress may have caused additional modules to - // be loaded, which may have added new entries to the - // ExternalSymbolRelocations map. Consquently, we need to update our - // iterator. This is also why retrieval of the relocation list - // associated with this symbol is deferred until below this point. - // New entries may have been added to the relocation list. - i = ExternalSymbolRelocations.find(Name); - } else { - // We found the symbol in our global table. It was probably in a - // Module that we loaded previously. - const auto &SymInfo = Loc->second; - Addr = getSectionLoadAddress(SymInfo.getSectionID()) + - SymInfo.getOffset(); - Flags = SymInfo.getFlags(); - } - - // FIXME: Implement error handling that doesn't kill the host program! - if (!Addr) - report_fatal_error("Program used external function '" + Name + - "' which could not be resolved!"); - - // If Resolver returned UINT64_MAX, the client wants to handle this symbol - // manually and we shouldn't resolve its relocations. - if (Addr != UINT64_MAX) { - - // Tweak the address based on the symbol flags if necessary. - // For example, this is used by RuntimeDyldMachOARM to toggle the low bit - // if the target symbol is Thumb. - Addr = modifyAddressBasedOnFlags(Addr, Flags); - - LLVM_DEBUG(dbgs() << "Resolving relocations Name: " << Name << "\t" - << format("0x%lx", Addr) << "\n"); - // This list may have been updated when we called getSymbolAddress, so - // don't change this code to get the list earlier. - RelocationList &Relocs = i->second; - resolveRelocationList(Relocs, Addr); - } - } - - ExternalSymbolRelocations.erase(i); - } -} - -Error RuntimeDyldImpl::resolveExternalSymbols() { - StringMap<JITEvaluatedSymbol> ExternalSymbolMap; - - // Resolution can trigger emission of more symbols, so iterate until - // we've resolved *everything*. - { - JITSymbolResolver::LookupSet ResolvedSymbols; - - while (true) { - JITSymbolResolver::LookupSet NewSymbols; - - for (auto &RelocKV : ExternalSymbolRelocations) { - StringRef Name = RelocKV.first(); - if (!Name.empty() && !GlobalSymbolTable.count(Name) && - !ResolvedSymbols.count(Name)) - NewSymbols.insert(Name); - } - - if (NewSymbols.empty()) - break; - -#ifdef _MSC_VER - using ExpectedLookupResult = - MSVCPExpected<JITSymbolResolver::LookupResult>; -#else - using ExpectedLookupResult = Expected<JITSymbolResolver::LookupResult>; -#endif - - auto NewSymbolsP = std::make_shared<std::promise<ExpectedLookupResult>>(); - auto NewSymbolsF = NewSymbolsP->get_future(); - Resolver.lookup(NewSymbols, - [=](Expected<JITSymbolResolver::LookupResult> Result) { - NewSymbolsP->set_value(std::move(Result)); - }); - - auto NewResolverResults = NewSymbolsF.get(); - - if (!NewResolverResults) - return NewResolverResults.takeError(); - - assert(NewResolverResults->size() == NewSymbols.size() && - "Should have errored on unresolved symbols"); - - for (auto &RRKV : *NewResolverResults) { - assert(!ResolvedSymbols.count(RRKV.first) && "Redundant resolution?"); - ExternalSymbolMap.insert(RRKV); - ResolvedSymbols.insert(RRKV.first); - } - } - } - - applyExternalSymbolRelocations(ExternalSymbolMap); - - return Error::success(); -} - -void RuntimeDyldImpl::finalizeAsync( - std::unique_ptr<RuntimeDyldImpl> This, +//===-- RuntimeDyld.cpp - Run-time dynamic linker for MC-JIT ----*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Implementation of the MC-JIT runtime dynamic linker. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ExecutionEngine/RuntimeDyld.h" +#include "RuntimeDyldCOFF.h" +#include "RuntimeDyldELF.h" +#include "RuntimeDyldImpl.h" +#include "RuntimeDyldMachO.h" +#include "llvm/Object/COFF.h" +#include "llvm/Object/ELFObjectFile.h" +#include "llvm/Support/Alignment.h" +#include "llvm/Support/MSVCErrorWorkarounds.h" +#include "llvm/Support/ManagedStatic.h" +#include "llvm/Support/MathExtras.h" +#include <mutex> + +#include <future> + +using namespace llvm; +using namespace llvm::object; + +#define DEBUG_TYPE "dyld" + +namespace { + +enum RuntimeDyldErrorCode { + GenericRTDyldError = 1 +}; + +// FIXME: This class is only here to support the transition to llvm::Error. It +// will be removed once this transition is complete. Clients should prefer to +// deal with the Error value directly, rather than converting to error_code. +class RuntimeDyldErrorCategory : public std::error_category { +public: + const char *name() const noexcept override { return "runtimedyld"; } + + std::string message(int Condition) const override { + switch (static_cast<RuntimeDyldErrorCode>(Condition)) { + case GenericRTDyldError: return "Generic RuntimeDyld error"; + } + llvm_unreachable("Unrecognized RuntimeDyldErrorCode"); + } +}; + +static ManagedStatic<RuntimeDyldErrorCategory> RTDyldErrorCategory; + +} + +char RuntimeDyldError::ID = 0; + +void RuntimeDyldError::log(raw_ostream &OS) const { + OS << ErrMsg << "\n"; +} + +std::error_code RuntimeDyldError::convertToErrorCode() const { + return std::error_code(GenericRTDyldError, *RTDyldErrorCategory); +} + +// Empty out-of-line virtual destructor as the key function. +RuntimeDyldImpl::~RuntimeDyldImpl() {} + +// Pin LoadedObjectInfo's vtables to this file. +void RuntimeDyld::LoadedObjectInfo::anchor() {} + +namespace llvm { + +void RuntimeDyldImpl::registerEHFrames() {} + +void RuntimeDyldImpl::deregisterEHFrames() { + MemMgr.deregisterEHFrames(); +} + +#ifndef NDEBUG +static void dumpSectionMemory(const SectionEntry &S, StringRef State) { + dbgs() << "----- Contents of section " << S.getName() << " " << State + << " -----"; + + if (S.getAddress() == nullptr) { + dbgs() << "\n <section not emitted>\n"; + return; + } + + const unsigned ColsPerRow = 16; + + uint8_t *DataAddr = S.getAddress(); + uint64_t LoadAddr = S.getLoadAddress(); + + unsigned StartPadding = LoadAddr & (ColsPerRow - 1); + unsigned BytesRemaining = S.getSize(); + + if (StartPadding) { + dbgs() << "\n" << format("0x%016" PRIx64, + LoadAddr & ~(uint64_t)(ColsPerRow - 1)) << ":"; + while (StartPadding--) + dbgs() << " "; + } + + while (BytesRemaining > 0) { + if ((LoadAddr & (ColsPerRow - 1)) == 0) + dbgs() << "\n" << format("0x%016" PRIx64, LoadAddr) << ":"; + + dbgs() << " " << format("%02x", *DataAddr); + + ++DataAddr; + ++LoadAddr; + --BytesRemaining; + } + + dbgs() << "\n"; +} +#endif + +// Resolve the relocations for all symbols we currently know about. +void RuntimeDyldImpl::resolveRelocations() { + std::lock_guard<sys::Mutex> locked(lock); + + // Print out the sections prior to relocation. + LLVM_DEBUG(for (int i = 0, e = Sections.size(); i != e; ++i) + dumpSectionMemory(Sections[i], "before relocations");); + + // First, resolve relocations associated with external symbols. + if (auto Err = resolveExternalSymbols()) { + HasError = true; + ErrorStr = toString(std::move(Err)); + } + + resolveLocalRelocations(); + + // Print out sections after relocation. + LLVM_DEBUG(for (int i = 0, e = Sections.size(); i != e; ++i) + dumpSectionMemory(Sections[i], "after relocations");); +} + +void RuntimeDyldImpl::resolveLocalRelocations() { + // Iterate over all outstanding relocations + for (auto it = Relocations.begin(), e = Relocations.end(); it != e; ++it) { + // The Section here (Sections[i]) refers to the section in which the + // symbol for the relocation is located. The SectionID in the relocation + // entry provides the section to which the relocation will be applied. + int Idx = it->first; + uint64_t Addr = Sections[Idx].getLoadAddress(); + LLVM_DEBUG(dbgs() << "Resolving relocations Section #" << Idx << "\t" + << format("%p", (uintptr_t)Addr) << "\n"); + resolveRelocationList(it->second, Addr); + } + Relocations.clear(); +} + +void RuntimeDyldImpl::mapSectionAddress(const void *LocalAddress, + uint64_t TargetAddress) { + std::lock_guard<sys::Mutex> locked(lock); + for (unsigned i = 0, e = Sections.size(); i != e; ++i) { + if (Sections[i].getAddress() == LocalAddress) { + reassignSectionAddress(i, TargetAddress); + return; + } + } + llvm_unreachable("Attempting to remap address of unknown section!"); +} + +static Error getOffset(const SymbolRef &Sym, SectionRef Sec, + uint64_t &Result) { + Expected<uint64_t> AddressOrErr = Sym.getAddress(); + if (!AddressOrErr) + return AddressOrErr.takeError(); + Result = *AddressOrErr - Sec.getAddress(); + return Error::success(); +} + +Expected<RuntimeDyldImpl::ObjSectionToIDMap> +RuntimeDyldImpl::loadObjectImpl(const object::ObjectFile &Obj) { + std::lock_guard<sys::Mutex> locked(lock); + + // Save information about our target + Arch = (Triple::ArchType)Obj.getArch(); + IsTargetLittleEndian = Obj.isLittleEndian(); + setMipsABI(Obj); + + // Compute the memory size required to load all sections to be loaded + // and pass this information to the memory manager + if (MemMgr.needsToReserveAllocationSpace()) { + uint64_t CodeSize = 0, RODataSize = 0, RWDataSize = 0; + uint32_t CodeAlign = 1, RODataAlign = 1, RWDataAlign = 1; + if (auto Err = computeTotalAllocSize(Obj, + CodeSize, CodeAlign, + RODataSize, RODataAlign, + RWDataSize, RWDataAlign)) + return std::move(Err); + MemMgr.reserveAllocationSpace(CodeSize, CodeAlign, RODataSize, RODataAlign, + RWDataSize, RWDataAlign); + } + + // Used sections from the object file + ObjSectionToIDMap LocalSections; + + // Common symbols requiring allocation, with their sizes and alignments + CommonSymbolList CommonSymbolsToAllocate; + + uint64_t CommonSize = 0; + uint32_t CommonAlign = 0; + + // First, collect all weak and common symbols. We need to know if stronger + // definitions occur elsewhere. + JITSymbolResolver::LookupSet ResponsibilitySet; + { + JITSymbolResolver::LookupSet Symbols; + for (auto &Sym : Obj.symbols()) { + Expected<uint32_t> FlagsOrErr = Sym.getFlags(); + if (!FlagsOrErr) + // TODO: Test this error. + return FlagsOrErr.takeError(); + if ((*FlagsOrErr & SymbolRef::SF_Common) || + (*FlagsOrErr & SymbolRef::SF_Weak)) { + // Get symbol name. + if (auto NameOrErr = Sym.getName()) + Symbols.insert(*NameOrErr); + else + return NameOrErr.takeError(); + } + } + + if (auto ResultOrErr = Resolver.getResponsibilitySet(Symbols)) + ResponsibilitySet = std::move(*ResultOrErr); + else + return ResultOrErr.takeError(); + } + + // Parse symbols + LLVM_DEBUG(dbgs() << "Parse symbols:\n"); + for (symbol_iterator I = Obj.symbol_begin(), E = Obj.symbol_end(); I != E; + ++I) { + Expected<uint32_t> FlagsOrErr = I->getFlags(); + if (!FlagsOrErr) + // TODO: Test this error. + return FlagsOrErr.takeError(); + + // Skip undefined symbols. + if (*FlagsOrErr & SymbolRef::SF_Undefined) + continue; + + // Get the symbol type. + object::SymbolRef::Type SymType; + if (auto SymTypeOrErr = I->getType()) + SymType = *SymTypeOrErr; + else + return SymTypeOrErr.takeError(); + + // Get symbol name. + StringRef Name; + if (auto NameOrErr = I->getName()) + Name = *NameOrErr; + else + return NameOrErr.takeError(); + + // Compute JIT symbol flags. + auto JITSymFlags = getJITSymbolFlags(*I); + if (!JITSymFlags) + return JITSymFlags.takeError(); + + // If this is a weak definition, check to see if there's a strong one. + // If there is, skip this symbol (we won't be providing it: the strong + // definition will). If there's no strong definition, make this definition + // strong. + if (JITSymFlags->isWeak() || JITSymFlags->isCommon()) { + // First check whether there's already a definition in this instance. + if (GlobalSymbolTable.count(Name)) + continue; + + // If we're not responsible for this symbol, skip it. + if (!ResponsibilitySet.count(Name)) + continue; + + // Otherwise update the flags on the symbol to make this definition + // strong. + if (JITSymFlags->isWeak()) + *JITSymFlags &= ~JITSymbolFlags::Weak; + if (JITSymFlags->isCommon()) { + *JITSymFlags &= ~JITSymbolFlags::Common; + uint32_t Align = I->getAlignment(); + uint64_t Size = I->getCommonSize(); + if (!CommonAlign) + CommonAlign = Align; + CommonSize = alignTo(CommonSize, Align) + Size; + CommonSymbolsToAllocate.push_back(*I); + } + } + + if (*FlagsOrErr & SymbolRef::SF_Absolute && + SymType != object::SymbolRef::ST_File) { + uint64_t Addr = 0; + if (auto AddrOrErr = I->getAddress()) + Addr = *AddrOrErr; + else + return AddrOrErr.takeError(); + + unsigned SectionID = AbsoluteSymbolSection; + + LLVM_DEBUG(dbgs() << "\tType: " << SymType << " (absolute) Name: " << Name + << " SID: " << SectionID + << " Offset: " << format("%p", (uintptr_t)Addr) + << " flags: " << *FlagsOrErr << "\n"); + if (!Name.empty()) // Skip absolute symbol relocations. + GlobalSymbolTable[Name] = + SymbolTableEntry(SectionID, Addr, *JITSymFlags); + } else if (SymType == object::SymbolRef::ST_Function || + SymType == object::SymbolRef::ST_Data || + SymType == object::SymbolRef::ST_Unknown || + SymType == object::SymbolRef::ST_Other) { + + section_iterator SI = Obj.section_end(); + if (auto SIOrErr = I->getSection()) + SI = *SIOrErr; + else + return SIOrErr.takeError(); + + if (SI == Obj.section_end()) + continue; + + // Get symbol offset. + uint64_t SectOffset; + if (auto Err = getOffset(*I, *SI, SectOffset)) + return std::move(Err); + + bool IsCode = SI->isText(); + unsigned SectionID; + if (auto SectionIDOrErr = + findOrEmitSection(Obj, *SI, IsCode, LocalSections)) + SectionID = *SectionIDOrErr; + else + return SectionIDOrErr.takeError(); + + LLVM_DEBUG(dbgs() << "\tType: " << SymType << " Name: " << Name + << " SID: " << SectionID + << " Offset: " << format("%p", (uintptr_t)SectOffset) + << " flags: " << *FlagsOrErr << "\n"); + if (!Name.empty()) // Skip absolute symbol relocations + GlobalSymbolTable[Name] = + SymbolTableEntry(SectionID, SectOffset, *JITSymFlags); + } + } + + // Allocate common symbols + if (auto Err = emitCommonSymbols(Obj, CommonSymbolsToAllocate, CommonSize, + CommonAlign)) + return std::move(Err); + + // Parse and process relocations + LLVM_DEBUG(dbgs() << "Parse relocations:\n"); + for (section_iterator SI = Obj.section_begin(), SE = Obj.section_end(); + SI != SE; ++SI) { + StubMap Stubs; + + Expected<section_iterator> RelSecOrErr = SI->getRelocatedSection(); + if (!RelSecOrErr) + return RelSecOrErr.takeError(); + + section_iterator RelocatedSection = *RelSecOrErr; + if (RelocatedSection == SE) + continue; + + relocation_iterator I = SI->relocation_begin(); + relocation_iterator E = SI->relocation_end(); + + if (I == E && !ProcessAllSections) + continue; + + bool IsCode = RelocatedSection->isText(); + unsigned SectionID = 0; + if (auto SectionIDOrErr = findOrEmitSection(Obj, *RelocatedSection, IsCode, + LocalSections)) + SectionID = *SectionIDOrErr; + else + return SectionIDOrErr.takeError(); + + LLVM_DEBUG(dbgs() << "\tSectionID: " << SectionID << "\n"); + + for (; I != E;) + if (auto IOrErr = processRelocationRef(SectionID, I, Obj, LocalSections, Stubs)) + I = *IOrErr; + else + return IOrErr.takeError(); + + // If there is a NotifyStubEmitted callback set, call it to register any + // stubs created for this section. + if (NotifyStubEmitted) { + StringRef FileName = Obj.getFileName(); + StringRef SectionName = Sections[SectionID].getName(); + for (auto &KV : Stubs) { + + auto &VR = KV.first; + uint64_t StubAddr = KV.second; + + // If this is a named stub, just call NotifyStubEmitted. + if (VR.SymbolName) { + NotifyStubEmitted(FileName, SectionName, VR.SymbolName, SectionID, + StubAddr); + continue; + } + + // Otherwise we will have to try a reverse lookup on the globla symbol table. + for (auto &GSTMapEntry : GlobalSymbolTable) { + StringRef SymbolName = GSTMapEntry.first(); + auto &GSTEntry = GSTMapEntry.second; + if (GSTEntry.getSectionID() == VR.SectionID && + GSTEntry.getOffset() == VR.Offset) { + NotifyStubEmitted(FileName, SectionName, SymbolName, SectionID, + StubAddr); + break; + } + } + } + } + } + + // Process remaining sections + if (ProcessAllSections) { + LLVM_DEBUG(dbgs() << "Process remaining sections:\n"); + for (section_iterator SI = Obj.section_begin(), SE = Obj.section_end(); + SI != SE; ++SI) { + + /* Ignore already loaded sections */ + if (LocalSections.find(*SI) != LocalSections.end()) + continue; + + bool IsCode = SI->isText(); + if (auto SectionIDOrErr = + findOrEmitSection(Obj, *SI, IsCode, LocalSections)) + LLVM_DEBUG(dbgs() << "\tSectionID: " << (*SectionIDOrErr) << "\n"); + else + return SectionIDOrErr.takeError(); + } + } + + // Give the subclasses a chance to tie-up any loose ends. + if (auto Err = finalizeLoad(Obj, LocalSections)) + return std::move(Err); + +// for (auto E : LocalSections) +// llvm::dbgs() << "Added: " << E.first.getRawDataRefImpl() << " -> " << E.second << "\n"; + + return LocalSections; +} + +// A helper method for computeTotalAllocSize. +// Computes the memory size required to allocate sections with the given sizes, +// assuming that all sections are allocated with the given alignment +static uint64_t +computeAllocationSizeForSections(std::vector<uint64_t> &SectionSizes, + uint64_t Alignment) { + uint64_t TotalSize = 0; + for (size_t Idx = 0, Cnt = SectionSizes.size(); Idx < Cnt; Idx++) { + uint64_t AlignedSize = + (SectionSizes[Idx] + Alignment - 1) / Alignment * Alignment; + TotalSize += AlignedSize; + } + return TotalSize; +} + +static bool isRequiredForExecution(const SectionRef Section) { + const ObjectFile *Obj = Section.getObject(); + if (isa<object::ELFObjectFileBase>(Obj)) + return ELFSectionRef(Section).getFlags() & ELF::SHF_ALLOC; + if (auto *COFFObj = dyn_cast<object::COFFObjectFile>(Obj)) { + const coff_section *CoffSection = COFFObj->getCOFFSection(Section); + // Avoid loading zero-sized COFF sections. + // In PE files, VirtualSize gives the section size, and SizeOfRawData + // may be zero for sections with content. In Obj files, SizeOfRawData + // gives the section size, and VirtualSize is always zero. Hence + // the need to check for both cases below. + bool HasContent = + (CoffSection->VirtualSize > 0) || (CoffSection->SizeOfRawData > 0); + bool IsDiscardable = + CoffSection->Characteristics & + (COFF::IMAGE_SCN_MEM_DISCARDABLE | COFF::IMAGE_SCN_LNK_INFO); + return HasContent && !IsDiscardable; + } + + assert(isa<MachOObjectFile>(Obj)); + return true; +} + +static bool isReadOnlyData(const SectionRef Section) { + const ObjectFile *Obj = Section.getObject(); + if (isa<object::ELFObjectFileBase>(Obj)) + return !(ELFSectionRef(Section).getFlags() & + (ELF::SHF_WRITE | ELF::SHF_EXECINSTR)); + if (auto *COFFObj = dyn_cast<object::COFFObjectFile>(Obj)) + return ((COFFObj->getCOFFSection(Section)->Characteristics & + (COFF::IMAGE_SCN_CNT_INITIALIZED_DATA + | COFF::IMAGE_SCN_MEM_READ + | COFF::IMAGE_SCN_MEM_WRITE)) + == + (COFF::IMAGE_SCN_CNT_INITIALIZED_DATA + | COFF::IMAGE_SCN_MEM_READ)); + + assert(isa<MachOObjectFile>(Obj)); + return false; +} + +static bool isZeroInit(const SectionRef Section) { + const ObjectFile *Obj = Section.getObject(); + if (isa<object::ELFObjectFileBase>(Obj)) + return ELFSectionRef(Section).getType() == ELF::SHT_NOBITS; + if (auto *COFFObj = dyn_cast<object::COFFObjectFile>(Obj)) + return COFFObj->getCOFFSection(Section)->Characteristics & + COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA; + + auto *MachO = cast<MachOObjectFile>(Obj); + unsigned SectionType = MachO->getSectionType(Section); + return SectionType == MachO::S_ZEROFILL || + SectionType == MachO::S_GB_ZEROFILL; +} + +// Compute an upper bound of the memory size that is required to load all +// sections +Error RuntimeDyldImpl::computeTotalAllocSize(const ObjectFile &Obj, + uint64_t &CodeSize, + uint32_t &CodeAlign, + uint64_t &RODataSize, + uint32_t &RODataAlign, + uint64_t &RWDataSize, + uint32_t &RWDataAlign) { + // Compute the size of all sections required for execution + std::vector<uint64_t> CodeSectionSizes; + std::vector<uint64_t> ROSectionSizes; + std::vector<uint64_t> RWSectionSizes; + + // Collect sizes of all sections to be loaded; + // also determine the max alignment of all sections + for (section_iterator SI = Obj.section_begin(), SE = Obj.section_end(); + SI != SE; ++SI) { + const SectionRef &Section = *SI; + + bool IsRequired = isRequiredForExecution(Section) || ProcessAllSections; + + // Consider only the sections that are required to be loaded for execution + if (IsRequired) { + uint64_t DataSize = Section.getSize(); + uint64_t Alignment64 = Section.getAlignment(); + unsigned Alignment = (unsigned)Alignment64 & 0xffffffffL; + bool IsCode = Section.isText(); + bool IsReadOnly = isReadOnlyData(Section); + + Expected<StringRef> NameOrErr = Section.getName(); + if (!NameOrErr) + return NameOrErr.takeError(); + StringRef Name = *NameOrErr; + + uint64_t StubBufSize = computeSectionStubBufSize(Obj, Section); + + uint64_t PaddingSize = 0; + if (Name == ".eh_frame") + PaddingSize += 4; + if (StubBufSize != 0) + PaddingSize += getStubAlignment() - 1; + + uint64_t SectionSize = DataSize + PaddingSize + StubBufSize; + + // The .eh_frame section (at least on Linux) needs an extra four bytes + // padded + // with zeroes added at the end. For MachO objects, this section has a + // slightly different name, so this won't have any effect for MachO + // objects. + if (Name == ".eh_frame") + SectionSize += 4; + + if (!SectionSize) + SectionSize = 1; + + if (IsCode) { + CodeAlign = std::max(CodeAlign, Alignment); + CodeSectionSizes.push_back(SectionSize); + } else if (IsReadOnly) { + RODataAlign = std::max(RODataAlign, Alignment); + ROSectionSizes.push_back(SectionSize); + } else { + RWDataAlign = std::max(RWDataAlign, Alignment); + RWSectionSizes.push_back(SectionSize); + } + } + } + + // Compute Global Offset Table size. If it is not zero we + // also update alignment, which is equal to a size of a + // single GOT entry. + if (unsigned GotSize = computeGOTSize(Obj)) { + RWSectionSizes.push_back(GotSize); + RWDataAlign = std::max<uint32_t>(RWDataAlign, getGOTEntrySize()); + } + + // Compute the size of all common symbols + uint64_t CommonSize = 0; + uint32_t CommonAlign = 1; + for (symbol_iterator I = Obj.symbol_begin(), E = Obj.symbol_end(); I != E; + ++I) { + Expected<uint32_t> FlagsOrErr = I->getFlags(); + if (!FlagsOrErr) + // TODO: Test this error. + return FlagsOrErr.takeError(); + if (*FlagsOrErr & SymbolRef::SF_Common) { + // Add the common symbols to a list. We'll allocate them all below. + uint64_t Size = I->getCommonSize(); + uint32_t Align = I->getAlignment(); + // If this is the first common symbol, use its alignment as the alignment + // for the common symbols section. + if (CommonSize == 0) + CommonAlign = Align; + CommonSize = alignTo(CommonSize, Align) + Size; + } + } + if (CommonSize != 0) { + RWSectionSizes.push_back(CommonSize); + RWDataAlign = std::max(RWDataAlign, CommonAlign); + } + + // Compute the required allocation space for each different type of sections + // (code, read-only data, read-write data) assuming that all sections are + // allocated with the max alignment. Note that we cannot compute with the + // individual alignments of the sections, because then the required size + // depends on the order, in which the sections are allocated. + CodeSize = computeAllocationSizeForSections(CodeSectionSizes, CodeAlign); + RODataSize = computeAllocationSizeForSections(ROSectionSizes, RODataAlign); + RWDataSize = computeAllocationSizeForSections(RWSectionSizes, RWDataAlign); + + return Error::success(); +} + +// compute GOT size +unsigned RuntimeDyldImpl::computeGOTSize(const ObjectFile &Obj) { + size_t GotEntrySize = getGOTEntrySize(); + if (!GotEntrySize) + return 0; + + size_t GotSize = 0; + for (section_iterator SI = Obj.section_begin(), SE = Obj.section_end(); + SI != SE; ++SI) { + + for (const RelocationRef &Reloc : SI->relocations()) + if (relocationNeedsGot(Reloc)) + GotSize += GotEntrySize; + } + + return GotSize; +} + +// compute stub buffer size for the given section +unsigned RuntimeDyldImpl::computeSectionStubBufSize(const ObjectFile &Obj, + const SectionRef &Section) { + unsigned StubSize = getMaxStubSize(); + if (StubSize == 0) { + return 0; + } + // FIXME: this is an inefficient way to handle this. We should computed the + // necessary section allocation size in loadObject by walking all the sections + // once. + unsigned StubBufSize = 0; + for (section_iterator SI = Obj.section_begin(), SE = Obj.section_end(); + SI != SE; ++SI) { + + Expected<section_iterator> RelSecOrErr = SI->getRelocatedSection(); + if (!RelSecOrErr) + report_fatal_error(toString(RelSecOrErr.takeError())); + + section_iterator RelSecI = *RelSecOrErr; + if (!(RelSecI == Section)) + continue; + + for (const RelocationRef &Reloc : SI->relocations()) + if (relocationNeedsStub(Reloc)) + StubBufSize += StubSize; + } + + // Get section data size and alignment + uint64_t DataSize = Section.getSize(); + uint64_t Alignment64 = Section.getAlignment(); + + // Add stubbuf size alignment + unsigned Alignment = (unsigned)Alignment64 & 0xffffffffL; + unsigned StubAlignment = getStubAlignment(); + unsigned EndAlignment = (DataSize | Alignment) & -(DataSize | Alignment); + if (StubAlignment > EndAlignment) + StubBufSize += StubAlignment - EndAlignment; + return StubBufSize; +} + +uint64_t RuntimeDyldImpl::readBytesUnaligned(uint8_t *Src, + unsigned Size) const { + uint64_t Result = 0; + if (IsTargetLittleEndian) { + Src += Size - 1; + while (Size--) + Result = (Result << 8) | *Src--; + } else + while (Size--) + Result = (Result << 8) | *Src++; + + return Result; +} + +void RuntimeDyldImpl::writeBytesUnaligned(uint64_t Value, uint8_t *Dst, + unsigned Size) const { + if (IsTargetLittleEndian) { + while (Size--) { + *Dst++ = Value & 0xFF; + Value >>= 8; + } + } else { + Dst += Size - 1; + while (Size--) { + *Dst-- = Value & 0xFF; + Value >>= 8; + } + } +} + +Expected<JITSymbolFlags> +RuntimeDyldImpl::getJITSymbolFlags(const SymbolRef &SR) { + return JITSymbolFlags::fromObjectSymbol(SR); +} + +Error RuntimeDyldImpl::emitCommonSymbols(const ObjectFile &Obj, + CommonSymbolList &SymbolsToAllocate, + uint64_t CommonSize, + uint32_t CommonAlign) { + if (SymbolsToAllocate.empty()) + return Error::success(); + + // Allocate memory for the section + unsigned SectionID = Sections.size(); + uint8_t *Addr = MemMgr.allocateDataSection(CommonSize, CommonAlign, SectionID, + "<common symbols>", false); + if (!Addr) + report_fatal_error("Unable to allocate memory for common symbols!"); + uint64_t Offset = 0; + Sections.push_back( + SectionEntry("<common symbols>", Addr, CommonSize, CommonSize, 0)); + memset(Addr, 0, CommonSize); + + LLVM_DEBUG(dbgs() << "emitCommonSection SectionID: " << SectionID + << " new addr: " << format("%p", Addr) + << " DataSize: " << CommonSize << "\n"); + + // Assign the address of each symbol + for (auto &Sym : SymbolsToAllocate) { + uint32_t Alignment = Sym.getAlignment(); + uint64_t Size = Sym.getCommonSize(); + StringRef Name; + if (auto NameOrErr = Sym.getName()) + Name = *NameOrErr; + else + return NameOrErr.takeError(); + if (Alignment) { + // This symbol has an alignment requirement. + uint64_t AlignOffset = + offsetToAlignment((uint64_t)Addr, Align(Alignment)); + Addr += AlignOffset; + Offset += AlignOffset; + } + auto JITSymFlags = getJITSymbolFlags(Sym); + + if (!JITSymFlags) + return JITSymFlags.takeError(); + + LLVM_DEBUG(dbgs() << "Allocating common symbol " << Name << " address " + << format("%p", Addr) << "\n"); + if (!Name.empty()) // Skip absolute symbol relocations. + GlobalSymbolTable[Name] = + SymbolTableEntry(SectionID, Offset, std::move(*JITSymFlags)); + Offset += Size; + Addr += Size; + } + + return Error::success(); +} + +Expected<unsigned> +RuntimeDyldImpl::emitSection(const ObjectFile &Obj, + const SectionRef &Section, + bool IsCode) { + StringRef data; + uint64_t Alignment64 = Section.getAlignment(); + + unsigned Alignment = (unsigned)Alignment64 & 0xffffffffL; + unsigned PaddingSize = 0; + unsigned StubBufSize = 0; + bool IsRequired = isRequiredForExecution(Section); + bool IsVirtual = Section.isVirtual(); + bool IsZeroInit = isZeroInit(Section); + bool IsReadOnly = isReadOnlyData(Section); + uint64_t DataSize = Section.getSize(); + + // An alignment of 0 (at least with ELF) is identical to an alignment of 1, + // while being more "polite". Other formats do not support 0-aligned sections + // anyway, so we should guarantee that the alignment is always at least 1. + Alignment = std::max(1u, Alignment); + + Expected<StringRef> NameOrErr = Section.getName(); + if (!NameOrErr) + return NameOrErr.takeError(); + StringRef Name = *NameOrErr; + + StubBufSize = computeSectionStubBufSize(Obj, Section); + + // The .eh_frame section (at least on Linux) needs an extra four bytes padded + // with zeroes added at the end. For MachO objects, this section has a + // slightly different name, so this won't have any effect for MachO objects. + if (Name == ".eh_frame") + PaddingSize = 4; + + uintptr_t Allocate; + unsigned SectionID = Sections.size(); + uint8_t *Addr; + const char *pData = nullptr; + + // If this section contains any bits (i.e. isn't a virtual or bss section), + // grab a reference to them. + if (!IsVirtual && !IsZeroInit) { + // In either case, set the location of the unrelocated section in memory, + // since we still process relocations for it even if we're not applying them. + if (Expected<StringRef> E = Section.getContents()) + data = *E; + else + return E.takeError(); + pData = data.data(); + } + + // If there are any stubs then the section alignment needs to be at least as + // high as stub alignment or padding calculations may by incorrect when the + // section is remapped. + if (StubBufSize != 0) { + Alignment = std::max(Alignment, getStubAlignment()); + PaddingSize += getStubAlignment() - 1; + } + + // Some sections, such as debug info, don't need to be loaded for execution. + // Process those only if explicitly requested. + if (IsRequired || ProcessAllSections) { + Allocate = DataSize + PaddingSize + StubBufSize; + if (!Allocate) + Allocate = 1; + Addr = IsCode ? MemMgr.allocateCodeSection(Allocate, Alignment, SectionID, + Name) + : MemMgr.allocateDataSection(Allocate, Alignment, SectionID, + Name, IsReadOnly); + if (!Addr) + report_fatal_error("Unable to allocate section memory!"); + + // Zero-initialize or copy the data from the image + if (IsZeroInit || IsVirtual) + memset(Addr, 0, DataSize); + else + memcpy(Addr, pData, DataSize); + + // Fill in any extra bytes we allocated for padding + if (PaddingSize != 0) { + memset(Addr + DataSize, 0, PaddingSize); + // Update the DataSize variable to include padding. + DataSize += PaddingSize; + + // Align DataSize to stub alignment if we have any stubs (PaddingSize will + // have been increased above to account for this). + if (StubBufSize > 0) + DataSize &= -(uint64_t)getStubAlignment(); + } + + LLVM_DEBUG(dbgs() << "emitSection SectionID: " << SectionID << " Name: " + << Name << " obj addr: " << format("%p", pData) + << " new addr: " << format("%p", Addr) << " DataSize: " + << DataSize << " StubBufSize: " << StubBufSize + << " Allocate: " << Allocate << "\n"); + } else { + // Even if we didn't load the section, we need to record an entry for it + // to handle later processing (and by 'handle' I mean don't do anything + // with these sections). + Allocate = 0; + Addr = nullptr; + LLVM_DEBUG( + dbgs() << "emitSection SectionID: " << SectionID << " Name: " << Name + << " obj addr: " << format("%p", data.data()) << " new addr: 0" + << " DataSize: " << DataSize << " StubBufSize: " << StubBufSize + << " Allocate: " << Allocate << "\n"); + } + + Sections.push_back( + SectionEntry(Name, Addr, DataSize, Allocate, (uintptr_t)pData)); + + // Debug info sections are linked as if their load address was zero + if (!IsRequired) + Sections.back().setLoadAddress(0); + + return SectionID; +} + +Expected<unsigned> +RuntimeDyldImpl::findOrEmitSection(const ObjectFile &Obj, + const SectionRef &Section, + bool IsCode, + ObjSectionToIDMap &LocalSections) { + + unsigned SectionID = 0; + ObjSectionToIDMap::iterator i = LocalSections.find(Section); + if (i != LocalSections.end()) + SectionID = i->second; + else { + if (auto SectionIDOrErr = emitSection(Obj, Section, IsCode)) + SectionID = *SectionIDOrErr; + else + return SectionIDOrErr.takeError(); + LocalSections[Section] = SectionID; + } + return SectionID; +} + +void RuntimeDyldImpl::addRelocationForSection(const RelocationEntry &RE, + unsigned SectionID) { + Relocations[SectionID].push_back(RE); +} + +void RuntimeDyldImpl::addRelocationForSymbol(const RelocationEntry &RE, + StringRef SymbolName) { + // Relocation by symbol. If the symbol is found in the global symbol table, + // create an appropriate section relocation. Otherwise, add it to + // ExternalSymbolRelocations. + RTDyldSymbolTable::const_iterator Loc = GlobalSymbolTable.find(SymbolName); + if (Loc == GlobalSymbolTable.end()) { + ExternalSymbolRelocations[SymbolName].push_back(RE); + } else { + assert(!SymbolName.empty() && + "Empty symbol should not be in GlobalSymbolTable"); + // Copy the RE since we want to modify its addend. + RelocationEntry RECopy = RE; + const auto &SymInfo = Loc->second; + RECopy.Addend += SymInfo.getOffset(); + Relocations[SymInfo.getSectionID()].push_back(RECopy); + } +} + +uint8_t *RuntimeDyldImpl::createStubFunction(uint8_t *Addr, + unsigned AbiVariant) { + if (Arch == Triple::aarch64 || Arch == Triple::aarch64_be || + Arch == Triple::aarch64_32) { + // This stub has to be able to access the full address space, + // since symbol lookup won't necessarily find a handy, in-range, + // PLT stub for functions which could be anywhere. + // Stub can use ip0 (== x16) to calculate address + writeBytesUnaligned(0xd2e00010, Addr, 4); // movz ip0, #:abs_g3:<addr> + writeBytesUnaligned(0xf2c00010, Addr+4, 4); // movk ip0, #:abs_g2_nc:<addr> + writeBytesUnaligned(0xf2a00010, Addr+8, 4); // movk ip0, #:abs_g1_nc:<addr> + writeBytesUnaligned(0xf2800010, Addr+12, 4); // movk ip0, #:abs_g0_nc:<addr> + writeBytesUnaligned(0xd61f0200, Addr+16, 4); // br ip0 + + return Addr; + } else if (Arch == Triple::arm || Arch == Triple::armeb) { + // TODO: There is only ARM far stub now. We should add the Thumb stub, + // and stubs for branches Thumb - ARM and ARM - Thumb. + writeBytesUnaligned(0xe51ff004, Addr, 4); // ldr pc, [pc, #-4] + return Addr + 4; + } else if (IsMipsO32ABI || IsMipsN32ABI) { + // 0: 3c190000 lui t9,%hi(addr). + // 4: 27390000 addiu t9,t9,%lo(addr). + // 8: 03200008 jr t9. + // c: 00000000 nop. + const unsigned LuiT9Instr = 0x3c190000, AdduiT9Instr = 0x27390000; + const unsigned NopInstr = 0x0; + unsigned JrT9Instr = 0x03200008; + if ((AbiVariant & ELF::EF_MIPS_ARCH) == ELF::EF_MIPS_ARCH_32R6 || + (AbiVariant & ELF::EF_MIPS_ARCH) == ELF::EF_MIPS_ARCH_64R6) + JrT9Instr = 0x03200009; + + writeBytesUnaligned(LuiT9Instr, Addr, 4); + writeBytesUnaligned(AdduiT9Instr, Addr + 4, 4); + writeBytesUnaligned(JrT9Instr, Addr + 8, 4); + writeBytesUnaligned(NopInstr, Addr + 12, 4); + return Addr; + } else if (IsMipsN64ABI) { + // 0: 3c190000 lui t9,%highest(addr). + // 4: 67390000 daddiu t9,t9,%higher(addr). + // 8: 0019CC38 dsll t9,t9,16. + // c: 67390000 daddiu t9,t9,%hi(addr). + // 10: 0019CC38 dsll t9,t9,16. + // 14: 67390000 daddiu t9,t9,%lo(addr). + // 18: 03200008 jr t9. + // 1c: 00000000 nop. + const unsigned LuiT9Instr = 0x3c190000, DaddiuT9Instr = 0x67390000, + DsllT9Instr = 0x19CC38; + const unsigned NopInstr = 0x0; + unsigned JrT9Instr = 0x03200008; + if ((AbiVariant & ELF::EF_MIPS_ARCH) == ELF::EF_MIPS_ARCH_64R6) + JrT9Instr = 0x03200009; + + writeBytesUnaligned(LuiT9Instr, Addr, 4); + writeBytesUnaligned(DaddiuT9Instr, Addr + 4, 4); + writeBytesUnaligned(DsllT9Instr, Addr + 8, 4); + writeBytesUnaligned(DaddiuT9Instr, Addr + 12, 4); + writeBytesUnaligned(DsllT9Instr, Addr + 16, 4); + writeBytesUnaligned(DaddiuT9Instr, Addr + 20, 4); + writeBytesUnaligned(JrT9Instr, Addr + 24, 4); + writeBytesUnaligned(NopInstr, Addr + 28, 4); + return Addr; + } else if (Arch == Triple::ppc64 || Arch == Triple::ppc64le) { + // Depending on which version of the ELF ABI is in use, we need to + // generate one of two variants of the stub. They both start with + // the same sequence to load the target address into r12. + writeInt32BE(Addr, 0x3D800000); // lis r12, highest(addr) + writeInt32BE(Addr+4, 0x618C0000); // ori r12, higher(addr) + writeInt32BE(Addr+8, 0x798C07C6); // sldi r12, r12, 32 + writeInt32BE(Addr+12, 0x658C0000); // oris r12, r12, h(addr) + writeInt32BE(Addr+16, 0x618C0000); // ori r12, r12, l(addr) + if (AbiVariant == 2) { + // PowerPC64 stub ELFv2 ABI: The address points to the function itself. + // The address is already in r12 as required by the ABI. Branch to it. + writeInt32BE(Addr+20, 0xF8410018); // std r2, 24(r1) + writeInt32BE(Addr+24, 0x7D8903A6); // mtctr r12 + writeInt32BE(Addr+28, 0x4E800420); // bctr + } else { + // PowerPC64 stub ELFv1 ABI: The address points to a function descriptor. + // Load the function address on r11 and sets it to control register. Also + // loads the function TOC in r2 and environment pointer to r11. + writeInt32BE(Addr+20, 0xF8410028); // std r2, 40(r1) + writeInt32BE(Addr+24, 0xE96C0000); // ld r11, 0(r12) + writeInt32BE(Addr+28, 0xE84C0008); // ld r2, 0(r12) + writeInt32BE(Addr+32, 0x7D6903A6); // mtctr r11 + writeInt32BE(Addr+36, 0xE96C0010); // ld r11, 16(r2) + writeInt32BE(Addr+40, 0x4E800420); // bctr + } + return Addr; + } else if (Arch == Triple::systemz) { + writeInt16BE(Addr, 0xC418); // lgrl %r1,.+8 + writeInt16BE(Addr+2, 0x0000); + writeInt16BE(Addr+4, 0x0004); + writeInt16BE(Addr+6, 0x07F1); // brc 15,%r1 + // 8-byte address stored at Addr + 8 + return Addr; + } else if (Arch == Triple::x86_64) { + *Addr = 0xFF; // jmp + *(Addr+1) = 0x25; // rip + // 32-bit PC-relative address of the GOT entry will be stored at Addr+2 + } else if (Arch == Triple::x86) { + *Addr = 0xE9; // 32-bit pc-relative jump. + } + return Addr; +} + +// Assign an address to a symbol name and resolve all the relocations +// associated with it. +void RuntimeDyldImpl::reassignSectionAddress(unsigned SectionID, + uint64_t Addr) { + // The address to use for relocation resolution is not + // the address of the local section buffer. We must be doing + // a remote execution environment of some sort. Relocations can't + // be applied until all the sections have been moved. The client must + // trigger this with a call to MCJIT::finalize() or + // RuntimeDyld::resolveRelocations(). + // + // Addr is a uint64_t because we can't assume the pointer width + // of the target is the same as that of the host. Just use a generic + // "big enough" type. + LLVM_DEBUG( + dbgs() << "Reassigning address for section " << SectionID << " (" + << Sections[SectionID].getName() << "): " + << format("0x%016" PRIx64, Sections[SectionID].getLoadAddress()) + << " -> " << format("0x%016" PRIx64, Addr) << "\n"); + Sections[SectionID].setLoadAddress(Addr); +} + +void RuntimeDyldImpl::resolveRelocationList(const RelocationList &Relocs, + uint64_t Value) { + for (unsigned i = 0, e = Relocs.size(); i != e; ++i) { + const RelocationEntry &RE = Relocs[i]; + // Ignore relocations for sections that were not loaded + if (Sections[RE.SectionID].getAddress() == nullptr) + continue; + resolveRelocation(RE, Value); + } +} + +void RuntimeDyldImpl::applyExternalSymbolRelocations( + const StringMap<JITEvaluatedSymbol> ExternalSymbolMap) { + while (!ExternalSymbolRelocations.empty()) { + + StringMap<RelocationList>::iterator i = ExternalSymbolRelocations.begin(); + + StringRef Name = i->first(); + if (Name.size() == 0) { + // This is an absolute symbol, use an address of zero. + LLVM_DEBUG(dbgs() << "Resolving absolute relocations." + << "\n"); + RelocationList &Relocs = i->second; + resolveRelocationList(Relocs, 0); + } else { + uint64_t Addr = 0; + JITSymbolFlags Flags; + RTDyldSymbolTable::const_iterator Loc = GlobalSymbolTable.find(Name); + if (Loc == GlobalSymbolTable.end()) { + auto RRI = ExternalSymbolMap.find(Name); + assert(RRI != ExternalSymbolMap.end() && "No result for symbol"); + Addr = RRI->second.getAddress(); + Flags = RRI->second.getFlags(); + // The call to getSymbolAddress may have caused additional modules to + // be loaded, which may have added new entries to the + // ExternalSymbolRelocations map. Consquently, we need to update our + // iterator. This is also why retrieval of the relocation list + // associated with this symbol is deferred until below this point. + // New entries may have been added to the relocation list. + i = ExternalSymbolRelocations.find(Name); + } else { + // We found the symbol in our global table. It was probably in a + // Module that we loaded previously. + const auto &SymInfo = Loc->second; + Addr = getSectionLoadAddress(SymInfo.getSectionID()) + + SymInfo.getOffset(); + Flags = SymInfo.getFlags(); + } + + // FIXME: Implement error handling that doesn't kill the host program! + if (!Addr) + report_fatal_error("Program used external function '" + Name + + "' which could not be resolved!"); + + // If Resolver returned UINT64_MAX, the client wants to handle this symbol + // manually and we shouldn't resolve its relocations. + if (Addr != UINT64_MAX) { + + // Tweak the address based on the symbol flags if necessary. + // For example, this is used by RuntimeDyldMachOARM to toggle the low bit + // if the target symbol is Thumb. + Addr = modifyAddressBasedOnFlags(Addr, Flags); + + LLVM_DEBUG(dbgs() << "Resolving relocations Name: " << Name << "\t" + << format("0x%lx", Addr) << "\n"); + // This list may have been updated when we called getSymbolAddress, so + // don't change this code to get the list earlier. + RelocationList &Relocs = i->second; + resolveRelocationList(Relocs, Addr); + } + } + + ExternalSymbolRelocations.erase(i); + } +} + +Error RuntimeDyldImpl::resolveExternalSymbols() { + StringMap<JITEvaluatedSymbol> ExternalSymbolMap; + + // Resolution can trigger emission of more symbols, so iterate until + // we've resolved *everything*. + { + JITSymbolResolver::LookupSet ResolvedSymbols; + + while (true) { + JITSymbolResolver::LookupSet NewSymbols; + + for (auto &RelocKV : ExternalSymbolRelocations) { + StringRef Name = RelocKV.first(); + if (!Name.empty() && !GlobalSymbolTable.count(Name) && + !ResolvedSymbols.count(Name)) + NewSymbols.insert(Name); + } + + if (NewSymbols.empty()) + break; + +#ifdef _MSC_VER + using ExpectedLookupResult = + MSVCPExpected<JITSymbolResolver::LookupResult>; +#else + using ExpectedLookupResult = Expected<JITSymbolResolver::LookupResult>; +#endif + + auto NewSymbolsP = std::make_shared<std::promise<ExpectedLookupResult>>(); + auto NewSymbolsF = NewSymbolsP->get_future(); + Resolver.lookup(NewSymbols, + [=](Expected<JITSymbolResolver::LookupResult> Result) { + NewSymbolsP->set_value(std::move(Result)); + }); + + auto NewResolverResults = NewSymbolsF.get(); + + if (!NewResolverResults) + return NewResolverResults.takeError(); + + assert(NewResolverResults->size() == NewSymbols.size() && + "Should have errored on unresolved symbols"); + + for (auto &RRKV : *NewResolverResults) { + assert(!ResolvedSymbols.count(RRKV.first) && "Redundant resolution?"); + ExternalSymbolMap.insert(RRKV); + ResolvedSymbols.insert(RRKV.first); + } + } + } + + applyExternalSymbolRelocations(ExternalSymbolMap); + + return Error::success(); +} + +void RuntimeDyldImpl::finalizeAsync( + std::unique_ptr<RuntimeDyldImpl> This, unique_function<void(object::OwningBinary<object::ObjectFile>, std::unique_ptr<RuntimeDyld::LoadedObjectInfo>, Error)> - OnEmitted, + OnEmitted, object::OwningBinary<object::ObjectFile> O, std::unique_ptr<RuntimeDyld::LoadedObjectInfo> Info) { - - auto SharedThis = std::shared_ptr<RuntimeDyldImpl>(std::move(This)); - auto PostResolveContinuation = + + auto SharedThis = std::shared_ptr<RuntimeDyldImpl>(std::move(This)); + auto PostResolveContinuation = [SharedThis, OnEmitted = std::move(OnEmitted), O = std::move(O), Info = std::move(Info)]( - Expected<JITSymbolResolver::LookupResult> Result) mutable { - if (!Result) { + Expected<JITSymbolResolver::LookupResult> Result) mutable { + if (!Result) { OnEmitted(std::move(O), std::move(Info), Result.takeError()); - return; - } - - /// Copy the result into a StringMap, where the keys are held by value. - StringMap<JITEvaluatedSymbol> Resolved; - for (auto &KV : *Result) - Resolved[KV.first] = KV.second; - - SharedThis->applyExternalSymbolRelocations(Resolved); - SharedThis->resolveLocalRelocations(); - SharedThis->registerEHFrames(); - std::string ErrMsg; - if (SharedThis->MemMgr.finalizeMemory(&ErrMsg)) + return; + } + + /// Copy the result into a StringMap, where the keys are held by value. + StringMap<JITEvaluatedSymbol> Resolved; + for (auto &KV : *Result) + Resolved[KV.first] = KV.second; + + SharedThis->applyExternalSymbolRelocations(Resolved); + SharedThis->resolveLocalRelocations(); + SharedThis->registerEHFrames(); + std::string ErrMsg; + if (SharedThis->MemMgr.finalizeMemory(&ErrMsg)) OnEmitted(std::move(O), std::move(Info), - make_error<StringError>(std::move(ErrMsg), - inconvertibleErrorCode())); - else + make_error<StringError>(std::move(ErrMsg), + inconvertibleErrorCode())); + else OnEmitted(std::move(O), std::move(Info), Error::success()); - }; - - JITSymbolResolver::LookupSet Symbols; - - for (auto &RelocKV : SharedThis->ExternalSymbolRelocations) { - StringRef Name = RelocKV.first(); - if (Name.empty()) // Skip absolute symbol relocations. - continue; - assert(!SharedThis->GlobalSymbolTable.count(Name) && - "Name already processed. RuntimeDyld instances can not be re-used " - "when finalizing with finalizeAsync."); - Symbols.insert(Name); - } - - if (!Symbols.empty()) { - SharedThis->Resolver.lookup(Symbols, std::move(PostResolveContinuation)); - } else - PostResolveContinuation(std::map<StringRef, JITEvaluatedSymbol>()); -} - -//===----------------------------------------------------------------------===// -// RuntimeDyld class implementation - -uint64_t RuntimeDyld::LoadedObjectInfo::getSectionLoadAddress( - const object::SectionRef &Sec) const { - - auto I = ObjSecToIDMap.find(Sec); - if (I != ObjSecToIDMap.end()) - return RTDyld.Sections[I->second].getLoadAddress(); - - return 0; -} - -void RuntimeDyld::MemoryManager::anchor() {} -void JITSymbolResolver::anchor() {} -void LegacyJITSymbolResolver::anchor() {} - -RuntimeDyld::RuntimeDyld(RuntimeDyld::MemoryManager &MemMgr, - JITSymbolResolver &Resolver) - : MemMgr(MemMgr), Resolver(Resolver) { - // FIXME: There's a potential issue lurking here if a single instance of - // RuntimeDyld is used to load multiple objects. The current implementation - // associates a single memory manager with a RuntimeDyld instance. Even - // though the public class spawns a new 'impl' instance for each load, - // they share a single memory manager. This can become a problem when page - // permissions are applied. - Dyld = nullptr; - ProcessAllSections = false; -} - -RuntimeDyld::~RuntimeDyld() {} - -static std::unique_ptr<RuntimeDyldCOFF> -createRuntimeDyldCOFF( - Triple::ArchType Arch, RuntimeDyld::MemoryManager &MM, - JITSymbolResolver &Resolver, bool ProcessAllSections, - RuntimeDyld::NotifyStubEmittedFunction NotifyStubEmitted) { - std::unique_ptr<RuntimeDyldCOFF> Dyld = - RuntimeDyldCOFF::create(Arch, MM, Resolver); - Dyld->setProcessAllSections(ProcessAllSections); - Dyld->setNotifyStubEmitted(std::move(NotifyStubEmitted)); - return Dyld; -} - -static std::unique_ptr<RuntimeDyldELF> -createRuntimeDyldELF(Triple::ArchType Arch, RuntimeDyld::MemoryManager &MM, - JITSymbolResolver &Resolver, bool ProcessAllSections, - RuntimeDyld::NotifyStubEmittedFunction NotifyStubEmitted) { - std::unique_ptr<RuntimeDyldELF> Dyld = - RuntimeDyldELF::create(Arch, MM, Resolver); - Dyld->setProcessAllSections(ProcessAllSections); - Dyld->setNotifyStubEmitted(std::move(NotifyStubEmitted)); - return Dyld; -} - -static std::unique_ptr<RuntimeDyldMachO> -createRuntimeDyldMachO( - Triple::ArchType Arch, RuntimeDyld::MemoryManager &MM, - JITSymbolResolver &Resolver, - bool ProcessAllSections, - RuntimeDyld::NotifyStubEmittedFunction NotifyStubEmitted) { - std::unique_ptr<RuntimeDyldMachO> Dyld = - RuntimeDyldMachO::create(Arch, MM, Resolver); - Dyld->setProcessAllSections(ProcessAllSections); - Dyld->setNotifyStubEmitted(std::move(NotifyStubEmitted)); - return Dyld; -} - -std::unique_ptr<RuntimeDyld::LoadedObjectInfo> -RuntimeDyld::loadObject(const ObjectFile &Obj) { - if (!Dyld) { - if (Obj.isELF()) - Dyld = - createRuntimeDyldELF(static_cast<Triple::ArchType>(Obj.getArch()), - MemMgr, Resolver, ProcessAllSections, - std::move(NotifyStubEmitted)); - else if (Obj.isMachO()) - Dyld = createRuntimeDyldMachO( - static_cast<Triple::ArchType>(Obj.getArch()), MemMgr, Resolver, - ProcessAllSections, std::move(NotifyStubEmitted)); - else if (Obj.isCOFF()) - Dyld = createRuntimeDyldCOFF( - static_cast<Triple::ArchType>(Obj.getArch()), MemMgr, Resolver, - ProcessAllSections, std::move(NotifyStubEmitted)); - else - report_fatal_error("Incompatible object format!"); - } - - if (!Dyld->isCompatibleFile(Obj)) - report_fatal_error("Incompatible object format!"); - - auto LoadedObjInfo = Dyld->loadObject(Obj); - MemMgr.notifyObjectLoaded(*this, Obj); - return LoadedObjInfo; -} - -void *RuntimeDyld::getSymbolLocalAddress(StringRef Name) const { - if (!Dyld) - return nullptr; - return Dyld->getSymbolLocalAddress(Name); -} - -unsigned RuntimeDyld::getSymbolSectionID(StringRef Name) const { - assert(Dyld && "No RuntimeDyld instance attached"); - return Dyld->getSymbolSectionID(Name); -} - -JITEvaluatedSymbol RuntimeDyld::getSymbol(StringRef Name) const { - if (!Dyld) - return nullptr; - return Dyld->getSymbol(Name); -} - -std::map<StringRef, JITEvaluatedSymbol> RuntimeDyld::getSymbolTable() const { - if (!Dyld) - return std::map<StringRef, JITEvaluatedSymbol>(); - return Dyld->getSymbolTable(); -} - -void RuntimeDyld::resolveRelocations() { Dyld->resolveRelocations(); } - -void RuntimeDyld::reassignSectionAddress(unsigned SectionID, uint64_t Addr) { - Dyld->reassignSectionAddress(SectionID, Addr); -} - -void RuntimeDyld::mapSectionAddress(const void *LocalAddress, - uint64_t TargetAddress) { - Dyld->mapSectionAddress(LocalAddress, TargetAddress); -} - -bool RuntimeDyld::hasError() { return Dyld->hasError(); } - -StringRef RuntimeDyld::getErrorString() { return Dyld->getErrorString(); } - -void RuntimeDyld::finalizeWithMemoryManagerLocking() { - bool MemoryFinalizationLocked = MemMgr.FinalizationLocked; - MemMgr.FinalizationLocked = true; - resolveRelocations(); - registerEHFrames(); - if (!MemoryFinalizationLocked) { - MemMgr.finalizeMemory(); - MemMgr.FinalizationLocked = false; - } -} - -StringRef RuntimeDyld::getSectionContent(unsigned SectionID) const { - assert(Dyld && "No Dyld instance attached"); - return Dyld->getSectionContent(SectionID); -} - -uint64_t RuntimeDyld::getSectionLoadAddress(unsigned SectionID) const { - assert(Dyld && "No Dyld instance attached"); - return Dyld->getSectionLoadAddress(SectionID); -} - -void RuntimeDyld::registerEHFrames() { - if (Dyld) - Dyld->registerEHFrames(); -} - -void RuntimeDyld::deregisterEHFrames() { - if (Dyld) - Dyld->deregisterEHFrames(); -} -// FIXME: Kill this with fire once we have a new JIT linker: this is only here -// so that we can re-use RuntimeDyld's implementation without twisting the -// interface any further for ORC's purposes. -void jitLinkForORC( - object::OwningBinary<object::ObjectFile> O, - RuntimeDyld::MemoryManager &MemMgr, JITSymbolResolver &Resolver, - bool ProcessAllSections, + }; + + JITSymbolResolver::LookupSet Symbols; + + for (auto &RelocKV : SharedThis->ExternalSymbolRelocations) { + StringRef Name = RelocKV.first(); + if (Name.empty()) // Skip absolute symbol relocations. + continue; + assert(!SharedThis->GlobalSymbolTable.count(Name) && + "Name already processed. RuntimeDyld instances can not be re-used " + "when finalizing with finalizeAsync."); + Symbols.insert(Name); + } + + if (!Symbols.empty()) { + SharedThis->Resolver.lookup(Symbols, std::move(PostResolveContinuation)); + } else + PostResolveContinuation(std::map<StringRef, JITEvaluatedSymbol>()); +} + +//===----------------------------------------------------------------------===// +// RuntimeDyld class implementation + +uint64_t RuntimeDyld::LoadedObjectInfo::getSectionLoadAddress( + const object::SectionRef &Sec) const { + + auto I = ObjSecToIDMap.find(Sec); + if (I != ObjSecToIDMap.end()) + return RTDyld.Sections[I->second].getLoadAddress(); + + return 0; +} + +void RuntimeDyld::MemoryManager::anchor() {} +void JITSymbolResolver::anchor() {} +void LegacyJITSymbolResolver::anchor() {} + +RuntimeDyld::RuntimeDyld(RuntimeDyld::MemoryManager &MemMgr, + JITSymbolResolver &Resolver) + : MemMgr(MemMgr), Resolver(Resolver) { + // FIXME: There's a potential issue lurking here if a single instance of + // RuntimeDyld is used to load multiple objects. The current implementation + // associates a single memory manager with a RuntimeDyld instance. Even + // though the public class spawns a new 'impl' instance for each load, + // they share a single memory manager. This can become a problem when page + // permissions are applied. + Dyld = nullptr; + ProcessAllSections = false; +} + +RuntimeDyld::~RuntimeDyld() {} + +static std::unique_ptr<RuntimeDyldCOFF> +createRuntimeDyldCOFF( + Triple::ArchType Arch, RuntimeDyld::MemoryManager &MM, + JITSymbolResolver &Resolver, bool ProcessAllSections, + RuntimeDyld::NotifyStubEmittedFunction NotifyStubEmitted) { + std::unique_ptr<RuntimeDyldCOFF> Dyld = + RuntimeDyldCOFF::create(Arch, MM, Resolver); + Dyld->setProcessAllSections(ProcessAllSections); + Dyld->setNotifyStubEmitted(std::move(NotifyStubEmitted)); + return Dyld; +} + +static std::unique_ptr<RuntimeDyldELF> +createRuntimeDyldELF(Triple::ArchType Arch, RuntimeDyld::MemoryManager &MM, + JITSymbolResolver &Resolver, bool ProcessAllSections, + RuntimeDyld::NotifyStubEmittedFunction NotifyStubEmitted) { + std::unique_ptr<RuntimeDyldELF> Dyld = + RuntimeDyldELF::create(Arch, MM, Resolver); + Dyld->setProcessAllSections(ProcessAllSections); + Dyld->setNotifyStubEmitted(std::move(NotifyStubEmitted)); + return Dyld; +} + +static std::unique_ptr<RuntimeDyldMachO> +createRuntimeDyldMachO( + Triple::ArchType Arch, RuntimeDyld::MemoryManager &MM, + JITSymbolResolver &Resolver, + bool ProcessAllSections, + RuntimeDyld::NotifyStubEmittedFunction NotifyStubEmitted) { + std::unique_ptr<RuntimeDyldMachO> Dyld = + RuntimeDyldMachO::create(Arch, MM, Resolver); + Dyld->setProcessAllSections(ProcessAllSections); + Dyld->setNotifyStubEmitted(std::move(NotifyStubEmitted)); + return Dyld; +} + +std::unique_ptr<RuntimeDyld::LoadedObjectInfo> +RuntimeDyld::loadObject(const ObjectFile &Obj) { + if (!Dyld) { + if (Obj.isELF()) + Dyld = + createRuntimeDyldELF(static_cast<Triple::ArchType>(Obj.getArch()), + MemMgr, Resolver, ProcessAllSections, + std::move(NotifyStubEmitted)); + else if (Obj.isMachO()) + Dyld = createRuntimeDyldMachO( + static_cast<Triple::ArchType>(Obj.getArch()), MemMgr, Resolver, + ProcessAllSections, std::move(NotifyStubEmitted)); + else if (Obj.isCOFF()) + Dyld = createRuntimeDyldCOFF( + static_cast<Triple::ArchType>(Obj.getArch()), MemMgr, Resolver, + ProcessAllSections, std::move(NotifyStubEmitted)); + else + report_fatal_error("Incompatible object format!"); + } + + if (!Dyld->isCompatibleFile(Obj)) + report_fatal_error("Incompatible object format!"); + + auto LoadedObjInfo = Dyld->loadObject(Obj); + MemMgr.notifyObjectLoaded(*this, Obj); + return LoadedObjInfo; +} + +void *RuntimeDyld::getSymbolLocalAddress(StringRef Name) const { + if (!Dyld) + return nullptr; + return Dyld->getSymbolLocalAddress(Name); +} + +unsigned RuntimeDyld::getSymbolSectionID(StringRef Name) const { + assert(Dyld && "No RuntimeDyld instance attached"); + return Dyld->getSymbolSectionID(Name); +} + +JITEvaluatedSymbol RuntimeDyld::getSymbol(StringRef Name) const { + if (!Dyld) + return nullptr; + return Dyld->getSymbol(Name); +} + +std::map<StringRef, JITEvaluatedSymbol> RuntimeDyld::getSymbolTable() const { + if (!Dyld) + return std::map<StringRef, JITEvaluatedSymbol>(); + return Dyld->getSymbolTable(); +} + +void RuntimeDyld::resolveRelocations() { Dyld->resolveRelocations(); } + +void RuntimeDyld::reassignSectionAddress(unsigned SectionID, uint64_t Addr) { + Dyld->reassignSectionAddress(SectionID, Addr); +} + +void RuntimeDyld::mapSectionAddress(const void *LocalAddress, + uint64_t TargetAddress) { + Dyld->mapSectionAddress(LocalAddress, TargetAddress); +} + +bool RuntimeDyld::hasError() { return Dyld->hasError(); } + +StringRef RuntimeDyld::getErrorString() { return Dyld->getErrorString(); } + +void RuntimeDyld::finalizeWithMemoryManagerLocking() { + bool MemoryFinalizationLocked = MemMgr.FinalizationLocked; + MemMgr.FinalizationLocked = true; + resolveRelocations(); + registerEHFrames(); + if (!MemoryFinalizationLocked) { + MemMgr.finalizeMemory(); + MemMgr.FinalizationLocked = false; + } +} + +StringRef RuntimeDyld::getSectionContent(unsigned SectionID) const { + assert(Dyld && "No Dyld instance attached"); + return Dyld->getSectionContent(SectionID); +} + +uint64_t RuntimeDyld::getSectionLoadAddress(unsigned SectionID) const { + assert(Dyld && "No Dyld instance attached"); + return Dyld->getSectionLoadAddress(SectionID); +} + +void RuntimeDyld::registerEHFrames() { + if (Dyld) + Dyld->registerEHFrames(); +} + +void RuntimeDyld::deregisterEHFrames() { + if (Dyld) + Dyld->deregisterEHFrames(); +} +// FIXME: Kill this with fire once we have a new JIT linker: this is only here +// so that we can re-use RuntimeDyld's implementation without twisting the +// interface any further for ORC's purposes. +void jitLinkForORC( + object::OwningBinary<object::ObjectFile> O, + RuntimeDyld::MemoryManager &MemMgr, JITSymbolResolver &Resolver, + bool ProcessAllSections, unique_function<Error(const object::ObjectFile &Obj, RuntimeDyld::LoadedObjectInfo &LoadedObj, std::map<StringRef, JITEvaluatedSymbol>)> - OnLoaded, + OnLoaded, unique_function<void(object::OwningBinary<object::ObjectFile>, std::unique_ptr<RuntimeDyld::LoadedObjectInfo>, Error)> - OnEmitted) { - - RuntimeDyld RTDyld(MemMgr, Resolver); - RTDyld.setProcessAllSections(ProcessAllSections); - - auto Info = RTDyld.loadObject(*O.getBinary()); - - if (RTDyld.hasError()) { + OnEmitted) { + + RuntimeDyld RTDyld(MemMgr, Resolver); + RTDyld.setProcessAllSections(ProcessAllSections); + + auto Info = RTDyld.loadObject(*O.getBinary()); + + if (RTDyld.hasError()) { OnEmitted(std::move(O), std::move(Info), make_error<StringError>(RTDyld.getErrorString(), inconvertibleErrorCode())); - return; - } - + return; + } + if (auto Err = OnLoaded(*O.getBinary(), *Info, RTDyld.getSymbolTable())) OnEmitted(std::move(O), std::move(Info), std::move(Err)); - - RuntimeDyldImpl::finalizeAsync(std::move(RTDyld.Dyld), std::move(OnEmitted), + + RuntimeDyldImpl::finalizeAsync(std::move(RTDyld.Dyld), std::move(OnEmitted), std::move(O), std::move(Info)); -} - -} // end namespace llvm +} + +} // end namespace llvm diff --git a/contrib/libs/llvm12/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldCOFF.cpp b/contrib/libs/llvm12/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldCOFF.cpp index 26831f4285..1d8f1ac8ac 100644 --- a/contrib/libs/llvm12/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldCOFF.cpp +++ b/contrib/libs/llvm12/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldCOFF.cpp @@ -1,121 +1,121 @@ -//===-- RuntimeDyldCOFF.cpp - Run-time dynamic linker for MC-JIT -*- C++ -*-==// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// Implementation of COFF support for the MC-JIT runtime dynamic linker. -// -//===----------------------------------------------------------------------===// - -#include "RuntimeDyldCOFF.h" -#include "Targets/RuntimeDyldCOFFAArch64.h" -#include "Targets/RuntimeDyldCOFFI386.h" -#include "Targets/RuntimeDyldCOFFThumb.h" -#include "Targets/RuntimeDyldCOFFX86_64.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/Triple.h" -#include "llvm/Object/ObjectFile.h" -#include "llvm/Support/FormatVariadic.h" - -using namespace llvm; -using namespace llvm::object; - -#define DEBUG_TYPE "dyld" - -namespace { - -class LoadedCOFFObjectInfo final - : public LoadedObjectInfoHelper<LoadedCOFFObjectInfo, - RuntimeDyld::LoadedObjectInfo> { -public: - LoadedCOFFObjectInfo( - RuntimeDyldImpl &RTDyld, - RuntimeDyld::LoadedObjectInfo::ObjSectionToIDMap ObjSecToIDMap) - : LoadedObjectInfoHelper(RTDyld, std::move(ObjSecToIDMap)) {} - - OwningBinary<ObjectFile> - getObjectForDebug(const ObjectFile &Obj) const override { - return OwningBinary<ObjectFile>(); - } -}; -} - -namespace llvm { - -std::unique_ptr<RuntimeDyldCOFF> -llvm::RuntimeDyldCOFF::create(Triple::ArchType Arch, - RuntimeDyld::MemoryManager &MemMgr, - JITSymbolResolver &Resolver) { - switch (Arch) { - default: llvm_unreachable("Unsupported target for RuntimeDyldCOFF."); - case Triple::x86: - return std::make_unique<RuntimeDyldCOFFI386>(MemMgr, Resolver); - case Triple::thumb: - return std::make_unique<RuntimeDyldCOFFThumb>(MemMgr, Resolver); - case Triple::x86_64: - return std::make_unique<RuntimeDyldCOFFX86_64>(MemMgr, Resolver); - case Triple::aarch64: - return std::make_unique<RuntimeDyldCOFFAArch64>(MemMgr, Resolver); - } -} - -std::unique_ptr<RuntimeDyld::LoadedObjectInfo> -RuntimeDyldCOFF::loadObject(const object::ObjectFile &O) { - if (auto ObjSectionToIDOrErr = loadObjectImpl(O)) { - return std::make_unique<LoadedCOFFObjectInfo>(*this, *ObjSectionToIDOrErr); - } else { - HasError = true; - raw_string_ostream ErrStream(ErrorStr); - logAllUnhandledErrors(ObjSectionToIDOrErr.takeError(), ErrStream); - return nullptr; - } -} - -uint64_t RuntimeDyldCOFF::getSymbolOffset(const SymbolRef &Sym) { - // The value in a relocatable COFF object is the offset. - return cantFail(Sym.getValue()); -} - -uint64_t RuntimeDyldCOFF::getDLLImportOffset(unsigned SectionID, StubMap &Stubs, - StringRef Name, - bool SetSectionIDMinus1) { - LLVM_DEBUG(dbgs() << "Getting DLLImport entry for " << Name << "... "); - assert(Name.startswith(getImportSymbolPrefix()) && "Not a DLLImport symbol?"); - RelocationValueRef Reloc; - Reloc.SymbolName = Name.data(); - auto I = Stubs.find(Reloc); - if (I != Stubs.end()) { - LLVM_DEBUG(dbgs() << format("{0:x8}", I->second) << "\n"); - return I->second; - } - - assert(SectionID < Sections.size() && "SectionID out of range"); - auto &Sec = Sections[SectionID]; - auto EntryOffset = alignTo(Sec.getStubOffset(), PointerSize); - Sec.advanceStubOffset(EntryOffset + PointerSize - Sec.getStubOffset()); - Stubs[Reloc] = EntryOffset; - - RelocationEntry RE(SectionID, EntryOffset, PointerReloc, 0, false, - Log2_64(PointerSize)); - // Hack to tell I386/Thumb resolveRelocation that this isn't section relative. - if (SetSectionIDMinus1) - RE.Sections.SectionA = -1; - addRelocationForSymbol(RE, Name.drop_front(getImportSymbolPrefix().size())); - - LLVM_DEBUG({ - dbgs() << "Creating entry at " - << formatv("{0:x16} + {1:x8} ( {2:x16} )", Sec.getLoadAddress(), - EntryOffset, Sec.getLoadAddress() + EntryOffset) - << "\n"; - }); - return EntryOffset; -} - -bool RuntimeDyldCOFF::isCompatibleFile(const object::ObjectFile &Obj) const { - return Obj.isCOFF(); -} - -} // namespace llvm +//===-- RuntimeDyldCOFF.cpp - Run-time dynamic linker for MC-JIT -*- C++ -*-==// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Implementation of COFF support for the MC-JIT runtime dynamic linker. +// +//===----------------------------------------------------------------------===// + +#include "RuntimeDyldCOFF.h" +#include "Targets/RuntimeDyldCOFFAArch64.h" +#include "Targets/RuntimeDyldCOFFI386.h" +#include "Targets/RuntimeDyldCOFFThumb.h" +#include "Targets/RuntimeDyldCOFFX86_64.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Object/ObjectFile.h" +#include "llvm/Support/FormatVariadic.h" + +using namespace llvm; +using namespace llvm::object; + +#define DEBUG_TYPE "dyld" + +namespace { + +class LoadedCOFFObjectInfo final + : public LoadedObjectInfoHelper<LoadedCOFFObjectInfo, + RuntimeDyld::LoadedObjectInfo> { +public: + LoadedCOFFObjectInfo( + RuntimeDyldImpl &RTDyld, + RuntimeDyld::LoadedObjectInfo::ObjSectionToIDMap ObjSecToIDMap) + : LoadedObjectInfoHelper(RTDyld, std::move(ObjSecToIDMap)) {} + + OwningBinary<ObjectFile> + getObjectForDebug(const ObjectFile &Obj) const override { + return OwningBinary<ObjectFile>(); + } +}; +} + +namespace llvm { + +std::unique_ptr<RuntimeDyldCOFF> +llvm::RuntimeDyldCOFF::create(Triple::ArchType Arch, + RuntimeDyld::MemoryManager &MemMgr, + JITSymbolResolver &Resolver) { + switch (Arch) { + default: llvm_unreachable("Unsupported target for RuntimeDyldCOFF."); + case Triple::x86: + return std::make_unique<RuntimeDyldCOFFI386>(MemMgr, Resolver); + case Triple::thumb: + return std::make_unique<RuntimeDyldCOFFThumb>(MemMgr, Resolver); + case Triple::x86_64: + return std::make_unique<RuntimeDyldCOFFX86_64>(MemMgr, Resolver); + case Triple::aarch64: + return std::make_unique<RuntimeDyldCOFFAArch64>(MemMgr, Resolver); + } +} + +std::unique_ptr<RuntimeDyld::LoadedObjectInfo> +RuntimeDyldCOFF::loadObject(const object::ObjectFile &O) { + if (auto ObjSectionToIDOrErr = loadObjectImpl(O)) { + return std::make_unique<LoadedCOFFObjectInfo>(*this, *ObjSectionToIDOrErr); + } else { + HasError = true; + raw_string_ostream ErrStream(ErrorStr); + logAllUnhandledErrors(ObjSectionToIDOrErr.takeError(), ErrStream); + return nullptr; + } +} + +uint64_t RuntimeDyldCOFF::getSymbolOffset(const SymbolRef &Sym) { + // The value in a relocatable COFF object is the offset. + return cantFail(Sym.getValue()); +} + +uint64_t RuntimeDyldCOFF::getDLLImportOffset(unsigned SectionID, StubMap &Stubs, + StringRef Name, + bool SetSectionIDMinus1) { + LLVM_DEBUG(dbgs() << "Getting DLLImport entry for " << Name << "... "); + assert(Name.startswith(getImportSymbolPrefix()) && "Not a DLLImport symbol?"); + RelocationValueRef Reloc; + Reloc.SymbolName = Name.data(); + auto I = Stubs.find(Reloc); + if (I != Stubs.end()) { + LLVM_DEBUG(dbgs() << format("{0:x8}", I->second) << "\n"); + return I->second; + } + + assert(SectionID < Sections.size() && "SectionID out of range"); + auto &Sec = Sections[SectionID]; + auto EntryOffset = alignTo(Sec.getStubOffset(), PointerSize); + Sec.advanceStubOffset(EntryOffset + PointerSize - Sec.getStubOffset()); + Stubs[Reloc] = EntryOffset; + + RelocationEntry RE(SectionID, EntryOffset, PointerReloc, 0, false, + Log2_64(PointerSize)); + // Hack to tell I386/Thumb resolveRelocation that this isn't section relative. + if (SetSectionIDMinus1) + RE.Sections.SectionA = -1; + addRelocationForSymbol(RE, Name.drop_front(getImportSymbolPrefix().size())); + + LLVM_DEBUG({ + dbgs() << "Creating entry at " + << formatv("{0:x16} + {1:x8} ( {2:x16} )", Sec.getLoadAddress(), + EntryOffset, Sec.getLoadAddress() + EntryOffset) + << "\n"; + }); + return EntryOffset; +} + +bool RuntimeDyldCOFF::isCompatibleFile(const object::ObjectFile &Obj) const { + return Obj.isCOFF(); +} + +} // namespace llvm diff --git a/contrib/libs/llvm12/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldCOFF.h b/contrib/libs/llvm12/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldCOFF.h index f9d895e36d..41ee06c154 100644 --- a/contrib/libs/llvm12/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldCOFF.h +++ b/contrib/libs/llvm12/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldCOFF.h @@ -1,61 +1,61 @@ -//===-- RuntimeDyldCOFF.h - Run-time dynamic linker for MC-JIT ---*- C++ -*-==// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// COFF support for MC-JIT runtime dynamic linker. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_RUNTIME_DYLD_COFF_H -#define LLVM_RUNTIME_DYLD_COFF_H - -#include "RuntimeDyldImpl.h" - -#define DEBUG_TYPE "dyld" - -using namespace llvm; - -namespace llvm { - -// Common base class for COFF dynamic linker support. -// Concrete subclasses for each target can be found in ./Targets. -class RuntimeDyldCOFF : public RuntimeDyldImpl { - -public: - std::unique_ptr<RuntimeDyld::LoadedObjectInfo> - loadObject(const object::ObjectFile &Obj) override; - bool isCompatibleFile(const object::ObjectFile &Obj) const override; - - static std::unique_ptr<RuntimeDyldCOFF> - create(Triple::ArchType Arch, RuntimeDyld::MemoryManager &MemMgr, - JITSymbolResolver &Resolver); - -protected: - RuntimeDyldCOFF(RuntimeDyld::MemoryManager &MemMgr, - JITSymbolResolver &Resolver, unsigned PointerSize, - uint32_t PointerReloc) - : RuntimeDyldImpl(MemMgr, Resolver), PointerSize(PointerSize), - PointerReloc(PointerReloc) { - assert((PointerSize == 4 || PointerSize == 8) && "Unexpected pointer size"); - } - - uint64_t getSymbolOffset(const SymbolRef &Sym); - uint64_t getDLLImportOffset(unsigned SectionID, StubMap &Stubs, - StringRef Name, bool SetSectionIDMinus1 = false); - - static constexpr StringRef getImportSymbolPrefix() { return "__imp_"; } - -private: - unsigned PointerSize; - uint32_t PointerReloc; -}; - -} // end namespace llvm - -#undef DEBUG_TYPE - -#endif +//===-- RuntimeDyldCOFF.h - Run-time dynamic linker for MC-JIT ---*- C++ -*-==// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// COFF support for MC-JIT runtime dynamic linker. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_RUNTIME_DYLD_COFF_H +#define LLVM_RUNTIME_DYLD_COFF_H + +#include "RuntimeDyldImpl.h" + +#define DEBUG_TYPE "dyld" + +using namespace llvm; + +namespace llvm { + +// Common base class for COFF dynamic linker support. +// Concrete subclasses for each target can be found in ./Targets. +class RuntimeDyldCOFF : public RuntimeDyldImpl { + +public: + std::unique_ptr<RuntimeDyld::LoadedObjectInfo> + loadObject(const object::ObjectFile &Obj) override; + bool isCompatibleFile(const object::ObjectFile &Obj) const override; + + static std::unique_ptr<RuntimeDyldCOFF> + create(Triple::ArchType Arch, RuntimeDyld::MemoryManager &MemMgr, + JITSymbolResolver &Resolver); + +protected: + RuntimeDyldCOFF(RuntimeDyld::MemoryManager &MemMgr, + JITSymbolResolver &Resolver, unsigned PointerSize, + uint32_t PointerReloc) + : RuntimeDyldImpl(MemMgr, Resolver), PointerSize(PointerSize), + PointerReloc(PointerReloc) { + assert((PointerSize == 4 || PointerSize == 8) && "Unexpected pointer size"); + } + + uint64_t getSymbolOffset(const SymbolRef &Sym); + uint64_t getDLLImportOffset(unsigned SectionID, StubMap &Stubs, + StringRef Name, bool SetSectionIDMinus1 = false); + + static constexpr StringRef getImportSymbolPrefix() { return "__imp_"; } + +private: + unsigned PointerSize; + uint32_t PointerReloc; +}; + +} // end namespace llvm + +#undef DEBUG_TYPE + +#endif diff --git a/contrib/libs/llvm12/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldChecker.cpp b/contrib/libs/llvm12/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldChecker.cpp index f4558702a6..2fbe707ce8 100644 --- a/contrib/libs/llvm12/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldChecker.cpp +++ b/contrib/libs/llvm12/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldChecker.cpp @@ -1,886 +1,886 @@ -//===--- RuntimeDyldChecker.cpp - RuntimeDyld tester framework --*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/ExecutionEngine/RuntimeDyldChecker.h" -#include "RuntimeDyldCheckerImpl.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/StringExtras.h" -#include "llvm/MC/MCContext.h" -#include "llvm/MC/MCDisassembler/MCDisassembler.h" -#include "llvm/MC/MCInst.h" -#include "llvm/Support/Endian.h" -#include "llvm/Support/MSVCErrorWorkarounds.h" -#include "llvm/Support/Path.h" -#include <cctype> -#include <memory> -#include <utility> - -#define DEBUG_TYPE "rtdyld" - -using namespace llvm; - -namespace llvm { - -// Helper class that implements the language evaluated by RuntimeDyldChecker. -class RuntimeDyldCheckerExprEval { -public: - RuntimeDyldCheckerExprEval(const RuntimeDyldCheckerImpl &Checker, - raw_ostream &ErrStream) - : Checker(Checker) {} - - bool evaluate(StringRef Expr) const { - // Expect equality expression of the form 'LHS = RHS'. - Expr = Expr.trim(); - size_t EQIdx = Expr.find('='); - - ParseContext OutsideLoad(false); - - // Evaluate LHS. - StringRef LHSExpr = Expr.substr(0, EQIdx).rtrim(); - StringRef RemainingExpr; - EvalResult LHSResult; - std::tie(LHSResult, RemainingExpr) = - evalComplexExpr(evalSimpleExpr(LHSExpr, OutsideLoad), OutsideLoad); - if (LHSResult.hasError()) - return handleError(Expr, LHSResult); - if (RemainingExpr != "") - return handleError(Expr, unexpectedToken(RemainingExpr, LHSExpr, "")); - - // Evaluate RHS. - StringRef RHSExpr = Expr.substr(EQIdx + 1).ltrim(); - EvalResult RHSResult; - std::tie(RHSResult, RemainingExpr) = - evalComplexExpr(evalSimpleExpr(RHSExpr, OutsideLoad), OutsideLoad); - if (RHSResult.hasError()) - return handleError(Expr, RHSResult); - if (RemainingExpr != "") - return handleError(Expr, unexpectedToken(RemainingExpr, RHSExpr, "")); - - if (LHSResult.getValue() != RHSResult.getValue()) { - Checker.ErrStream << "Expression '" << Expr << "' is false: " - << format("0x%" PRIx64, LHSResult.getValue()) - << " != " << format("0x%" PRIx64, RHSResult.getValue()) - << "\n"; - return false; - } - return true; - } - -private: - // RuntimeDyldCheckerExprEval requires some context when parsing exprs. In - // particular, it needs to know whether a symbol is being evaluated in the - // context of a load, in which case we want the linker's local address for - // the symbol, or outside of a load, in which case we want the symbol's - // address in the remote target. - - struct ParseContext { - bool IsInsideLoad; - ParseContext(bool IsInsideLoad) : IsInsideLoad(IsInsideLoad) {} - }; - - const RuntimeDyldCheckerImpl &Checker; - - enum class BinOpToken : unsigned { - Invalid, - Add, - Sub, - BitwiseAnd, - BitwiseOr, - ShiftLeft, - ShiftRight - }; - - class EvalResult { - public: - EvalResult() : Value(0), ErrorMsg("") {} - EvalResult(uint64_t Value) : Value(Value), ErrorMsg("") {} - EvalResult(std::string ErrorMsg) - : Value(0), ErrorMsg(std::move(ErrorMsg)) {} - uint64_t getValue() const { return Value; } - bool hasError() const { return ErrorMsg != ""; } - const std::string &getErrorMsg() const { return ErrorMsg; } - - private: - uint64_t Value; - std::string ErrorMsg; - }; - - StringRef getTokenForError(StringRef Expr) const { - if (Expr.empty()) - return ""; - - StringRef Token, Remaining; - if (isalpha(Expr[0])) - std::tie(Token, Remaining) = parseSymbol(Expr); - else if (isdigit(Expr[0])) - std::tie(Token, Remaining) = parseNumberString(Expr); - else { - unsigned TokLen = 1; - if (Expr.startswith("<<") || Expr.startswith(">>")) - TokLen = 2; - Token = Expr.substr(0, TokLen); - } - return Token; - } - - EvalResult unexpectedToken(StringRef TokenStart, StringRef SubExpr, - StringRef ErrText) const { - std::string ErrorMsg("Encountered unexpected token '"); - ErrorMsg += getTokenForError(TokenStart); - if (SubExpr != "") { - ErrorMsg += "' while parsing subexpression '"; - ErrorMsg += SubExpr; - } - ErrorMsg += "'"; - if (ErrText != "") { - ErrorMsg += " "; - ErrorMsg += ErrText; - } - return EvalResult(std::move(ErrorMsg)); - } - - bool handleError(StringRef Expr, const EvalResult &R) const { - assert(R.hasError() && "Not an error result."); - Checker.ErrStream << "Error evaluating expression '" << Expr - << "': " << R.getErrorMsg() << "\n"; - return false; - } - - std::pair<BinOpToken, StringRef> parseBinOpToken(StringRef Expr) const { - if (Expr.empty()) - return std::make_pair(BinOpToken::Invalid, ""); - - // Handle the two 2-character tokens. - if (Expr.startswith("<<")) - return std::make_pair(BinOpToken::ShiftLeft, Expr.substr(2).ltrim()); - if (Expr.startswith(">>")) - return std::make_pair(BinOpToken::ShiftRight, Expr.substr(2).ltrim()); - - // Handle one-character tokens. - BinOpToken Op; - switch (Expr[0]) { - default: - return std::make_pair(BinOpToken::Invalid, Expr); - case '+': - Op = BinOpToken::Add; - break; - case '-': - Op = BinOpToken::Sub; - break; - case '&': - Op = BinOpToken::BitwiseAnd; - break; - case '|': - Op = BinOpToken::BitwiseOr; - break; - } - - return std::make_pair(Op, Expr.substr(1).ltrim()); - } - - EvalResult computeBinOpResult(BinOpToken Op, const EvalResult &LHSResult, - const EvalResult &RHSResult) const { - switch (Op) { - default: - llvm_unreachable("Tried to evaluate unrecognized operation."); - case BinOpToken::Add: - return EvalResult(LHSResult.getValue() + RHSResult.getValue()); - case BinOpToken::Sub: - return EvalResult(LHSResult.getValue() - RHSResult.getValue()); - case BinOpToken::BitwiseAnd: - return EvalResult(LHSResult.getValue() & RHSResult.getValue()); - case BinOpToken::BitwiseOr: - return EvalResult(LHSResult.getValue() | RHSResult.getValue()); - case BinOpToken::ShiftLeft: - return EvalResult(LHSResult.getValue() << RHSResult.getValue()); - case BinOpToken::ShiftRight: - return EvalResult(LHSResult.getValue() >> RHSResult.getValue()); - } - } - - // Parse a symbol and return a (string, string) pair representing the symbol - // name and expression remaining to be parsed. - std::pair<StringRef, StringRef> parseSymbol(StringRef Expr) const { - size_t FirstNonSymbol = Expr.find_first_not_of("0123456789" - "abcdefghijklmnopqrstuvwxyz" - "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - ":_.$"); - return std::make_pair(Expr.substr(0, FirstNonSymbol), - Expr.substr(FirstNonSymbol).ltrim()); - } - - // Evaluate a call to decode_operand. Decode the instruction operand at the - // given symbol and get the value of the requested operand. - // Returns an error if the instruction cannot be decoded, or the requested - // operand is not an immediate. - // On success, returns a pair containing the value of the operand, plus - // the expression remaining to be evaluated. - std::pair<EvalResult, StringRef> evalDecodeOperand(StringRef Expr) const { - if (!Expr.startswith("(")) - return std::make_pair(unexpectedToken(Expr, Expr, "expected '('"), ""); - StringRef RemainingExpr = Expr.substr(1).ltrim(); - StringRef Symbol; - std::tie(Symbol, RemainingExpr) = parseSymbol(RemainingExpr); - - if (!Checker.isSymbolValid(Symbol)) - return std::make_pair( - EvalResult(("Cannot decode unknown symbol '" + Symbol + "'").str()), - ""); - - if (!RemainingExpr.startswith(",")) - return std::make_pair( - unexpectedToken(RemainingExpr, RemainingExpr, "expected ','"), ""); - RemainingExpr = RemainingExpr.substr(1).ltrim(); - - EvalResult OpIdxExpr; - std::tie(OpIdxExpr, RemainingExpr) = evalNumberExpr(RemainingExpr); - if (OpIdxExpr.hasError()) - return std::make_pair(OpIdxExpr, ""); - - if (!RemainingExpr.startswith(")")) - return std::make_pair( - unexpectedToken(RemainingExpr, RemainingExpr, "expected ')'"), ""); - RemainingExpr = RemainingExpr.substr(1).ltrim(); - - MCInst Inst; - uint64_t Size; - if (!decodeInst(Symbol, Inst, Size)) - return std::make_pair( - EvalResult(("Couldn't decode instruction at '" + Symbol + "'").str()), - ""); - - unsigned OpIdx = OpIdxExpr.getValue(); - if (OpIdx >= Inst.getNumOperands()) { - std::string ErrMsg; - raw_string_ostream ErrMsgStream(ErrMsg); - ErrMsgStream << "Invalid operand index '" << format("%i", OpIdx) - << "' for instruction '" << Symbol - << "'. Instruction has only " - << format("%i", Inst.getNumOperands()) - << " operands.\nInstruction is:\n "; - Inst.dump_pretty(ErrMsgStream, Checker.InstPrinter); - return std::make_pair(EvalResult(ErrMsgStream.str()), ""); - } - - const MCOperand &Op = Inst.getOperand(OpIdx); - if (!Op.isImm()) { - std::string ErrMsg; - raw_string_ostream ErrMsgStream(ErrMsg); - ErrMsgStream << "Operand '" << format("%i", OpIdx) << "' of instruction '" - << Symbol << "' is not an immediate.\nInstruction is:\n "; - Inst.dump_pretty(ErrMsgStream, Checker.InstPrinter); - - return std::make_pair(EvalResult(ErrMsgStream.str()), ""); - } - - return std::make_pair(EvalResult(Op.getImm()), RemainingExpr); - } - - // Evaluate a call to next_pc. - // Decode the instruction at the given symbol and return the following program - // counter. - // Returns an error if the instruction cannot be decoded. - // On success, returns a pair containing the next PC, plus of the - // expression remaining to be evaluated. - std::pair<EvalResult, StringRef> evalNextPC(StringRef Expr, - ParseContext PCtx) const { - if (!Expr.startswith("(")) - return std::make_pair(unexpectedToken(Expr, Expr, "expected '('"), ""); - StringRef RemainingExpr = Expr.substr(1).ltrim(); - StringRef Symbol; - std::tie(Symbol, RemainingExpr) = parseSymbol(RemainingExpr); - - if (!Checker.isSymbolValid(Symbol)) - return std::make_pair( - EvalResult(("Cannot decode unknown symbol '" + Symbol + "'").str()), - ""); - - if (!RemainingExpr.startswith(")")) - return std::make_pair( - unexpectedToken(RemainingExpr, RemainingExpr, "expected ')'"), ""); - RemainingExpr = RemainingExpr.substr(1).ltrim(); - - MCInst Inst; - uint64_t InstSize; - if (!decodeInst(Symbol, Inst, InstSize)) - return std::make_pair( - EvalResult(("Couldn't decode instruction at '" + Symbol + "'").str()), - ""); - - uint64_t SymbolAddr = PCtx.IsInsideLoad - ? Checker.getSymbolLocalAddr(Symbol) - : Checker.getSymbolRemoteAddr(Symbol); - uint64_t NextPC = SymbolAddr + InstSize; - - return std::make_pair(EvalResult(NextPC), RemainingExpr); - } - - // Evaluate a call to stub_addr/got_addr. - // Look up and return the address of the stub for the given - // (<file name>, <section name>, <symbol name>) tuple. - // On success, returns a pair containing the stub address, plus the expression - // remaining to be evaluated. - std::pair<EvalResult, StringRef> - evalStubOrGOTAddr(StringRef Expr, ParseContext PCtx, bool IsStubAddr) const { - if (!Expr.startswith("(")) - return std::make_pair(unexpectedToken(Expr, Expr, "expected '('"), ""); - StringRef RemainingExpr = Expr.substr(1).ltrim(); - - // Handle file-name specially, as it may contain characters that aren't - // legal for symbols. - StringRef StubContainerName; - size_t ComaIdx = RemainingExpr.find(','); - StubContainerName = RemainingExpr.substr(0, ComaIdx).rtrim(); - RemainingExpr = RemainingExpr.substr(ComaIdx).ltrim(); - - if (!RemainingExpr.startswith(",")) - return std::make_pair( - unexpectedToken(RemainingExpr, Expr, "expected ','"), ""); - RemainingExpr = RemainingExpr.substr(1).ltrim(); - - StringRef Symbol; - std::tie(Symbol, RemainingExpr) = parseSymbol(RemainingExpr); - - if (!RemainingExpr.startswith(")")) - return std::make_pair( - unexpectedToken(RemainingExpr, Expr, "expected ')'"), ""); - RemainingExpr = RemainingExpr.substr(1).ltrim(); - - uint64_t StubAddr; +//===--- RuntimeDyldChecker.cpp - RuntimeDyld tester framework --*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/ExecutionEngine/RuntimeDyldChecker.h" +#include "RuntimeDyldCheckerImpl.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCDisassembler/MCDisassembler.h" +#include "llvm/MC/MCInst.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/MSVCErrorWorkarounds.h" +#include "llvm/Support/Path.h" +#include <cctype> +#include <memory> +#include <utility> + +#define DEBUG_TYPE "rtdyld" + +using namespace llvm; + +namespace llvm { + +// Helper class that implements the language evaluated by RuntimeDyldChecker. +class RuntimeDyldCheckerExprEval { +public: + RuntimeDyldCheckerExprEval(const RuntimeDyldCheckerImpl &Checker, + raw_ostream &ErrStream) + : Checker(Checker) {} + + bool evaluate(StringRef Expr) const { + // Expect equality expression of the form 'LHS = RHS'. + Expr = Expr.trim(); + size_t EQIdx = Expr.find('='); + + ParseContext OutsideLoad(false); + + // Evaluate LHS. + StringRef LHSExpr = Expr.substr(0, EQIdx).rtrim(); + StringRef RemainingExpr; + EvalResult LHSResult; + std::tie(LHSResult, RemainingExpr) = + evalComplexExpr(evalSimpleExpr(LHSExpr, OutsideLoad), OutsideLoad); + if (LHSResult.hasError()) + return handleError(Expr, LHSResult); + if (RemainingExpr != "") + return handleError(Expr, unexpectedToken(RemainingExpr, LHSExpr, "")); + + // Evaluate RHS. + StringRef RHSExpr = Expr.substr(EQIdx + 1).ltrim(); + EvalResult RHSResult; + std::tie(RHSResult, RemainingExpr) = + evalComplexExpr(evalSimpleExpr(RHSExpr, OutsideLoad), OutsideLoad); + if (RHSResult.hasError()) + return handleError(Expr, RHSResult); + if (RemainingExpr != "") + return handleError(Expr, unexpectedToken(RemainingExpr, RHSExpr, "")); + + if (LHSResult.getValue() != RHSResult.getValue()) { + Checker.ErrStream << "Expression '" << Expr << "' is false: " + << format("0x%" PRIx64, LHSResult.getValue()) + << " != " << format("0x%" PRIx64, RHSResult.getValue()) + << "\n"; + return false; + } + return true; + } + +private: + // RuntimeDyldCheckerExprEval requires some context when parsing exprs. In + // particular, it needs to know whether a symbol is being evaluated in the + // context of a load, in which case we want the linker's local address for + // the symbol, or outside of a load, in which case we want the symbol's + // address in the remote target. + + struct ParseContext { + bool IsInsideLoad; + ParseContext(bool IsInsideLoad) : IsInsideLoad(IsInsideLoad) {} + }; + + const RuntimeDyldCheckerImpl &Checker; + + enum class BinOpToken : unsigned { + Invalid, + Add, + Sub, + BitwiseAnd, + BitwiseOr, + ShiftLeft, + ShiftRight + }; + + class EvalResult { + public: + EvalResult() : Value(0), ErrorMsg("") {} + EvalResult(uint64_t Value) : Value(Value), ErrorMsg("") {} + EvalResult(std::string ErrorMsg) + : Value(0), ErrorMsg(std::move(ErrorMsg)) {} + uint64_t getValue() const { return Value; } + bool hasError() const { return ErrorMsg != ""; } + const std::string &getErrorMsg() const { return ErrorMsg; } + + private: + uint64_t Value; std::string ErrorMsg; - std::tie(StubAddr, ErrorMsg) = Checker.getStubOrGOTAddrFor( - StubContainerName, Symbol, PCtx.IsInsideLoad, IsStubAddr); - - if (ErrorMsg != "") - return std::make_pair(EvalResult(ErrorMsg), ""); - - return std::make_pair(EvalResult(StubAddr), RemainingExpr); - } - - std::pair<EvalResult, StringRef> evalSectionAddr(StringRef Expr, - ParseContext PCtx) const { - if (!Expr.startswith("(")) - return std::make_pair(unexpectedToken(Expr, Expr, "expected '('"), ""); - StringRef RemainingExpr = Expr.substr(1).ltrim(); - - // Handle file-name specially, as it may contain characters that aren't - // legal for symbols. - StringRef FileName; - size_t ComaIdx = RemainingExpr.find(','); - FileName = RemainingExpr.substr(0, ComaIdx).rtrim(); - RemainingExpr = RemainingExpr.substr(ComaIdx).ltrim(); - - if (!RemainingExpr.startswith(",")) - return std::make_pair( - unexpectedToken(RemainingExpr, Expr, "expected ','"), ""); - RemainingExpr = RemainingExpr.substr(1).ltrim(); - - StringRef SectionName; - std::tie(SectionName, RemainingExpr) = parseSymbol(RemainingExpr); - - if (!RemainingExpr.startswith(")")) - return std::make_pair( - unexpectedToken(RemainingExpr, Expr, "expected ')'"), ""); - RemainingExpr = RemainingExpr.substr(1).ltrim(); - - uint64_t StubAddr; + }; + + StringRef getTokenForError(StringRef Expr) const { + if (Expr.empty()) + return ""; + + StringRef Token, Remaining; + if (isalpha(Expr[0])) + std::tie(Token, Remaining) = parseSymbol(Expr); + else if (isdigit(Expr[0])) + std::tie(Token, Remaining) = parseNumberString(Expr); + else { + unsigned TokLen = 1; + if (Expr.startswith("<<") || Expr.startswith(">>")) + TokLen = 2; + Token = Expr.substr(0, TokLen); + } + return Token; + } + + EvalResult unexpectedToken(StringRef TokenStart, StringRef SubExpr, + StringRef ErrText) const { + std::string ErrorMsg("Encountered unexpected token '"); + ErrorMsg += getTokenForError(TokenStart); + if (SubExpr != "") { + ErrorMsg += "' while parsing subexpression '"; + ErrorMsg += SubExpr; + } + ErrorMsg += "'"; + if (ErrText != "") { + ErrorMsg += " "; + ErrorMsg += ErrText; + } + return EvalResult(std::move(ErrorMsg)); + } + + bool handleError(StringRef Expr, const EvalResult &R) const { + assert(R.hasError() && "Not an error result."); + Checker.ErrStream << "Error evaluating expression '" << Expr + << "': " << R.getErrorMsg() << "\n"; + return false; + } + + std::pair<BinOpToken, StringRef> parseBinOpToken(StringRef Expr) const { + if (Expr.empty()) + return std::make_pair(BinOpToken::Invalid, ""); + + // Handle the two 2-character tokens. + if (Expr.startswith("<<")) + return std::make_pair(BinOpToken::ShiftLeft, Expr.substr(2).ltrim()); + if (Expr.startswith(">>")) + return std::make_pair(BinOpToken::ShiftRight, Expr.substr(2).ltrim()); + + // Handle one-character tokens. + BinOpToken Op; + switch (Expr[0]) { + default: + return std::make_pair(BinOpToken::Invalid, Expr); + case '+': + Op = BinOpToken::Add; + break; + case '-': + Op = BinOpToken::Sub; + break; + case '&': + Op = BinOpToken::BitwiseAnd; + break; + case '|': + Op = BinOpToken::BitwiseOr; + break; + } + + return std::make_pair(Op, Expr.substr(1).ltrim()); + } + + EvalResult computeBinOpResult(BinOpToken Op, const EvalResult &LHSResult, + const EvalResult &RHSResult) const { + switch (Op) { + default: + llvm_unreachable("Tried to evaluate unrecognized operation."); + case BinOpToken::Add: + return EvalResult(LHSResult.getValue() + RHSResult.getValue()); + case BinOpToken::Sub: + return EvalResult(LHSResult.getValue() - RHSResult.getValue()); + case BinOpToken::BitwiseAnd: + return EvalResult(LHSResult.getValue() & RHSResult.getValue()); + case BinOpToken::BitwiseOr: + return EvalResult(LHSResult.getValue() | RHSResult.getValue()); + case BinOpToken::ShiftLeft: + return EvalResult(LHSResult.getValue() << RHSResult.getValue()); + case BinOpToken::ShiftRight: + return EvalResult(LHSResult.getValue() >> RHSResult.getValue()); + } + } + + // Parse a symbol and return a (string, string) pair representing the symbol + // name and expression remaining to be parsed. + std::pair<StringRef, StringRef> parseSymbol(StringRef Expr) const { + size_t FirstNonSymbol = Expr.find_first_not_of("0123456789" + "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + ":_.$"); + return std::make_pair(Expr.substr(0, FirstNonSymbol), + Expr.substr(FirstNonSymbol).ltrim()); + } + + // Evaluate a call to decode_operand. Decode the instruction operand at the + // given symbol and get the value of the requested operand. + // Returns an error if the instruction cannot be decoded, or the requested + // operand is not an immediate. + // On success, returns a pair containing the value of the operand, plus + // the expression remaining to be evaluated. + std::pair<EvalResult, StringRef> evalDecodeOperand(StringRef Expr) const { + if (!Expr.startswith("(")) + return std::make_pair(unexpectedToken(Expr, Expr, "expected '('"), ""); + StringRef RemainingExpr = Expr.substr(1).ltrim(); + StringRef Symbol; + std::tie(Symbol, RemainingExpr) = parseSymbol(RemainingExpr); + + if (!Checker.isSymbolValid(Symbol)) + return std::make_pair( + EvalResult(("Cannot decode unknown symbol '" + Symbol + "'").str()), + ""); + + if (!RemainingExpr.startswith(",")) + return std::make_pair( + unexpectedToken(RemainingExpr, RemainingExpr, "expected ','"), ""); + RemainingExpr = RemainingExpr.substr(1).ltrim(); + + EvalResult OpIdxExpr; + std::tie(OpIdxExpr, RemainingExpr) = evalNumberExpr(RemainingExpr); + if (OpIdxExpr.hasError()) + return std::make_pair(OpIdxExpr, ""); + + if (!RemainingExpr.startswith(")")) + return std::make_pair( + unexpectedToken(RemainingExpr, RemainingExpr, "expected ')'"), ""); + RemainingExpr = RemainingExpr.substr(1).ltrim(); + + MCInst Inst; + uint64_t Size; + if (!decodeInst(Symbol, Inst, Size)) + return std::make_pair( + EvalResult(("Couldn't decode instruction at '" + Symbol + "'").str()), + ""); + + unsigned OpIdx = OpIdxExpr.getValue(); + if (OpIdx >= Inst.getNumOperands()) { + std::string ErrMsg; + raw_string_ostream ErrMsgStream(ErrMsg); + ErrMsgStream << "Invalid operand index '" << format("%i", OpIdx) + << "' for instruction '" << Symbol + << "'. Instruction has only " + << format("%i", Inst.getNumOperands()) + << " operands.\nInstruction is:\n "; + Inst.dump_pretty(ErrMsgStream, Checker.InstPrinter); + return std::make_pair(EvalResult(ErrMsgStream.str()), ""); + } + + const MCOperand &Op = Inst.getOperand(OpIdx); + if (!Op.isImm()) { + std::string ErrMsg; + raw_string_ostream ErrMsgStream(ErrMsg); + ErrMsgStream << "Operand '" << format("%i", OpIdx) << "' of instruction '" + << Symbol << "' is not an immediate.\nInstruction is:\n "; + Inst.dump_pretty(ErrMsgStream, Checker.InstPrinter); + + return std::make_pair(EvalResult(ErrMsgStream.str()), ""); + } + + return std::make_pair(EvalResult(Op.getImm()), RemainingExpr); + } + + // Evaluate a call to next_pc. + // Decode the instruction at the given symbol and return the following program + // counter. + // Returns an error if the instruction cannot be decoded. + // On success, returns a pair containing the next PC, plus of the + // expression remaining to be evaluated. + std::pair<EvalResult, StringRef> evalNextPC(StringRef Expr, + ParseContext PCtx) const { + if (!Expr.startswith("(")) + return std::make_pair(unexpectedToken(Expr, Expr, "expected '('"), ""); + StringRef RemainingExpr = Expr.substr(1).ltrim(); + StringRef Symbol; + std::tie(Symbol, RemainingExpr) = parseSymbol(RemainingExpr); + + if (!Checker.isSymbolValid(Symbol)) + return std::make_pair( + EvalResult(("Cannot decode unknown symbol '" + Symbol + "'").str()), + ""); + + if (!RemainingExpr.startswith(")")) + return std::make_pair( + unexpectedToken(RemainingExpr, RemainingExpr, "expected ')'"), ""); + RemainingExpr = RemainingExpr.substr(1).ltrim(); + + MCInst Inst; + uint64_t InstSize; + if (!decodeInst(Symbol, Inst, InstSize)) + return std::make_pair( + EvalResult(("Couldn't decode instruction at '" + Symbol + "'").str()), + ""); + + uint64_t SymbolAddr = PCtx.IsInsideLoad + ? Checker.getSymbolLocalAddr(Symbol) + : Checker.getSymbolRemoteAddr(Symbol); + uint64_t NextPC = SymbolAddr + InstSize; + + return std::make_pair(EvalResult(NextPC), RemainingExpr); + } + + // Evaluate a call to stub_addr/got_addr. + // Look up and return the address of the stub for the given + // (<file name>, <section name>, <symbol name>) tuple. + // On success, returns a pair containing the stub address, plus the expression + // remaining to be evaluated. + std::pair<EvalResult, StringRef> + evalStubOrGOTAddr(StringRef Expr, ParseContext PCtx, bool IsStubAddr) const { + if (!Expr.startswith("(")) + return std::make_pair(unexpectedToken(Expr, Expr, "expected '('"), ""); + StringRef RemainingExpr = Expr.substr(1).ltrim(); + + // Handle file-name specially, as it may contain characters that aren't + // legal for symbols. + StringRef StubContainerName; + size_t ComaIdx = RemainingExpr.find(','); + StubContainerName = RemainingExpr.substr(0, ComaIdx).rtrim(); + RemainingExpr = RemainingExpr.substr(ComaIdx).ltrim(); + + if (!RemainingExpr.startswith(",")) + return std::make_pair( + unexpectedToken(RemainingExpr, Expr, "expected ','"), ""); + RemainingExpr = RemainingExpr.substr(1).ltrim(); + + StringRef Symbol; + std::tie(Symbol, RemainingExpr) = parseSymbol(RemainingExpr); + + if (!RemainingExpr.startswith(")")) + return std::make_pair( + unexpectedToken(RemainingExpr, Expr, "expected ')'"), ""); + RemainingExpr = RemainingExpr.substr(1).ltrim(); + + uint64_t StubAddr; std::string ErrorMsg; - std::tie(StubAddr, ErrorMsg) = Checker.getSectionAddr( - FileName, SectionName, PCtx.IsInsideLoad); - - if (ErrorMsg != "") - return std::make_pair(EvalResult(ErrorMsg), ""); - - return std::make_pair(EvalResult(StubAddr), RemainingExpr); - } - - // Evaluate an identiefer expr, which may be a symbol, or a call to - // one of the builtin functions: get_insn_opcode or get_insn_length. - // Return the result, plus the expression remaining to be parsed. - std::pair<EvalResult, StringRef> evalIdentifierExpr(StringRef Expr, - ParseContext PCtx) const { - StringRef Symbol; - StringRef RemainingExpr; - std::tie(Symbol, RemainingExpr) = parseSymbol(Expr); - - // Check for builtin function calls. - if (Symbol == "decode_operand") - return evalDecodeOperand(RemainingExpr); - else if (Symbol == "next_pc") - return evalNextPC(RemainingExpr, PCtx); - else if (Symbol == "stub_addr") - return evalStubOrGOTAddr(RemainingExpr, PCtx, true); - else if (Symbol == "got_addr") - return evalStubOrGOTAddr(RemainingExpr, PCtx, false); - else if (Symbol == "section_addr") - return evalSectionAddr(RemainingExpr, PCtx); - - if (!Checker.isSymbolValid(Symbol)) { - std::string ErrMsg("No known address for symbol '"); - ErrMsg += Symbol; - ErrMsg += "'"; - if (Symbol.startswith("L")) - ErrMsg += " (this appears to be an assembler local label - " - " perhaps drop the 'L'?)"; - - return std::make_pair(EvalResult(ErrMsg), ""); - } - - // The value for the symbol depends on the context we're evaluating in: - // Inside a load this is the address in the linker's memory, outside a - // load it's the address in the target processes memory. - uint64_t Value = PCtx.IsInsideLoad ? Checker.getSymbolLocalAddr(Symbol) - : Checker.getSymbolRemoteAddr(Symbol); - - // Looks like a plain symbol reference. - return std::make_pair(EvalResult(Value), RemainingExpr); - } - - // Parse a number (hexadecimal or decimal) and return a (string, string) - // pair representing the number and the expression remaining to be parsed. - std::pair<StringRef, StringRef> parseNumberString(StringRef Expr) const { - size_t FirstNonDigit = StringRef::npos; - if (Expr.startswith("0x")) { - FirstNonDigit = Expr.find_first_not_of("0123456789abcdefABCDEF", 2); - if (FirstNonDigit == StringRef::npos) - FirstNonDigit = Expr.size(); - } else { - FirstNonDigit = Expr.find_first_not_of("0123456789"); - if (FirstNonDigit == StringRef::npos) - FirstNonDigit = Expr.size(); - } - return std::make_pair(Expr.substr(0, FirstNonDigit), - Expr.substr(FirstNonDigit)); - } - - // Evaluate a constant numeric expression (hexadecimal or decimal) and - // return a pair containing the result, and the expression remaining to be - // evaluated. - std::pair<EvalResult, StringRef> evalNumberExpr(StringRef Expr) const { - StringRef ValueStr; - StringRef RemainingExpr; - std::tie(ValueStr, RemainingExpr) = parseNumberString(Expr); - - if (ValueStr.empty() || !isdigit(ValueStr[0])) - return std::make_pair( - unexpectedToken(RemainingExpr, RemainingExpr, "expected number"), ""); - uint64_t Value; - ValueStr.getAsInteger(0, Value); - return std::make_pair(EvalResult(Value), RemainingExpr); - } - - // Evaluate an expression of the form "(<expr>)" and return a pair - // containing the result of evaluating <expr>, plus the expression - // remaining to be parsed. - std::pair<EvalResult, StringRef> evalParensExpr(StringRef Expr, - ParseContext PCtx) const { - assert(Expr.startswith("(") && "Not a parenthesized expression"); - EvalResult SubExprResult; - StringRef RemainingExpr; - std::tie(SubExprResult, RemainingExpr) = - evalComplexExpr(evalSimpleExpr(Expr.substr(1).ltrim(), PCtx), PCtx); - if (SubExprResult.hasError()) - return std::make_pair(SubExprResult, ""); - if (!RemainingExpr.startswith(")")) - return std::make_pair( - unexpectedToken(RemainingExpr, Expr, "expected ')'"), ""); - RemainingExpr = RemainingExpr.substr(1).ltrim(); - return std::make_pair(SubExprResult, RemainingExpr); - } - - // Evaluate an expression in one of the following forms: - // *{<number>}<expr> - // Return a pair containing the result, plus the expression remaining to be - // parsed. - std::pair<EvalResult, StringRef> evalLoadExpr(StringRef Expr) const { - assert(Expr.startswith("*") && "Not a load expression"); - StringRef RemainingExpr = Expr.substr(1).ltrim(); - - // Parse read size. - if (!RemainingExpr.startswith("{")) - return std::make_pair(EvalResult("Expected '{' following '*'."), ""); - RemainingExpr = RemainingExpr.substr(1).ltrim(); - EvalResult ReadSizeExpr; - std::tie(ReadSizeExpr, RemainingExpr) = evalNumberExpr(RemainingExpr); - if (ReadSizeExpr.hasError()) - return std::make_pair(ReadSizeExpr, RemainingExpr); - uint64_t ReadSize = ReadSizeExpr.getValue(); - if (ReadSize < 1 || ReadSize > 8) - return std::make_pair(EvalResult("Invalid size for dereference."), ""); - if (!RemainingExpr.startswith("}")) - return std::make_pair(EvalResult("Missing '}' for dereference."), ""); - RemainingExpr = RemainingExpr.substr(1).ltrim(); - - // Evaluate the expression representing the load address. - ParseContext LoadCtx(true); - EvalResult LoadAddrExprResult; - std::tie(LoadAddrExprResult, RemainingExpr) = - evalComplexExpr(evalSimpleExpr(RemainingExpr, LoadCtx), LoadCtx); - - if (LoadAddrExprResult.hasError()) - return std::make_pair(LoadAddrExprResult, ""); - - uint64_t LoadAddr = LoadAddrExprResult.getValue(); - - // If there is no error but the content pointer is null then this is a - // zero-fill symbol/section. - if (LoadAddr == 0) - return std::make_pair(0, RemainingExpr); - - return std::make_pair( - EvalResult(Checker.readMemoryAtAddr(LoadAddr, ReadSize)), - RemainingExpr); - } - - // Evaluate a "simple" expression. This is any expression that _isn't_ an - // un-parenthesized binary expression. - // - // "Simple" expressions can be optionally bit-sliced. See evalSlicedExpr. - // - // Returns a pair containing the result of the evaluation, plus the - // expression remaining to be parsed. - std::pair<EvalResult, StringRef> evalSimpleExpr(StringRef Expr, - ParseContext PCtx) const { - EvalResult SubExprResult; - StringRef RemainingExpr; - - if (Expr.empty()) - return std::make_pair(EvalResult("Unexpected end of expression"), ""); - - if (Expr[0] == '(') - std::tie(SubExprResult, RemainingExpr) = evalParensExpr(Expr, PCtx); - else if (Expr[0] == '*') - std::tie(SubExprResult, RemainingExpr) = evalLoadExpr(Expr); - else if (isalpha(Expr[0]) || Expr[0] == '_') - std::tie(SubExprResult, RemainingExpr) = evalIdentifierExpr(Expr, PCtx); - else if (isdigit(Expr[0])) - std::tie(SubExprResult, RemainingExpr) = evalNumberExpr(Expr); - else - return std::make_pair( - unexpectedToken(Expr, Expr, - "expected '(', '*', identifier, or number"), ""); - - if (SubExprResult.hasError()) - return std::make_pair(SubExprResult, RemainingExpr); - - // Evaluate bit-slice if present. - if (RemainingExpr.startswith("[")) - std::tie(SubExprResult, RemainingExpr) = - evalSliceExpr(std::make_pair(SubExprResult, RemainingExpr)); - - return std::make_pair(SubExprResult, RemainingExpr); - } - - // Evaluate a bit-slice of an expression. - // A bit-slice has the form "<expr>[high:low]". The result of evaluating a - // slice is the bits between high and low (inclusive) in the original - // expression, right shifted so that the "low" bit is in position 0 in the - // result. - // Returns a pair containing the result of the slice operation, plus the - // expression remaining to be parsed. - std::pair<EvalResult, StringRef> - evalSliceExpr(const std::pair<EvalResult, StringRef> &Ctx) const { - EvalResult SubExprResult; - StringRef RemainingExpr; - std::tie(SubExprResult, RemainingExpr) = Ctx; - - assert(RemainingExpr.startswith("[") && "Not a slice expr."); - RemainingExpr = RemainingExpr.substr(1).ltrim(); - - EvalResult HighBitExpr; - std::tie(HighBitExpr, RemainingExpr) = evalNumberExpr(RemainingExpr); - - if (HighBitExpr.hasError()) - return std::make_pair(HighBitExpr, RemainingExpr); - - if (!RemainingExpr.startswith(":")) - return std::make_pair( - unexpectedToken(RemainingExpr, RemainingExpr, "expected ':'"), ""); - RemainingExpr = RemainingExpr.substr(1).ltrim(); - - EvalResult LowBitExpr; - std::tie(LowBitExpr, RemainingExpr) = evalNumberExpr(RemainingExpr); - - if (LowBitExpr.hasError()) - return std::make_pair(LowBitExpr, RemainingExpr); - - if (!RemainingExpr.startswith("]")) - return std::make_pair( - unexpectedToken(RemainingExpr, RemainingExpr, "expected ']'"), ""); - RemainingExpr = RemainingExpr.substr(1).ltrim(); - - unsigned HighBit = HighBitExpr.getValue(); - unsigned LowBit = LowBitExpr.getValue(); - uint64_t Mask = ((uint64_t)1 << (HighBit - LowBit + 1)) - 1; - uint64_t SlicedValue = (SubExprResult.getValue() >> LowBit) & Mask; - return std::make_pair(EvalResult(SlicedValue), RemainingExpr); - } - - // Evaluate a "complex" expression. - // Takes an already evaluated subexpression and checks for the presence of a - // binary operator, computing the result of the binary operation if one is - // found. Used to make arithmetic expressions left-associative. - // Returns a pair containing the ultimate result of evaluating the - // expression, plus the expression remaining to be evaluated. - std::pair<EvalResult, StringRef> - evalComplexExpr(const std::pair<EvalResult, StringRef> &LHSAndRemaining, - ParseContext PCtx) const { - EvalResult LHSResult; - StringRef RemainingExpr; - std::tie(LHSResult, RemainingExpr) = LHSAndRemaining; - - // If there was an error, or there's nothing left to evaluate, return the - // result. - if (LHSResult.hasError() || RemainingExpr == "") - return std::make_pair(LHSResult, RemainingExpr); - - // Otherwise check if this is a binary expressioan. - BinOpToken BinOp; - std::tie(BinOp, RemainingExpr) = parseBinOpToken(RemainingExpr); - - // If this isn't a recognized expression just return. - if (BinOp == BinOpToken::Invalid) - return std::make_pair(LHSResult, RemainingExpr); - - // This is a recognized bin-op. Evaluate the RHS, then evaluate the binop. - EvalResult RHSResult; - std::tie(RHSResult, RemainingExpr) = evalSimpleExpr(RemainingExpr, PCtx); - - // If there was an error evaluating the RHS, return it. - if (RHSResult.hasError()) - return std::make_pair(RHSResult, RemainingExpr); - - // This is a binary expression - evaluate and try to continue as a - // complex expr. - EvalResult ThisResult(computeBinOpResult(BinOp, LHSResult, RHSResult)); - - return evalComplexExpr(std::make_pair(ThisResult, RemainingExpr), PCtx); - } - - bool decodeInst(StringRef Symbol, MCInst &Inst, uint64_t &Size) const { - MCDisassembler *Dis = Checker.Disassembler; - StringRef SymbolMem = Checker.getSymbolContent(Symbol); - ArrayRef<uint8_t> SymbolBytes(SymbolMem.bytes_begin(), SymbolMem.size()); - - MCDisassembler::DecodeStatus S = - Dis->getInstruction(Inst, Size, SymbolBytes, 0, nulls()); - - return (S == MCDisassembler::Success); - } -}; -} - -RuntimeDyldCheckerImpl::RuntimeDyldCheckerImpl( - IsSymbolValidFunction IsSymbolValid, GetSymbolInfoFunction GetSymbolInfo, - GetSectionInfoFunction GetSectionInfo, GetStubInfoFunction GetStubInfo, - GetGOTInfoFunction GetGOTInfo, support::endianness Endianness, - MCDisassembler *Disassembler, MCInstPrinter *InstPrinter, - raw_ostream &ErrStream) - : IsSymbolValid(std::move(IsSymbolValid)), - GetSymbolInfo(std::move(GetSymbolInfo)), - GetSectionInfo(std::move(GetSectionInfo)), - GetStubInfo(std::move(GetStubInfo)), GetGOTInfo(std::move(GetGOTInfo)), - Endianness(Endianness), Disassembler(Disassembler), - InstPrinter(InstPrinter), ErrStream(ErrStream) {} - -bool RuntimeDyldCheckerImpl::check(StringRef CheckExpr) const { - CheckExpr = CheckExpr.trim(); - LLVM_DEBUG(dbgs() << "RuntimeDyldChecker: Checking '" << CheckExpr - << "'...\n"); - RuntimeDyldCheckerExprEval P(*this, ErrStream); - bool Result = P.evaluate(CheckExpr); - (void)Result; - LLVM_DEBUG(dbgs() << "RuntimeDyldChecker: '" << CheckExpr << "' " - << (Result ? "passed" : "FAILED") << ".\n"); - return Result; -} - -bool RuntimeDyldCheckerImpl::checkAllRulesInBuffer(StringRef RulePrefix, - MemoryBuffer *MemBuf) const { - bool DidAllTestsPass = true; - unsigned NumRules = 0; - - std::string CheckExpr; - const char *LineStart = MemBuf->getBufferStart(); - - // Eat whitespace. - while (LineStart != MemBuf->getBufferEnd() && isSpace(*LineStart)) - ++LineStart; - - while (LineStart != MemBuf->getBufferEnd() && *LineStart != '\0') { - const char *LineEnd = LineStart; - while (LineEnd != MemBuf->getBufferEnd() && *LineEnd != '\r' && - *LineEnd != '\n') - ++LineEnd; - - StringRef Line(LineStart, LineEnd - LineStart); - if (Line.startswith(RulePrefix)) - CheckExpr += Line.substr(RulePrefix.size()).str(); - - // If there's a check expr string... - if (!CheckExpr.empty()) { - // ... and it's complete then run it, otherwise remove the trailer '\'. - if (CheckExpr.back() != '\\') { - DidAllTestsPass &= check(CheckExpr); - CheckExpr.clear(); - ++NumRules; - } else - CheckExpr.pop_back(); - } - - // Eat whitespace. - LineStart = LineEnd; - while (LineStart != MemBuf->getBufferEnd() && isSpace(*LineStart)) - ++LineStart; - } - return DidAllTestsPass && (NumRules != 0); -} - -bool RuntimeDyldCheckerImpl::isSymbolValid(StringRef Symbol) const { - return IsSymbolValid(Symbol); -} - -uint64_t RuntimeDyldCheckerImpl::getSymbolLocalAddr(StringRef Symbol) const { - auto SymInfo = GetSymbolInfo(Symbol); - if (!SymInfo) { - logAllUnhandledErrors(SymInfo.takeError(), errs(), "RTDyldChecker: "); - return 0; - } - - if (SymInfo->isZeroFill()) - return 0; - - return static_cast<uint64_t>( - reinterpret_cast<uintptr_t>(SymInfo->getContent().data())); -} - -uint64_t RuntimeDyldCheckerImpl::getSymbolRemoteAddr(StringRef Symbol) const { - auto SymInfo = GetSymbolInfo(Symbol); - if (!SymInfo) { - logAllUnhandledErrors(SymInfo.takeError(), errs(), "RTDyldChecker: "); - return 0; - } - - return SymInfo->getTargetAddress(); -} - -uint64_t RuntimeDyldCheckerImpl::readMemoryAtAddr(uint64_t SrcAddr, - unsigned Size) const { - uintptr_t PtrSizedAddr = static_cast<uintptr_t>(SrcAddr); - assert(PtrSizedAddr == SrcAddr && "Linker memory pointer out-of-range."); - void *Ptr = reinterpret_cast<void*>(PtrSizedAddr); - - switch (Size) { - case 1: - return support::endian::read<uint8_t>(Ptr, Endianness); - case 2: - return support::endian::read<uint16_t>(Ptr, Endianness); - case 4: - return support::endian::read<uint32_t>(Ptr, Endianness); - case 8: - return support::endian::read<uint64_t>(Ptr, Endianness); - } - llvm_unreachable("Unsupported read size"); -} - -StringRef RuntimeDyldCheckerImpl::getSymbolContent(StringRef Symbol) const { - auto SymInfo = GetSymbolInfo(Symbol); - if (!SymInfo) { - logAllUnhandledErrors(SymInfo.takeError(), errs(), "RTDyldChecker: "); - return StringRef(); - } - return SymInfo->getContent(); -} - -std::pair<uint64_t, std::string> RuntimeDyldCheckerImpl::getSectionAddr( - StringRef FileName, StringRef SectionName, bool IsInsideLoad) const { - - auto SecInfo = GetSectionInfo(FileName, SectionName); - if (!SecInfo) { - std::string ErrMsg; - { - raw_string_ostream ErrMsgStream(ErrMsg); - logAllUnhandledErrors(SecInfo.takeError(), ErrMsgStream, - "RTDyldChecker: "); - } - return std::make_pair(0, std::move(ErrMsg)); - } - - // If this address is being looked up in "load" mode, return the content - // pointer, otherwise return the target address. - - uint64_t Addr = 0; - - if (IsInsideLoad) { - if (SecInfo->isZeroFill()) - Addr = 0; - else - Addr = pointerToJITTargetAddress(SecInfo->getContent().data()); - } else - Addr = SecInfo->getTargetAddress(); - - return std::make_pair(Addr, ""); -} - -std::pair<uint64_t, std::string> RuntimeDyldCheckerImpl::getStubOrGOTAddrFor( - StringRef StubContainerName, StringRef SymbolName, bool IsInsideLoad, - bool IsStubAddr) const { - - auto StubInfo = IsStubAddr ? GetStubInfo(StubContainerName, SymbolName) - : GetGOTInfo(StubContainerName, SymbolName); - - if (!StubInfo) { - std::string ErrMsg; - { - raw_string_ostream ErrMsgStream(ErrMsg); - logAllUnhandledErrors(StubInfo.takeError(), ErrMsgStream, - "RTDyldChecker: "); - } - return std::make_pair((uint64_t)0, std::move(ErrMsg)); - } - - uint64_t Addr = 0; - - if (IsInsideLoad) { - if (StubInfo->isZeroFill()) - return std::make_pair((uint64_t)0, "Detected zero-filled stub/GOT entry"); - Addr = pointerToJITTargetAddress(StubInfo->getContent().data()); - } else - Addr = StubInfo->getTargetAddress(); - - return std::make_pair(Addr, ""); -} - -RuntimeDyldChecker::RuntimeDyldChecker( - IsSymbolValidFunction IsSymbolValid, GetSymbolInfoFunction GetSymbolInfo, - GetSectionInfoFunction GetSectionInfo, GetStubInfoFunction GetStubInfo, - GetGOTInfoFunction GetGOTInfo, support::endianness Endianness, - MCDisassembler *Disassembler, MCInstPrinter *InstPrinter, - raw_ostream &ErrStream) - : Impl(::std::make_unique<RuntimeDyldCheckerImpl>( - std::move(IsSymbolValid), std::move(GetSymbolInfo), - std::move(GetSectionInfo), std::move(GetStubInfo), - std::move(GetGOTInfo), Endianness, Disassembler, InstPrinter, - ErrStream)) {} - -RuntimeDyldChecker::~RuntimeDyldChecker() {} - -bool RuntimeDyldChecker::check(StringRef CheckExpr) const { - return Impl->check(CheckExpr); -} - -bool RuntimeDyldChecker::checkAllRulesInBuffer(StringRef RulePrefix, - MemoryBuffer *MemBuf) const { - return Impl->checkAllRulesInBuffer(RulePrefix, MemBuf); -} - -std::pair<uint64_t, std::string> -RuntimeDyldChecker::getSectionAddr(StringRef FileName, StringRef SectionName, - bool LocalAddress) { - return Impl->getSectionAddr(FileName, SectionName, LocalAddress); -} + std::tie(StubAddr, ErrorMsg) = Checker.getStubOrGOTAddrFor( + StubContainerName, Symbol, PCtx.IsInsideLoad, IsStubAddr); + + if (ErrorMsg != "") + return std::make_pair(EvalResult(ErrorMsg), ""); + + return std::make_pair(EvalResult(StubAddr), RemainingExpr); + } + + std::pair<EvalResult, StringRef> evalSectionAddr(StringRef Expr, + ParseContext PCtx) const { + if (!Expr.startswith("(")) + return std::make_pair(unexpectedToken(Expr, Expr, "expected '('"), ""); + StringRef RemainingExpr = Expr.substr(1).ltrim(); + + // Handle file-name specially, as it may contain characters that aren't + // legal for symbols. + StringRef FileName; + size_t ComaIdx = RemainingExpr.find(','); + FileName = RemainingExpr.substr(0, ComaIdx).rtrim(); + RemainingExpr = RemainingExpr.substr(ComaIdx).ltrim(); + + if (!RemainingExpr.startswith(",")) + return std::make_pair( + unexpectedToken(RemainingExpr, Expr, "expected ','"), ""); + RemainingExpr = RemainingExpr.substr(1).ltrim(); + + StringRef SectionName; + std::tie(SectionName, RemainingExpr) = parseSymbol(RemainingExpr); + + if (!RemainingExpr.startswith(")")) + return std::make_pair( + unexpectedToken(RemainingExpr, Expr, "expected ')'"), ""); + RemainingExpr = RemainingExpr.substr(1).ltrim(); + + uint64_t StubAddr; + std::string ErrorMsg; + std::tie(StubAddr, ErrorMsg) = Checker.getSectionAddr( + FileName, SectionName, PCtx.IsInsideLoad); + + if (ErrorMsg != "") + return std::make_pair(EvalResult(ErrorMsg), ""); + + return std::make_pair(EvalResult(StubAddr), RemainingExpr); + } + + // Evaluate an identiefer expr, which may be a symbol, or a call to + // one of the builtin functions: get_insn_opcode or get_insn_length. + // Return the result, plus the expression remaining to be parsed. + std::pair<EvalResult, StringRef> evalIdentifierExpr(StringRef Expr, + ParseContext PCtx) const { + StringRef Symbol; + StringRef RemainingExpr; + std::tie(Symbol, RemainingExpr) = parseSymbol(Expr); + + // Check for builtin function calls. + if (Symbol == "decode_operand") + return evalDecodeOperand(RemainingExpr); + else if (Symbol == "next_pc") + return evalNextPC(RemainingExpr, PCtx); + else if (Symbol == "stub_addr") + return evalStubOrGOTAddr(RemainingExpr, PCtx, true); + else if (Symbol == "got_addr") + return evalStubOrGOTAddr(RemainingExpr, PCtx, false); + else if (Symbol == "section_addr") + return evalSectionAddr(RemainingExpr, PCtx); + + if (!Checker.isSymbolValid(Symbol)) { + std::string ErrMsg("No known address for symbol '"); + ErrMsg += Symbol; + ErrMsg += "'"; + if (Symbol.startswith("L")) + ErrMsg += " (this appears to be an assembler local label - " + " perhaps drop the 'L'?)"; + + return std::make_pair(EvalResult(ErrMsg), ""); + } + + // The value for the symbol depends on the context we're evaluating in: + // Inside a load this is the address in the linker's memory, outside a + // load it's the address in the target processes memory. + uint64_t Value = PCtx.IsInsideLoad ? Checker.getSymbolLocalAddr(Symbol) + : Checker.getSymbolRemoteAddr(Symbol); + + // Looks like a plain symbol reference. + return std::make_pair(EvalResult(Value), RemainingExpr); + } + + // Parse a number (hexadecimal or decimal) and return a (string, string) + // pair representing the number and the expression remaining to be parsed. + std::pair<StringRef, StringRef> parseNumberString(StringRef Expr) const { + size_t FirstNonDigit = StringRef::npos; + if (Expr.startswith("0x")) { + FirstNonDigit = Expr.find_first_not_of("0123456789abcdefABCDEF", 2); + if (FirstNonDigit == StringRef::npos) + FirstNonDigit = Expr.size(); + } else { + FirstNonDigit = Expr.find_first_not_of("0123456789"); + if (FirstNonDigit == StringRef::npos) + FirstNonDigit = Expr.size(); + } + return std::make_pair(Expr.substr(0, FirstNonDigit), + Expr.substr(FirstNonDigit)); + } + + // Evaluate a constant numeric expression (hexadecimal or decimal) and + // return a pair containing the result, and the expression remaining to be + // evaluated. + std::pair<EvalResult, StringRef> evalNumberExpr(StringRef Expr) const { + StringRef ValueStr; + StringRef RemainingExpr; + std::tie(ValueStr, RemainingExpr) = parseNumberString(Expr); + + if (ValueStr.empty() || !isdigit(ValueStr[0])) + return std::make_pair( + unexpectedToken(RemainingExpr, RemainingExpr, "expected number"), ""); + uint64_t Value; + ValueStr.getAsInteger(0, Value); + return std::make_pair(EvalResult(Value), RemainingExpr); + } + + // Evaluate an expression of the form "(<expr>)" and return a pair + // containing the result of evaluating <expr>, plus the expression + // remaining to be parsed. + std::pair<EvalResult, StringRef> evalParensExpr(StringRef Expr, + ParseContext PCtx) const { + assert(Expr.startswith("(") && "Not a parenthesized expression"); + EvalResult SubExprResult; + StringRef RemainingExpr; + std::tie(SubExprResult, RemainingExpr) = + evalComplexExpr(evalSimpleExpr(Expr.substr(1).ltrim(), PCtx), PCtx); + if (SubExprResult.hasError()) + return std::make_pair(SubExprResult, ""); + if (!RemainingExpr.startswith(")")) + return std::make_pair( + unexpectedToken(RemainingExpr, Expr, "expected ')'"), ""); + RemainingExpr = RemainingExpr.substr(1).ltrim(); + return std::make_pair(SubExprResult, RemainingExpr); + } + + // Evaluate an expression in one of the following forms: + // *{<number>}<expr> + // Return a pair containing the result, plus the expression remaining to be + // parsed. + std::pair<EvalResult, StringRef> evalLoadExpr(StringRef Expr) const { + assert(Expr.startswith("*") && "Not a load expression"); + StringRef RemainingExpr = Expr.substr(1).ltrim(); + + // Parse read size. + if (!RemainingExpr.startswith("{")) + return std::make_pair(EvalResult("Expected '{' following '*'."), ""); + RemainingExpr = RemainingExpr.substr(1).ltrim(); + EvalResult ReadSizeExpr; + std::tie(ReadSizeExpr, RemainingExpr) = evalNumberExpr(RemainingExpr); + if (ReadSizeExpr.hasError()) + return std::make_pair(ReadSizeExpr, RemainingExpr); + uint64_t ReadSize = ReadSizeExpr.getValue(); + if (ReadSize < 1 || ReadSize > 8) + return std::make_pair(EvalResult("Invalid size for dereference."), ""); + if (!RemainingExpr.startswith("}")) + return std::make_pair(EvalResult("Missing '}' for dereference."), ""); + RemainingExpr = RemainingExpr.substr(1).ltrim(); + + // Evaluate the expression representing the load address. + ParseContext LoadCtx(true); + EvalResult LoadAddrExprResult; + std::tie(LoadAddrExprResult, RemainingExpr) = + evalComplexExpr(evalSimpleExpr(RemainingExpr, LoadCtx), LoadCtx); + + if (LoadAddrExprResult.hasError()) + return std::make_pair(LoadAddrExprResult, ""); + + uint64_t LoadAddr = LoadAddrExprResult.getValue(); + + // If there is no error but the content pointer is null then this is a + // zero-fill symbol/section. + if (LoadAddr == 0) + return std::make_pair(0, RemainingExpr); + + return std::make_pair( + EvalResult(Checker.readMemoryAtAddr(LoadAddr, ReadSize)), + RemainingExpr); + } + + // Evaluate a "simple" expression. This is any expression that _isn't_ an + // un-parenthesized binary expression. + // + // "Simple" expressions can be optionally bit-sliced. See evalSlicedExpr. + // + // Returns a pair containing the result of the evaluation, plus the + // expression remaining to be parsed. + std::pair<EvalResult, StringRef> evalSimpleExpr(StringRef Expr, + ParseContext PCtx) const { + EvalResult SubExprResult; + StringRef RemainingExpr; + + if (Expr.empty()) + return std::make_pair(EvalResult("Unexpected end of expression"), ""); + + if (Expr[0] == '(') + std::tie(SubExprResult, RemainingExpr) = evalParensExpr(Expr, PCtx); + else if (Expr[0] == '*') + std::tie(SubExprResult, RemainingExpr) = evalLoadExpr(Expr); + else if (isalpha(Expr[0]) || Expr[0] == '_') + std::tie(SubExprResult, RemainingExpr) = evalIdentifierExpr(Expr, PCtx); + else if (isdigit(Expr[0])) + std::tie(SubExprResult, RemainingExpr) = evalNumberExpr(Expr); + else + return std::make_pair( + unexpectedToken(Expr, Expr, + "expected '(', '*', identifier, or number"), ""); + + if (SubExprResult.hasError()) + return std::make_pair(SubExprResult, RemainingExpr); + + // Evaluate bit-slice if present. + if (RemainingExpr.startswith("[")) + std::tie(SubExprResult, RemainingExpr) = + evalSliceExpr(std::make_pair(SubExprResult, RemainingExpr)); + + return std::make_pair(SubExprResult, RemainingExpr); + } + + // Evaluate a bit-slice of an expression. + // A bit-slice has the form "<expr>[high:low]". The result of evaluating a + // slice is the bits between high and low (inclusive) in the original + // expression, right shifted so that the "low" bit is in position 0 in the + // result. + // Returns a pair containing the result of the slice operation, plus the + // expression remaining to be parsed. + std::pair<EvalResult, StringRef> + evalSliceExpr(const std::pair<EvalResult, StringRef> &Ctx) const { + EvalResult SubExprResult; + StringRef RemainingExpr; + std::tie(SubExprResult, RemainingExpr) = Ctx; + + assert(RemainingExpr.startswith("[") && "Not a slice expr."); + RemainingExpr = RemainingExpr.substr(1).ltrim(); + + EvalResult HighBitExpr; + std::tie(HighBitExpr, RemainingExpr) = evalNumberExpr(RemainingExpr); + + if (HighBitExpr.hasError()) + return std::make_pair(HighBitExpr, RemainingExpr); + + if (!RemainingExpr.startswith(":")) + return std::make_pair( + unexpectedToken(RemainingExpr, RemainingExpr, "expected ':'"), ""); + RemainingExpr = RemainingExpr.substr(1).ltrim(); + + EvalResult LowBitExpr; + std::tie(LowBitExpr, RemainingExpr) = evalNumberExpr(RemainingExpr); + + if (LowBitExpr.hasError()) + return std::make_pair(LowBitExpr, RemainingExpr); + + if (!RemainingExpr.startswith("]")) + return std::make_pair( + unexpectedToken(RemainingExpr, RemainingExpr, "expected ']'"), ""); + RemainingExpr = RemainingExpr.substr(1).ltrim(); + + unsigned HighBit = HighBitExpr.getValue(); + unsigned LowBit = LowBitExpr.getValue(); + uint64_t Mask = ((uint64_t)1 << (HighBit - LowBit + 1)) - 1; + uint64_t SlicedValue = (SubExprResult.getValue() >> LowBit) & Mask; + return std::make_pair(EvalResult(SlicedValue), RemainingExpr); + } + + // Evaluate a "complex" expression. + // Takes an already evaluated subexpression and checks for the presence of a + // binary operator, computing the result of the binary operation if one is + // found. Used to make arithmetic expressions left-associative. + // Returns a pair containing the ultimate result of evaluating the + // expression, plus the expression remaining to be evaluated. + std::pair<EvalResult, StringRef> + evalComplexExpr(const std::pair<EvalResult, StringRef> &LHSAndRemaining, + ParseContext PCtx) const { + EvalResult LHSResult; + StringRef RemainingExpr; + std::tie(LHSResult, RemainingExpr) = LHSAndRemaining; + + // If there was an error, or there's nothing left to evaluate, return the + // result. + if (LHSResult.hasError() || RemainingExpr == "") + return std::make_pair(LHSResult, RemainingExpr); + + // Otherwise check if this is a binary expressioan. + BinOpToken BinOp; + std::tie(BinOp, RemainingExpr) = parseBinOpToken(RemainingExpr); + + // If this isn't a recognized expression just return. + if (BinOp == BinOpToken::Invalid) + return std::make_pair(LHSResult, RemainingExpr); + + // This is a recognized bin-op. Evaluate the RHS, then evaluate the binop. + EvalResult RHSResult; + std::tie(RHSResult, RemainingExpr) = evalSimpleExpr(RemainingExpr, PCtx); + + // If there was an error evaluating the RHS, return it. + if (RHSResult.hasError()) + return std::make_pair(RHSResult, RemainingExpr); + + // This is a binary expression - evaluate and try to continue as a + // complex expr. + EvalResult ThisResult(computeBinOpResult(BinOp, LHSResult, RHSResult)); + + return evalComplexExpr(std::make_pair(ThisResult, RemainingExpr), PCtx); + } + + bool decodeInst(StringRef Symbol, MCInst &Inst, uint64_t &Size) const { + MCDisassembler *Dis = Checker.Disassembler; + StringRef SymbolMem = Checker.getSymbolContent(Symbol); + ArrayRef<uint8_t> SymbolBytes(SymbolMem.bytes_begin(), SymbolMem.size()); + + MCDisassembler::DecodeStatus S = + Dis->getInstruction(Inst, Size, SymbolBytes, 0, nulls()); + + return (S == MCDisassembler::Success); + } +}; +} + +RuntimeDyldCheckerImpl::RuntimeDyldCheckerImpl( + IsSymbolValidFunction IsSymbolValid, GetSymbolInfoFunction GetSymbolInfo, + GetSectionInfoFunction GetSectionInfo, GetStubInfoFunction GetStubInfo, + GetGOTInfoFunction GetGOTInfo, support::endianness Endianness, + MCDisassembler *Disassembler, MCInstPrinter *InstPrinter, + raw_ostream &ErrStream) + : IsSymbolValid(std::move(IsSymbolValid)), + GetSymbolInfo(std::move(GetSymbolInfo)), + GetSectionInfo(std::move(GetSectionInfo)), + GetStubInfo(std::move(GetStubInfo)), GetGOTInfo(std::move(GetGOTInfo)), + Endianness(Endianness), Disassembler(Disassembler), + InstPrinter(InstPrinter), ErrStream(ErrStream) {} + +bool RuntimeDyldCheckerImpl::check(StringRef CheckExpr) const { + CheckExpr = CheckExpr.trim(); + LLVM_DEBUG(dbgs() << "RuntimeDyldChecker: Checking '" << CheckExpr + << "'...\n"); + RuntimeDyldCheckerExprEval P(*this, ErrStream); + bool Result = P.evaluate(CheckExpr); + (void)Result; + LLVM_DEBUG(dbgs() << "RuntimeDyldChecker: '" << CheckExpr << "' " + << (Result ? "passed" : "FAILED") << ".\n"); + return Result; +} + +bool RuntimeDyldCheckerImpl::checkAllRulesInBuffer(StringRef RulePrefix, + MemoryBuffer *MemBuf) const { + bool DidAllTestsPass = true; + unsigned NumRules = 0; + + std::string CheckExpr; + const char *LineStart = MemBuf->getBufferStart(); + + // Eat whitespace. + while (LineStart != MemBuf->getBufferEnd() && isSpace(*LineStart)) + ++LineStart; + + while (LineStart != MemBuf->getBufferEnd() && *LineStart != '\0') { + const char *LineEnd = LineStart; + while (LineEnd != MemBuf->getBufferEnd() && *LineEnd != '\r' && + *LineEnd != '\n') + ++LineEnd; + + StringRef Line(LineStart, LineEnd - LineStart); + if (Line.startswith(RulePrefix)) + CheckExpr += Line.substr(RulePrefix.size()).str(); + + // If there's a check expr string... + if (!CheckExpr.empty()) { + // ... and it's complete then run it, otherwise remove the trailer '\'. + if (CheckExpr.back() != '\\') { + DidAllTestsPass &= check(CheckExpr); + CheckExpr.clear(); + ++NumRules; + } else + CheckExpr.pop_back(); + } + + // Eat whitespace. + LineStart = LineEnd; + while (LineStart != MemBuf->getBufferEnd() && isSpace(*LineStart)) + ++LineStart; + } + return DidAllTestsPass && (NumRules != 0); +} + +bool RuntimeDyldCheckerImpl::isSymbolValid(StringRef Symbol) const { + return IsSymbolValid(Symbol); +} + +uint64_t RuntimeDyldCheckerImpl::getSymbolLocalAddr(StringRef Symbol) const { + auto SymInfo = GetSymbolInfo(Symbol); + if (!SymInfo) { + logAllUnhandledErrors(SymInfo.takeError(), errs(), "RTDyldChecker: "); + return 0; + } + + if (SymInfo->isZeroFill()) + return 0; + + return static_cast<uint64_t>( + reinterpret_cast<uintptr_t>(SymInfo->getContent().data())); +} + +uint64_t RuntimeDyldCheckerImpl::getSymbolRemoteAddr(StringRef Symbol) const { + auto SymInfo = GetSymbolInfo(Symbol); + if (!SymInfo) { + logAllUnhandledErrors(SymInfo.takeError(), errs(), "RTDyldChecker: "); + return 0; + } + + return SymInfo->getTargetAddress(); +} + +uint64_t RuntimeDyldCheckerImpl::readMemoryAtAddr(uint64_t SrcAddr, + unsigned Size) const { + uintptr_t PtrSizedAddr = static_cast<uintptr_t>(SrcAddr); + assert(PtrSizedAddr == SrcAddr && "Linker memory pointer out-of-range."); + void *Ptr = reinterpret_cast<void*>(PtrSizedAddr); + + switch (Size) { + case 1: + return support::endian::read<uint8_t>(Ptr, Endianness); + case 2: + return support::endian::read<uint16_t>(Ptr, Endianness); + case 4: + return support::endian::read<uint32_t>(Ptr, Endianness); + case 8: + return support::endian::read<uint64_t>(Ptr, Endianness); + } + llvm_unreachable("Unsupported read size"); +} + +StringRef RuntimeDyldCheckerImpl::getSymbolContent(StringRef Symbol) const { + auto SymInfo = GetSymbolInfo(Symbol); + if (!SymInfo) { + logAllUnhandledErrors(SymInfo.takeError(), errs(), "RTDyldChecker: "); + return StringRef(); + } + return SymInfo->getContent(); +} + +std::pair<uint64_t, std::string> RuntimeDyldCheckerImpl::getSectionAddr( + StringRef FileName, StringRef SectionName, bool IsInsideLoad) const { + + auto SecInfo = GetSectionInfo(FileName, SectionName); + if (!SecInfo) { + std::string ErrMsg; + { + raw_string_ostream ErrMsgStream(ErrMsg); + logAllUnhandledErrors(SecInfo.takeError(), ErrMsgStream, + "RTDyldChecker: "); + } + return std::make_pair(0, std::move(ErrMsg)); + } + + // If this address is being looked up in "load" mode, return the content + // pointer, otherwise return the target address. + + uint64_t Addr = 0; + + if (IsInsideLoad) { + if (SecInfo->isZeroFill()) + Addr = 0; + else + Addr = pointerToJITTargetAddress(SecInfo->getContent().data()); + } else + Addr = SecInfo->getTargetAddress(); + + return std::make_pair(Addr, ""); +} + +std::pair<uint64_t, std::string> RuntimeDyldCheckerImpl::getStubOrGOTAddrFor( + StringRef StubContainerName, StringRef SymbolName, bool IsInsideLoad, + bool IsStubAddr) const { + + auto StubInfo = IsStubAddr ? GetStubInfo(StubContainerName, SymbolName) + : GetGOTInfo(StubContainerName, SymbolName); + + if (!StubInfo) { + std::string ErrMsg; + { + raw_string_ostream ErrMsgStream(ErrMsg); + logAllUnhandledErrors(StubInfo.takeError(), ErrMsgStream, + "RTDyldChecker: "); + } + return std::make_pair((uint64_t)0, std::move(ErrMsg)); + } + + uint64_t Addr = 0; + + if (IsInsideLoad) { + if (StubInfo->isZeroFill()) + return std::make_pair((uint64_t)0, "Detected zero-filled stub/GOT entry"); + Addr = pointerToJITTargetAddress(StubInfo->getContent().data()); + } else + Addr = StubInfo->getTargetAddress(); + + return std::make_pair(Addr, ""); +} + +RuntimeDyldChecker::RuntimeDyldChecker( + IsSymbolValidFunction IsSymbolValid, GetSymbolInfoFunction GetSymbolInfo, + GetSectionInfoFunction GetSectionInfo, GetStubInfoFunction GetStubInfo, + GetGOTInfoFunction GetGOTInfo, support::endianness Endianness, + MCDisassembler *Disassembler, MCInstPrinter *InstPrinter, + raw_ostream &ErrStream) + : Impl(::std::make_unique<RuntimeDyldCheckerImpl>( + std::move(IsSymbolValid), std::move(GetSymbolInfo), + std::move(GetSectionInfo), std::move(GetStubInfo), + std::move(GetGOTInfo), Endianness, Disassembler, InstPrinter, + ErrStream)) {} + +RuntimeDyldChecker::~RuntimeDyldChecker() {} + +bool RuntimeDyldChecker::check(StringRef CheckExpr) const { + return Impl->check(CheckExpr); +} + +bool RuntimeDyldChecker::checkAllRulesInBuffer(StringRef RulePrefix, + MemoryBuffer *MemBuf) const { + return Impl->checkAllRulesInBuffer(RulePrefix, MemBuf); +} + +std::pair<uint64_t, std::string> +RuntimeDyldChecker::getSectionAddr(StringRef FileName, StringRef SectionName, + bool LocalAddress) { + return Impl->getSectionAddr(FileName, SectionName, LocalAddress); +} diff --git a/contrib/libs/llvm12/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldCheckerImpl.h b/contrib/libs/llvm12/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldCheckerImpl.h index c23557c06e..ac9d4d4602 100644 --- a/contrib/libs/llvm12/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldCheckerImpl.h +++ b/contrib/libs/llvm12/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldCheckerImpl.h @@ -1,74 +1,74 @@ -//===-- RuntimeDyldCheckerImpl.h -- RuntimeDyld test framework --*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_RUNTIMEDYLDCHECKERIMPL_H -#define LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_RUNTIMEDYLDCHECKERIMPL_H - -#include "RuntimeDyldImpl.h" - -namespace llvm { - -class RuntimeDyldCheckerImpl { - friend class RuntimeDyldChecker; - friend class RuntimeDyldCheckerExprEval; - - using IsSymbolValidFunction = - RuntimeDyldChecker::IsSymbolValidFunction; - using GetSymbolInfoFunction = RuntimeDyldChecker::GetSymbolInfoFunction; - using GetSectionInfoFunction = RuntimeDyldChecker::GetSectionInfoFunction; - using GetStubInfoFunction = RuntimeDyldChecker::GetStubInfoFunction; - using GetGOTInfoFunction = RuntimeDyldChecker::GetGOTInfoFunction; - -public: - RuntimeDyldCheckerImpl( - IsSymbolValidFunction IsSymbolValid, GetSymbolInfoFunction GetSymbolInfo, - GetSectionInfoFunction GetSectionInfo, GetStubInfoFunction GetStubInfo, - GetGOTInfoFunction GetGOTInfo, support::endianness Endianness, - MCDisassembler *Disassembler, MCInstPrinter *InstPrinter, - llvm::raw_ostream &ErrStream); - - bool check(StringRef CheckExpr) const; - bool checkAllRulesInBuffer(StringRef RulePrefix, MemoryBuffer *MemBuf) const; - -private: - - // StubMap typedefs. - - Expected<JITSymbolResolver::LookupResult> - lookup(const JITSymbolResolver::LookupSet &Symbols) const; - - bool isSymbolValid(StringRef Symbol) const; - uint64_t getSymbolLocalAddr(StringRef Symbol) const; - uint64_t getSymbolRemoteAddr(StringRef Symbol) const; - uint64_t readMemoryAtAddr(uint64_t Addr, unsigned Size) const; - - StringRef getSymbolContent(StringRef Symbol) const; - - std::pair<uint64_t, std::string> getSectionAddr(StringRef FileName, - StringRef SectionName, - bool IsInsideLoad) const; - - std::pair<uint64_t, std::string> - getStubOrGOTAddrFor(StringRef StubContainerName, StringRef Symbol, - bool IsInsideLoad, bool IsStubAddr) const; - - Optional<uint64_t> getSectionLoadAddress(void *LocalAddr) const; - - IsSymbolValidFunction IsSymbolValid; - GetSymbolInfoFunction GetSymbolInfo; - GetSectionInfoFunction GetSectionInfo; - GetStubInfoFunction GetStubInfo; - GetGOTInfoFunction GetGOTInfo; - support::endianness Endianness; - MCDisassembler *Disassembler; - MCInstPrinter *InstPrinter; - llvm::raw_ostream &ErrStream; -}; -} - -#endif +//===-- RuntimeDyldCheckerImpl.h -- RuntimeDyld test framework --*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_RUNTIMEDYLDCHECKERIMPL_H +#define LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_RUNTIMEDYLDCHECKERIMPL_H + +#include "RuntimeDyldImpl.h" + +namespace llvm { + +class RuntimeDyldCheckerImpl { + friend class RuntimeDyldChecker; + friend class RuntimeDyldCheckerExprEval; + + using IsSymbolValidFunction = + RuntimeDyldChecker::IsSymbolValidFunction; + using GetSymbolInfoFunction = RuntimeDyldChecker::GetSymbolInfoFunction; + using GetSectionInfoFunction = RuntimeDyldChecker::GetSectionInfoFunction; + using GetStubInfoFunction = RuntimeDyldChecker::GetStubInfoFunction; + using GetGOTInfoFunction = RuntimeDyldChecker::GetGOTInfoFunction; + +public: + RuntimeDyldCheckerImpl( + IsSymbolValidFunction IsSymbolValid, GetSymbolInfoFunction GetSymbolInfo, + GetSectionInfoFunction GetSectionInfo, GetStubInfoFunction GetStubInfo, + GetGOTInfoFunction GetGOTInfo, support::endianness Endianness, + MCDisassembler *Disassembler, MCInstPrinter *InstPrinter, + llvm::raw_ostream &ErrStream); + + bool check(StringRef CheckExpr) const; + bool checkAllRulesInBuffer(StringRef RulePrefix, MemoryBuffer *MemBuf) const; + +private: + + // StubMap typedefs. + + Expected<JITSymbolResolver::LookupResult> + lookup(const JITSymbolResolver::LookupSet &Symbols) const; + + bool isSymbolValid(StringRef Symbol) const; + uint64_t getSymbolLocalAddr(StringRef Symbol) const; + uint64_t getSymbolRemoteAddr(StringRef Symbol) const; + uint64_t readMemoryAtAddr(uint64_t Addr, unsigned Size) const; + + StringRef getSymbolContent(StringRef Symbol) const; + + std::pair<uint64_t, std::string> getSectionAddr(StringRef FileName, + StringRef SectionName, + bool IsInsideLoad) const; + + std::pair<uint64_t, std::string> + getStubOrGOTAddrFor(StringRef StubContainerName, StringRef Symbol, + bool IsInsideLoad, bool IsStubAddr) const; + + Optional<uint64_t> getSectionLoadAddress(void *LocalAddr) const; + + IsSymbolValidFunction IsSymbolValid; + GetSymbolInfoFunction GetSymbolInfo; + GetSectionInfoFunction GetSectionInfo; + GetStubInfoFunction GetStubInfo; + GetGOTInfoFunction GetGOTInfo; + support::endianness Endianness; + MCDisassembler *Disassembler; + MCInstPrinter *InstPrinter; + llvm::raw_ostream &ErrStream; +}; +} + +#endif diff --git a/contrib/libs/llvm12/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp b/contrib/libs/llvm12/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp index b63f378692..28e1faab5a 100644 --- a/contrib/libs/llvm12/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp +++ b/contrib/libs/llvm12/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp @@ -1,1964 +1,1964 @@ -//===-- RuntimeDyldELF.cpp - Run-time dynamic linker for MC-JIT -*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// Implementation of ELF support for the MC-JIT runtime dynamic linker. -// -//===----------------------------------------------------------------------===// - -#include "RuntimeDyldELF.h" -#include "RuntimeDyldCheckerImpl.h" -#include "Targets/RuntimeDyldELFMips.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/ADT/Triple.h" -#include "llvm/BinaryFormat/ELF.h" -#include "llvm/Object/ELFObjectFile.h" -#include "llvm/Object/ObjectFile.h" -#include "llvm/Support/Endian.h" -#include "llvm/Support/MemoryBuffer.h" - -using namespace llvm; -using namespace llvm::object; -using namespace llvm::support::endian; - -#define DEBUG_TYPE "dyld" - -static void or32le(void *P, int32_t V) { write32le(P, read32le(P) | V); } - -static void or32AArch64Imm(void *L, uint64_t Imm) { - or32le(L, (Imm & 0xFFF) << 10); -} - -template <class T> static void write(bool isBE, void *P, T V) { - isBE ? write<T, support::big>(P, V) : write<T, support::little>(P, V); -} - -static void write32AArch64Addr(void *L, uint64_t Imm) { - uint32_t ImmLo = (Imm & 0x3) << 29; - uint32_t ImmHi = (Imm & 0x1FFFFC) << 3; - uint64_t Mask = (0x3 << 29) | (0x1FFFFC << 3); - write32le(L, (read32le(L) & ~Mask) | ImmLo | ImmHi); -} - -// Return the bits [Start, End] from Val shifted Start bits. -// For instance, getBits(0xF0, 4, 8) returns 0xF. -static uint64_t getBits(uint64_t Val, int Start, int End) { - uint64_t Mask = ((uint64_t)1 << (End + 1 - Start)) - 1; - return (Val >> Start) & Mask; -} - -namespace { - -template <class ELFT> class DyldELFObject : public ELFObjectFile<ELFT> { - LLVM_ELF_IMPORT_TYPES_ELFT(ELFT) - - typedef typename ELFT::uint addr_type; - - DyldELFObject(ELFObjectFile<ELFT> &&Obj); - -public: - static Expected<std::unique_ptr<DyldELFObject>> - create(MemoryBufferRef Wrapper); - - void updateSectionAddress(const SectionRef &Sec, uint64_t Addr); - - void updateSymbolAddress(const SymbolRef &SymRef, uint64_t Addr); - - // Methods for type inquiry through isa, cast and dyn_cast - static bool classof(const Binary *v) { - return (isa<ELFObjectFile<ELFT>>(v) && - classof(cast<ELFObjectFile<ELFT>>(v))); - } - static bool classof(const ELFObjectFile<ELFT> *v) { - return v->isDyldType(); - } -}; - - - -// The MemoryBuffer passed into this constructor is just a wrapper around the -// actual memory. Ultimately, the Binary parent class will take ownership of -// this MemoryBuffer object but not the underlying memory. -template <class ELFT> -DyldELFObject<ELFT>::DyldELFObject(ELFObjectFile<ELFT> &&Obj) - : ELFObjectFile<ELFT>(std::move(Obj)) { - this->isDyldELFObject = true; -} - -template <class ELFT> -Expected<std::unique_ptr<DyldELFObject<ELFT>>> -DyldELFObject<ELFT>::create(MemoryBufferRef Wrapper) { - auto Obj = ELFObjectFile<ELFT>::create(Wrapper); - if (auto E = Obj.takeError()) - return std::move(E); - std::unique_ptr<DyldELFObject<ELFT>> Ret( - new DyldELFObject<ELFT>(std::move(*Obj))); - return std::move(Ret); -} - -template <class ELFT> -void DyldELFObject<ELFT>::updateSectionAddress(const SectionRef &Sec, - uint64_t Addr) { - DataRefImpl ShdrRef = Sec.getRawDataRefImpl(); - Elf_Shdr *shdr = - const_cast<Elf_Shdr *>(reinterpret_cast<const Elf_Shdr *>(ShdrRef.p)); - - // This assumes the address passed in matches the target address bitness - // The template-based type cast handles everything else. - shdr->sh_addr = static_cast<addr_type>(Addr); -} - -template <class ELFT> -void DyldELFObject<ELFT>::updateSymbolAddress(const SymbolRef &SymRef, - uint64_t Addr) { - - Elf_Sym *sym = const_cast<Elf_Sym *>( - ELFObjectFile<ELFT>::getSymbol(SymRef.getRawDataRefImpl())); - - // This assumes the address passed in matches the target address bitness - // The template-based type cast handles everything else. - sym->st_value = static_cast<addr_type>(Addr); -} - -class LoadedELFObjectInfo final - : public LoadedObjectInfoHelper<LoadedELFObjectInfo, - RuntimeDyld::LoadedObjectInfo> { -public: - LoadedELFObjectInfo(RuntimeDyldImpl &RTDyld, ObjSectionToIDMap ObjSecToIDMap) - : LoadedObjectInfoHelper(RTDyld, std::move(ObjSecToIDMap)) {} - - OwningBinary<ObjectFile> - getObjectForDebug(const ObjectFile &Obj) const override; -}; - -template <typename ELFT> -static Expected<std::unique_ptr<DyldELFObject<ELFT>>> -createRTDyldELFObject(MemoryBufferRef Buffer, const ObjectFile &SourceObject, - const LoadedELFObjectInfo &L) { - typedef typename ELFT::Shdr Elf_Shdr; - typedef typename ELFT::uint addr_type; - - Expected<std::unique_ptr<DyldELFObject<ELFT>>> ObjOrErr = - DyldELFObject<ELFT>::create(Buffer); - if (Error E = ObjOrErr.takeError()) - return std::move(E); - - std::unique_ptr<DyldELFObject<ELFT>> Obj = std::move(*ObjOrErr); - - // Iterate over all sections in the object. - auto SI = SourceObject.section_begin(); - for (const auto &Sec : Obj->sections()) { - Expected<StringRef> NameOrErr = Sec.getName(); - if (!NameOrErr) { - consumeError(NameOrErr.takeError()); - continue; - } - - if (*NameOrErr != "") { - DataRefImpl ShdrRef = Sec.getRawDataRefImpl(); - Elf_Shdr *shdr = const_cast<Elf_Shdr *>( - reinterpret_cast<const Elf_Shdr *>(ShdrRef.p)); - - if (uint64_t SecLoadAddr = L.getSectionLoadAddress(*SI)) { - // This assumes that the address passed in matches the target address - // bitness. The template-based type cast handles everything else. - shdr->sh_addr = static_cast<addr_type>(SecLoadAddr); - } - } - ++SI; - } - - return std::move(Obj); -} - -static OwningBinary<ObjectFile> -createELFDebugObject(const ObjectFile &Obj, const LoadedELFObjectInfo &L) { - assert(Obj.isELF() && "Not an ELF object file."); - - std::unique_ptr<MemoryBuffer> Buffer = - MemoryBuffer::getMemBufferCopy(Obj.getData(), Obj.getFileName()); - - Expected<std::unique_ptr<ObjectFile>> DebugObj(nullptr); - handleAllErrors(DebugObj.takeError()); - if (Obj.getBytesInAddress() == 4 && Obj.isLittleEndian()) - DebugObj = - createRTDyldELFObject<ELF32LE>(Buffer->getMemBufferRef(), Obj, L); - else if (Obj.getBytesInAddress() == 4 && !Obj.isLittleEndian()) - DebugObj = - createRTDyldELFObject<ELF32BE>(Buffer->getMemBufferRef(), Obj, L); - else if (Obj.getBytesInAddress() == 8 && !Obj.isLittleEndian()) - DebugObj = - createRTDyldELFObject<ELF64BE>(Buffer->getMemBufferRef(), Obj, L); - else if (Obj.getBytesInAddress() == 8 && Obj.isLittleEndian()) - DebugObj = - createRTDyldELFObject<ELF64LE>(Buffer->getMemBufferRef(), Obj, L); - else - llvm_unreachable("Unexpected ELF format"); - - handleAllErrors(DebugObj.takeError()); - return OwningBinary<ObjectFile>(std::move(*DebugObj), std::move(Buffer)); -} - -OwningBinary<ObjectFile> -LoadedELFObjectInfo::getObjectForDebug(const ObjectFile &Obj) const { - return createELFDebugObject(Obj, *this); -} - -} // anonymous namespace - -namespace llvm { - -RuntimeDyldELF::RuntimeDyldELF(RuntimeDyld::MemoryManager &MemMgr, - JITSymbolResolver &Resolver) - : RuntimeDyldImpl(MemMgr, Resolver), GOTSectionID(0), CurrentGOTIndex(0) {} -RuntimeDyldELF::~RuntimeDyldELF() {} - -void RuntimeDyldELF::registerEHFrames() { - for (int i = 0, e = UnregisteredEHFrameSections.size(); i != e; ++i) { - SID EHFrameSID = UnregisteredEHFrameSections[i]; - uint8_t *EHFrameAddr = Sections[EHFrameSID].getAddress(); - uint64_t EHFrameLoadAddr = Sections[EHFrameSID].getLoadAddress(); - size_t EHFrameSize = Sections[EHFrameSID].getSize(); - MemMgr.registerEHFrames(EHFrameAddr, EHFrameLoadAddr, EHFrameSize); - } - UnregisteredEHFrameSections.clear(); -} - -std::unique_ptr<RuntimeDyldELF> -llvm::RuntimeDyldELF::create(Triple::ArchType Arch, - RuntimeDyld::MemoryManager &MemMgr, - JITSymbolResolver &Resolver) { - switch (Arch) { - default: - return std::make_unique<RuntimeDyldELF>(MemMgr, Resolver); - case Triple::mips: - case Triple::mipsel: - case Triple::mips64: - case Triple::mips64el: - return std::make_unique<RuntimeDyldELFMips>(MemMgr, Resolver); - } -} - -std::unique_ptr<RuntimeDyld::LoadedObjectInfo> -RuntimeDyldELF::loadObject(const object::ObjectFile &O) { - if (auto ObjSectionToIDOrErr = loadObjectImpl(O)) - return std::make_unique<LoadedELFObjectInfo>(*this, *ObjSectionToIDOrErr); - else { - HasError = true; - raw_string_ostream ErrStream(ErrorStr); - logAllUnhandledErrors(ObjSectionToIDOrErr.takeError(), ErrStream); - return nullptr; - } -} - -void RuntimeDyldELF::resolveX86_64Relocation(const SectionEntry &Section, - uint64_t Offset, uint64_t Value, - uint32_t Type, int64_t Addend, - uint64_t SymOffset) { - switch (Type) { - default: - report_fatal_error("Relocation type not implemented yet!"); - break; - case ELF::R_X86_64_NONE: - break; - case ELF::R_X86_64_64: { - support::ulittle64_t::ref(Section.getAddressWithOffset(Offset)) = - Value + Addend; - LLVM_DEBUG(dbgs() << "Writing " << format("%p", (Value + Addend)) << " at " - << format("%p\n", Section.getAddressWithOffset(Offset))); - break; - } - case ELF::R_X86_64_32: - case ELF::R_X86_64_32S: { - Value += Addend; - assert((Type == ELF::R_X86_64_32 && (Value <= UINT32_MAX)) || - (Type == ELF::R_X86_64_32S && - ((int64_t)Value <= INT32_MAX && (int64_t)Value >= INT32_MIN))); - uint32_t TruncatedAddr = (Value & 0xFFFFFFFF); - support::ulittle32_t::ref(Section.getAddressWithOffset(Offset)) = - TruncatedAddr; - LLVM_DEBUG(dbgs() << "Writing " << format("%p", TruncatedAddr) << " at " - << format("%p\n", Section.getAddressWithOffset(Offset))); - break; - } - case ELF::R_X86_64_PC8: { - uint64_t FinalAddress = Section.getLoadAddressWithOffset(Offset); - int64_t RealOffset = Value + Addend - FinalAddress; - assert(isInt<8>(RealOffset)); - int8_t TruncOffset = (RealOffset & 0xFF); - Section.getAddress()[Offset] = TruncOffset; - break; - } - case ELF::R_X86_64_PC32: { - uint64_t FinalAddress = Section.getLoadAddressWithOffset(Offset); - int64_t RealOffset = Value + Addend - FinalAddress; - assert(isInt<32>(RealOffset)); - int32_t TruncOffset = (RealOffset & 0xFFFFFFFF); - support::ulittle32_t::ref(Section.getAddressWithOffset(Offset)) = - TruncOffset; - break; - } - case ELF::R_X86_64_PC64: { - uint64_t FinalAddress = Section.getLoadAddressWithOffset(Offset); - int64_t RealOffset = Value + Addend - FinalAddress; - support::ulittle64_t::ref(Section.getAddressWithOffset(Offset)) = - RealOffset; - LLVM_DEBUG(dbgs() << "Writing " << format("%p", RealOffset) << " at " - << format("%p\n", FinalAddress)); - break; - } - case ELF::R_X86_64_GOTOFF64: { - // Compute Value - GOTBase. - uint64_t GOTBase = 0; - for (const auto &Section : Sections) { - if (Section.getName() == ".got") { - GOTBase = Section.getLoadAddressWithOffset(0); - break; - } - } - assert(GOTBase != 0 && "missing GOT"); - int64_t GOTOffset = Value - GOTBase + Addend; - support::ulittle64_t::ref(Section.getAddressWithOffset(Offset)) = GOTOffset; - break; - } - } -} - -void RuntimeDyldELF::resolveX86Relocation(const SectionEntry &Section, - uint64_t Offset, uint32_t Value, - uint32_t Type, int32_t Addend) { - switch (Type) { - case ELF::R_386_32: { - support::ulittle32_t::ref(Section.getAddressWithOffset(Offset)) = - Value + Addend; - break; - } - // Handle R_386_PLT32 like R_386_PC32 since it should be able to - // reach any 32 bit address. - case ELF::R_386_PLT32: - case ELF::R_386_PC32: { - uint32_t FinalAddress = - Section.getLoadAddressWithOffset(Offset) & 0xFFFFFFFF; - uint32_t RealOffset = Value + Addend - FinalAddress; - support::ulittle32_t::ref(Section.getAddressWithOffset(Offset)) = - RealOffset; - break; - } - default: - // There are other relocation types, but it appears these are the - // only ones currently used by the LLVM ELF object writer - report_fatal_error("Relocation type not implemented yet!"); - break; - } -} - -void RuntimeDyldELF::resolveAArch64Relocation(const SectionEntry &Section, - uint64_t Offset, uint64_t Value, - uint32_t Type, int64_t Addend) { - uint32_t *TargetPtr = - reinterpret_cast<uint32_t *>(Section.getAddressWithOffset(Offset)); - uint64_t FinalAddress = Section.getLoadAddressWithOffset(Offset); - // Data should use target endian. Code should always use little endian. - bool isBE = Arch == Triple::aarch64_be; - - LLVM_DEBUG(dbgs() << "resolveAArch64Relocation, LocalAddress: 0x" - << format("%llx", Section.getAddressWithOffset(Offset)) - << " FinalAddress: 0x" << format("%llx", FinalAddress) - << " Value: 0x" << format("%llx", Value) << " Type: 0x" - << format("%x", Type) << " Addend: 0x" - << format("%llx", Addend) << "\n"); - - switch (Type) { - default: - report_fatal_error("Relocation type not implemented yet!"); - break; - case ELF::R_AARCH64_ABS16: { - uint64_t Result = Value + Addend; - assert(static_cast<int64_t>(Result) >= INT16_MIN && Result < UINT16_MAX); - write(isBE, TargetPtr, static_cast<uint16_t>(Result & 0xffffU)); - break; - } - case ELF::R_AARCH64_ABS32: { - uint64_t Result = Value + Addend; - assert(static_cast<int64_t>(Result) >= INT32_MIN && Result < UINT32_MAX); - write(isBE, TargetPtr, static_cast<uint32_t>(Result & 0xffffffffU)); - break; - } - case ELF::R_AARCH64_ABS64: - write(isBE, TargetPtr, Value + Addend); - break; - case ELF::R_AARCH64_PLT32: { - uint64_t Result = Value + Addend - FinalAddress; - assert(static_cast<int64_t>(Result) >= INT32_MIN && - static_cast<int64_t>(Result) <= INT32_MAX); - write(isBE, TargetPtr, static_cast<uint32_t>(Result)); - break; - } - case ELF::R_AARCH64_PREL32: { - uint64_t Result = Value + Addend - FinalAddress; - assert(static_cast<int64_t>(Result) >= INT32_MIN && - static_cast<int64_t>(Result) <= UINT32_MAX); - write(isBE, TargetPtr, static_cast<uint32_t>(Result & 0xffffffffU)); - break; - } - case ELF::R_AARCH64_PREL64: - write(isBE, TargetPtr, Value + Addend - FinalAddress); - break; - case ELF::R_AARCH64_CALL26: // fallthrough - case ELF::R_AARCH64_JUMP26: { - // Operation: S+A-P. Set Call or B immediate value to bits fff_fffc of the - // calculation. - uint64_t BranchImm = Value + Addend - FinalAddress; - - // "Check that -2^27 <= result < 2^27". - assert(isInt<28>(BranchImm)); - or32le(TargetPtr, (BranchImm & 0x0FFFFFFC) >> 2); - break; - } - case ELF::R_AARCH64_MOVW_UABS_G3: - or32le(TargetPtr, ((Value + Addend) & 0xFFFF000000000000) >> 43); - break; - case ELF::R_AARCH64_MOVW_UABS_G2_NC: - or32le(TargetPtr, ((Value + Addend) & 0xFFFF00000000) >> 27); - break; - case ELF::R_AARCH64_MOVW_UABS_G1_NC: - or32le(TargetPtr, ((Value + Addend) & 0xFFFF0000) >> 11); - break; - case ELF::R_AARCH64_MOVW_UABS_G0_NC: - or32le(TargetPtr, ((Value + Addend) & 0xFFFF) << 5); - break; - case ELF::R_AARCH64_ADR_PREL_PG_HI21: { - // Operation: Page(S+A) - Page(P) - uint64_t Result = - ((Value + Addend) & ~0xfffULL) - (FinalAddress & ~0xfffULL); - - // Check that -2^32 <= X < 2^32 - assert(isInt<33>(Result) && "overflow check failed for relocation"); - - // Immediate goes in bits 30:29 + 5:23 of ADRP instruction, taken - // from bits 32:12 of X. - write32AArch64Addr(TargetPtr, Result >> 12); - break; - } - case ELF::R_AARCH64_ADD_ABS_LO12_NC: - // Operation: S + A - // Immediate goes in bits 21:10 of LD/ST instruction, taken - // from bits 11:0 of X - or32AArch64Imm(TargetPtr, Value + Addend); - break; - case ELF::R_AARCH64_LDST8_ABS_LO12_NC: - // Operation: S + A - // Immediate goes in bits 21:10 of LD/ST instruction, taken - // from bits 11:0 of X - or32AArch64Imm(TargetPtr, getBits(Value + Addend, 0, 11)); - break; - case ELF::R_AARCH64_LDST16_ABS_LO12_NC: - // Operation: S + A - // Immediate goes in bits 21:10 of LD/ST instruction, taken - // from bits 11:1 of X - or32AArch64Imm(TargetPtr, getBits(Value + Addend, 1, 11)); - break; - case ELF::R_AARCH64_LDST32_ABS_LO12_NC: - // Operation: S + A - // Immediate goes in bits 21:10 of LD/ST instruction, taken - // from bits 11:2 of X - or32AArch64Imm(TargetPtr, getBits(Value + Addend, 2, 11)); - break; - case ELF::R_AARCH64_LDST64_ABS_LO12_NC: - // Operation: S + A - // Immediate goes in bits 21:10 of LD/ST instruction, taken - // from bits 11:3 of X - or32AArch64Imm(TargetPtr, getBits(Value + Addend, 3, 11)); - break; - case ELF::R_AARCH64_LDST128_ABS_LO12_NC: - // Operation: S + A - // Immediate goes in bits 21:10 of LD/ST instruction, taken - // from bits 11:4 of X - or32AArch64Imm(TargetPtr, getBits(Value + Addend, 4, 11)); - break; - } -} - -void RuntimeDyldELF::resolveARMRelocation(const SectionEntry &Section, - uint64_t Offset, uint32_t Value, - uint32_t Type, int32_t Addend) { - // TODO: Add Thumb relocations. - uint32_t *TargetPtr = - reinterpret_cast<uint32_t *>(Section.getAddressWithOffset(Offset)); - uint32_t FinalAddress = Section.getLoadAddressWithOffset(Offset) & 0xFFFFFFFF; - Value += Addend; - - LLVM_DEBUG(dbgs() << "resolveARMRelocation, LocalAddress: " - << Section.getAddressWithOffset(Offset) - << " FinalAddress: " << format("%p", FinalAddress) - << " Value: " << format("%x", Value) - << " Type: " << format("%x", Type) - << " Addend: " << format("%x", Addend) << "\n"); - - switch (Type) { - default: - llvm_unreachable("Not implemented relocation type!"); - - case ELF::R_ARM_NONE: - break; - // Write a 31bit signed offset - case ELF::R_ARM_PREL31: - support::ulittle32_t::ref{TargetPtr} = - (support::ulittle32_t::ref{TargetPtr} & 0x80000000) | - ((Value - FinalAddress) & ~0x80000000); - break; - case ELF::R_ARM_TARGET1: - case ELF::R_ARM_ABS32: - support::ulittle32_t::ref{TargetPtr} = Value; - break; - // Write first 16 bit of 32 bit value to the mov instruction. - // Last 4 bit should be shifted. - case ELF::R_ARM_MOVW_ABS_NC: - case ELF::R_ARM_MOVT_ABS: - if (Type == ELF::R_ARM_MOVW_ABS_NC) - Value = Value & 0xFFFF; - else if (Type == ELF::R_ARM_MOVT_ABS) - Value = (Value >> 16) & 0xFFFF; - support::ulittle32_t::ref{TargetPtr} = - (support::ulittle32_t::ref{TargetPtr} & ~0x000F0FFF) | (Value & 0xFFF) | - (((Value >> 12) & 0xF) << 16); - break; - // Write 24 bit relative value to the branch instruction. - case ELF::R_ARM_PC24: // Fall through. - case ELF::R_ARM_CALL: // Fall through. - case ELF::R_ARM_JUMP24: - int32_t RelValue = static_cast<int32_t>(Value - FinalAddress - 8); - RelValue = (RelValue & 0x03FFFFFC) >> 2; - assert((support::ulittle32_t::ref{TargetPtr} & 0xFFFFFF) == 0xFFFFFE); - support::ulittle32_t::ref{TargetPtr} = - (support::ulittle32_t::ref{TargetPtr} & 0xFF000000) | RelValue; - break; - } -} - -void RuntimeDyldELF::setMipsABI(const ObjectFile &Obj) { - if (Arch == Triple::UnknownArch || - !StringRef(Triple::getArchTypePrefix(Arch)).equals("mips")) { - IsMipsO32ABI = false; - IsMipsN32ABI = false; - IsMipsN64ABI = false; - return; - } - if (auto *E = dyn_cast<ELFObjectFileBase>(&Obj)) { - unsigned AbiVariant = E->getPlatformFlags(); - IsMipsO32ABI = AbiVariant & ELF::EF_MIPS_ABI_O32; - IsMipsN32ABI = AbiVariant & ELF::EF_MIPS_ABI2; - } - IsMipsN64ABI = Obj.getFileFormatName().equals("elf64-mips"); -} - -// Return the .TOC. section and offset. -Error RuntimeDyldELF::findPPC64TOCSection(const ELFObjectFileBase &Obj, - ObjSectionToIDMap &LocalSections, - RelocationValueRef &Rel) { - // Set a default SectionID in case we do not find a TOC section below. - // This may happen for references to TOC base base (sym@toc, .odp - // relocation) without a .toc directive. In this case just use the - // first section (which is usually the .odp) since the code won't - // reference the .toc base directly. - Rel.SymbolName = nullptr; - Rel.SectionID = 0; - - // The TOC consists of sections .got, .toc, .tocbss, .plt in that - // order. The TOC starts where the first of these sections starts. - for (auto &Section : Obj.sections()) { - Expected<StringRef> NameOrErr = Section.getName(); - if (!NameOrErr) - return NameOrErr.takeError(); - StringRef SectionName = *NameOrErr; - - if (SectionName == ".got" - || SectionName == ".toc" - || SectionName == ".tocbss" - || SectionName == ".plt") { - if (auto SectionIDOrErr = - findOrEmitSection(Obj, Section, false, LocalSections)) - Rel.SectionID = *SectionIDOrErr; - else - return SectionIDOrErr.takeError(); - break; - } - } - - // Per the ppc64-elf-linux ABI, The TOC base is TOC value plus 0x8000 - // thus permitting a full 64 Kbytes segment. - Rel.Addend = 0x8000; - - return Error::success(); -} - -// Returns the sections and offset associated with the ODP entry referenced -// by Symbol. -Error RuntimeDyldELF::findOPDEntrySection(const ELFObjectFileBase &Obj, - ObjSectionToIDMap &LocalSections, - RelocationValueRef &Rel) { - // Get the ELF symbol value (st_value) to compare with Relocation offset in - // .opd entries - for (section_iterator si = Obj.section_begin(), se = Obj.section_end(); - si != se; ++si) { - - Expected<section_iterator> RelSecOrErr = si->getRelocatedSection(); - if (!RelSecOrErr) - report_fatal_error(toString(RelSecOrErr.takeError())); - - section_iterator RelSecI = *RelSecOrErr; - if (RelSecI == Obj.section_end()) - continue; - - Expected<StringRef> NameOrErr = RelSecI->getName(); - if (!NameOrErr) - return NameOrErr.takeError(); - StringRef RelSectionName = *NameOrErr; - - if (RelSectionName != ".opd") - continue; - - for (elf_relocation_iterator i = si->relocation_begin(), - e = si->relocation_end(); - i != e;) { - // The R_PPC64_ADDR64 relocation indicates the first field - // of a .opd entry - uint64_t TypeFunc = i->getType(); - if (TypeFunc != ELF::R_PPC64_ADDR64) { - ++i; - continue; - } - - uint64_t TargetSymbolOffset = i->getOffset(); - symbol_iterator TargetSymbol = i->getSymbol(); - int64_t Addend; - if (auto AddendOrErr = i->getAddend()) - Addend = *AddendOrErr; - else - return AddendOrErr.takeError(); - - ++i; - if (i == e) - break; - - // Just check if following relocation is a R_PPC64_TOC - uint64_t TypeTOC = i->getType(); - if (TypeTOC != ELF::R_PPC64_TOC) - continue; - - // Finally compares the Symbol value and the target symbol offset - // to check if this .opd entry refers to the symbol the relocation - // points to. - if (Rel.Addend != (int64_t)TargetSymbolOffset) - continue; - - section_iterator TSI = Obj.section_end(); - if (auto TSIOrErr = TargetSymbol->getSection()) - TSI = *TSIOrErr; - else - return TSIOrErr.takeError(); - assert(TSI != Obj.section_end() && "TSI should refer to a valid section"); - - bool IsCode = TSI->isText(); - if (auto SectionIDOrErr = findOrEmitSection(Obj, *TSI, IsCode, - LocalSections)) - Rel.SectionID = *SectionIDOrErr; - else - return SectionIDOrErr.takeError(); - Rel.Addend = (intptr_t)Addend; - return Error::success(); - } - } - llvm_unreachable("Attempting to get address of ODP entry!"); -} - -// Relocation masks following the #lo(value), #hi(value), #ha(value), -// #higher(value), #highera(value), #highest(value), and #highesta(value) -// macros defined in section 4.5.1. Relocation Types of the PPC-elf64abi -// document. - -static inline uint16_t applyPPClo(uint64_t value) { return value & 0xffff; } - -static inline uint16_t applyPPChi(uint64_t value) { - return (value >> 16) & 0xffff; -} - -static inline uint16_t applyPPCha (uint64_t value) { - return ((value + 0x8000) >> 16) & 0xffff; -} - -static inline uint16_t applyPPChigher(uint64_t value) { - return (value >> 32) & 0xffff; -} - -static inline uint16_t applyPPChighera (uint64_t value) { - return ((value + 0x8000) >> 32) & 0xffff; -} - -static inline uint16_t applyPPChighest(uint64_t value) { - return (value >> 48) & 0xffff; -} - -static inline uint16_t applyPPChighesta (uint64_t value) { - return ((value + 0x8000) >> 48) & 0xffff; -} - -void RuntimeDyldELF::resolvePPC32Relocation(const SectionEntry &Section, - uint64_t Offset, uint64_t Value, - uint32_t Type, int64_t Addend) { - uint8_t *LocalAddress = Section.getAddressWithOffset(Offset); - switch (Type) { - default: - report_fatal_error("Relocation type not implemented yet!"); - break; - case ELF::R_PPC_ADDR16_LO: - writeInt16BE(LocalAddress, applyPPClo(Value + Addend)); - break; - case ELF::R_PPC_ADDR16_HI: - writeInt16BE(LocalAddress, applyPPChi(Value + Addend)); - break; - case ELF::R_PPC_ADDR16_HA: - writeInt16BE(LocalAddress, applyPPCha(Value + Addend)); - break; - } -} - -void RuntimeDyldELF::resolvePPC64Relocation(const SectionEntry &Section, - uint64_t Offset, uint64_t Value, - uint32_t Type, int64_t Addend) { - uint8_t *LocalAddress = Section.getAddressWithOffset(Offset); - switch (Type) { - default: - report_fatal_error("Relocation type not implemented yet!"); - break; - case ELF::R_PPC64_ADDR16: - writeInt16BE(LocalAddress, applyPPClo(Value + Addend)); - break; - case ELF::R_PPC64_ADDR16_DS: - writeInt16BE(LocalAddress, applyPPClo(Value + Addend) & ~3); - break; - case ELF::R_PPC64_ADDR16_LO: - writeInt16BE(LocalAddress, applyPPClo(Value + Addend)); - break; - case ELF::R_PPC64_ADDR16_LO_DS: - writeInt16BE(LocalAddress, applyPPClo(Value + Addend) & ~3); - break; - case ELF::R_PPC64_ADDR16_HI: - case ELF::R_PPC64_ADDR16_HIGH: - writeInt16BE(LocalAddress, applyPPChi(Value + Addend)); - break; - case ELF::R_PPC64_ADDR16_HA: - case ELF::R_PPC64_ADDR16_HIGHA: - writeInt16BE(LocalAddress, applyPPCha(Value + Addend)); - break; - case ELF::R_PPC64_ADDR16_HIGHER: - writeInt16BE(LocalAddress, applyPPChigher(Value + Addend)); - break; - case ELF::R_PPC64_ADDR16_HIGHERA: - writeInt16BE(LocalAddress, applyPPChighera(Value + Addend)); - break; - case ELF::R_PPC64_ADDR16_HIGHEST: - writeInt16BE(LocalAddress, applyPPChighest(Value + Addend)); - break; - case ELF::R_PPC64_ADDR16_HIGHESTA: - writeInt16BE(LocalAddress, applyPPChighesta(Value + Addend)); - break; - case ELF::R_PPC64_ADDR14: { - assert(((Value + Addend) & 3) == 0); - // Preserve the AA/LK bits in the branch instruction - uint8_t aalk = *(LocalAddress + 3); - writeInt16BE(LocalAddress + 2, (aalk & 3) | ((Value + Addend) & 0xfffc)); - } break; - case ELF::R_PPC64_REL16_LO: { - uint64_t FinalAddress = Section.getLoadAddressWithOffset(Offset); - uint64_t Delta = Value - FinalAddress + Addend; - writeInt16BE(LocalAddress, applyPPClo(Delta)); - } break; - case ELF::R_PPC64_REL16_HI: { - uint64_t FinalAddress = Section.getLoadAddressWithOffset(Offset); - uint64_t Delta = Value - FinalAddress + Addend; - writeInt16BE(LocalAddress, applyPPChi(Delta)); - } break; - case ELF::R_PPC64_REL16_HA: { - uint64_t FinalAddress = Section.getLoadAddressWithOffset(Offset); - uint64_t Delta = Value - FinalAddress + Addend; - writeInt16BE(LocalAddress, applyPPCha(Delta)); - } break; - case ELF::R_PPC64_ADDR32: { - int64_t Result = static_cast<int64_t>(Value + Addend); - if (SignExtend64<32>(Result) != Result) - llvm_unreachable("Relocation R_PPC64_ADDR32 overflow"); - writeInt32BE(LocalAddress, Result); - } break; - case ELF::R_PPC64_REL24: { - uint64_t FinalAddress = Section.getLoadAddressWithOffset(Offset); - int64_t delta = static_cast<int64_t>(Value - FinalAddress + Addend); - if (SignExtend64<26>(delta) != delta) - llvm_unreachable("Relocation R_PPC64_REL24 overflow"); - // We preserve bits other than LI field, i.e. PO and AA/LK fields. - uint32_t Inst = readBytesUnaligned(LocalAddress, 4); - writeInt32BE(LocalAddress, (Inst & 0xFC000003) | (delta & 0x03FFFFFC)); - } break; - case ELF::R_PPC64_REL32: { - uint64_t FinalAddress = Section.getLoadAddressWithOffset(Offset); - int64_t delta = static_cast<int64_t>(Value - FinalAddress + Addend); - if (SignExtend64<32>(delta) != delta) - llvm_unreachable("Relocation R_PPC64_REL32 overflow"); - writeInt32BE(LocalAddress, delta); - } break; - case ELF::R_PPC64_REL64: { - uint64_t FinalAddress = Section.getLoadAddressWithOffset(Offset); - uint64_t Delta = Value - FinalAddress + Addend; - writeInt64BE(LocalAddress, Delta); - } break; - case ELF::R_PPC64_ADDR64: - writeInt64BE(LocalAddress, Value + Addend); - break; - } -} - -void RuntimeDyldELF::resolveSystemZRelocation(const SectionEntry &Section, - uint64_t Offset, uint64_t Value, - uint32_t Type, int64_t Addend) { - uint8_t *LocalAddress = Section.getAddressWithOffset(Offset); - switch (Type) { - default: - report_fatal_error("Relocation type not implemented yet!"); - break; - case ELF::R_390_PC16DBL: - case ELF::R_390_PLT16DBL: { - int64_t Delta = (Value + Addend) - Section.getLoadAddressWithOffset(Offset); - assert(int16_t(Delta / 2) * 2 == Delta && "R_390_PC16DBL overflow"); - writeInt16BE(LocalAddress, Delta / 2); - break; - } - case ELF::R_390_PC32DBL: - case ELF::R_390_PLT32DBL: { - int64_t Delta = (Value + Addend) - Section.getLoadAddressWithOffset(Offset); - assert(int32_t(Delta / 2) * 2 == Delta && "R_390_PC32DBL overflow"); - writeInt32BE(LocalAddress, Delta / 2); - break; - } - case ELF::R_390_PC16: { - int64_t Delta = (Value + Addend) - Section.getLoadAddressWithOffset(Offset); - assert(int16_t(Delta) == Delta && "R_390_PC16 overflow"); - writeInt16BE(LocalAddress, Delta); - break; - } - case ELF::R_390_PC32: { - int64_t Delta = (Value + Addend) - Section.getLoadAddressWithOffset(Offset); - assert(int32_t(Delta) == Delta && "R_390_PC32 overflow"); - writeInt32BE(LocalAddress, Delta); - break; - } - case ELF::R_390_PC64: { - int64_t Delta = (Value + Addend) - Section.getLoadAddressWithOffset(Offset); - writeInt64BE(LocalAddress, Delta); - break; - } - case ELF::R_390_8: - *LocalAddress = (uint8_t)(Value + Addend); - break; - case ELF::R_390_16: - writeInt16BE(LocalAddress, Value + Addend); - break; - case ELF::R_390_32: - writeInt32BE(LocalAddress, Value + Addend); - break; - case ELF::R_390_64: - writeInt64BE(LocalAddress, Value + Addend); - break; - } -} - -void RuntimeDyldELF::resolveBPFRelocation(const SectionEntry &Section, - uint64_t Offset, uint64_t Value, - uint32_t Type, int64_t Addend) { - bool isBE = Arch == Triple::bpfeb; - - switch (Type) { - default: - report_fatal_error("Relocation type not implemented yet!"); - break; - case ELF::R_BPF_NONE: - break; - case ELF::R_BPF_64_64: { - write(isBE, Section.getAddressWithOffset(Offset), Value + Addend); - LLVM_DEBUG(dbgs() << "Writing " << format("%p", (Value + Addend)) << " at " - << format("%p\n", Section.getAddressWithOffset(Offset))); - break; - } - case ELF::R_BPF_64_32: { - Value += Addend; - assert(Value <= UINT32_MAX); - write(isBE, Section.getAddressWithOffset(Offset), static_cast<uint32_t>(Value)); - LLVM_DEBUG(dbgs() << "Writing " << format("%p", Value) << " at " - << format("%p\n", Section.getAddressWithOffset(Offset))); - break; - } - } -} - -// The target location for the relocation is described by RE.SectionID and -// RE.Offset. RE.SectionID can be used to find the SectionEntry. Each -// SectionEntry has three members describing its location. -// SectionEntry::Address is the address at which the section has been loaded -// into memory in the current (host) process. SectionEntry::LoadAddress is the -// address that the section will have in the target process. -// SectionEntry::ObjAddress is the address of the bits for this section in the -// original emitted object image (also in the current address space). -// -// Relocations will be applied as if the section were loaded at -// SectionEntry::LoadAddress, but they will be applied at an address based -// on SectionEntry::Address. SectionEntry::ObjAddress will be used to refer to -// Target memory contents if they are required for value calculations. -// -// The Value parameter here is the load address of the symbol for the -// relocation to be applied. For relocations which refer to symbols in the -// current object Value will be the LoadAddress of the section in which -// the symbol resides (RE.Addend provides additional information about the -// symbol location). For external symbols, Value will be the address of the -// symbol in the target address space. -void RuntimeDyldELF::resolveRelocation(const RelocationEntry &RE, - uint64_t Value) { - const SectionEntry &Section = Sections[RE.SectionID]; - return resolveRelocation(Section, RE.Offset, Value, RE.RelType, RE.Addend, - RE.SymOffset, RE.SectionID); -} - -void RuntimeDyldELF::resolveRelocation(const SectionEntry &Section, - uint64_t Offset, uint64_t Value, - uint32_t Type, int64_t Addend, - uint64_t SymOffset, SID SectionID) { - switch (Arch) { - case Triple::x86_64: - resolveX86_64Relocation(Section, Offset, Value, Type, Addend, SymOffset); - break; - case Triple::x86: - resolveX86Relocation(Section, Offset, (uint32_t)(Value & 0xffffffffL), Type, - (uint32_t)(Addend & 0xffffffffL)); - break; - case Triple::aarch64: - case Triple::aarch64_be: - resolveAArch64Relocation(Section, Offset, Value, Type, Addend); - break; - case Triple::arm: // Fall through. - case Triple::armeb: - case Triple::thumb: - case Triple::thumbeb: - resolveARMRelocation(Section, Offset, (uint32_t)(Value & 0xffffffffL), Type, - (uint32_t)(Addend & 0xffffffffL)); - break; +//===-- RuntimeDyldELF.cpp - Run-time dynamic linker for MC-JIT -*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Implementation of ELF support for the MC-JIT runtime dynamic linker. +// +//===----------------------------------------------------------------------===// + +#include "RuntimeDyldELF.h" +#include "RuntimeDyldCheckerImpl.h" +#include "Targets/RuntimeDyldELFMips.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/Triple.h" +#include "llvm/BinaryFormat/ELF.h" +#include "llvm/Object/ELFObjectFile.h" +#include "llvm/Object/ObjectFile.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/MemoryBuffer.h" + +using namespace llvm; +using namespace llvm::object; +using namespace llvm::support::endian; + +#define DEBUG_TYPE "dyld" + +static void or32le(void *P, int32_t V) { write32le(P, read32le(P) | V); } + +static void or32AArch64Imm(void *L, uint64_t Imm) { + or32le(L, (Imm & 0xFFF) << 10); +} + +template <class T> static void write(bool isBE, void *P, T V) { + isBE ? write<T, support::big>(P, V) : write<T, support::little>(P, V); +} + +static void write32AArch64Addr(void *L, uint64_t Imm) { + uint32_t ImmLo = (Imm & 0x3) << 29; + uint32_t ImmHi = (Imm & 0x1FFFFC) << 3; + uint64_t Mask = (0x3 << 29) | (0x1FFFFC << 3); + write32le(L, (read32le(L) & ~Mask) | ImmLo | ImmHi); +} + +// Return the bits [Start, End] from Val shifted Start bits. +// For instance, getBits(0xF0, 4, 8) returns 0xF. +static uint64_t getBits(uint64_t Val, int Start, int End) { + uint64_t Mask = ((uint64_t)1 << (End + 1 - Start)) - 1; + return (Val >> Start) & Mask; +} + +namespace { + +template <class ELFT> class DyldELFObject : public ELFObjectFile<ELFT> { + LLVM_ELF_IMPORT_TYPES_ELFT(ELFT) + + typedef typename ELFT::uint addr_type; + + DyldELFObject(ELFObjectFile<ELFT> &&Obj); + +public: + static Expected<std::unique_ptr<DyldELFObject>> + create(MemoryBufferRef Wrapper); + + void updateSectionAddress(const SectionRef &Sec, uint64_t Addr); + + void updateSymbolAddress(const SymbolRef &SymRef, uint64_t Addr); + + // Methods for type inquiry through isa, cast and dyn_cast + static bool classof(const Binary *v) { + return (isa<ELFObjectFile<ELFT>>(v) && + classof(cast<ELFObjectFile<ELFT>>(v))); + } + static bool classof(const ELFObjectFile<ELFT> *v) { + return v->isDyldType(); + } +}; + + + +// The MemoryBuffer passed into this constructor is just a wrapper around the +// actual memory. Ultimately, the Binary parent class will take ownership of +// this MemoryBuffer object but not the underlying memory. +template <class ELFT> +DyldELFObject<ELFT>::DyldELFObject(ELFObjectFile<ELFT> &&Obj) + : ELFObjectFile<ELFT>(std::move(Obj)) { + this->isDyldELFObject = true; +} + +template <class ELFT> +Expected<std::unique_ptr<DyldELFObject<ELFT>>> +DyldELFObject<ELFT>::create(MemoryBufferRef Wrapper) { + auto Obj = ELFObjectFile<ELFT>::create(Wrapper); + if (auto E = Obj.takeError()) + return std::move(E); + std::unique_ptr<DyldELFObject<ELFT>> Ret( + new DyldELFObject<ELFT>(std::move(*Obj))); + return std::move(Ret); +} + +template <class ELFT> +void DyldELFObject<ELFT>::updateSectionAddress(const SectionRef &Sec, + uint64_t Addr) { + DataRefImpl ShdrRef = Sec.getRawDataRefImpl(); + Elf_Shdr *shdr = + const_cast<Elf_Shdr *>(reinterpret_cast<const Elf_Shdr *>(ShdrRef.p)); + + // This assumes the address passed in matches the target address bitness + // The template-based type cast handles everything else. + shdr->sh_addr = static_cast<addr_type>(Addr); +} + +template <class ELFT> +void DyldELFObject<ELFT>::updateSymbolAddress(const SymbolRef &SymRef, + uint64_t Addr) { + + Elf_Sym *sym = const_cast<Elf_Sym *>( + ELFObjectFile<ELFT>::getSymbol(SymRef.getRawDataRefImpl())); + + // This assumes the address passed in matches the target address bitness + // The template-based type cast handles everything else. + sym->st_value = static_cast<addr_type>(Addr); +} + +class LoadedELFObjectInfo final + : public LoadedObjectInfoHelper<LoadedELFObjectInfo, + RuntimeDyld::LoadedObjectInfo> { +public: + LoadedELFObjectInfo(RuntimeDyldImpl &RTDyld, ObjSectionToIDMap ObjSecToIDMap) + : LoadedObjectInfoHelper(RTDyld, std::move(ObjSecToIDMap)) {} + + OwningBinary<ObjectFile> + getObjectForDebug(const ObjectFile &Obj) const override; +}; + +template <typename ELFT> +static Expected<std::unique_ptr<DyldELFObject<ELFT>>> +createRTDyldELFObject(MemoryBufferRef Buffer, const ObjectFile &SourceObject, + const LoadedELFObjectInfo &L) { + typedef typename ELFT::Shdr Elf_Shdr; + typedef typename ELFT::uint addr_type; + + Expected<std::unique_ptr<DyldELFObject<ELFT>>> ObjOrErr = + DyldELFObject<ELFT>::create(Buffer); + if (Error E = ObjOrErr.takeError()) + return std::move(E); + + std::unique_ptr<DyldELFObject<ELFT>> Obj = std::move(*ObjOrErr); + + // Iterate over all sections in the object. + auto SI = SourceObject.section_begin(); + for (const auto &Sec : Obj->sections()) { + Expected<StringRef> NameOrErr = Sec.getName(); + if (!NameOrErr) { + consumeError(NameOrErr.takeError()); + continue; + } + + if (*NameOrErr != "") { + DataRefImpl ShdrRef = Sec.getRawDataRefImpl(); + Elf_Shdr *shdr = const_cast<Elf_Shdr *>( + reinterpret_cast<const Elf_Shdr *>(ShdrRef.p)); + + if (uint64_t SecLoadAddr = L.getSectionLoadAddress(*SI)) { + // This assumes that the address passed in matches the target address + // bitness. The template-based type cast handles everything else. + shdr->sh_addr = static_cast<addr_type>(SecLoadAddr); + } + } + ++SI; + } + + return std::move(Obj); +} + +static OwningBinary<ObjectFile> +createELFDebugObject(const ObjectFile &Obj, const LoadedELFObjectInfo &L) { + assert(Obj.isELF() && "Not an ELF object file."); + + std::unique_ptr<MemoryBuffer> Buffer = + MemoryBuffer::getMemBufferCopy(Obj.getData(), Obj.getFileName()); + + Expected<std::unique_ptr<ObjectFile>> DebugObj(nullptr); + handleAllErrors(DebugObj.takeError()); + if (Obj.getBytesInAddress() == 4 && Obj.isLittleEndian()) + DebugObj = + createRTDyldELFObject<ELF32LE>(Buffer->getMemBufferRef(), Obj, L); + else if (Obj.getBytesInAddress() == 4 && !Obj.isLittleEndian()) + DebugObj = + createRTDyldELFObject<ELF32BE>(Buffer->getMemBufferRef(), Obj, L); + else if (Obj.getBytesInAddress() == 8 && !Obj.isLittleEndian()) + DebugObj = + createRTDyldELFObject<ELF64BE>(Buffer->getMemBufferRef(), Obj, L); + else if (Obj.getBytesInAddress() == 8 && Obj.isLittleEndian()) + DebugObj = + createRTDyldELFObject<ELF64LE>(Buffer->getMemBufferRef(), Obj, L); + else + llvm_unreachable("Unexpected ELF format"); + + handleAllErrors(DebugObj.takeError()); + return OwningBinary<ObjectFile>(std::move(*DebugObj), std::move(Buffer)); +} + +OwningBinary<ObjectFile> +LoadedELFObjectInfo::getObjectForDebug(const ObjectFile &Obj) const { + return createELFDebugObject(Obj, *this); +} + +} // anonymous namespace + +namespace llvm { + +RuntimeDyldELF::RuntimeDyldELF(RuntimeDyld::MemoryManager &MemMgr, + JITSymbolResolver &Resolver) + : RuntimeDyldImpl(MemMgr, Resolver), GOTSectionID(0), CurrentGOTIndex(0) {} +RuntimeDyldELF::~RuntimeDyldELF() {} + +void RuntimeDyldELF::registerEHFrames() { + for (int i = 0, e = UnregisteredEHFrameSections.size(); i != e; ++i) { + SID EHFrameSID = UnregisteredEHFrameSections[i]; + uint8_t *EHFrameAddr = Sections[EHFrameSID].getAddress(); + uint64_t EHFrameLoadAddr = Sections[EHFrameSID].getLoadAddress(); + size_t EHFrameSize = Sections[EHFrameSID].getSize(); + MemMgr.registerEHFrames(EHFrameAddr, EHFrameLoadAddr, EHFrameSize); + } + UnregisteredEHFrameSections.clear(); +} + +std::unique_ptr<RuntimeDyldELF> +llvm::RuntimeDyldELF::create(Triple::ArchType Arch, + RuntimeDyld::MemoryManager &MemMgr, + JITSymbolResolver &Resolver) { + switch (Arch) { + default: + return std::make_unique<RuntimeDyldELF>(MemMgr, Resolver); + case Triple::mips: + case Triple::mipsel: + case Triple::mips64: + case Triple::mips64el: + return std::make_unique<RuntimeDyldELFMips>(MemMgr, Resolver); + } +} + +std::unique_ptr<RuntimeDyld::LoadedObjectInfo> +RuntimeDyldELF::loadObject(const object::ObjectFile &O) { + if (auto ObjSectionToIDOrErr = loadObjectImpl(O)) + return std::make_unique<LoadedELFObjectInfo>(*this, *ObjSectionToIDOrErr); + else { + HasError = true; + raw_string_ostream ErrStream(ErrorStr); + logAllUnhandledErrors(ObjSectionToIDOrErr.takeError(), ErrStream); + return nullptr; + } +} + +void RuntimeDyldELF::resolveX86_64Relocation(const SectionEntry &Section, + uint64_t Offset, uint64_t Value, + uint32_t Type, int64_t Addend, + uint64_t SymOffset) { + switch (Type) { + default: + report_fatal_error("Relocation type not implemented yet!"); + break; + case ELF::R_X86_64_NONE: + break; + case ELF::R_X86_64_64: { + support::ulittle64_t::ref(Section.getAddressWithOffset(Offset)) = + Value + Addend; + LLVM_DEBUG(dbgs() << "Writing " << format("%p", (Value + Addend)) << " at " + << format("%p\n", Section.getAddressWithOffset(Offset))); + break; + } + case ELF::R_X86_64_32: + case ELF::R_X86_64_32S: { + Value += Addend; + assert((Type == ELF::R_X86_64_32 && (Value <= UINT32_MAX)) || + (Type == ELF::R_X86_64_32S && + ((int64_t)Value <= INT32_MAX && (int64_t)Value >= INT32_MIN))); + uint32_t TruncatedAddr = (Value & 0xFFFFFFFF); + support::ulittle32_t::ref(Section.getAddressWithOffset(Offset)) = + TruncatedAddr; + LLVM_DEBUG(dbgs() << "Writing " << format("%p", TruncatedAddr) << " at " + << format("%p\n", Section.getAddressWithOffset(Offset))); + break; + } + case ELF::R_X86_64_PC8: { + uint64_t FinalAddress = Section.getLoadAddressWithOffset(Offset); + int64_t RealOffset = Value + Addend - FinalAddress; + assert(isInt<8>(RealOffset)); + int8_t TruncOffset = (RealOffset & 0xFF); + Section.getAddress()[Offset] = TruncOffset; + break; + } + case ELF::R_X86_64_PC32: { + uint64_t FinalAddress = Section.getLoadAddressWithOffset(Offset); + int64_t RealOffset = Value + Addend - FinalAddress; + assert(isInt<32>(RealOffset)); + int32_t TruncOffset = (RealOffset & 0xFFFFFFFF); + support::ulittle32_t::ref(Section.getAddressWithOffset(Offset)) = + TruncOffset; + break; + } + case ELF::R_X86_64_PC64: { + uint64_t FinalAddress = Section.getLoadAddressWithOffset(Offset); + int64_t RealOffset = Value + Addend - FinalAddress; + support::ulittle64_t::ref(Section.getAddressWithOffset(Offset)) = + RealOffset; + LLVM_DEBUG(dbgs() << "Writing " << format("%p", RealOffset) << " at " + << format("%p\n", FinalAddress)); + break; + } + case ELF::R_X86_64_GOTOFF64: { + // Compute Value - GOTBase. + uint64_t GOTBase = 0; + for (const auto &Section : Sections) { + if (Section.getName() == ".got") { + GOTBase = Section.getLoadAddressWithOffset(0); + break; + } + } + assert(GOTBase != 0 && "missing GOT"); + int64_t GOTOffset = Value - GOTBase + Addend; + support::ulittle64_t::ref(Section.getAddressWithOffset(Offset)) = GOTOffset; + break; + } + } +} + +void RuntimeDyldELF::resolveX86Relocation(const SectionEntry &Section, + uint64_t Offset, uint32_t Value, + uint32_t Type, int32_t Addend) { + switch (Type) { + case ELF::R_386_32: { + support::ulittle32_t::ref(Section.getAddressWithOffset(Offset)) = + Value + Addend; + break; + } + // Handle R_386_PLT32 like R_386_PC32 since it should be able to + // reach any 32 bit address. + case ELF::R_386_PLT32: + case ELF::R_386_PC32: { + uint32_t FinalAddress = + Section.getLoadAddressWithOffset(Offset) & 0xFFFFFFFF; + uint32_t RealOffset = Value + Addend - FinalAddress; + support::ulittle32_t::ref(Section.getAddressWithOffset(Offset)) = + RealOffset; + break; + } + default: + // There are other relocation types, but it appears these are the + // only ones currently used by the LLVM ELF object writer + report_fatal_error("Relocation type not implemented yet!"); + break; + } +} + +void RuntimeDyldELF::resolveAArch64Relocation(const SectionEntry &Section, + uint64_t Offset, uint64_t Value, + uint32_t Type, int64_t Addend) { + uint32_t *TargetPtr = + reinterpret_cast<uint32_t *>(Section.getAddressWithOffset(Offset)); + uint64_t FinalAddress = Section.getLoadAddressWithOffset(Offset); + // Data should use target endian. Code should always use little endian. + bool isBE = Arch == Triple::aarch64_be; + + LLVM_DEBUG(dbgs() << "resolveAArch64Relocation, LocalAddress: 0x" + << format("%llx", Section.getAddressWithOffset(Offset)) + << " FinalAddress: 0x" << format("%llx", FinalAddress) + << " Value: 0x" << format("%llx", Value) << " Type: 0x" + << format("%x", Type) << " Addend: 0x" + << format("%llx", Addend) << "\n"); + + switch (Type) { + default: + report_fatal_error("Relocation type not implemented yet!"); + break; + case ELF::R_AARCH64_ABS16: { + uint64_t Result = Value + Addend; + assert(static_cast<int64_t>(Result) >= INT16_MIN && Result < UINT16_MAX); + write(isBE, TargetPtr, static_cast<uint16_t>(Result & 0xffffU)); + break; + } + case ELF::R_AARCH64_ABS32: { + uint64_t Result = Value + Addend; + assert(static_cast<int64_t>(Result) >= INT32_MIN && Result < UINT32_MAX); + write(isBE, TargetPtr, static_cast<uint32_t>(Result & 0xffffffffU)); + break; + } + case ELF::R_AARCH64_ABS64: + write(isBE, TargetPtr, Value + Addend); + break; + case ELF::R_AARCH64_PLT32: { + uint64_t Result = Value + Addend - FinalAddress; + assert(static_cast<int64_t>(Result) >= INT32_MIN && + static_cast<int64_t>(Result) <= INT32_MAX); + write(isBE, TargetPtr, static_cast<uint32_t>(Result)); + break; + } + case ELF::R_AARCH64_PREL32: { + uint64_t Result = Value + Addend - FinalAddress; + assert(static_cast<int64_t>(Result) >= INT32_MIN && + static_cast<int64_t>(Result) <= UINT32_MAX); + write(isBE, TargetPtr, static_cast<uint32_t>(Result & 0xffffffffU)); + break; + } + case ELF::R_AARCH64_PREL64: + write(isBE, TargetPtr, Value + Addend - FinalAddress); + break; + case ELF::R_AARCH64_CALL26: // fallthrough + case ELF::R_AARCH64_JUMP26: { + // Operation: S+A-P. Set Call or B immediate value to bits fff_fffc of the + // calculation. + uint64_t BranchImm = Value + Addend - FinalAddress; + + // "Check that -2^27 <= result < 2^27". + assert(isInt<28>(BranchImm)); + or32le(TargetPtr, (BranchImm & 0x0FFFFFFC) >> 2); + break; + } + case ELF::R_AARCH64_MOVW_UABS_G3: + or32le(TargetPtr, ((Value + Addend) & 0xFFFF000000000000) >> 43); + break; + case ELF::R_AARCH64_MOVW_UABS_G2_NC: + or32le(TargetPtr, ((Value + Addend) & 0xFFFF00000000) >> 27); + break; + case ELF::R_AARCH64_MOVW_UABS_G1_NC: + or32le(TargetPtr, ((Value + Addend) & 0xFFFF0000) >> 11); + break; + case ELF::R_AARCH64_MOVW_UABS_G0_NC: + or32le(TargetPtr, ((Value + Addend) & 0xFFFF) << 5); + break; + case ELF::R_AARCH64_ADR_PREL_PG_HI21: { + // Operation: Page(S+A) - Page(P) + uint64_t Result = + ((Value + Addend) & ~0xfffULL) - (FinalAddress & ~0xfffULL); + + // Check that -2^32 <= X < 2^32 + assert(isInt<33>(Result) && "overflow check failed for relocation"); + + // Immediate goes in bits 30:29 + 5:23 of ADRP instruction, taken + // from bits 32:12 of X. + write32AArch64Addr(TargetPtr, Result >> 12); + break; + } + case ELF::R_AARCH64_ADD_ABS_LO12_NC: + // Operation: S + A + // Immediate goes in bits 21:10 of LD/ST instruction, taken + // from bits 11:0 of X + or32AArch64Imm(TargetPtr, Value + Addend); + break; + case ELF::R_AARCH64_LDST8_ABS_LO12_NC: + // Operation: S + A + // Immediate goes in bits 21:10 of LD/ST instruction, taken + // from bits 11:0 of X + or32AArch64Imm(TargetPtr, getBits(Value + Addend, 0, 11)); + break; + case ELF::R_AARCH64_LDST16_ABS_LO12_NC: + // Operation: S + A + // Immediate goes in bits 21:10 of LD/ST instruction, taken + // from bits 11:1 of X + or32AArch64Imm(TargetPtr, getBits(Value + Addend, 1, 11)); + break; + case ELF::R_AARCH64_LDST32_ABS_LO12_NC: + // Operation: S + A + // Immediate goes in bits 21:10 of LD/ST instruction, taken + // from bits 11:2 of X + or32AArch64Imm(TargetPtr, getBits(Value + Addend, 2, 11)); + break; + case ELF::R_AARCH64_LDST64_ABS_LO12_NC: + // Operation: S + A + // Immediate goes in bits 21:10 of LD/ST instruction, taken + // from bits 11:3 of X + or32AArch64Imm(TargetPtr, getBits(Value + Addend, 3, 11)); + break; + case ELF::R_AARCH64_LDST128_ABS_LO12_NC: + // Operation: S + A + // Immediate goes in bits 21:10 of LD/ST instruction, taken + // from bits 11:4 of X + or32AArch64Imm(TargetPtr, getBits(Value + Addend, 4, 11)); + break; + } +} + +void RuntimeDyldELF::resolveARMRelocation(const SectionEntry &Section, + uint64_t Offset, uint32_t Value, + uint32_t Type, int32_t Addend) { + // TODO: Add Thumb relocations. + uint32_t *TargetPtr = + reinterpret_cast<uint32_t *>(Section.getAddressWithOffset(Offset)); + uint32_t FinalAddress = Section.getLoadAddressWithOffset(Offset) & 0xFFFFFFFF; + Value += Addend; + + LLVM_DEBUG(dbgs() << "resolveARMRelocation, LocalAddress: " + << Section.getAddressWithOffset(Offset) + << " FinalAddress: " << format("%p", FinalAddress) + << " Value: " << format("%x", Value) + << " Type: " << format("%x", Type) + << " Addend: " << format("%x", Addend) << "\n"); + + switch (Type) { + default: + llvm_unreachable("Not implemented relocation type!"); + + case ELF::R_ARM_NONE: + break; + // Write a 31bit signed offset + case ELF::R_ARM_PREL31: + support::ulittle32_t::ref{TargetPtr} = + (support::ulittle32_t::ref{TargetPtr} & 0x80000000) | + ((Value - FinalAddress) & ~0x80000000); + break; + case ELF::R_ARM_TARGET1: + case ELF::R_ARM_ABS32: + support::ulittle32_t::ref{TargetPtr} = Value; + break; + // Write first 16 bit of 32 bit value to the mov instruction. + // Last 4 bit should be shifted. + case ELF::R_ARM_MOVW_ABS_NC: + case ELF::R_ARM_MOVT_ABS: + if (Type == ELF::R_ARM_MOVW_ABS_NC) + Value = Value & 0xFFFF; + else if (Type == ELF::R_ARM_MOVT_ABS) + Value = (Value >> 16) & 0xFFFF; + support::ulittle32_t::ref{TargetPtr} = + (support::ulittle32_t::ref{TargetPtr} & ~0x000F0FFF) | (Value & 0xFFF) | + (((Value >> 12) & 0xF) << 16); + break; + // Write 24 bit relative value to the branch instruction. + case ELF::R_ARM_PC24: // Fall through. + case ELF::R_ARM_CALL: // Fall through. + case ELF::R_ARM_JUMP24: + int32_t RelValue = static_cast<int32_t>(Value - FinalAddress - 8); + RelValue = (RelValue & 0x03FFFFFC) >> 2; + assert((support::ulittle32_t::ref{TargetPtr} & 0xFFFFFF) == 0xFFFFFE); + support::ulittle32_t::ref{TargetPtr} = + (support::ulittle32_t::ref{TargetPtr} & 0xFF000000) | RelValue; + break; + } +} + +void RuntimeDyldELF::setMipsABI(const ObjectFile &Obj) { + if (Arch == Triple::UnknownArch || + !StringRef(Triple::getArchTypePrefix(Arch)).equals("mips")) { + IsMipsO32ABI = false; + IsMipsN32ABI = false; + IsMipsN64ABI = false; + return; + } + if (auto *E = dyn_cast<ELFObjectFileBase>(&Obj)) { + unsigned AbiVariant = E->getPlatformFlags(); + IsMipsO32ABI = AbiVariant & ELF::EF_MIPS_ABI_O32; + IsMipsN32ABI = AbiVariant & ELF::EF_MIPS_ABI2; + } + IsMipsN64ABI = Obj.getFileFormatName().equals("elf64-mips"); +} + +// Return the .TOC. section and offset. +Error RuntimeDyldELF::findPPC64TOCSection(const ELFObjectFileBase &Obj, + ObjSectionToIDMap &LocalSections, + RelocationValueRef &Rel) { + // Set a default SectionID in case we do not find a TOC section below. + // This may happen for references to TOC base base (sym@toc, .odp + // relocation) without a .toc directive. In this case just use the + // first section (which is usually the .odp) since the code won't + // reference the .toc base directly. + Rel.SymbolName = nullptr; + Rel.SectionID = 0; + + // The TOC consists of sections .got, .toc, .tocbss, .plt in that + // order. The TOC starts where the first of these sections starts. + for (auto &Section : Obj.sections()) { + Expected<StringRef> NameOrErr = Section.getName(); + if (!NameOrErr) + return NameOrErr.takeError(); + StringRef SectionName = *NameOrErr; + + if (SectionName == ".got" + || SectionName == ".toc" + || SectionName == ".tocbss" + || SectionName == ".plt") { + if (auto SectionIDOrErr = + findOrEmitSection(Obj, Section, false, LocalSections)) + Rel.SectionID = *SectionIDOrErr; + else + return SectionIDOrErr.takeError(); + break; + } + } + + // Per the ppc64-elf-linux ABI, The TOC base is TOC value plus 0x8000 + // thus permitting a full 64 Kbytes segment. + Rel.Addend = 0x8000; + + return Error::success(); +} + +// Returns the sections and offset associated with the ODP entry referenced +// by Symbol. +Error RuntimeDyldELF::findOPDEntrySection(const ELFObjectFileBase &Obj, + ObjSectionToIDMap &LocalSections, + RelocationValueRef &Rel) { + // Get the ELF symbol value (st_value) to compare with Relocation offset in + // .opd entries + for (section_iterator si = Obj.section_begin(), se = Obj.section_end(); + si != se; ++si) { + + Expected<section_iterator> RelSecOrErr = si->getRelocatedSection(); + if (!RelSecOrErr) + report_fatal_error(toString(RelSecOrErr.takeError())); + + section_iterator RelSecI = *RelSecOrErr; + if (RelSecI == Obj.section_end()) + continue; + + Expected<StringRef> NameOrErr = RelSecI->getName(); + if (!NameOrErr) + return NameOrErr.takeError(); + StringRef RelSectionName = *NameOrErr; + + if (RelSectionName != ".opd") + continue; + + for (elf_relocation_iterator i = si->relocation_begin(), + e = si->relocation_end(); + i != e;) { + // The R_PPC64_ADDR64 relocation indicates the first field + // of a .opd entry + uint64_t TypeFunc = i->getType(); + if (TypeFunc != ELF::R_PPC64_ADDR64) { + ++i; + continue; + } + + uint64_t TargetSymbolOffset = i->getOffset(); + symbol_iterator TargetSymbol = i->getSymbol(); + int64_t Addend; + if (auto AddendOrErr = i->getAddend()) + Addend = *AddendOrErr; + else + return AddendOrErr.takeError(); + + ++i; + if (i == e) + break; + + // Just check if following relocation is a R_PPC64_TOC + uint64_t TypeTOC = i->getType(); + if (TypeTOC != ELF::R_PPC64_TOC) + continue; + + // Finally compares the Symbol value and the target symbol offset + // to check if this .opd entry refers to the symbol the relocation + // points to. + if (Rel.Addend != (int64_t)TargetSymbolOffset) + continue; + + section_iterator TSI = Obj.section_end(); + if (auto TSIOrErr = TargetSymbol->getSection()) + TSI = *TSIOrErr; + else + return TSIOrErr.takeError(); + assert(TSI != Obj.section_end() && "TSI should refer to a valid section"); + + bool IsCode = TSI->isText(); + if (auto SectionIDOrErr = findOrEmitSection(Obj, *TSI, IsCode, + LocalSections)) + Rel.SectionID = *SectionIDOrErr; + else + return SectionIDOrErr.takeError(); + Rel.Addend = (intptr_t)Addend; + return Error::success(); + } + } + llvm_unreachable("Attempting to get address of ODP entry!"); +} + +// Relocation masks following the #lo(value), #hi(value), #ha(value), +// #higher(value), #highera(value), #highest(value), and #highesta(value) +// macros defined in section 4.5.1. Relocation Types of the PPC-elf64abi +// document. + +static inline uint16_t applyPPClo(uint64_t value) { return value & 0xffff; } + +static inline uint16_t applyPPChi(uint64_t value) { + return (value >> 16) & 0xffff; +} + +static inline uint16_t applyPPCha (uint64_t value) { + return ((value + 0x8000) >> 16) & 0xffff; +} + +static inline uint16_t applyPPChigher(uint64_t value) { + return (value >> 32) & 0xffff; +} + +static inline uint16_t applyPPChighera (uint64_t value) { + return ((value + 0x8000) >> 32) & 0xffff; +} + +static inline uint16_t applyPPChighest(uint64_t value) { + return (value >> 48) & 0xffff; +} + +static inline uint16_t applyPPChighesta (uint64_t value) { + return ((value + 0x8000) >> 48) & 0xffff; +} + +void RuntimeDyldELF::resolvePPC32Relocation(const SectionEntry &Section, + uint64_t Offset, uint64_t Value, + uint32_t Type, int64_t Addend) { + uint8_t *LocalAddress = Section.getAddressWithOffset(Offset); + switch (Type) { + default: + report_fatal_error("Relocation type not implemented yet!"); + break; + case ELF::R_PPC_ADDR16_LO: + writeInt16BE(LocalAddress, applyPPClo(Value + Addend)); + break; + case ELF::R_PPC_ADDR16_HI: + writeInt16BE(LocalAddress, applyPPChi(Value + Addend)); + break; + case ELF::R_PPC_ADDR16_HA: + writeInt16BE(LocalAddress, applyPPCha(Value + Addend)); + break; + } +} + +void RuntimeDyldELF::resolvePPC64Relocation(const SectionEntry &Section, + uint64_t Offset, uint64_t Value, + uint32_t Type, int64_t Addend) { + uint8_t *LocalAddress = Section.getAddressWithOffset(Offset); + switch (Type) { + default: + report_fatal_error("Relocation type not implemented yet!"); + break; + case ELF::R_PPC64_ADDR16: + writeInt16BE(LocalAddress, applyPPClo(Value + Addend)); + break; + case ELF::R_PPC64_ADDR16_DS: + writeInt16BE(LocalAddress, applyPPClo(Value + Addend) & ~3); + break; + case ELF::R_PPC64_ADDR16_LO: + writeInt16BE(LocalAddress, applyPPClo(Value + Addend)); + break; + case ELF::R_PPC64_ADDR16_LO_DS: + writeInt16BE(LocalAddress, applyPPClo(Value + Addend) & ~3); + break; + case ELF::R_PPC64_ADDR16_HI: + case ELF::R_PPC64_ADDR16_HIGH: + writeInt16BE(LocalAddress, applyPPChi(Value + Addend)); + break; + case ELF::R_PPC64_ADDR16_HA: + case ELF::R_PPC64_ADDR16_HIGHA: + writeInt16BE(LocalAddress, applyPPCha(Value + Addend)); + break; + case ELF::R_PPC64_ADDR16_HIGHER: + writeInt16BE(LocalAddress, applyPPChigher(Value + Addend)); + break; + case ELF::R_PPC64_ADDR16_HIGHERA: + writeInt16BE(LocalAddress, applyPPChighera(Value + Addend)); + break; + case ELF::R_PPC64_ADDR16_HIGHEST: + writeInt16BE(LocalAddress, applyPPChighest(Value + Addend)); + break; + case ELF::R_PPC64_ADDR16_HIGHESTA: + writeInt16BE(LocalAddress, applyPPChighesta(Value + Addend)); + break; + case ELF::R_PPC64_ADDR14: { + assert(((Value + Addend) & 3) == 0); + // Preserve the AA/LK bits in the branch instruction + uint8_t aalk = *(LocalAddress + 3); + writeInt16BE(LocalAddress + 2, (aalk & 3) | ((Value + Addend) & 0xfffc)); + } break; + case ELF::R_PPC64_REL16_LO: { + uint64_t FinalAddress = Section.getLoadAddressWithOffset(Offset); + uint64_t Delta = Value - FinalAddress + Addend; + writeInt16BE(LocalAddress, applyPPClo(Delta)); + } break; + case ELF::R_PPC64_REL16_HI: { + uint64_t FinalAddress = Section.getLoadAddressWithOffset(Offset); + uint64_t Delta = Value - FinalAddress + Addend; + writeInt16BE(LocalAddress, applyPPChi(Delta)); + } break; + case ELF::R_PPC64_REL16_HA: { + uint64_t FinalAddress = Section.getLoadAddressWithOffset(Offset); + uint64_t Delta = Value - FinalAddress + Addend; + writeInt16BE(LocalAddress, applyPPCha(Delta)); + } break; + case ELF::R_PPC64_ADDR32: { + int64_t Result = static_cast<int64_t>(Value + Addend); + if (SignExtend64<32>(Result) != Result) + llvm_unreachable("Relocation R_PPC64_ADDR32 overflow"); + writeInt32BE(LocalAddress, Result); + } break; + case ELF::R_PPC64_REL24: { + uint64_t FinalAddress = Section.getLoadAddressWithOffset(Offset); + int64_t delta = static_cast<int64_t>(Value - FinalAddress + Addend); + if (SignExtend64<26>(delta) != delta) + llvm_unreachable("Relocation R_PPC64_REL24 overflow"); + // We preserve bits other than LI field, i.e. PO and AA/LK fields. + uint32_t Inst = readBytesUnaligned(LocalAddress, 4); + writeInt32BE(LocalAddress, (Inst & 0xFC000003) | (delta & 0x03FFFFFC)); + } break; + case ELF::R_PPC64_REL32: { + uint64_t FinalAddress = Section.getLoadAddressWithOffset(Offset); + int64_t delta = static_cast<int64_t>(Value - FinalAddress + Addend); + if (SignExtend64<32>(delta) != delta) + llvm_unreachable("Relocation R_PPC64_REL32 overflow"); + writeInt32BE(LocalAddress, delta); + } break; + case ELF::R_PPC64_REL64: { + uint64_t FinalAddress = Section.getLoadAddressWithOffset(Offset); + uint64_t Delta = Value - FinalAddress + Addend; + writeInt64BE(LocalAddress, Delta); + } break; + case ELF::R_PPC64_ADDR64: + writeInt64BE(LocalAddress, Value + Addend); + break; + } +} + +void RuntimeDyldELF::resolveSystemZRelocation(const SectionEntry &Section, + uint64_t Offset, uint64_t Value, + uint32_t Type, int64_t Addend) { + uint8_t *LocalAddress = Section.getAddressWithOffset(Offset); + switch (Type) { + default: + report_fatal_error("Relocation type not implemented yet!"); + break; + case ELF::R_390_PC16DBL: + case ELF::R_390_PLT16DBL: { + int64_t Delta = (Value + Addend) - Section.getLoadAddressWithOffset(Offset); + assert(int16_t(Delta / 2) * 2 == Delta && "R_390_PC16DBL overflow"); + writeInt16BE(LocalAddress, Delta / 2); + break; + } + case ELF::R_390_PC32DBL: + case ELF::R_390_PLT32DBL: { + int64_t Delta = (Value + Addend) - Section.getLoadAddressWithOffset(Offset); + assert(int32_t(Delta / 2) * 2 == Delta && "R_390_PC32DBL overflow"); + writeInt32BE(LocalAddress, Delta / 2); + break; + } + case ELF::R_390_PC16: { + int64_t Delta = (Value + Addend) - Section.getLoadAddressWithOffset(Offset); + assert(int16_t(Delta) == Delta && "R_390_PC16 overflow"); + writeInt16BE(LocalAddress, Delta); + break; + } + case ELF::R_390_PC32: { + int64_t Delta = (Value + Addend) - Section.getLoadAddressWithOffset(Offset); + assert(int32_t(Delta) == Delta && "R_390_PC32 overflow"); + writeInt32BE(LocalAddress, Delta); + break; + } + case ELF::R_390_PC64: { + int64_t Delta = (Value + Addend) - Section.getLoadAddressWithOffset(Offset); + writeInt64BE(LocalAddress, Delta); + break; + } + case ELF::R_390_8: + *LocalAddress = (uint8_t)(Value + Addend); + break; + case ELF::R_390_16: + writeInt16BE(LocalAddress, Value + Addend); + break; + case ELF::R_390_32: + writeInt32BE(LocalAddress, Value + Addend); + break; + case ELF::R_390_64: + writeInt64BE(LocalAddress, Value + Addend); + break; + } +} + +void RuntimeDyldELF::resolveBPFRelocation(const SectionEntry &Section, + uint64_t Offset, uint64_t Value, + uint32_t Type, int64_t Addend) { + bool isBE = Arch == Triple::bpfeb; + + switch (Type) { + default: + report_fatal_error("Relocation type not implemented yet!"); + break; + case ELF::R_BPF_NONE: + break; + case ELF::R_BPF_64_64: { + write(isBE, Section.getAddressWithOffset(Offset), Value + Addend); + LLVM_DEBUG(dbgs() << "Writing " << format("%p", (Value + Addend)) << " at " + << format("%p\n", Section.getAddressWithOffset(Offset))); + break; + } + case ELF::R_BPF_64_32: { + Value += Addend; + assert(Value <= UINT32_MAX); + write(isBE, Section.getAddressWithOffset(Offset), static_cast<uint32_t>(Value)); + LLVM_DEBUG(dbgs() << "Writing " << format("%p", Value) << " at " + << format("%p\n", Section.getAddressWithOffset(Offset))); + break; + } + } +} + +// The target location for the relocation is described by RE.SectionID and +// RE.Offset. RE.SectionID can be used to find the SectionEntry. Each +// SectionEntry has three members describing its location. +// SectionEntry::Address is the address at which the section has been loaded +// into memory in the current (host) process. SectionEntry::LoadAddress is the +// address that the section will have in the target process. +// SectionEntry::ObjAddress is the address of the bits for this section in the +// original emitted object image (also in the current address space). +// +// Relocations will be applied as if the section were loaded at +// SectionEntry::LoadAddress, but they will be applied at an address based +// on SectionEntry::Address. SectionEntry::ObjAddress will be used to refer to +// Target memory contents if they are required for value calculations. +// +// The Value parameter here is the load address of the symbol for the +// relocation to be applied. For relocations which refer to symbols in the +// current object Value will be the LoadAddress of the section in which +// the symbol resides (RE.Addend provides additional information about the +// symbol location). For external symbols, Value will be the address of the +// symbol in the target address space. +void RuntimeDyldELF::resolveRelocation(const RelocationEntry &RE, + uint64_t Value) { + const SectionEntry &Section = Sections[RE.SectionID]; + return resolveRelocation(Section, RE.Offset, Value, RE.RelType, RE.Addend, + RE.SymOffset, RE.SectionID); +} + +void RuntimeDyldELF::resolveRelocation(const SectionEntry &Section, + uint64_t Offset, uint64_t Value, + uint32_t Type, int64_t Addend, + uint64_t SymOffset, SID SectionID) { + switch (Arch) { + case Triple::x86_64: + resolveX86_64Relocation(Section, Offset, Value, Type, Addend, SymOffset); + break; + case Triple::x86: + resolveX86Relocation(Section, Offset, (uint32_t)(Value & 0xffffffffL), Type, + (uint32_t)(Addend & 0xffffffffL)); + break; + case Triple::aarch64: + case Triple::aarch64_be: + resolveAArch64Relocation(Section, Offset, Value, Type, Addend); + break; + case Triple::arm: // Fall through. + case Triple::armeb: + case Triple::thumb: + case Triple::thumbeb: + resolveARMRelocation(Section, Offset, (uint32_t)(Value & 0xffffffffL), Type, + (uint32_t)(Addend & 0xffffffffL)); + break; case Triple::ppc: // Fall through. case Triple::ppcle: - resolvePPC32Relocation(Section, Offset, Value, Type, Addend); - break; - case Triple::ppc64: // Fall through. - case Triple::ppc64le: - resolvePPC64Relocation(Section, Offset, Value, Type, Addend); - break; - case Triple::systemz: - resolveSystemZRelocation(Section, Offset, Value, Type, Addend); - break; - case Triple::bpfel: - case Triple::bpfeb: - resolveBPFRelocation(Section, Offset, Value, Type, Addend); - break; - default: - llvm_unreachable("Unsupported CPU type!"); - } -} - -void *RuntimeDyldELF::computePlaceholderAddress(unsigned SectionID, uint64_t Offset) const { - return (void *)(Sections[SectionID].getObjAddress() + Offset); -} - -void RuntimeDyldELF::processSimpleRelocation(unsigned SectionID, uint64_t Offset, unsigned RelType, RelocationValueRef Value) { - RelocationEntry RE(SectionID, Offset, RelType, Value.Addend, Value.Offset); - if (Value.SymbolName) - addRelocationForSymbol(RE, Value.SymbolName); - else - addRelocationForSection(RE, Value.SectionID); -} - -uint32_t RuntimeDyldELF::getMatchingLoRelocation(uint32_t RelType, - bool IsLocal) const { - switch (RelType) { - case ELF::R_MICROMIPS_GOT16: - if (IsLocal) - return ELF::R_MICROMIPS_LO16; - break; - case ELF::R_MICROMIPS_HI16: - return ELF::R_MICROMIPS_LO16; - case ELF::R_MIPS_GOT16: - if (IsLocal) - return ELF::R_MIPS_LO16; - break; - case ELF::R_MIPS_HI16: - return ELF::R_MIPS_LO16; - case ELF::R_MIPS_PCHI16: - return ELF::R_MIPS_PCLO16; - default: - break; - } - return ELF::R_MIPS_NONE; -} - -// Sometimes we don't need to create thunk for a branch. -// This typically happens when branch target is located -// in the same object file. In such case target is either -// a weak symbol or symbol in a different executable section. -// This function checks if branch target is located in the -// same object file and if distance between source and target -// fits R_AARCH64_CALL26 relocation. If both conditions are -// met, it emits direct jump to the target and returns true. -// Otherwise false is returned and thunk is created. -bool RuntimeDyldELF::resolveAArch64ShortBranch( - unsigned SectionID, relocation_iterator RelI, - const RelocationValueRef &Value) { - uint64_t Address; - if (Value.SymbolName) { - auto Loc = GlobalSymbolTable.find(Value.SymbolName); - - // Don't create direct branch for external symbols. - if (Loc == GlobalSymbolTable.end()) - return false; - - const auto &SymInfo = Loc->second; - Address = - uint64_t(Sections[SymInfo.getSectionID()].getLoadAddressWithOffset( - SymInfo.getOffset())); - } else { - Address = uint64_t(Sections[Value.SectionID].getLoadAddress()); - } - uint64_t Offset = RelI->getOffset(); - uint64_t SourceAddress = Sections[SectionID].getLoadAddressWithOffset(Offset); - - // R_AARCH64_CALL26 requires immediate to be in range -2^27 <= imm < 2^27 - // If distance between source and target is out of range then we should - // create thunk. - if (!isInt<28>(Address + Value.Addend - SourceAddress)) - return false; - - resolveRelocation(Sections[SectionID], Offset, Address, RelI->getType(), - Value.Addend); - - return true; -} - -void RuntimeDyldELF::resolveAArch64Branch(unsigned SectionID, - const RelocationValueRef &Value, - relocation_iterator RelI, - StubMap &Stubs) { - - LLVM_DEBUG(dbgs() << "\t\tThis is an AArch64 branch relocation."); - SectionEntry &Section = Sections[SectionID]; - - uint64_t Offset = RelI->getOffset(); - unsigned RelType = RelI->getType(); - // Look for an existing stub. - StubMap::const_iterator i = Stubs.find(Value); - if (i != Stubs.end()) { - resolveRelocation(Section, Offset, - (uint64_t)Section.getAddressWithOffset(i->second), - RelType, 0); - LLVM_DEBUG(dbgs() << " Stub function found\n"); - } else if (!resolveAArch64ShortBranch(SectionID, RelI, Value)) { - // Create a new stub function. - LLVM_DEBUG(dbgs() << " Create a new stub function\n"); - Stubs[Value] = Section.getStubOffset(); - uint8_t *StubTargetAddr = createStubFunction( - Section.getAddressWithOffset(Section.getStubOffset())); - - RelocationEntry REmovz_g3(SectionID, StubTargetAddr - Section.getAddress(), - ELF::R_AARCH64_MOVW_UABS_G3, Value.Addend); - RelocationEntry REmovk_g2(SectionID, - StubTargetAddr - Section.getAddress() + 4, - ELF::R_AARCH64_MOVW_UABS_G2_NC, Value.Addend); - RelocationEntry REmovk_g1(SectionID, - StubTargetAddr - Section.getAddress() + 8, - ELF::R_AARCH64_MOVW_UABS_G1_NC, Value.Addend); - RelocationEntry REmovk_g0(SectionID, - StubTargetAddr - Section.getAddress() + 12, - ELF::R_AARCH64_MOVW_UABS_G0_NC, Value.Addend); - - if (Value.SymbolName) { - addRelocationForSymbol(REmovz_g3, Value.SymbolName); - addRelocationForSymbol(REmovk_g2, Value.SymbolName); - addRelocationForSymbol(REmovk_g1, Value.SymbolName); - addRelocationForSymbol(REmovk_g0, Value.SymbolName); - } else { - addRelocationForSection(REmovz_g3, Value.SectionID); - addRelocationForSection(REmovk_g2, Value.SectionID); - addRelocationForSection(REmovk_g1, Value.SectionID); - addRelocationForSection(REmovk_g0, Value.SectionID); - } - resolveRelocation(Section, Offset, - reinterpret_cast<uint64_t>(Section.getAddressWithOffset( - Section.getStubOffset())), - RelType, 0); - Section.advanceStubOffset(getMaxStubSize()); - } -} - -Expected<relocation_iterator> -RuntimeDyldELF::processRelocationRef( - unsigned SectionID, relocation_iterator RelI, const ObjectFile &O, - ObjSectionToIDMap &ObjSectionToID, StubMap &Stubs) { - const auto &Obj = cast<ELFObjectFileBase>(O); - uint64_t RelType = RelI->getType(); - int64_t Addend = 0; - if (Expected<int64_t> AddendOrErr = ELFRelocationRef(*RelI).getAddend()) - Addend = *AddendOrErr; - else - consumeError(AddendOrErr.takeError()); - elf_symbol_iterator Symbol = RelI->getSymbol(); - - // Obtain the symbol name which is referenced in the relocation - StringRef TargetName; - if (Symbol != Obj.symbol_end()) { - if (auto TargetNameOrErr = Symbol->getName()) - TargetName = *TargetNameOrErr; - else - return TargetNameOrErr.takeError(); - } - LLVM_DEBUG(dbgs() << "\t\tRelType: " << RelType << " Addend: " << Addend - << " TargetName: " << TargetName << "\n"); - RelocationValueRef Value; - // First search for the symbol in the local symbol table - SymbolRef::Type SymType = SymbolRef::ST_Unknown; - - // Search for the symbol in the global symbol table - RTDyldSymbolTable::const_iterator gsi = GlobalSymbolTable.end(); - if (Symbol != Obj.symbol_end()) { - gsi = GlobalSymbolTable.find(TargetName.data()); - Expected<SymbolRef::Type> SymTypeOrErr = Symbol->getType(); - if (!SymTypeOrErr) { - std::string Buf; - raw_string_ostream OS(Buf); - logAllUnhandledErrors(SymTypeOrErr.takeError(), OS); - OS.flush(); - report_fatal_error(Buf); - } - SymType = *SymTypeOrErr; - } - if (gsi != GlobalSymbolTable.end()) { - const auto &SymInfo = gsi->second; - Value.SectionID = SymInfo.getSectionID(); - Value.Offset = SymInfo.getOffset(); - Value.Addend = SymInfo.getOffset() + Addend; - } else { - switch (SymType) { - case SymbolRef::ST_Debug: { - // TODO: Now ELF SymbolRef::ST_Debug = STT_SECTION, it's not obviously - // and can be changed by another developers. Maybe best way is add - // a new symbol type ST_Section to SymbolRef and use it. - auto SectionOrErr = Symbol->getSection(); - if (!SectionOrErr) { - std::string Buf; - raw_string_ostream OS(Buf); - logAllUnhandledErrors(SectionOrErr.takeError(), OS); - OS.flush(); - report_fatal_error(Buf); - } - section_iterator si = *SectionOrErr; - if (si == Obj.section_end()) - llvm_unreachable("Symbol section not found, bad object file format!"); - LLVM_DEBUG(dbgs() << "\t\tThis is section symbol\n"); - bool isCode = si->isText(); - if (auto SectionIDOrErr = findOrEmitSection(Obj, (*si), isCode, - ObjSectionToID)) - Value.SectionID = *SectionIDOrErr; - else - return SectionIDOrErr.takeError(); - Value.Addend = Addend; - break; - } - case SymbolRef::ST_Data: - case SymbolRef::ST_Function: - case SymbolRef::ST_Unknown: { - Value.SymbolName = TargetName.data(); - Value.Addend = Addend; - - // Absolute relocations will have a zero symbol ID (STN_UNDEF), which - // will manifest here as a NULL symbol name. - // We can set this as a valid (but empty) symbol name, and rely - // on addRelocationForSymbol to handle this. - if (!Value.SymbolName) - Value.SymbolName = ""; - break; - } - default: - llvm_unreachable("Unresolved symbol type!"); - break; - } - } - - uint64_t Offset = RelI->getOffset(); - - LLVM_DEBUG(dbgs() << "\t\tSectionID: " << SectionID << " Offset: " << Offset - << "\n"); - if ((Arch == Triple::aarch64 || Arch == Triple::aarch64_be)) { - if (RelType == ELF::R_AARCH64_CALL26 || RelType == ELF::R_AARCH64_JUMP26) { - resolveAArch64Branch(SectionID, Value, RelI, Stubs); - } else if (RelType == ELF::R_AARCH64_ADR_GOT_PAGE) { - // Craete new GOT entry or find existing one. If GOT entry is - // to be created, then we also emit ABS64 relocation for it. - uint64_t GOTOffset = findOrAllocGOTEntry(Value, ELF::R_AARCH64_ABS64); - resolveGOTOffsetRelocation(SectionID, Offset, GOTOffset + Addend, - ELF::R_AARCH64_ADR_PREL_PG_HI21); - - } else if (RelType == ELF::R_AARCH64_LD64_GOT_LO12_NC) { - uint64_t GOTOffset = findOrAllocGOTEntry(Value, ELF::R_AARCH64_ABS64); - resolveGOTOffsetRelocation(SectionID, Offset, GOTOffset + Addend, - ELF::R_AARCH64_LDST64_ABS_LO12_NC); - } else { - processSimpleRelocation(SectionID, Offset, RelType, Value); - } - } else if (Arch == Triple::arm) { - if (RelType == ELF::R_ARM_PC24 || RelType == ELF::R_ARM_CALL || - RelType == ELF::R_ARM_JUMP24) { - // This is an ARM branch relocation, need to use a stub function. - LLVM_DEBUG(dbgs() << "\t\tThis is an ARM branch relocation.\n"); - SectionEntry &Section = Sections[SectionID]; - - // Look for an existing stub. - StubMap::const_iterator i = Stubs.find(Value); - if (i != Stubs.end()) { - resolveRelocation( - Section, Offset, - reinterpret_cast<uint64_t>(Section.getAddressWithOffset(i->second)), - RelType, 0); - LLVM_DEBUG(dbgs() << " Stub function found\n"); - } else { - // Create a new stub function. - LLVM_DEBUG(dbgs() << " Create a new stub function\n"); - Stubs[Value] = Section.getStubOffset(); - uint8_t *StubTargetAddr = createStubFunction( - Section.getAddressWithOffset(Section.getStubOffset())); - RelocationEntry RE(SectionID, StubTargetAddr - Section.getAddress(), - ELF::R_ARM_ABS32, Value.Addend); - if (Value.SymbolName) - addRelocationForSymbol(RE, Value.SymbolName); - else - addRelocationForSection(RE, Value.SectionID); - - resolveRelocation(Section, Offset, reinterpret_cast<uint64_t>( - Section.getAddressWithOffset( - Section.getStubOffset())), - RelType, 0); - Section.advanceStubOffset(getMaxStubSize()); - } - } else { - uint32_t *Placeholder = - reinterpret_cast<uint32_t*>(computePlaceholderAddress(SectionID, Offset)); - if (RelType == ELF::R_ARM_PREL31 || RelType == ELF::R_ARM_TARGET1 || - RelType == ELF::R_ARM_ABS32) { - Value.Addend += *Placeholder; - } else if (RelType == ELF::R_ARM_MOVW_ABS_NC || RelType == ELF::R_ARM_MOVT_ABS) { - // See ELF for ARM documentation - Value.Addend += (int16_t)((*Placeholder & 0xFFF) | (((*Placeholder >> 16) & 0xF) << 12)); - } - processSimpleRelocation(SectionID, Offset, RelType, Value); - } - } else if (IsMipsO32ABI) { - uint8_t *Placeholder = reinterpret_cast<uint8_t *>( - computePlaceholderAddress(SectionID, Offset)); - uint32_t Opcode = readBytesUnaligned(Placeholder, 4); - if (RelType == ELF::R_MIPS_26) { - // This is an Mips branch relocation, need to use a stub function. - LLVM_DEBUG(dbgs() << "\t\tThis is a Mips branch relocation."); - SectionEntry &Section = Sections[SectionID]; - - // Extract the addend from the instruction. - // We shift up by two since the Value will be down shifted again - // when applying the relocation. - uint32_t Addend = (Opcode & 0x03ffffff) << 2; - - Value.Addend += Addend; - - // Look up for existing stub. - StubMap::const_iterator i = Stubs.find(Value); - if (i != Stubs.end()) { - RelocationEntry RE(SectionID, Offset, RelType, i->second); - addRelocationForSection(RE, SectionID); - LLVM_DEBUG(dbgs() << " Stub function found\n"); - } else { - // Create a new stub function. - LLVM_DEBUG(dbgs() << " Create a new stub function\n"); - Stubs[Value] = Section.getStubOffset(); - - unsigned AbiVariant = Obj.getPlatformFlags(); - - uint8_t *StubTargetAddr = createStubFunction( - Section.getAddressWithOffset(Section.getStubOffset()), AbiVariant); - - // Creating Hi and Lo relocations for the filled stub instructions. - RelocationEntry REHi(SectionID, StubTargetAddr - Section.getAddress(), - ELF::R_MIPS_HI16, Value.Addend); - RelocationEntry RELo(SectionID, - StubTargetAddr - Section.getAddress() + 4, - ELF::R_MIPS_LO16, Value.Addend); - - if (Value.SymbolName) { - addRelocationForSymbol(REHi, Value.SymbolName); - addRelocationForSymbol(RELo, Value.SymbolName); - } else { - addRelocationForSection(REHi, Value.SectionID); - addRelocationForSection(RELo, Value.SectionID); - } - - RelocationEntry RE(SectionID, Offset, RelType, Section.getStubOffset()); - addRelocationForSection(RE, SectionID); - Section.advanceStubOffset(getMaxStubSize()); - } - } else if (RelType == ELF::R_MIPS_HI16 || RelType == ELF::R_MIPS_PCHI16) { - int64_t Addend = (Opcode & 0x0000ffff) << 16; - RelocationEntry RE(SectionID, Offset, RelType, Addend); - PendingRelocs.push_back(std::make_pair(Value, RE)); - } else if (RelType == ELF::R_MIPS_LO16 || RelType == ELF::R_MIPS_PCLO16) { - int64_t Addend = Value.Addend + SignExtend32<16>(Opcode & 0x0000ffff); - for (auto I = PendingRelocs.begin(); I != PendingRelocs.end();) { - const RelocationValueRef &MatchingValue = I->first; - RelocationEntry &Reloc = I->second; - if (MatchingValue == Value && - RelType == getMatchingLoRelocation(Reloc.RelType) && - SectionID == Reloc.SectionID) { - Reloc.Addend += Addend; - if (Value.SymbolName) - addRelocationForSymbol(Reloc, Value.SymbolName); - else - addRelocationForSection(Reloc, Value.SectionID); - I = PendingRelocs.erase(I); - } else - ++I; - } - RelocationEntry RE(SectionID, Offset, RelType, Addend); - if (Value.SymbolName) - addRelocationForSymbol(RE, Value.SymbolName); - else - addRelocationForSection(RE, Value.SectionID); - } else { - if (RelType == ELF::R_MIPS_32) - Value.Addend += Opcode; - else if (RelType == ELF::R_MIPS_PC16) - Value.Addend += SignExtend32<18>((Opcode & 0x0000ffff) << 2); - else if (RelType == ELF::R_MIPS_PC19_S2) - Value.Addend += SignExtend32<21>((Opcode & 0x0007ffff) << 2); - else if (RelType == ELF::R_MIPS_PC21_S2) - Value.Addend += SignExtend32<23>((Opcode & 0x001fffff) << 2); - else if (RelType == ELF::R_MIPS_PC26_S2) - Value.Addend += SignExtend32<28>((Opcode & 0x03ffffff) << 2); - processSimpleRelocation(SectionID, Offset, RelType, Value); - } - } else if (IsMipsN32ABI || IsMipsN64ABI) { - uint32_t r_type = RelType & 0xff; - RelocationEntry RE(SectionID, Offset, RelType, Value.Addend); - if (r_type == ELF::R_MIPS_CALL16 || r_type == ELF::R_MIPS_GOT_PAGE - || r_type == ELF::R_MIPS_GOT_DISP) { - StringMap<uint64_t>::iterator i = GOTSymbolOffsets.find(TargetName); - if (i != GOTSymbolOffsets.end()) - RE.SymOffset = i->second; - else { - RE.SymOffset = allocateGOTEntries(1); - GOTSymbolOffsets[TargetName] = RE.SymOffset; - } - if (Value.SymbolName) - addRelocationForSymbol(RE, Value.SymbolName); - else - addRelocationForSection(RE, Value.SectionID); - } else if (RelType == ELF::R_MIPS_26) { - // This is an Mips branch relocation, need to use a stub function. - LLVM_DEBUG(dbgs() << "\t\tThis is a Mips branch relocation."); - SectionEntry &Section = Sections[SectionID]; - - // Look up for existing stub. - StubMap::const_iterator i = Stubs.find(Value); - if (i != Stubs.end()) { - RelocationEntry RE(SectionID, Offset, RelType, i->second); - addRelocationForSection(RE, SectionID); - LLVM_DEBUG(dbgs() << " Stub function found\n"); - } else { - // Create a new stub function. - LLVM_DEBUG(dbgs() << " Create a new stub function\n"); - Stubs[Value] = Section.getStubOffset(); - - unsigned AbiVariant = Obj.getPlatformFlags(); - - uint8_t *StubTargetAddr = createStubFunction( - Section.getAddressWithOffset(Section.getStubOffset()), AbiVariant); - - if (IsMipsN32ABI) { - // Creating Hi and Lo relocations for the filled stub instructions. - RelocationEntry REHi(SectionID, StubTargetAddr - Section.getAddress(), - ELF::R_MIPS_HI16, Value.Addend); - RelocationEntry RELo(SectionID, - StubTargetAddr - Section.getAddress() + 4, - ELF::R_MIPS_LO16, Value.Addend); - if (Value.SymbolName) { - addRelocationForSymbol(REHi, Value.SymbolName); - addRelocationForSymbol(RELo, Value.SymbolName); - } else { - addRelocationForSection(REHi, Value.SectionID); - addRelocationForSection(RELo, Value.SectionID); - } - } else { - // Creating Highest, Higher, Hi and Lo relocations for the filled stub - // instructions. - RelocationEntry REHighest(SectionID, - StubTargetAddr - Section.getAddress(), - ELF::R_MIPS_HIGHEST, Value.Addend); - RelocationEntry REHigher(SectionID, - StubTargetAddr - Section.getAddress() + 4, - ELF::R_MIPS_HIGHER, Value.Addend); - RelocationEntry REHi(SectionID, - StubTargetAddr - Section.getAddress() + 12, - ELF::R_MIPS_HI16, Value.Addend); - RelocationEntry RELo(SectionID, - StubTargetAddr - Section.getAddress() + 20, - ELF::R_MIPS_LO16, Value.Addend); - if (Value.SymbolName) { - addRelocationForSymbol(REHighest, Value.SymbolName); - addRelocationForSymbol(REHigher, Value.SymbolName); - addRelocationForSymbol(REHi, Value.SymbolName); - addRelocationForSymbol(RELo, Value.SymbolName); - } else { - addRelocationForSection(REHighest, Value.SectionID); - addRelocationForSection(REHigher, Value.SectionID); - addRelocationForSection(REHi, Value.SectionID); - addRelocationForSection(RELo, Value.SectionID); - } - } - RelocationEntry RE(SectionID, Offset, RelType, Section.getStubOffset()); - addRelocationForSection(RE, SectionID); - Section.advanceStubOffset(getMaxStubSize()); - } - } else { - processSimpleRelocation(SectionID, Offset, RelType, Value); - } - - } else if (Arch == Triple::ppc64 || Arch == Triple::ppc64le) { - if (RelType == ELF::R_PPC64_REL24) { - // Determine ABI variant in use for this object. - unsigned AbiVariant = Obj.getPlatformFlags(); - AbiVariant &= ELF::EF_PPC64_ABI; - // A PPC branch relocation will need a stub function if the target is - // an external symbol (either Value.SymbolName is set, or SymType is - // Symbol::ST_Unknown) or if the target address is not within the - // signed 24-bits branch address. - SectionEntry &Section = Sections[SectionID]; - uint8_t *Target = Section.getAddressWithOffset(Offset); - bool RangeOverflow = false; - bool IsExtern = Value.SymbolName || SymType == SymbolRef::ST_Unknown; - if (!IsExtern) { - if (AbiVariant != 2) { - // In the ELFv1 ABI, a function call may point to the .opd entry, - // so the final symbol value is calculated based on the relocation - // values in the .opd section. - if (auto Err = findOPDEntrySection(Obj, ObjSectionToID, Value)) - return std::move(Err); - } else { - // In the ELFv2 ABI, a function symbol may provide a local entry - // point, which must be used for direct calls. - if (Value.SectionID == SectionID){ - uint8_t SymOther = Symbol->getOther(); - Value.Addend += ELF::decodePPC64LocalEntryOffset(SymOther); - } - } - uint8_t *RelocTarget = - Sections[Value.SectionID].getAddressWithOffset(Value.Addend); - int64_t delta = static_cast<int64_t>(Target - RelocTarget); - // If it is within 26-bits branch range, just set the branch target - if (SignExtend64<26>(delta) != delta) { - RangeOverflow = true; - } else if ((AbiVariant != 2) || - (AbiVariant == 2 && Value.SectionID == SectionID)) { - RelocationEntry RE(SectionID, Offset, RelType, Value.Addend); - addRelocationForSection(RE, Value.SectionID); - } - } - if (IsExtern || (AbiVariant == 2 && Value.SectionID != SectionID) || - RangeOverflow) { - // It is an external symbol (either Value.SymbolName is set, or - // SymType is SymbolRef::ST_Unknown) or out of range. - StubMap::const_iterator i = Stubs.find(Value); - if (i != Stubs.end()) { - // Symbol function stub already created, just relocate to it - resolveRelocation(Section, Offset, - reinterpret_cast<uint64_t>( - Section.getAddressWithOffset(i->second)), - RelType, 0); - LLVM_DEBUG(dbgs() << " Stub function found\n"); - } else { - // Create a new stub function. - LLVM_DEBUG(dbgs() << " Create a new stub function\n"); - Stubs[Value] = Section.getStubOffset(); - uint8_t *StubTargetAddr = createStubFunction( - Section.getAddressWithOffset(Section.getStubOffset()), - AbiVariant); - RelocationEntry RE(SectionID, StubTargetAddr - Section.getAddress(), - ELF::R_PPC64_ADDR64, Value.Addend); - - // Generates the 64-bits address loads as exemplified in section - // 4.5.1 in PPC64 ELF ABI. Note that the relocations need to - // apply to the low part of the instructions, so we have to update - // the offset according to the target endianness. - uint64_t StubRelocOffset = StubTargetAddr - Section.getAddress(); - if (!IsTargetLittleEndian) - StubRelocOffset += 2; - - RelocationEntry REhst(SectionID, StubRelocOffset + 0, - ELF::R_PPC64_ADDR16_HIGHEST, Value.Addend); - RelocationEntry REhr(SectionID, StubRelocOffset + 4, - ELF::R_PPC64_ADDR16_HIGHER, Value.Addend); - RelocationEntry REh(SectionID, StubRelocOffset + 12, - ELF::R_PPC64_ADDR16_HI, Value.Addend); - RelocationEntry REl(SectionID, StubRelocOffset + 16, - ELF::R_PPC64_ADDR16_LO, Value.Addend); - - if (Value.SymbolName) { - addRelocationForSymbol(REhst, Value.SymbolName); - addRelocationForSymbol(REhr, Value.SymbolName); - addRelocationForSymbol(REh, Value.SymbolName); - addRelocationForSymbol(REl, Value.SymbolName); - } else { - addRelocationForSection(REhst, Value.SectionID); - addRelocationForSection(REhr, Value.SectionID); - addRelocationForSection(REh, Value.SectionID); - addRelocationForSection(REl, Value.SectionID); - } - - resolveRelocation(Section, Offset, reinterpret_cast<uint64_t>( - Section.getAddressWithOffset( - Section.getStubOffset())), - RelType, 0); - Section.advanceStubOffset(getMaxStubSize()); - } - if (IsExtern || (AbiVariant == 2 && Value.SectionID != SectionID)) { - // Restore the TOC for external calls - if (AbiVariant == 2) - writeInt32BE(Target + 4, 0xE8410018); // ld r2,24(r1) - else - writeInt32BE(Target + 4, 0xE8410028); // ld r2,40(r1) - } - } - } else if (RelType == ELF::R_PPC64_TOC16 || - RelType == ELF::R_PPC64_TOC16_DS || - RelType == ELF::R_PPC64_TOC16_LO || - RelType == ELF::R_PPC64_TOC16_LO_DS || - RelType == ELF::R_PPC64_TOC16_HI || - RelType == ELF::R_PPC64_TOC16_HA) { - // These relocations are supposed to subtract the TOC address from - // the final value. This does not fit cleanly into the RuntimeDyld - // scheme, since there may be *two* sections involved in determining - // the relocation value (the section of the symbol referred to by the - // relocation, and the TOC section associated with the current module). - // - // Fortunately, these relocations are currently only ever generated - // referring to symbols that themselves reside in the TOC, which means - // that the two sections are actually the same. Thus they cancel out - // and we can immediately resolve the relocation right now. - switch (RelType) { - case ELF::R_PPC64_TOC16: RelType = ELF::R_PPC64_ADDR16; break; - case ELF::R_PPC64_TOC16_DS: RelType = ELF::R_PPC64_ADDR16_DS; break; - case ELF::R_PPC64_TOC16_LO: RelType = ELF::R_PPC64_ADDR16_LO; break; - case ELF::R_PPC64_TOC16_LO_DS: RelType = ELF::R_PPC64_ADDR16_LO_DS; break; - case ELF::R_PPC64_TOC16_HI: RelType = ELF::R_PPC64_ADDR16_HI; break; - case ELF::R_PPC64_TOC16_HA: RelType = ELF::R_PPC64_ADDR16_HA; break; - default: llvm_unreachable("Wrong relocation type."); - } - - RelocationValueRef TOCValue; - if (auto Err = findPPC64TOCSection(Obj, ObjSectionToID, TOCValue)) - return std::move(Err); - if (Value.SymbolName || Value.SectionID != TOCValue.SectionID) - llvm_unreachable("Unsupported TOC relocation."); - Value.Addend -= TOCValue.Addend; - resolveRelocation(Sections[SectionID], Offset, Value.Addend, RelType, 0); - } else { - // There are two ways to refer to the TOC address directly: either - // via a ELF::R_PPC64_TOC relocation (where both symbol and addend are - // ignored), or via any relocation that refers to the magic ".TOC." - // symbols (in which case the addend is respected). - if (RelType == ELF::R_PPC64_TOC) { - RelType = ELF::R_PPC64_ADDR64; - if (auto Err = findPPC64TOCSection(Obj, ObjSectionToID, Value)) - return std::move(Err); - } else if (TargetName == ".TOC.") { - if (auto Err = findPPC64TOCSection(Obj, ObjSectionToID, Value)) - return std::move(Err); - Value.Addend += Addend; - } - - RelocationEntry RE(SectionID, Offset, RelType, Value.Addend); - - if (Value.SymbolName) - addRelocationForSymbol(RE, Value.SymbolName); - else - addRelocationForSection(RE, Value.SectionID); - } - } else if (Arch == Triple::systemz && - (RelType == ELF::R_390_PLT32DBL || RelType == ELF::R_390_GOTENT)) { - // Create function stubs for both PLT and GOT references, regardless of - // whether the GOT reference is to data or code. The stub contains the - // full address of the symbol, as needed by GOT references, and the - // executable part only adds an overhead of 8 bytes. - // - // We could try to conserve space by allocating the code and data - // parts of the stub separately. However, as things stand, we allocate - // a stub for every relocation, so using a GOT in JIT code should be - // no less space efficient than using an explicit constant pool. - LLVM_DEBUG(dbgs() << "\t\tThis is a SystemZ indirect relocation."); - SectionEntry &Section = Sections[SectionID]; - - // Look for an existing stub. - StubMap::const_iterator i = Stubs.find(Value); - uintptr_t StubAddress; - if (i != Stubs.end()) { - StubAddress = uintptr_t(Section.getAddressWithOffset(i->second)); - LLVM_DEBUG(dbgs() << " Stub function found\n"); - } else { - // Create a new stub function. - LLVM_DEBUG(dbgs() << " Create a new stub function\n"); - - uintptr_t BaseAddress = uintptr_t(Section.getAddress()); - uintptr_t StubAlignment = getStubAlignment(); - StubAddress = - (BaseAddress + Section.getStubOffset() + StubAlignment - 1) & - -StubAlignment; - unsigned StubOffset = StubAddress - BaseAddress; - - Stubs[Value] = StubOffset; - createStubFunction((uint8_t *)StubAddress); - RelocationEntry RE(SectionID, StubOffset + 8, ELF::R_390_64, - Value.Offset); - if (Value.SymbolName) - addRelocationForSymbol(RE, Value.SymbolName); - else - addRelocationForSection(RE, Value.SectionID); - Section.advanceStubOffset(getMaxStubSize()); - } - - if (RelType == ELF::R_390_GOTENT) - resolveRelocation(Section, Offset, StubAddress + 8, ELF::R_390_PC32DBL, - Addend); - else - resolveRelocation(Section, Offset, StubAddress, RelType, Addend); - } else if (Arch == Triple::x86_64) { - if (RelType == ELF::R_X86_64_PLT32) { - // The way the PLT relocations normally work is that the linker allocates - // the - // PLT and this relocation makes a PC-relative call into the PLT. The PLT - // entry will then jump to an address provided by the GOT. On first call, - // the - // GOT address will point back into PLT code that resolves the symbol. After - // the first call, the GOT entry points to the actual function. - // - // For local functions we're ignoring all of that here and just replacing - // the PLT32 relocation type with PC32, which will translate the relocation - // into a PC-relative call directly to the function. For external symbols we - // can't be sure the function will be within 2^32 bytes of the call site, so - // we need to create a stub, which calls into the GOT. This case is - // equivalent to the usual PLT implementation except that we use the stub - // mechanism in RuntimeDyld (which puts stubs at the end of the section) - // rather than allocating a PLT section. - if (Value.SymbolName) { - // This is a call to an external function. - // Look for an existing stub. + resolvePPC32Relocation(Section, Offset, Value, Type, Addend); + break; + case Triple::ppc64: // Fall through. + case Triple::ppc64le: + resolvePPC64Relocation(Section, Offset, Value, Type, Addend); + break; + case Triple::systemz: + resolveSystemZRelocation(Section, Offset, Value, Type, Addend); + break; + case Triple::bpfel: + case Triple::bpfeb: + resolveBPFRelocation(Section, Offset, Value, Type, Addend); + break; + default: + llvm_unreachable("Unsupported CPU type!"); + } +} + +void *RuntimeDyldELF::computePlaceholderAddress(unsigned SectionID, uint64_t Offset) const { + return (void *)(Sections[SectionID].getObjAddress() + Offset); +} + +void RuntimeDyldELF::processSimpleRelocation(unsigned SectionID, uint64_t Offset, unsigned RelType, RelocationValueRef Value) { + RelocationEntry RE(SectionID, Offset, RelType, Value.Addend, Value.Offset); + if (Value.SymbolName) + addRelocationForSymbol(RE, Value.SymbolName); + else + addRelocationForSection(RE, Value.SectionID); +} + +uint32_t RuntimeDyldELF::getMatchingLoRelocation(uint32_t RelType, + bool IsLocal) const { + switch (RelType) { + case ELF::R_MICROMIPS_GOT16: + if (IsLocal) + return ELF::R_MICROMIPS_LO16; + break; + case ELF::R_MICROMIPS_HI16: + return ELF::R_MICROMIPS_LO16; + case ELF::R_MIPS_GOT16: + if (IsLocal) + return ELF::R_MIPS_LO16; + break; + case ELF::R_MIPS_HI16: + return ELF::R_MIPS_LO16; + case ELF::R_MIPS_PCHI16: + return ELF::R_MIPS_PCLO16; + default: + break; + } + return ELF::R_MIPS_NONE; +} + +// Sometimes we don't need to create thunk for a branch. +// This typically happens when branch target is located +// in the same object file. In such case target is either +// a weak symbol or symbol in a different executable section. +// This function checks if branch target is located in the +// same object file and if distance between source and target +// fits R_AARCH64_CALL26 relocation. If both conditions are +// met, it emits direct jump to the target and returns true. +// Otherwise false is returned and thunk is created. +bool RuntimeDyldELF::resolveAArch64ShortBranch( + unsigned SectionID, relocation_iterator RelI, + const RelocationValueRef &Value) { + uint64_t Address; + if (Value.SymbolName) { + auto Loc = GlobalSymbolTable.find(Value.SymbolName); + + // Don't create direct branch for external symbols. + if (Loc == GlobalSymbolTable.end()) + return false; + + const auto &SymInfo = Loc->second; + Address = + uint64_t(Sections[SymInfo.getSectionID()].getLoadAddressWithOffset( + SymInfo.getOffset())); + } else { + Address = uint64_t(Sections[Value.SectionID].getLoadAddress()); + } + uint64_t Offset = RelI->getOffset(); + uint64_t SourceAddress = Sections[SectionID].getLoadAddressWithOffset(Offset); + + // R_AARCH64_CALL26 requires immediate to be in range -2^27 <= imm < 2^27 + // If distance between source and target is out of range then we should + // create thunk. + if (!isInt<28>(Address + Value.Addend - SourceAddress)) + return false; + + resolveRelocation(Sections[SectionID], Offset, Address, RelI->getType(), + Value.Addend); + + return true; +} + +void RuntimeDyldELF::resolveAArch64Branch(unsigned SectionID, + const RelocationValueRef &Value, + relocation_iterator RelI, + StubMap &Stubs) { + + LLVM_DEBUG(dbgs() << "\t\tThis is an AArch64 branch relocation."); + SectionEntry &Section = Sections[SectionID]; + + uint64_t Offset = RelI->getOffset(); + unsigned RelType = RelI->getType(); + // Look for an existing stub. + StubMap::const_iterator i = Stubs.find(Value); + if (i != Stubs.end()) { + resolveRelocation(Section, Offset, + (uint64_t)Section.getAddressWithOffset(i->second), + RelType, 0); + LLVM_DEBUG(dbgs() << " Stub function found\n"); + } else if (!resolveAArch64ShortBranch(SectionID, RelI, Value)) { + // Create a new stub function. + LLVM_DEBUG(dbgs() << " Create a new stub function\n"); + Stubs[Value] = Section.getStubOffset(); + uint8_t *StubTargetAddr = createStubFunction( + Section.getAddressWithOffset(Section.getStubOffset())); + + RelocationEntry REmovz_g3(SectionID, StubTargetAddr - Section.getAddress(), + ELF::R_AARCH64_MOVW_UABS_G3, Value.Addend); + RelocationEntry REmovk_g2(SectionID, + StubTargetAddr - Section.getAddress() + 4, + ELF::R_AARCH64_MOVW_UABS_G2_NC, Value.Addend); + RelocationEntry REmovk_g1(SectionID, + StubTargetAddr - Section.getAddress() + 8, + ELF::R_AARCH64_MOVW_UABS_G1_NC, Value.Addend); + RelocationEntry REmovk_g0(SectionID, + StubTargetAddr - Section.getAddress() + 12, + ELF::R_AARCH64_MOVW_UABS_G0_NC, Value.Addend); + + if (Value.SymbolName) { + addRelocationForSymbol(REmovz_g3, Value.SymbolName); + addRelocationForSymbol(REmovk_g2, Value.SymbolName); + addRelocationForSymbol(REmovk_g1, Value.SymbolName); + addRelocationForSymbol(REmovk_g0, Value.SymbolName); + } else { + addRelocationForSection(REmovz_g3, Value.SectionID); + addRelocationForSection(REmovk_g2, Value.SectionID); + addRelocationForSection(REmovk_g1, Value.SectionID); + addRelocationForSection(REmovk_g0, Value.SectionID); + } + resolveRelocation(Section, Offset, + reinterpret_cast<uint64_t>(Section.getAddressWithOffset( + Section.getStubOffset())), + RelType, 0); + Section.advanceStubOffset(getMaxStubSize()); + } +} + +Expected<relocation_iterator> +RuntimeDyldELF::processRelocationRef( + unsigned SectionID, relocation_iterator RelI, const ObjectFile &O, + ObjSectionToIDMap &ObjSectionToID, StubMap &Stubs) { + const auto &Obj = cast<ELFObjectFileBase>(O); + uint64_t RelType = RelI->getType(); + int64_t Addend = 0; + if (Expected<int64_t> AddendOrErr = ELFRelocationRef(*RelI).getAddend()) + Addend = *AddendOrErr; + else + consumeError(AddendOrErr.takeError()); + elf_symbol_iterator Symbol = RelI->getSymbol(); + + // Obtain the symbol name which is referenced in the relocation + StringRef TargetName; + if (Symbol != Obj.symbol_end()) { + if (auto TargetNameOrErr = Symbol->getName()) + TargetName = *TargetNameOrErr; + else + return TargetNameOrErr.takeError(); + } + LLVM_DEBUG(dbgs() << "\t\tRelType: " << RelType << " Addend: " << Addend + << " TargetName: " << TargetName << "\n"); + RelocationValueRef Value; + // First search for the symbol in the local symbol table + SymbolRef::Type SymType = SymbolRef::ST_Unknown; + + // Search for the symbol in the global symbol table + RTDyldSymbolTable::const_iterator gsi = GlobalSymbolTable.end(); + if (Symbol != Obj.symbol_end()) { + gsi = GlobalSymbolTable.find(TargetName.data()); + Expected<SymbolRef::Type> SymTypeOrErr = Symbol->getType(); + if (!SymTypeOrErr) { + std::string Buf; + raw_string_ostream OS(Buf); + logAllUnhandledErrors(SymTypeOrErr.takeError(), OS); + OS.flush(); + report_fatal_error(Buf); + } + SymType = *SymTypeOrErr; + } + if (gsi != GlobalSymbolTable.end()) { + const auto &SymInfo = gsi->second; + Value.SectionID = SymInfo.getSectionID(); + Value.Offset = SymInfo.getOffset(); + Value.Addend = SymInfo.getOffset() + Addend; + } else { + switch (SymType) { + case SymbolRef::ST_Debug: { + // TODO: Now ELF SymbolRef::ST_Debug = STT_SECTION, it's not obviously + // and can be changed by another developers. Maybe best way is add + // a new symbol type ST_Section to SymbolRef and use it. + auto SectionOrErr = Symbol->getSection(); + if (!SectionOrErr) { + std::string Buf; + raw_string_ostream OS(Buf); + logAllUnhandledErrors(SectionOrErr.takeError(), OS); + OS.flush(); + report_fatal_error(Buf); + } + section_iterator si = *SectionOrErr; + if (si == Obj.section_end()) + llvm_unreachable("Symbol section not found, bad object file format!"); + LLVM_DEBUG(dbgs() << "\t\tThis is section symbol\n"); + bool isCode = si->isText(); + if (auto SectionIDOrErr = findOrEmitSection(Obj, (*si), isCode, + ObjSectionToID)) + Value.SectionID = *SectionIDOrErr; + else + return SectionIDOrErr.takeError(); + Value.Addend = Addend; + break; + } + case SymbolRef::ST_Data: + case SymbolRef::ST_Function: + case SymbolRef::ST_Unknown: { + Value.SymbolName = TargetName.data(); + Value.Addend = Addend; + + // Absolute relocations will have a zero symbol ID (STN_UNDEF), which + // will manifest here as a NULL symbol name. + // We can set this as a valid (but empty) symbol name, and rely + // on addRelocationForSymbol to handle this. + if (!Value.SymbolName) + Value.SymbolName = ""; + break; + } + default: + llvm_unreachable("Unresolved symbol type!"); + break; + } + } + + uint64_t Offset = RelI->getOffset(); + + LLVM_DEBUG(dbgs() << "\t\tSectionID: " << SectionID << " Offset: " << Offset + << "\n"); + if ((Arch == Triple::aarch64 || Arch == Triple::aarch64_be)) { + if (RelType == ELF::R_AARCH64_CALL26 || RelType == ELF::R_AARCH64_JUMP26) { + resolveAArch64Branch(SectionID, Value, RelI, Stubs); + } else if (RelType == ELF::R_AARCH64_ADR_GOT_PAGE) { + // Craete new GOT entry or find existing one. If GOT entry is + // to be created, then we also emit ABS64 relocation for it. + uint64_t GOTOffset = findOrAllocGOTEntry(Value, ELF::R_AARCH64_ABS64); + resolveGOTOffsetRelocation(SectionID, Offset, GOTOffset + Addend, + ELF::R_AARCH64_ADR_PREL_PG_HI21); + + } else if (RelType == ELF::R_AARCH64_LD64_GOT_LO12_NC) { + uint64_t GOTOffset = findOrAllocGOTEntry(Value, ELF::R_AARCH64_ABS64); + resolveGOTOffsetRelocation(SectionID, Offset, GOTOffset + Addend, + ELF::R_AARCH64_LDST64_ABS_LO12_NC); + } else { + processSimpleRelocation(SectionID, Offset, RelType, Value); + } + } else if (Arch == Triple::arm) { + if (RelType == ELF::R_ARM_PC24 || RelType == ELF::R_ARM_CALL || + RelType == ELF::R_ARM_JUMP24) { + // This is an ARM branch relocation, need to use a stub function. + LLVM_DEBUG(dbgs() << "\t\tThis is an ARM branch relocation.\n"); + SectionEntry &Section = Sections[SectionID]; + + // Look for an existing stub. + StubMap::const_iterator i = Stubs.find(Value); + if (i != Stubs.end()) { + resolveRelocation( + Section, Offset, + reinterpret_cast<uint64_t>(Section.getAddressWithOffset(i->second)), + RelType, 0); + LLVM_DEBUG(dbgs() << " Stub function found\n"); + } else { + // Create a new stub function. + LLVM_DEBUG(dbgs() << " Create a new stub function\n"); + Stubs[Value] = Section.getStubOffset(); + uint8_t *StubTargetAddr = createStubFunction( + Section.getAddressWithOffset(Section.getStubOffset())); + RelocationEntry RE(SectionID, StubTargetAddr - Section.getAddress(), + ELF::R_ARM_ABS32, Value.Addend); + if (Value.SymbolName) + addRelocationForSymbol(RE, Value.SymbolName); + else + addRelocationForSection(RE, Value.SectionID); + + resolveRelocation(Section, Offset, reinterpret_cast<uint64_t>( + Section.getAddressWithOffset( + Section.getStubOffset())), + RelType, 0); + Section.advanceStubOffset(getMaxStubSize()); + } + } else { + uint32_t *Placeholder = + reinterpret_cast<uint32_t*>(computePlaceholderAddress(SectionID, Offset)); + if (RelType == ELF::R_ARM_PREL31 || RelType == ELF::R_ARM_TARGET1 || + RelType == ELF::R_ARM_ABS32) { + Value.Addend += *Placeholder; + } else if (RelType == ELF::R_ARM_MOVW_ABS_NC || RelType == ELF::R_ARM_MOVT_ABS) { + // See ELF for ARM documentation + Value.Addend += (int16_t)((*Placeholder & 0xFFF) | (((*Placeholder >> 16) & 0xF) << 12)); + } + processSimpleRelocation(SectionID, Offset, RelType, Value); + } + } else if (IsMipsO32ABI) { + uint8_t *Placeholder = reinterpret_cast<uint8_t *>( + computePlaceholderAddress(SectionID, Offset)); + uint32_t Opcode = readBytesUnaligned(Placeholder, 4); + if (RelType == ELF::R_MIPS_26) { + // This is an Mips branch relocation, need to use a stub function. + LLVM_DEBUG(dbgs() << "\t\tThis is a Mips branch relocation."); + SectionEntry &Section = Sections[SectionID]; + + // Extract the addend from the instruction. + // We shift up by two since the Value will be down shifted again + // when applying the relocation. + uint32_t Addend = (Opcode & 0x03ffffff) << 2; + + Value.Addend += Addend; + + // Look up for existing stub. + StubMap::const_iterator i = Stubs.find(Value); + if (i != Stubs.end()) { + RelocationEntry RE(SectionID, Offset, RelType, i->second); + addRelocationForSection(RE, SectionID); + LLVM_DEBUG(dbgs() << " Stub function found\n"); + } else { + // Create a new stub function. + LLVM_DEBUG(dbgs() << " Create a new stub function\n"); + Stubs[Value] = Section.getStubOffset(); + + unsigned AbiVariant = Obj.getPlatformFlags(); + + uint8_t *StubTargetAddr = createStubFunction( + Section.getAddressWithOffset(Section.getStubOffset()), AbiVariant); + + // Creating Hi and Lo relocations for the filled stub instructions. + RelocationEntry REHi(SectionID, StubTargetAddr - Section.getAddress(), + ELF::R_MIPS_HI16, Value.Addend); + RelocationEntry RELo(SectionID, + StubTargetAddr - Section.getAddress() + 4, + ELF::R_MIPS_LO16, Value.Addend); + + if (Value.SymbolName) { + addRelocationForSymbol(REHi, Value.SymbolName); + addRelocationForSymbol(RELo, Value.SymbolName); + } else { + addRelocationForSection(REHi, Value.SectionID); + addRelocationForSection(RELo, Value.SectionID); + } + + RelocationEntry RE(SectionID, Offset, RelType, Section.getStubOffset()); + addRelocationForSection(RE, SectionID); + Section.advanceStubOffset(getMaxStubSize()); + } + } else if (RelType == ELF::R_MIPS_HI16 || RelType == ELF::R_MIPS_PCHI16) { + int64_t Addend = (Opcode & 0x0000ffff) << 16; + RelocationEntry RE(SectionID, Offset, RelType, Addend); + PendingRelocs.push_back(std::make_pair(Value, RE)); + } else if (RelType == ELF::R_MIPS_LO16 || RelType == ELF::R_MIPS_PCLO16) { + int64_t Addend = Value.Addend + SignExtend32<16>(Opcode & 0x0000ffff); + for (auto I = PendingRelocs.begin(); I != PendingRelocs.end();) { + const RelocationValueRef &MatchingValue = I->first; + RelocationEntry &Reloc = I->second; + if (MatchingValue == Value && + RelType == getMatchingLoRelocation(Reloc.RelType) && + SectionID == Reloc.SectionID) { + Reloc.Addend += Addend; + if (Value.SymbolName) + addRelocationForSymbol(Reloc, Value.SymbolName); + else + addRelocationForSection(Reloc, Value.SectionID); + I = PendingRelocs.erase(I); + } else + ++I; + } + RelocationEntry RE(SectionID, Offset, RelType, Addend); + if (Value.SymbolName) + addRelocationForSymbol(RE, Value.SymbolName); + else + addRelocationForSection(RE, Value.SectionID); + } else { + if (RelType == ELF::R_MIPS_32) + Value.Addend += Opcode; + else if (RelType == ELF::R_MIPS_PC16) + Value.Addend += SignExtend32<18>((Opcode & 0x0000ffff) << 2); + else if (RelType == ELF::R_MIPS_PC19_S2) + Value.Addend += SignExtend32<21>((Opcode & 0x0007ffff) << 2); + else if (RelType == ELF::R_MIPS_PC21_S2) + Value.Addend += SignExtend32<23>((Opcode & 0x001fffff) << 2); + else if (RelType == ELF::R_MIPS_PC26_S2) + Value.Addend += SignExtend32<28>((Opcode & 0x03ffffff) << 2); + processSimpleRelocation(SectionID, Offset, RelType, Value); + } + } else if (IsMipsN32ABI || IsMipsN64ABI) { + uint32_t r_type = RelType & 0xff; + RelocationEntry RE(SectionID, Offset, RelType, Value.Addend); + if (r_type == ELF::R_MIPS_CALL16 || r_type == ELF::R_MIPS_GOT_PAGE + || r_type == ELF::R_MIPS_GOT_DISP) { + StringMap<uint64_t>::iterator i = GOTSymbolOffsets.find(TargetName); + if (i != GOTSymbolOffsets.end()) + RE.SymOffset = i->second; + else { + RE.SymOffset = allocateGOTEntries(1); + GOTSymbolOffsets[TargetName] = RE.SymOffset; + } + if (Value.SymbolName) + addRelocationForSymbol(RE, Value.SymbolName); + else + addRelocationForSection(RE, Value.SectionID); + } else if (RelType == ELF::R_MIPS_26) { + // This is an Mips branch relocation, need to use a stub function. + LLVM_DEBUG(dbgs() << "\t\tThis is a Mips branch relocation."); + SectionEntry &Section = Sections[SectionID]; + + // Look up for existing stub. + StubMap::const_iterator i = Stubs.find(Value); + if (i != Stubs.end()) { + RelocationEntry RE(SectionID, Offset, RelType, i->second); + addRelocationForSection(RE, SectionID); + LLVM_DEBUG(dbgs() << " Stub function found\n"); + } else { + // Create a new stub function. + LLVM_DEBUG(dbgs() << " Create a new stub function\n"); + Stubs[Value] = Section.getStubOffset(); + + unsigned AbiVariant = Obj.getPlatformFlags(); + + uint8_t *StubTargetAddr = createStubFunction( + Section.getAddressWithOffset(Section.getStubOffset()), AbiVariant); + + if (IsMipsN32ABI) { + // Creating Hi and Lo relocations for the filled stub instructions. + RelocationEntry REHi(SectionID, StubTargetAddr - Section.getAddress(), + ELF::R_MIPS_HI16, Value.Addend); + RelocationEntry RELo(SectionID, + StubTargetAddr - Section.getAddress() + 4, + ELF::R_MIPS_LO16, Value.Addend); + if (Value.SymbolName) { + addRelocationForSymbol(REHi, Value.SymbolName); + addRelocationForSymbol(RELo, Value.SymbolName); + } else { + addRelocationForSection(REHi, Value.SectionID); + addRelocationForSection(RELo, Value.SectionID); + } + } else { + // Creating Highest, Higher, Hi and Lo relocations for the filled stub + // instructions. + RelocationEntry REHighest(SectionID, + StubTargetAddr - Section.getAddress(), + ELF::R_MIPS_HIGHEST, Value.Addend); + RelocationEntry REHigher(SectionID, + StubTargetAddr - Section.getAddress() + 4, + ELF::R_MIPS_HIGHER, Value.Addend); + RelocationEntry REHi(SectionID, + StubTargetAddr - Section.getAddress() + 12, + ELF::R_MIPS_HI16, Value.Addend); + RelocationEntry RELo(SectionID, + StubTargetAddr - Section.getAddress() + 20, + ELF::R_MIPS_LO16, Value.Addend); + if (Value.SymbolName) { + addRelocationForSymbol(REHighest, Value.SymbolName); + addRelocationForSymbol(REHigher, Value.SymbolName); + addRelocationForSymbol(REHi, Value.SymbolName); + addRelocationForSymbol(RELo, Value.SymbolName); + } else { + addRelocationForSection(REHighest, Value.SectionID); + addRelocationForSection(REHigher, Value.SectionID); + addRelocationForSection(REHi, Value.SectionID); + addRelocationForSection(RELo, Value.SectionID); + } + } + RelocationEntry RE(SectionID, Offset, RelType, Section.getStubOffset()); + addRelocationForSection(RE, SectionID); + Section.advanceStubOffset(getMaxStubSize()); + } + } else { + processSimpleRelocation(SectionID, Offset, RelType, Value); + } + + } else if (Arch == Triple::ppc64 || Arch == Triple::ppc64le) { + if (RelType == ELF::R_PPC64_REL24) { + // Determine ABI variant in use for this object. + unsigned AbiVariant = Obj.getPlatformFlags(); + AbiVariant &= ELF::EF_PPC64_ABI; + // A PPC branch relocation will need a stub function if the target is + // an external symbol (either Value.SymbolName is set, or SymType is + // Symbol::ST_Unknown) or if the target address is not within the + // signed 24-bits branch address. + SectionEntry &Section = Sections[SectionID]; + uint8_t *Target = Section.getAddressWithOffset(Offset); + bool RangeOverflow = false; + bool IsExtern = Value.SymbolName || SymType == SymbolRef::ST_Unknown; + if (!IsExtern) { + if (AbiVariant != 2) { + // In the ELFv1 ABI, a function call may point to the .opd entry, + // so the final symbol value is calculated based on the relocation + // values in the .opd section. + if (auto Err = findOPDEntrySection(Obj, ObjSectionToID, Value)) + return std::move(Err); + } else { + // In the ELFv2 ABI, a function symbol may provide a local entry + // point, which must be used for direct calls. + if (Value.SectionID == SectionID){ + uint8_t SymOther = Symbol->getOther(); + Value.Addend += ELF::decodePPC64LocalEntryOffset(SymOther); + } + } + uint8_t *RelocTarget = + Sections[Value.SectionID].getAddressWithOffset(Value.Addend); + int64_t delta = static_cast<int64_t>(Target - RelocTarget); + // If it is within 26-bits branch range, just set the branch target + if (SignExtend64<26>(delta) != delta) { + RangeOverflow = true; + } else if ((AbiVariant != 2) || + (AbiVariant == 2 && Value.SectionID == SectionID)) { + RelocationEntry RE(SectionID, Offset, RelType, Value.Addend); + addRelocationForSection(RE, Value.SectionID); + } + } + if (IsExtern || (AbiVariant == 2 && Value.SectionID != SectionID) || + RangeOverflow) { + // It is an external symbol (either Value.SymbolName is set, or + // SymType is SymbolRef::ST_Unknown) or out of range. + StubMap::const_iterator i = Stubs.find(Value); + if (i != Stubs.end()) { + // Symbol function stub already created, just relocate to it + resolveRelocation(Section, Offset, + reinterpret_cast<uint64_t>( + Section.getAddressWithOffset(i->second)), + RelType, 0); + LLVM_DEBUG(dbgs() << " Stub function found\n"); + } else { + // Create a new stub function. + LLVM_DEBUG(dbgs() << " Create a new stub function\n"); + Stubs[Value] = Section.getStubOffset(); + uint8_t *StubTargetAddr = createStubFunction( + Section.getAddressWithOffset(Section.getStubOffset()), + AbiVariant); + RelocationEntry RE(SectionID, StubTargetAddr - Section.getAddress(), + ELF::R_PPC64_ADDR64, Value.Addend); + + // Generates the 64-bits address loads as exemplified in section + // 4.5.1 in PPC64 ELF ABI. Note that the relocations need to + // apply to the low part of the instructions, so we have to update + // the offset according to the target endianness. + uint64_t StubRelocOffset = StubTargetAddr - Section.getAddress(); + if (!IsTargetLittleEndian) + StubRelocOffset += 2; + + RelocationEntry REhst(SectionID, StubRelocOffset + 0, + ELF::R_PPC64_ADDR16_HIGHEST, Value.Addend); + RelocationEntry REhr(SectionID, StubRelocOffset + 4, + ELF::R_PPC64_ADDR16_HIGHER, Value.Addend); + RelocationEntry REh(SectionID, StubRelocOffset + 12, + ELF::R_PPC64_ADDR16_HI, Value.Addend); + RelocationEntry REl(SectionID, StubRelocOffset + 16, + ELF::R_PPC64_ADDR16_LO, Value.Addend); + + if (Value.SymbolName) { + addRelocationForSymbol(REhst, Value.SymbolName); + addRelocationForSymbol(REhr, Value.SymbolName); + addRelocationForSymbol(REh, Value.SymbolName); + addRelocationForSymbol(REl, Value.SymbolName); + } else { + addRelocationForSection(REhst, Value.SectionID); + addRelocationForSection(REhr, Value.SectionID); + addRelocationForSection(REh, Value.SectionID); + addRelocationForSection(REl, Value.SectionID); + } + + resolveRelocation(Section, Offset, reinterpret_cast<uint64_t>( + Section.getAddressWithOffset( + Section.getStubOffset())), + RelType, 0); + Section.advanceStubOffset(getMaxStubSize()); + } + if (IsExtern || (AbiVariant == 2 && Value.SectionID != SectionID)) { + // Restore the TOC for external calls + if (AbiVariant == 2) + writeInt32BE(Target + 4, 0xE8410018); // ld r2,24(r1) + else + writeInt32BE(Target + 4, 0xE8410028); // ld r2,40(r1) + } + } + } else if (RelType == ELF::R_PPC64_TOC16 || + RelType == ELF::R_PPC64_TOC16_DS || + RelType == ELF::R_PPC64_TOC16_LO || + RelType == ELF::R_PPC64_TOC16_LO_DS || + RelType == ELF::R_PPC64_TOC16_HI || + RelType == ELF::R_PPC64_TOC16_HA) { + // These relocations are supposed to subtract the TOC address from + // the final value. This does not fit cleanly into the RuntimeDyld + // scheme, since there may be *two* sections involved in determining + // the relocation value (the section of the symbol referred to by the + // relocation, and the TOC section associated with the current module). + // + // Fortunately, these relocations are currently only ever generated + // referring to symbols that themselves reside in the TOC, which means + // that the two sections are actually the same. Thus they cancel out + // and we can immediately resolve the relocation right now. + switch (RelType) { + case ELF::R_PPC64_TOC16: RelType = ELF::R_PPC64_ADDR16; break; + case ELF::R_PPC64_TOC16_DS: RelType = ELF::R_PPC64_ADDR16_DS; break; + case ELF::R_PPC64_TOC16_LO: RelType = ELF::R_PPC64_ADDR16_LO; break; + case ELF::R_PPC64_TOC16_LO_DS: RelType = ELF::R_PPC64_ADDR16_LO_DS; break; + case ELF::R_PPC64_TOC16_HI: RelType = ELF::R_PPC64_ADDR16_HI; break; + case ELF::R_PPC64_TOC16_HA: RelType = ELF::R_PPC64_ADDR16_HA; break; + default: llvm_unreachable("Wrong relocation type."); + } + + RelocationValueRef TOCValue; + if (auto Err = findPPC64TOCSection(Obj, ObjSectionToID, TOCValue)) + return std::move(Err); + if (Value.SymbolName || Value.SectionID != TOCValue.SectionID) + llvm_unreachable("Unsupported TOC relocation."); + Value.Addend -= TOCValue.Addend; + resolveRelocation(Sections[SectionID], Offset, Value.Addend, RelType, 0); + } else { + // There are two ways to refer to the TOC address directly: either + // via a ELF::R_PPC64_TOC relocation (where both symbol and addend are + // ignored), or via any relocation that refers to the magic ".TOC." + // symbols (in which case the addend is respected). + if (RelType == ELF::R_PPC64_TOC) { + RelType = ELF::R_PPC64_ADDR64; + if (auto Err = findPPC64TOCSection(Obj, ObjSectionToID, Value)) + return std::move(Err); + } else if (TargetName == ".TOC.") { + if (auto Err = findPPC64TOCSection(Obj, ObjSectionToID, Value)) + return std::move(Err); + Value.Addend += Addend; + } + + RelocationEntry RE(SectionID, Offset, RelType, Value.Addend); + + if (Value.SymbolName) + addRelocationForSymbol(RE, Value.SymbolName); + else + addRelocationForSection(RE, Value.SectionID); + } + } else if (Arch == Triple::systemz && + (RelType == ELF::R_390_PLT32DBL || RelType == ELF::R_390_GOTENT)) { + // Create function stubs for both PLT and GOT references, regardless of + // whether the GOT reference is to data or code. The stub contains the + // full address of the symbol, as needed by GOT references, and the + // executable part only adds an overhead of 8 bytes. + // + // We could try to conserve space by allocating the code and data + // parts of the stub separately. However, as things stand, we allocate + // a stub for every relocation, so using a GOT in JIT code should be + // no less space efficient than using an explicit constant pool. + LLVM_DEBUG(dbgs() << "\t\tThis is a SystemZ indirect relocation."); + SectionEntry &Section = Sections[SectionID]; + + // Look for an existing stub. + StubMap::const_iterator i = Stubs.find(Value); + uintptr_t StubAddress; + if (i != Stubs.end()) { + StubAddress = uintptr_t(Section.getAddressWithOffset(i->second)); + LLVM_DEBUG(dbgs() << " Stub function found\n"); + } else { + // Create a new stub function. + LLVM_DEBUG(dbgs() << " Create a new stub function\n"); + + uintptr_t BaseAddress = uintptr_t(Section.getAddress()); + uintptr_t StubAlignment = getStubAlignment(); + StubAddress = + (BaseAddress + Section.getStubOffset() + StubAlignment - 1) & + -StubAlignment; + unsigned StubOffset = StubAddress - BaseAddress; + + Stubs[Value] = StubOffset; + createStubFunction((uint8_t *)StubAddress); + RelocationEntry RE(SectionID, StubOffset + 8, ELF::R_390_64, + Value.Offset); + if (Value.SymbolName) + addRelocationForSymbol(RE, Value.SymbolName); + else + addRelocationForSection(RE, Value.SectionID); + Section.advanceStubOffset(getMaxStubSize()); + } + + if (RelType == ELF::R_390_GOTENT) + resolveRelocation(Section, Offset, StubAddress + 8, ELF::R_390_PC32DBL, + Addend); + else + resolveRelocation(Section, Offset, StubAddress, RelType, Addend); + } else if (Arch == Triple::x86_64) { + if (RelType == ELF::R_X86_64_PLT32) { + // The way the PLT relocations normally work is that the linker allocates + // the + // PLT and this relocation makes a PC-relative call into the PLT. The PLT + // entry will then jump to an address provided by the GOT. On first call, + // the + // GOT address will point back into PLT code that resolves the symbol. After + // the first call, the GOT entry points to the actual function. + // + // For local functions we're ignoring all of that here and just replacing + // the PLT32 relocation type with PC32, which will translate the relocation + // into a PC-relative call directly to the function. For external symbols we + // can't be sure the function will be within 2^32 bytes of the call site, so + // we need to create a stub, which calls into the GOT. This case is + // equivalent to the usual PLT implementation except that we use the stub + // mechanism in RuntimeDyld (which puts stubs at the end of the section) + // rather than allocating a PLT section. + if (Value.SymbolName) { + // This is a call to an external function. + // Look for an existing stub. SectionEntry *Section = &Sections[SectionID]; - StubMap::const_iterator i = Stubs.find(Value); - uintptr_t StubAddress; - if (i != Stubs.end()) { + StubMap::const_iterator i = Stubs.find(Value); + uintptr_t StubAddress; + if (i != Stubs.end()) { StubAddress = uintptr_t(Section->getAddress()) + i->second; - LLVM_DEBUG(dbgs() << " Stub function found\n"); - } else { - // Create a new stub function (equivalent to a PLT entry). - LLVM_DEBUG(dbgs() << " Create a new stub function\n"); - + LLVM_DEBUG(dbgs() << " Stub function found\n"); + } else { + // Create a new stub function (equivalent to a PLT entry). + LLVM_DEBUG(dbgs() << " Create a new stub function\n"); + uintptr_t BaseAddress = uintptr_t(Section->getAddress()); - uintptr_t StubAlignment = getStubAlignment(); - StubAddress = + uintptr_t StubAlignment = getStubAlignment(); + StubAddress = (BaseAddress + Section->getStubOffset() + StubAlignment - 1) & - -StubAlignment; - unsigned StubOffset = StubAddress - BaseAddress; - Stubs[Value] = StubOffset; - createStubFunction((uint8_t *)StubAddress); - - // Bump our stub offset counter + -StubAlignment; + unsigned StubOffset = StubAddress - BaseAddress; + Stubs[Value] = StubOffset; + createStubFunction((uint8_t *)StubAddress); + + // Bump our stub offset counter Section->advanceStubOffset(getMaxStubSize()); - - // Allocate a GOT Entry - uint64_t GOTOffset = allocateGOTEntries(1); + + // Allocate a GOT Entry + uint64_t GOTOffset = allocateGOTEntries(1); // This potentially creates a new Section which potentially // invalidates the Section pointer, so reload it. Section = &Sections[SectionID]; - - // The load of the GOT address has an addend of -4 - resolveGOTOffsetRelocation(SectionID, StubOffset + 2, GOTOffset - 4, - ELF::R_X86_64_PC32); - - // Fill in the value of the symbol we're targeting into the GOT - addRelocationForSymbol( - computeGOTOffsetRE(GOTOffset, 0, ELF::R_X86_64_64), - Value.SymbolName); - } - - // Make the target call a call into the stub table. + + // The load of the GOT address has an addend of -4 + resolveGOTOffsetRelocation(SectionID, StubOffset + 2, GOTOffset - 4, + ELF::R_X86_64_PC32); + + // Fill in the value of the symbol we're targeting into the GOT + addRelocationForSymbol( + computeGOTOffsetRE(GOTOffset, 0, ELF::R_X86_64_64), + Value.SymbolName); + } + + // Make the target call a call into the stub table. resolveRelocation(*Section, Offset, StubAddress, ELF::R_X86_64_PC32, - Addend); - } else { - RelocationEntry RE(SectionID, Offset, ELF::R_X86_64_PC32, Value.Addend, - Value.Offset); - addRelocationForSection(RE, Value.SectionID); - } - } else if (RelType == ELF::R_X86_64_GOTPCREL || - RelType == ELF::R_X86_64_GOTPCRELX || - RelType == ELF::R_X86_64_REX_GOTPCRELX) { - uint64_t GOTOffset = allocateGOTEntries(1); - resolveGOTOffsetRelocation(SectionID, Offset, GOTOffset + Addend, - ELF::R_X86_64_PC32); - - // Fill in the value of the symbol we're targeting into the GOT - RelocationEntry RE = - computeGOTOffsetRE(GOTOffset, Value.Offset, ELF::R_X86_64_64); - if (Value.SymbolName) - addRelocationForSymbol(RE, Value.SymbolName); - else - addRelocationForSection(RE, Value.SectionID); - } else if (RelType == ELF::R_X86_64_GOT64) { - // Fill in a 64-bit GOT offset. - uint64_t GOTOffset = allocateGOTEntries(1); - resolveRelocation(Sections[SectionID], Offset, GOTOffset, - ELF::R_X86_64_64, 0); - - // Fill in the value of the symbol we're targeting into the GOT - RelocationEntry RE = - computeGOTOffsetRE(GOTOffset, Value.Offset, ELF::R_X86_64_64); - if (Value.SymbolName) - addRelocationForSymbol(RE, Value.SymbolName); - else - addRelocationForSection(RE, Value.SectionID); - } else if (RelType == ELF::R_X86_64_GOTPC64) { - // Materialize the address of the base of the GOT relative to the PC. - // This doesn't create a GOT entry, but it does mean we need a GOT - // section. - (void)allocateGOTEntries(0); - resolveGOTOffsetRelocation(SectionID, Offset, Addend, ELF::R_X86_64_PC64); - } else if (RelType == ELF::R_X86_64_GOTOFF64) { - // GOTOFF relocations ultimately require a section difference relocation. - (void)allocateGOTEntries(0); - processSimpleRelocation(SectionID, Offset, RelType, Value); - } else if (RelType == ELF::R_X86_64_PC32) { - Value.Addend += support::ulittle32_t::ref(computePlaceholderAddress(SectionID, Offset)); - processSimpleRelocation(SectionID, Offset, RelType, Value); - } else if (RelType == ELF::R_X86_64_PC64) { - Value.Addend += support::ulittle64_t::ref(computePlaceholderAddress(SectionID, Offset)); - processSimpleRelocation(SectionID, Offset, RelType, Value); - } else { - processSimpleRelocation(SectionID, Offset, RelType, Value); - } - } else { - if (Arch == Triple::x86) { - Value.Addend += support::ulittle32_t::ref(computePlaceholderAddress(SectionID, Offset)); - } - processSimpleRelocation(SectionID, Offset, RelType, Value); - } - return ++RelI; -} - -size_t RuntimeDyldELF::getGOTEntrySize() { - // We don't use the GOT in all of these cases, but it's essentially free - // to put them all here. - size_t Result = 0; - switch (Arch) { - case Triple::x86_64: - case Triple::aarch64: - case Triple::aarch64_be: - case Triple::ppc64: - case Triple::ppc64le: - case Triple::systemz: - Result = sizeof(uint64_t); - break; - case Triple::x86: - case Triple::arm: - case Triple::thumb: - Result = sizeof(uint32_t); - break; - case Triple::mips: - case Triple::mipsel: - case Triple::mips64: - case Triple::mips64el: - if (IsMipsO32ABI || IsMipsN32ABI) - Result = sizeof(uint32_t); - else if (IsMipsN64ABI) - Result = sizeof(uint64_t); - else - llvm_unreachable("Mips ABI not handled"); - break; - default: - llvm_unreachable("Unsupported CPU type!"); - } - return Result; -} - -uint64_t RuntimeDyldELF::allocateGOTEntries(unsigned no) { - if (GOTSectionID == 0) { - GOTSectionID = Sections.size(); - // Reserve a section id. We'll allocate the section later - // once we know the total size - Sections.push_back(SectionEntry(".got", nullptr, 0, 0, 0)); - } - uint64_t StartOffset = CurrentGOTIndex * getGOTEntrySize(); - CurrentGOTIndex += no; - return StartOffset; -} - -uint64_t RuntimeDyldELF::findOrAllocGOTEntry(const RelocationValueRef &Value, - unsigned GOTRelType) { - auto E = GOTOffsetMap.insert({Value, 0}); - if (E.second) { - uint64_t GOTOffset = allocateGOTEntries(1); - - // Create relocation for newly created GOT entry - RelocationEntry RE = - computeGOTOffsetRE(GOTOffset, Value.Offset, GOTRelType); - if (Value.SymbolName) - addRelocationForSymbol(RE, Value.SymbolName); - else - addRelocationForSection(RE, Value.SectionID); - - E.first->second = GOTOffset; - } - - return E.first->second; -} - -void RuntimeDyldELF::resolveGOTOffsetRelocation(unsigned SectionID, - uint64_t Offset, - uint64_t GOTOffset, - uint32_t Type) { - // Fill in the relative address of the GOT Entry into the stub - RelocationEntry GOTRE(SectionID, Offset, Type, GOTOffset); - addRelocationForSection(GOTRE, GOTSectionID); -} - -RelocationEntry RuntimeDyldELF::computeGOTOffsetRE(uint64_t GOTOffset, - uint64_t SymbolOffset, - uint32_t Type) { - return RelocationEntry(GOTSectionID, GOTOffset, Type, SymbolOffset); -} - -Error RuntimeDyldELF::finalizeLoad(const ObjectFile &Obj, - ObjSectionToIDMap &SectionMap) { - if (IsMipsO32ABI) - if (!PendingRelocs.empty()) - return make_error<RuntimeDyldError>("Can't find matching LO16 reloc"); - - // If necessary, allocate the global offset table - if (GOTSectionID != 0) { - // Allocate memory for the section - size_t TotalSize = CurrentGOTIndex * getGOTEntrySize(); - uint8_t *Addr = MemMgr.allocateDataSection(TotalSize, getGOTEntrySize(), - GOTSectionID, ".got", false); - if (!Addr) - return make_error<RuntimeDyldError>("Unable to allocate memory for GOT!"); - - Sections[GOTSectionID] = - SectionEntry(".got", Addr, TotalSize, TotalSize, 0); - - // For now, initialize all GOT entries to zero. We'll fill them in as - // needed when GOT-based relocations are applied. - memset(Addr, 0, TotalSize); - if (IsMipsN32ABI || IsMipsN64ABI) { - // To correctly resolve Mips GOT relocations, we need a mapping from - // object's sections to GOTs. - for (section_iterator SI = Obj.section_begin(), SE = Obj.section_end(); - SI != SE; ++SI) { - if (SI->relocation_begin() != SI->relocation_end()) { - Expected<section_iterator> RelSecOrErr = SI->getRelocatedSection(); - if (!RelSecOrErr) - return make_error<RuntimeDyldError>( - toString(RelSecOrErr.takeError())); - - section_iterator RelocatedSection = *RelSecOrErr; - ObjSectionToIDMap::iterator i = SectionMap.find(*RelocatedSection); - assert (i != SectionMap.end()); - SectionToGOTMap[i->second] = GOTSectionID; - } - } - GOTSymbolOffsets.clear(); - } - } - - // Look for and record the EH frame section. - ObjSectionToIDMap::iterator i, e; - for (i = SectionMap.begin(), e = SectionMap.end(); i != e; ++i) { - const SectionRef &Section = i->first; - - StringRef Name; - Expected<StringRef> NameOrErr = Section.getName(); - if (NameOrErr) - Name = *NameOrErr; - else - consumeError(NameOrErr.takeError()); - - if (Name == ".eh_frame") { - UnregisteredEHFrameSections.push_back(i->second); - break; - } - } - - GOTSectionID = 0; - CurrentGOTIndex = 0; - - return Error::success(); -} - -bool RuntimeDyldELF::isCompatibleFile(const object::ObjectFile &Obj) const { - return Obj.isELF(); -} - -bool RuntimeDyldELF::relocationNeedsGot(const RelocationRef &R) const { - unsigned RelTy = R.getType(); - if (Arch == Triple::aarch64 || Arch == Triple::aarch64_be) - return RelTy == ELF::R_AARCH64_ADR_GOT_PAGE || - RelTy == ELF::R_AARCH64_LD64_GOT_LO12_NC; - - if (Arch == Triple::x86_64) - return RelTy == ELF::R_X86_64_GOTPCREL || - RelTy == ELF::R_X86_64_GOTPCRELX || - RelTy == ELF::R_X86_64_GOT64 || - RelTy == ELF::R_X86_64_REX_GOTPCRELX; - return false; -} - -bool RuntimeDyldELF::relocationNeedsStub(const RelocationRef &R) const { - if (Arch != Triple::x86_64) - return true; // Conservative answer - - switch (R.getType()) { - default: - return true; // Conservative answer - - - case ELF::R_X86_64_GOTPCREL: - case ELF::R_X86_64_GOTPCRELX: - case ELF::R_X86_64_REX_GOTPCRELX: - case ELF::R_X86_64_GOTPC64: - case ELF::R_X86_64_GOT64: - case ELF::R_X86_64_GOTOFF64: - case ELF::R_X86_64_PC32: - case ELF::R_X86_64_PC64: - case ELF::R_X86_64_64: - // We know that these reloation types won't need a stub function. This list - // can be extended as needed. - return false; - } -} - -} // namespace llvm + Addend); + } else { + RelocationEntry RE(SectionID, Offset, ELF::R_X86_64_PC32, Value.Addend, + Value.Offset); + addRelocationForSection(RE, Value.SectionID); + } + } else if (RelType == ELF::R_X86_64_GOTPCREL || + RelType == ELF::R_X86_64_GOTPCRELX || + RelType == ELF::R_X86_64_REX_GOTPCRELX) { + uint64_t GOTOffset = allocateGOTEntries(1); + resolveGOTOffsetRelocation(SectionID, Offset, GOTOffset + Addend, + ELF::R_X86_64_PC32); + + // Fill in the value of the symbol we're targeting into the GOT + RelocationEntry RE = + computeGOTOffsetRE(GOTOffset, Value.Offset, ELF::R_X86_64_64); + if (Value.SymbolName) + addRelocationForSymbol(RE, Value.SymbolName); + else + addRelocationForSection(RE, Value.SectionID); + } else if (RelType == ELF::R_X86_64_GOT64) { + // Fill in a 64-bit GOT offset. + uint64_t GOTOffset = allocateGOTEntries(1); + resolveRelocation(Sections[SectionID], Offset, GOTOffset, + ELF::R_X86_64_64, 0); + + // Fill in the value of the symbol we're targeting into the GOT + RelocationEntry RE = + computeGOTOffsetRE(GOTOffset, Value.Offset, ELF::R_X86_64_64); + if (Value.SymbolName) + addRelocationForSymbol(RE, Value.SymbolName); + else + addRelocationForSection(RE, Value.SectionID); + } else if (RelType == ELF::R_X86_64_GOTPC64) { + // Materialize the address of the base of the GOT relative to the PC. + // This doesn't create a GOT entry, but it does mean we need a GOT + // section. + (void)allocateGOTEntries(0); + resolveGOTOffsetRelocation(SectionID, Offset, Addend, ELF::R_X86_64_PC64); + } else if (RelType == ELF::R_X86_64_GOTOFF64) { + // GOTOFF relocations ultimately require a section difference relocation. + (void)allocateGOTEntries(0); + processSimpleRelocation(SectionID, Offset, RelType, Value); + } else if (RelType == ELF::R_X86_64_PC32) { + Value.Addend += support::ulittle32_t::ref(computePlaceholderAddress(SectionID, Offset)); + processSimpleRelocation(SectionID, Offset, RelType, Value); + } else if (RelType == ELF::R_X86_64_PC64) { + Value.Addend += support::ulittle64_t::ref(computePlaceholderAddress(SectionID, Offset)); + processSimpleRelocation(SectionID, Offset, RelType, Value); + } else { + processSimpleRelocation(SectionID, Offset, RelType, Value); + } + } else { + if (Arch == Triple::x86) { + Value.Addend += support::ulittle32_t::ref(computePlaceholderAddress(SectionID, Offset)); + } + processSimpleRelocation(SectionID, Offset, RelType, Value); + } + return ++RelI; +} + +size_t RuntimeDyldELF::getGOTEntrySize() { + // We don't use the GOT in all of these cases, but it's essentially free + // to put them all here. + size_t Result = 0; + switch (Arch) { + case Triple::x86_64: + case Triple::aarch64: + case Triple::aarch64_be: + case Triple::ppc64: + case Triple::ppc64le: + case Triple::systemz: + Result = sizeof(uint64_t); + break; + case Triple::x86: + case Triple::arm: + case Triple::thumb: + Result = sizeof(uint32_t); + break; + case Triple::mips: + case Triple::mipsel: + case Triple::mips64: + case Triple::mips64el: + if (IsMipsO32ABI || IsMipsN32ABI) + Result = sizeof(uint32_t); + else if (IsMipsN64ABI) + Result = sizeof(uint64_t); + else + llvm_unreachable("Mips ABI not handled"); + break; + default: + llvm_unreachable("Unsupported CPU type!"); + } + return Result; +} + +uint64_t RuntimeDyldELF::allocateGOTEntries(unsigned no) { + if (GOTSectionID == 0) { + GOTSectionID = Sections.size(); + // Reserve a section id. We'll allocate the section later + // once we know the total size + Sections.push_back(SectionEntry(".got", nullptr, 0, 0, 0)); + } + uint64_t StartOffset = CurrentGOTIndex * getGOTEntrySize(); + CurrentGOTIndex += no; + return StartOffset; +} + +uint64_t RuntimeDyldELF::findOrAllocGOTEntry(const RelocationValueRef &Value, + unsigned GOTRelType) { + auto E = GOTOffsetMap.insert({Value, 0}); + if (E.second) { + uint64_t GOTOffset = allocateGOTEntries(1); + + // Create relocation for newly created GOT entry + RelocationEntry RE = + computeGOTOffsetRE(GOTOffset, Value.Offset, GOTRelType); + if (Value.SymbolName) + addRelocationForSymbol(RE, Value.SymbolName); + else + addRelocationForSection(RE, Value.SectionID); + + E.first->second = GOTOffset; + } + + return E.first->second; +} + +void RuntimeDyldELF::resolveGOTOffsetRelocation(unsigned SectionID, + uint64_t Offset, + uint64_t GOTOffset, + uint32_t Type) { + // Fill in the relative address of the GOT Entry into the stub + RelocationEntry GOTRE(SectionID, Offset, Type, GOTOffset); + addRelocationForSection(GOTRE, GOTSectionID); +} + +RelocationEntry RuntimeDyldELF::computeGOTOffsetRE(uint64_t GOTOffset, + uint64_t SymbolOffset, + uint32_t Type) { + return RelocationEntry(GOTSectionID, GOTOffset, Type, SymbolOffset); +} + +Error RuntimeDyldELF::finalizeLoad(const ObjectFile &Obj, + ObjSectionToIDMap &SectionMap) { + if (IsMipsO32ABI) + if (!PendingRelocs.empty()) + return make_error<RuntimeDyldError>("Can't find matching LO16 reloc"); + + // If necessary, allocate the global offset table + if (GOTSectionID != 0) { + // Allocate memory for the section + size_t TotalSize = CurrentGOTIndex * getGOTEntrySize(); + uint8_t *Addr = MemMgr.allocateDataSection(TotalSize, getGOTEntrySize(), + GOTSectionID, ".got", false); + if (!Addr) + return make_error<RuntimeDyldError>("Unable to allocate memory for GOT!"); + + Sections[GOTSectionID] = + SectionEntry(".got", Addr, TotalSize, TotalSize, 0); + + // For now, initialize all GOT entries to zero. We'll fill them in as + // needed when GOT-based relocations are applied. + memset(Addr, 0, TotalSize); + if (IsMipsN32ABI || IsMipsN64ABI) { + // To correctly resolve Mips GOT relocations, we need a mapping from + // object's sections to GOTs. + for (section_iterator SI = Obj.section_begin(), SE = Obj.section_end(); + SI != SE; ++SI) { + if (SI->relocation_begin() != SI->relocation_end()) { + Expected<section_iterator> RelSecOrErr = SI->getRelocatedSection(); + if (!RelSecOrErr) + return make_error<RuntimeDyldError>( + toString(RelSecOrErr.takeError())); + + section_iterator RelocatedSection = *RelSecOrErr; + ObjSectionToIDMap::iterator i = SectionMap.find(*RelocatedSection); + assert (i != SectionMap.end()); + SectionToGOTMap[i->second] = GOTSectionID; + } + } + GOTSymbolOffsets.clear(); + } + } + + // Look for and record the EH frame section. + ObjSectionToIDMap::iterator i, e; + for (i = SectionMap.begin(), e = SectionMap.end(); i != e; ++i) { + const SectionRef &Section = i->first; + + StringRef Name; + Expected<StringRef> NameOrErr = Section.getName(); + if (NameOrErr) + Name = *NameOrErr; + else + consumeError(NameOrErr.takeError()); + + if (Name == ".eh_frame") { + UnregisteredEHFrameSections.push_back(i->second); + break; + } + } + + GOTSectionID = 0; + CurrentGOTIndex = 0; + + return Error::success(); +} + +bool RuntimeDyldELF::isCompatibleFile(const object::ObjectFile &Obj) const { + return Obj.isELF(); +} + +bool RuntimeDyldELF::relocationNeedsGot(const RelocationRef &R) const { + unsigned RelTy = R.getType(); + if (Arch == Triple::aarch64 || Arch == Triple::aarch64_be) + return RelTy == ELF::R_AARCH64_ADR_GOT_PAGE || + RelTy == ELF::R_AARCH64_LD64_GOT_LO12_NC; + + if (Arch == Triple::x86_64) + return RelTy == ELF::R_X86_64_GOTPCREL || + RelTy == ELF::R_X86_64_GOTPCRELX || + RelTy == ELF::R_X86_64_GOT64 || + RelTy == ELF::R_X86_64_REX_GOTPCRELX; + return false; +} + +bool RuntimeDyldELF::relocationNeedsStub(const RelocationRef &R) const { + if (Arch != Triple::x86_64) + return true; // Conservative answer + + switch (R.getType()) { + default: + return true; // Conservative answer + + + case ELF::R_X86_64_GOTPCREL: + case ELF::R_X86_64_GOTPCRELX: + case ELF::R_X86_64_REX_GOTPCRELX: + case ELF::R_X86_64_GOTPC64: + case ELF::R_X86_64_GOT64: + case ELF::R_X86_64_GOTOFF64: + case ELF::R_X86_64_PC32: + case ELF::R_X86_64_PC64: + case ELF::R_X86_64_64: + // We know that these reloation types won't need a stub function. This list + // can be extended as needed. + return false; + } +} + +} // namespace llvm diff --git a/contrib/libs/llvm12/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h b/contrib/libs/llvm12/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h index fc6d0614b8..31892b7466 100644 --- a/contrib/libs/llvm12/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h +++ b/contrib/libs/llvm12/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h @@ -1,190 +1,190 @@ -//===-- RuntimeDyldELF.h - Run-time dynamic linker for MC-JIT ---*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// ELF support for MC-JIT runtime dynamic linker. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_RUNTIMEDYLDELF_H -#define LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_RUNTIMEDYLDELF_H - -#include "RuntimeDyldImpl.h" -#include "llvm/ADT/DenseMap.h" - -using namespace llvm; - -namespace llvm { -namespace object { -class ELFObjectFileBase; -} - -class RuntimeDyldELF : public RuntimeDyldImpl { - - void resolveRelocation(const SectionEntry &Section, uint64_t Offset, - uint64_t Value, uint32_t Type, int64_t Addend, - uint64_t SymOffset = 0, SID SectionID = 0); - - void resolveX86_64Relocation(const SectionEntry &Section, uint64_t Offset, - uint64_t Value, uint32_t Type, int64_t Addend, - uint64_t SymOffset); - - void resolveX86Relocation(const SectionEntry &Section, uint64_t Offset, - uint32_t Value, uint32_t Type, int32_t Addend); - - void resolveAArch64Relocation(const SectionEntry &Section, uint64_t Offset, - uint64_t Value, uint32_t Type, int64_t Addend); - - bool resolveAArch64ShortBranch(unsigned SectionID, relocation_iterator RelI, - const RelocationValueRef &Value); - - void resolveAArch64Branch(unsigned SectionID, const RelocationValueRef &Value, - relocation_iterator RelI, StubMap &Stubs); - - void resolveARMRelocation(const SectionEntry &Section, uint64_t Offset, - uint32_t Value, uint32_t Type, int32_t Addend); - - void resolvePPC32Relocation(const SectionEntry &Section, uint64_t Offset, - uint64_t Value, uint32_t Type, int64_t Addend); - - void resolvePPC64Relocation(const SectionEntry &Section, uint64_t Offset, - uint64_t Value, uint32_t Type, int64_t Addend); - - void resolveSystemZRelocation(const SectionEntry &Section, uint64_t Offset, - uint64_t Value, uint32_t Type, int64_t Addend); - - void resolveBPFRelocation(const SectionEntry &Section, uint64_t Offset, - uint64_t Value, uint32_t Type, int64_t Addend); - - unsigned getMaxStubSize() const override { - if (Arch == Triple::aarch64 || Arch == Triple::aarch64_be) - return 20; // movz; movk; movk; movk; br - if (Arch == Triple::arm || Arch == Triple::thumb) - return 8; // 32-bit instruction and 32-bit address - else if (IsMipsO32ABI || IsMipsN32ABI) - return 16; - else if (IsMipsN64ABI) - return 32; - else if (Arch == Triple::ppc64 || Arch == Triple::ppc64le) - return 44; - else if (Arch == Triple::x86_64) - return 6; // 2-byte jmp instruction + 32-bit relative address - else if (Arch == Triple::systemz) - return 16; - else - return 0; - } - - unsigned getStubAlignment() override { - if (Arch == Triple::systemz) - return 8; - else - return 1; - } - - void setMipsABI(const ObjectFile &Obj) override; - - Error findPPC64TOCSection(const object::ELFObjectFileBase &Obj, - ObjSectionToIDMap &LocalSections, - RelocationValueRef &Rel); - Error findOPDEntrySection(const object::ELFObjectFileBase &Obj, - ObjSectionToIDMap &LocalSections, - RelocationValueRef &Rel); - -protected: - size_t getGOTEntrySize() override; - -private: - SectionEntry &getSection(unsigned SectionID) { return Sections[SectionID]; } - - // Allocate no GOT entries for use in the given section. - uint64_t allocateGOTEntries(unsigned no); - - // Find GOT entry corresponding to relocation or create new one. - uint64_t findOrAllocGOTEntry(const RelocationValueRef &Value, - unsigned GOTRelType); - - // Resolve the relvative address of GOTOffset in Section ID and place - // it at the given Offset - void resolveGOTOffsetRelocation(unsigned SectionID, uint64_t Offset, - uint64_t GOTOffset, uint32_t Type); - - // For a GOT entry referenced from SectionID, compute a relocation entry - // that will place the final resolved value in the GOT slot - RelocationEntry computeGOTOffsetRE(uint64_t GOTOffset, uint64_t SymbolOffset, - unsigned Type); - - // Compute the address in memory where we can find the placeholder - void *computePlaceholderAddress(unsigned SectionID, uint64_t Offset) const; - - // Split out common case for createing the RelocationEntry for when the relocation requires - // no particular advanced processing. - void processSimpleRelocation(unsigned SectionID, uint64_t Offset, unsigned RelType, RelocationValueRef Value); - - // Return matching *LO16 relocation (Mips specific) - uint32_t getMatchingLoRelocation(uint32_t RelType, - bool IsLocal = false) const; - - // The tentative ID for the GOT section - unsigned GOTSectionID; - - // Records the current number of allocated slots in the GOT - // (This would be equivalent to GOTEntries.size() were it not for relocations - // that consume more than one slot) - unsigned CurrentGOTIndex; - -protected: - // A map from section to a GOT section that has entries for section's GOT - // relocations. (Mips64 specific) - DenseMap<SID, SID> SectionToGOTMap; - -private: - // A map to avoid duplicate got entries (Mips64 specific) - StringMap<uint64_t> GOTSymbolOffsets; - - // *HI16 relocations will be added for resolving when we find matching - // *LO16 part. (Mips specific) - SmallVector<std::pair<RelocationValueRef, RelocationEntry>, 8> PendingRelocs; - - // When a module is loaded we save the SectionID of the EH frame section - // in a table until we receive a request to register all unregistered - // EH frame sections with the memory manager. - SmallVector<SID, 2> UnregisteredEHFrameSections; - - // Map between GOT relocation value and corresponding GOT offset - std::map<RelocationValueRef, uint64_t> GOTOffsetMap; - - bool relocationNeedsGot(const RelocationRef &R) const override; - bool relocationNeedsStub(const RelocationRef &R) const override; - -public: - RuntimeDyldELF(RuntimeDyld::MemoryManager &MemMgr, - JITSymbolResolver &Resolver); - ~RuntimeDyldELF() override; - - static std::unique_ptr<RuntimeDyldELF> - create(Triple::ArchType Arch, RuntimeDyld::MemoryManager &MemMgr, - JITSymbolResolver &Resolver); - - std::unique_ptr<RuntimeDyld::LoadedObjectInfo> - loadObject(const object::ObjectFile &O) override; - - void resolveRelocation(const RelocationEntry &RE, uint64_t Value) override; - Expected<relocation_iterator> - processRelocationRef(unsigned SectionID, relocation_iterator RelI, - const ObjectFile &Obj, - ObjSectionToIDMap &ObjSectionToID, - StubMap &Stubs) override; - bool isCompatibleFile(const object::ObjectFile &Obj) const override; - void registerEHFrames() override; - Error finalizeLoad(const ObjectFile &Obj, - ObjSectionToIDMap &SectionMap) override; -}; - -} // end namespace llvm - -#endif +//===-- RuntimeDyldELF.h - Run-time dynamic linker for MC-JIT ---*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// ELF support for MC-JIT runtime dynamic linker. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_RUNTIMEDYLDELF_H +#define LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_RUNTIMEDYLDELF_H + +#include "RuntimeDyldImpl.h" +#include "llvm/ADT/DenseMap.h" + +using namespace llvm; + +namespace llvm { +namespace object { +class ELFObjectFileBase; +} + +class RuntimeDyldELF : public RuntimeDyldImpl { + + void resolveRelocation(const SectionEntry &Section, uint64_t Offset, + uint64_t Value, uint32_t Type, int64_t Addend, + uint64_t SymOffset = 0, SID SectionID = 0); + + void resolveX86_64Relocation(const SectionEntry &Section, uint64_t Offset, + uint64_t Value, uint32_t Type, int64_t Addend, + uint64_t SymOffset); + + void resolveX86Relocation(const SectionEntry &Section, uint64_t Offset, + uint32_t Value, uint32_t Type, int32_t Addend); + + void resolveAArch64Relocation(const SectionEntry &Section, uint64_t Offset, + uint64_t Value, uint32_t Type, int64_t Addend); + + bool resolveAArch64ShortBranch(unsigned SectionID, relocation_iterator RelI, + const RelocationValueRef &Value); + + void resolveAArch64Branch(unsigned SectionID, const RelocationValueRef &Value, + relocation_iterator RelI, StubMap &Stubs); + + void resolveARMRelocation(const SectionEntry &Section, uint64_t Offset, + uint32_t Value, uint32_t Type, int32_t Addend); + + void resolvePPC32Relocation(const SectionEntry &Section, uint64_t Offset, + uint64_t Value, uint32_t Type, int64_t Addend); + + void resolvePPC64Relocation(const SectionEntry &Section, uint64_t Offset, + uint64_t Value, uint32_t Type, int64_t Addend); + + void resolveSystemZRelocation(const SectionEntry &Section, uint64_t Offset, + uint64_t Value, uint32_t Type, int64_t Addend); + + void resolveBPFRelocation(const SectionEntry &Section, uint64_t Offset, + uint64_t Value, uint32_t Type, int64_t Addend); + + unsigned getMaxStubSize() const override { + if (Arch == Triple::aarch64 || Arch == Triple::aarch64_be) + return 20; // movz; movk; movk; movk; br + if (Arch == Triple::arm || Arch == Triple::thumb) + return 8; // 32-bit instruction and 32-bit address + else if (IsMipsO32ABI || IsMipsN32ABI) + return 16; + else if (IsMipsN64ABI) + return 32; + else if (Arch == Triple::ppc64 || Arch == Triple::ppc64le) + return 44; + else if (Arch == Triple::x86_64) + return 6; // 2-byte jmp instruction + 32-bit relative address + else if (Arch == Triple::systemz) + return 16; + else + return 0; + } + + unsigned getStubAlignment() override { + if (Arch == Triple::systemz) + return 8; + else + return 1; + } + + void setMipsABI(const ObjectFile &Obj) override; + + Error findPPC64TOCSection(const object::ELFObjectFileBase &Obj, + ObjSectionToIDMap &LocalSections, + RelocationValueRef &Rel); + Error findOPDEntrySection(const object::ELFObjectFileBase &Obj, + ObjSectionToIDMap &LocalSections, + RelocationValueRef &Rel); + +protected: + size_t getGOTEntrySize() override; + +private: + SectionEntry &getSection(unsigned SectionID) { return Sections[SectionID]; } + + // Allocate no GOT entries for use in the given section. + uint64_t allocateGOTEntries(unsigned no); + + // Find GOT entry corresponding to relocation or create new one. + uint64_t findOrAllocGOTEntry(const RelocationValueRef &Value, + unsigned GOTRelType); + + // Resolve the relvative address of GOTOffset in Section ID and place + // it at the given Offset + void resolveGOTOffsetRelocation(unsigned SectionID, uint64_t Offset, + uint64_t GOTOffset, uint32_t Type); + + // For a GOT entry referenced from SectionID, compute a relocation entry + // that will place the final resolved value in the GOT slot + RelocationEntry computeGOTOffsetRE(uint64_t GOTOffset, uint64_t SymbolOffset, + unsigned Type); + + // Compute the address in memory where we can find the placeholder + void *computePlaceholderAddress(unsigned SectionID, uint64_t Offset) const; + + // Split out common case for createing the RelocationEntry for when the relocation requires + // no particular advanced processing. + void processSimpleRelocation(unsigned SectionID, uint64_t Offset, unsigned RelType, RelocationValueRef Value); + + // Return matching *LO16 relocation (Mips specific) + uint32_t getMatchingLoRelocation(uint32_t RelType, + bool IsLocal = false) const; + + // The tentative ID for the GOT section + unsigned GOTSectionID; + + // Records the current number of allocated slots in the GOT + // (This would be equivalent to GOTEntries.size() were it not for relocations + // that consume more than one slot) + unsigned CurrentGOTIndex; + +protected: + // A map from section to a GOT section that has entries for section's GOT + // relocations. (Mips64 specific) + DenseMap<SID, SID> SectionToGOTMap; + +private: + // A map to avoid duplicate got entries (Mips64 specific) + StringMap<uint64_t> GOTSymbolOffsets; + + // *HI16 relocations will be added for resolving when we find matching + // *LO16 part. (Mips specific) + SmallVector<std::pair<RelocationValueRef, RelocationEntry>, 8> PendingRelocs; + + // When a module is loaded we save the SectionID of the EH frame section + // in a table until we receive a request to register all unregistered + // EH frame sections with the memory manager. + SmallVector<SID, 2> UnregisteredEHFrameSections; + + // Map between GOT relocation value and corresponding GOT offset + std::map<RelocationValueRef, uint64_t> GOTOffsetMap; + + bool relocationNeedsGot(const RelocationRef &R) const override; + bool relocationNeedsStub(const RelocationRef &R) const override; + +public: + RuntimeDyldELF(RuntimeDyld::MemoryManager &MemMgr, + JITSymbolResolver &Resolver); + ~RuntimeDyldELF() override; + + static std::unique_ptr<RuntimeDyldELF> + create(Triple::ArchType Arch, RuntimeDyld::MemoryManager &MemMgr, + JITSymbolResolver &Resolver); + + std::unique_ptr<RuntimeDyld::LoadedObjectInfo> + loadObject(const object::ObjectFile &O) override; + + void resolveRelocation(const RelocationEntry &RE, uint64_t Value) override; + Expected<relocation_iterator> + processRelocationRef(unsigned SectionID, relocation_iterator RelI, + const ObjectFile &Obj, + ObjSectionToIDMap &ObjSectionToID, + StubMap &Stubs) override; + bool isCompatibleFile(const object::ObjectFile &Obj) const override; + void registerEHFrames() override; + Error finalizeLoad(const ObjectFile &Obj, + ObjSectionToIDMap &SectionMap) override; +}; + +} // end namespace llvm + +#endif diff --git a/contrib/libs/llvm12/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h b/contrib/libs/llvm12/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h index e35d610b95..d34fae9aaf 100644 --- a/contrib/libs/llvm12/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h +++ b/contrib/libs/llvm12/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h @@ -1,576 +1,576 @@ -//===-- RuntimeDyldImpl.h - Run-time dynamic linker for MC-JIT --*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// Interface for the implementations of runtime dynamic linker facilities. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_RUNTIMEDYLDIMPL_H -#define LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_RUNTIMEDYLDIMPL_H - -#include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/StringMap.h" -#include "llvm/ADT/Triple.h" -#include "llvm/ExecutionEngine/RTDyldMemoryManager.h" -#include "llvm/ExecutionEngine/RuntimeDyld.h" -#include "llvm/ExecutionEngine/RuntimeDyldChecker.h" -#include "llvm/Object/ObjectFile.h" -#include "llvm/Support/Debug.h" -#include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/Format.h" -#include "llvm/Support/Host.h" -#include "llvm/Support/Mutex.h" -#include "llvm/Support/SwapByteOrder.h" -#include <deque> -#include <map> -#include <system_error> -#include <unordered_map> - -using namespace llvm; -using namespace llvm::object; - -namespace llvm { - -#define UNIMPLEMENTED_RELOC(RelType) \ - case RelType: \ - return make_error<RuntimeDyldError>("Unimplemented relocation: " #RelType) - -/// SectionEntry - represents a section emitted into memory by the dynamic -/// linker. -class SectionEntry { - /// Name - section name. - std::string Name; - - /// Address - address in the linker's memory where the section resides. - uint8_t *Address; - - /// Size - section size. Doesn't include the stubs. - size_t Size; - - /// LoadAddress - the address of the section in the target process's memory. - /// Used for situations in which JIT-ed code is being executed in the address - /// space of a separate process. If the code executes in the same address - /// space where it was JIT-ed, this just equals Address. - uint64_t LoadAddress; - - /// StubOffset - used for architectures with stub functions for far - /// relocations (like ARM). - uintptr_t StubOffset; - - /// The total amount of space allocated for this section. This includes the - /// section size and the maximum amount of space that the stubs can occupy. - size_t AllocationSize; - - /// ObjAddress - address of the section in the in-memory object file. Used - /// for calculating relocations in some object formats (like MachO). - uintptr_t ObjAddress; - -public: - SectionEntry(StringRef name, uint8_t *address, size_t size, - size_t allocationSize, uintptr_t objAddress) - : Name(std::string(name)), Address(address), Size(size), - LoadAddress(reinterpret_cast<uintptr_t>(address)), StubOffset(size), - AllocationSize(allocationSize), ObjAddress(objAddress) { - // AllocationSize is used only in asserts, prevent an "unused private field" - // warning: - (void)AllocationSize; - } - - StringRef getName() const { return Name; } - - uint8_t *getAddress() const { return Address; } - - /// Return the address of this section with an offset. - uint8_t *getAddressWithOffset(unsigned OffsetBytes) const { - assert(OffsetBytes <= AllocationSize && "Offset out of bounds!"); - return Address + OffsetBytes; - } - - size_t getSize() const { return Size; } - - uint64_t getLoadAddress() const { return LoadAddress; } - void setLoadAddress(uint64_t LA) { LoadAddress = LA; } - - /// Return the load address of this section with an offset. - uint64_t getLoadAddressWithOffset(unsigned OffsetBytes) const { - assert(OffsetBytes <= AllocationSize && "Offset out of bounds!"); - return LoadAddress + OffsetBytes; - } - - uintptr_t getStubOffset() const { return StubOffset; } - - void advanceStubOffset(unsigned StubSize) { - StubOffset += StubSize; - assert(StubOffset <= AllocationSize && "Not enough space allocated!"); - } - - uintptr_t getObjAddress() const { return ObjAddress; } -}; - -/// RelocationEntry - used to represent relocations internally in the dynamic -/// linker. -class RelocationEntry { -public: - /// SectionID - the section this relocation points to. - unsigned SectionID; - - /// Offset - offset into the section. - uint64_t Offset; - - /// RelType - relocation type. - uint32_t RelType; - - /// Addend - the relocation addend encoded in the instruction itself. Also - /// used to make a relocation section relative instead of symbol relative. - int64_t Addend; - - struct SectionPair { - uint32_t SectionA; - uint32_t SectionB; - }; - - /// SymOffset - Section offset of the relocation entry's symbol (used for GOT - /// lookup). - union { - uint64_t SymOffset; - SectionPair Sections; - }; - - /// True if this is a PCRel relocation (MachO specific). - bool IsPCRel; - - /// The size of this relocation (MachO specific). - unsigned Size; - - // ARM (MachO and COFF) specific. - bool IsTargetThumbFunc = false; - - RelocationEntry(unsigned id, uint64_t offset, uint32_t type, int64_t addend) - : SectionID(id), Offset(offset), RelType(type), Addend(addend), - SymOffset(0), IsPCRel(false), Size(0), IsTargetThumbFunc(false) {} - - RelocationEntry(unsigned id, uint64_t offset, uint32_t type, int64_t addend, - uint64_t symoffset) - : SectionID(id), Offset(offset), RelType(type), Addend(addend), - SymOffset(symoffset), IsPCRel(false), Size(0), - IsTargetThumbFunc(false) {} - - RelocationEntry(unsigned id, uint64_t offset, uint32_t type, int64_t addend, - bool IsPCRel, unsigned Size) - : SectionID(id), Offset(offset), RelType(type), Addend(addend), - SymOffset(0), IsPCRel(IsPCRel), Size(Size), IsTargetThumbFunc(false) {} - - RelocationEntry(unsigned id, uint64_t offset, uint32_t type, int64_t addend, - unsigned SectionA, uint64_t SectionAOffset, unsigned SectionB, - uint64_t SectionBOffset, bool IsPCRel, unsigned Size) - : SectionID(id), Offset(offset), RelType(type), - Addend(SectionAOffset - SectionBOffset + addend), IsPCRel(IsPCRel), - Size(Size), IsTargetThumbFunc(false) { - Sections.SectionA = SectionA; - Sections.SectionB = SectionB; - } - - RelocationEntry(unsigned id, uint64_t offset, uint32_t type, int64_t addend, - unsigned SectionA, uint64_t SectionAOffset, unsigned SectionB, - uint64_t SectionBOffset, bool IsPCRel, unsigned Size, - bool IsTargetThumbFunc) - : SectionID(id), Offset(offset), RelType(type), - Addend(SectionAOffset - SectionBOffset + addend), IsPCRel(IsPCRel), - Size(Size), IsTargetThumbFunc(IsTargetThumbFunc) { - Sections.SectionA = SectionA; - Sections.SectionB = SectionB; - } -}; - -class RelocationValueRef { -public: - unsigned SectionID = 0; - uint64_t Offset = 0; - int64_t Addend = 0; - const char *SymbolName = nullptr; - bool IsStubThumb = false; - - inline bool operator==(const RelocationValueRef &Other) const { - return SectionID == Other.SectionID && Offset == Other.Offset && - Addend == Other.Addend && SymbolName == Other.SymbolName && - IsStubThumb == Other.IsStubThumb; - } - inline bool operator<(const RelocationValueRef &Other) const { - if (SectionID != Other.SectionID) - return SectionID < Other.SectionID; - if (Offset != Other.Offset) - return Offset < Other.Offset; - if (Addend != Other.Addend) - return Addend < Other.Addend; - if (IsStubThumb != Other.IsStubThumb) - return IsStubThumb < Other.IsStubThumb; - return SymbolName < Other.SymbolName; - } -}; - -/// Symbol info for RuntimeDyld. -class SymbolTableEntry { -public: - SymbolTableEntry() = default; - - SymbolTableEntry(unsigned SectionID, uint64_t Offset, JITSymbolFlags Flags) - : Offset(Offset), SectionID(SectionID), Flags(Flags) {} - - unsigned getSectionID() const { return SectionID; } - uint64_t getOffset() const { return Offset; } - void setOffset(uint64_t NewOffset) { Offset = NewOffset; } - - JITSymbolFlags getFlags() const { return Flags; } - -private: - uint64_t Offset = 0; - unsigned SectionID = 0; - JITSymbolFlags Flags = JITSymbolFlags::None; -}; - -typedef StringMap<SymbolTableEntry> RTDyldSymbolTable; - -class RuntimeDyldImpl { - friend class RuntimeDyld::LoadedObjectInfo; -protected: - static const unsigned AbsoluteSymbolSection = ~0U; - - // The MemoryManager to load objects into. - RuntimeDyld::MemoryManager &MemMgr; - - // The symbol resolver to use for external symbols. - JITSymbolResolver &Resolver; - - // A list of all sections emitted by the dynamic linker. These sections are - // referenced in the code by means of their index in this list - SectionID. - // Because references may be kept while the list grows, use a container that - // guarantees reference stability. - typedef std::deque<SectionEntry> SectionList; - SectionList Sections; - - typedef unsigned SID; // Type for SectionIDs -#define RTDYLD_INVALID_SECTION_ID ((RuntimeDyldImpl::SID)(-1)) - - // Keep a map of sections from object file to the SectionID which - // references it. - typedef std::map<SectionRef, unsigned> ObjSectionToIDMap; - - // A global symbol table for symbols from all loaded modules. - RTDyldSymbolTable GlobalSymbolTable; - - // Keep a map of common symbols to their info pairs - typedef std::vector<SymbolRef> CommonSymbolList; - - // For each symbol, keep a list of relocations based on it. Anytime - // its address is reassigned (the JIT re-compiled the function, e.g.), - // the relocations get re-resolved. - // The symbol (or section) the relocation is sourced from is the Key - // in the relocation list where it's stored. - typedef SmallVector<RelocationEntry, 64> RelocationList; - // Relocations to sections already loaded. Indexed by SectionID which is the - // source of the address. The target where the address will be written is - // SectionID/Offset in the relocation itself. - std::unordered_map<unsigned, RelocationList> Relocations; - - // Relocations to external symbols that are not yet resolved. Symbols are - // external when they aren't found in the global symbol table of all loaded - // modules. This map is indexed by symbol name. - StringMap<RelocationList> ExternalSymbolRelocations; - - - typedef std::map<RelocationValueRef, uintptr_t> StubMap; - - Triple::ArchType Arch; - bool IsTargetLittleEndian; - bool IsMipsO32ABI; - bool IsMipsN32ABI; - bool IsMipsN64ABI; - - // True if all sections should be passed to the memory manager, false if only - // sections containing relocations should be. Defaults to 'false'. - bool ProcessAllSections; - - // This mutex prevents simultaneously loading objects from two different - // threads. This keeps us from having to protect individual data structures - // and guarantees that section allocation requests to the memory manager - // won't be interleaved between modules. It is also used in mapSectionAddress - // and resolveRelocations to protect write access to internal data structures. - // - // loadObject may be called on the same thread during the handling of of - // processRelocations, and that's OK. The handling of the relocation lists - // is written in such a way as to work correctly if new elements are added to - // the end of the list while the list is being processed. - sys::Mutex lock; - - using NotifyStubEmittedFunction = - RuntimeDyld::NotifyStubEmittedFunction; - NotifyStubEmittedFunction NotifyStubEmitted; - - virtual unsigned getMaxStubSize() const = 0; - virtual unsigned getStubAlignment() = 0; - - bool HasError; - std::string ErrorStr; - - void writeInt16BE(uint8_t *Addr, uint16_t Value) { - llvm::support::endian::write<uint16_t, llvm::support::unaligned>( - Addr, Value, IsTargetLittleEndian ? support::little : support::big); - } - - void writeInt32BE(uint8_t *Addr, uint32_t Value) { - llvm::support::endian::write<uint32_t, llvm::support::unaligned>( - Addr, Value, IsTargetLittleEndian ? support::little : support::big); - } - - void writeInt64BE(uint8_t *Addr, uint64_t Value) { - llvm::support::endian::write<uint64_t, llvm::support::unaligned>( - Addr, Value, IsTargetLittleEndian ? support::little : support::big); - } - - virtual void setMipsABI(const ObjectFile &Obj) { - IsMipsO32ABI = false; - IsMipsN32ABI = false; - IsMipsN64ABI = false; - } - - /// Endian-aware read Read the least significant Size bytes from Src. - uint64_t readBytesUnaligned(uint8_t *Src, unsigned Size) const; - - /// Endian-aware write. Write the least significant Size bytes from Value to - /// Dst. - void writeBytesUnaligned(uint64_t Value, uint8_t *Dst, unsigned Size) const; - - /// Generate JITSymbolFlags from a libObject symbol. - virtual Expected<JITSymbolFlags> getJITSymbolFlags(const SymbolRef &Sym); - - /// Modify the given target address based on the given symbol flags. - /// This can be used by subclasses to tweak addresses based on symbol flags, - /// For example: the MachO/ARM target uses it to set the low bit if the target - /// is a thumb symbol. - virtual uint64_t modifyAddressBasedOnFlags(uint64_t Addr, - JITSymbolFlags Flags) const { - return Addr; - } - - /// Given the common symbols discovered in the object file, emit a - /// new section for them and update the symbol mappings in the object and - /// symbol table. - Error emitCommonSymbols(const ObjectFile &Obj, - CommonSymbolList &CommonSymbols, uint64_t CommonSize, - uint32_t CommonAlign); - - /// Emits section data from the object file to the MemoryManager. - /// \param IsCode if it's true then allocateCodeSection() will be - /// used for emits, else allocateDataSection() will be used. - /// \return SectionID. - Expected<unsigned> emitSection(const ObjectFile &Obj, - const SectionRef &Section, - bool IsCode); - - /// Find Section in LocalSections. If the secton is not found - emit - /// it and store in LocalSections. - /// \param IsCode if it's true then allocateCodeSection() will be - /// used for emmits, else allocateDataSection() will be used. - /// \return SectionID. - Expected<unsigned> findOrEmitSection(const ObjectFile &Obj, - const SectionRef &Section, bool IsCode, - ObjSectionToIDMap &LocalSections); - - // Add a relocation entry that uses the given section. - void addRelocationForSection(const RelocationEntry &RE, unsigned SectionID); - - // Add a relocation entry that uses the given symbol. This symbol may - // be found in the global symbol table, or it may be external. - void addRelocationForSymbol(const RelocationEntry &RE, StringRef SymbolName); - - /// Emits long jump instruction to Addr. - /// \return Pointer to the memory area for emitting target address. - uint8_t *createStubFunction(uint8_t *Addr, unsigned AbiVariant = 0); - - /// Resolves relocations from Relocs list with address from Value. - void resolveRelocationList(const RelocationList &Relocs, uint64_t Value); - - /// A object file specific relocation resolver - /// \param RE The relocation to be resolved - /// \param Value Target symbol address to apply the relocation action - virtual void resolveRelocation(const RelocationEntry &RE, uint64_t Value) = 0; - - /// Parses one or more object file relocations (some object files use - /// relocation pairs) and stores it to Relocations or SymbolRelocations - /// (this depends on the object file type). - /// \return Iterator to the next relocation that needs to be parsed. - virtual Expected<relocation_iterator> - processRelocationRef(unsigned SectionID, relocation_iterator RelI, - const ObjectFile &Obj, ObjSectionToIDMap &ObjSectionToID, - StubMap &Stubs) = 0; - - void applyExternalSymbolRelocations( - const StringMap<JITEvaluatedSymbol> ExternalSymbolMap); - - /// Resolve relocations to external symbols. - Error resolveExternalSymbols(); - - // Compute an upper bound of the memory that is required to load all - // sections - Error computeTotalAllocSize(const ObjectFile &Obj, - uint64_t &CodeSize, uint32_t &CodeAlign, - uint64_t &RODataSize, uint32_t &RODataAlign, - uint64_t &RWDataSize, uint32_t &RWDataAlign); - - // Compute GOT size - unsigned computeGOTSize(const ObjectFile &Obj); - - // Compute the stub buffer size required for a section - unsigned computeSectionStubBufSize(const ObjectFile &Obj, - const SectionRef &Section); - - // Implementation of the generic part of the loadObject algorithm. - Expected<ObjSectionToIDMap> loadObjectImpl(const object::ObjectFile &Obj); - - // Return size of Global Offset Table (GOT) entry - virtual size_t getGOTEntrySize() { return 0; } - - // Return true if the relocation R may require allocating a GOT entry. - virtual bool relocationNeedsGot(const RelocationRef &R) const { - return false; - } - - // Return true if the relocation R may require allocating a stub. - virtual bool relocationNeedsStub(const RelocationRef &R) const { - return true; // Conservative answer - } - -public: - RuntimeDyldImpl(RuntimeDyld::MemoryManager &MemMgr, - JITSymbolResolver &Resolver) - : MemMgr(MemMgr), Resolver(Resolver), - ProcessAllSections(false), HasError(false) { - } - - virtual ~RuntimeDyldImpl(); - - void setProcessAllSections(bool ProcessAllSections) { - this->ProcessAllSections = ProcessAllSections; - } - - virtual std::unique_ptr<RuntimeDyld::LoadedObjectInfo> - loadObject(const object::ObjectFile &Obj) = 0; - - uint64_t getSectionLoadAddress(unsigned SectionID) const { - return Sections[SectionID].getLoadAddress(); - } - - uint8_t *getSectionAddress(unsigned SectionID) const { - return Sections[SectionID].getAddress(); - } - - StringRef getSectionContent(unsigned SectionID) const { - return StringRef(reinterpret_cast<char *>(Sections[SectionID].getAddress()), - Sections[SectionID].getStubOffset() + getMaxStubSize()); - } - - uint8_t* getSymbolLocalAddress(StringRef Name) const { - // FIXME: Just look up as a function for now. Overly simple of course. - // Work in progress. - RTDyldSymbolTable::const_iterator pos = GlobalSymbolTable.find(Name); - if (pos == GlobalSymbolTable.end()) - return nullptr; - const auto &SymInfo = pos->second; - // Absolute symbols do not have a local address. - if (SymInfo.getSectionID() == AbsoluteSymbolSection) - return nullptr; - return getSectionAddress(SymInfo.getSectionID()) + SymInfo.getOffset(); - } - - unsigned getSymbolSectionID(StringRef Name) const { - auto GSTItr = GlobalSymbolTable.find(Name); - if (GSTItr == GlobalSymbolTable.end()) - return ~0U; - return GSTItr->second.getSectionID(); - } - - JITEvaluatedSymbol getSymbol(StringRef Name) const { - // FIXME: Just look up as a function for now. Overly simple of course. - // Work in progress. - RTDyldSymbolTable::const_iterator pos = GlobalSymbolTable.find(Name); - if (pos == GlobalSymbolTable.end()) - return nullptr; - const auto &SymEntry = pos->second; - uint64_t SectionAddr = 0; - if (SymEntry.getSectionID() != AbsoluteSymbolSection) - SectionAddr = getSectionLoadAddress(SymEntry.getSectionID()); - uint64_t TargetAddr = SectionAddr + SymEntry.getOffset(); - - // FIXME: Have getSymbol should return the actual address and the client - // modify it based on the flags. This will require clients to be - // aware of the target architecture, which we should build - // infrastructure for. - TargetAddr = modifyAddressBasedOnFlags(TargetAddr, SymEntry.getFlags()); - return JITEvaluatedSymbol(TargetAddr, SymEntry.getFlags()); - } - - std::map<StringRef, JITEvaluatedSymbol> getSymbolTable() const { - std::map<StringRef, JITEvaluatedSymbol> Result; - - for (auto &KV : GlobalSymbolTable) { - auto SectionID = KV.second.getSectionID(); - uint64_t SectionAddr = 0; - if (SectionID != AbsoluteSymbolSection) - SectionAddr = getSectionLoadAddress(SectionID); - Result[KV.first()] = - JITEvaluatedSymbol(SectionAddr + KV.second.getOffset(), KV.second.getFlags()); - } - - return Result; - } - - void resolveRelocations(); - - void resolveLocalRelocations(); - - static void finalizeAsync( - std::unique_ptr<RuntimeDyldImpl> This, +//===-- RuntimeDyldImpl.h - Run-time dynamic linker for MC-JIT --*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Interface for the implementations of runtime dynamic linker facilities. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_RUNTIMEDYLDIMPL_H +#define LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_RUNTIMEDYLDIMPL_H + +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/Triple.h" +#include "llvm/ExecutionEngine/RTDyldMemoryManager.h" +#include "llvm/ExecutionEngine/RuntimeDyld.h" +#include "llvm/ExecutionEngine/RuntimeDyldChecker.h" +#include "llvm/Object/ObjectFile.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/Host.h" +#include "llvm/Support/Mutex.h" +#include "llvm/Support/SwapByteOrder.h" +#include <deque> +#include <map> +#include <system_error> +#include <unordered_map> + +using namespace llvm; +using namespace llvm::object; + +namespace llvm { + +#define UNIMPLEMENTED_RELOC(RelType) \ + case RelType: \ + return make_error<RuntimeDyldError>("Unimplemented relocation: " #RelType) + +/// SectionEntry - represents a section emitted into memory by the dynamic +/// linker. +class SectionEntry { + /// Name - section name. + std::string Name; + + /// Address - address in the linker's memory where the section resides. + uint8_t *Address; + + /// Size - section size. Doesn't include the stubs. + size_t Size; + + /// LoadAddress - the address of the section in the target process's memory. + /// Used for situations in which JIT-ed code is being executed in the address + /// space of a separate process. If the code executes in the same address + /// space where it was JIT-ed, this just equals Address. + uint64_t LoadAddress; + + /// StubOffset - used for architectures with stub functions for far + /// relocations (like ARM). + uintptr_t StubOffset; + + /// The total amount of space allocated for this section. This includes the + /// section size and the maximum amount of space that the stubs can occupy. + size_t AllocationSize; + + /// ObjAddress - address of the section in the in-memory object file. Used + /// for calculating relocations in some object formats (like MachO). + uintptr_t ObjAddress; + +public: + SectionEntry(StringRef name, uint8_t *address, size_t size, + size_t allocationSize, uintptr_t objAddress) + : Name(std::string(name)), Address(address), Size(size), + LoadAddress(reinterpret_cast<uintptr_t>(address)), StubOffset(size), + AllocationSize(allocationSize), ObjAddress(objAddress) { + // AllocationSize is used only in asserts, prevent an "unused private field" + // warning: + (void)AllocationSize; + } + + StringRef getName() const { return Name; } + + uint8_t *getAddress() const { return Address; } + + /// Return the address of this section with an offset. + uint8_t *getAddressWithOffset(unsigned OffsetBytes) const { + assert(OffsetBytes <= AllocationSize && "Offset out of bounds!"); + return Address + OffsetBytes; + } + + size_t getSize() const { return Size; } + + uint64_t getLoadAddress() const { return LoadAddress; } + void setLoadAddress(uint64_t LA) { LoadAddress = LA; } + + /// Return the load address of this section with an offset. + uint64_t getLoadAddressWithOffset(unsigned OffsetBytes) const { + assert(OffsetBytes <= AllocationSize && "Offset out of bounds!"); + return LoadAddress + OffsetBytes; + } + + uintptr_t getStubOffset() const { return StubOffset; } + + void advanceStubOffset(unsigned StubSize) { + StubOffset += StubSize; + assert(StubOffset <= AllocationSize && "Not enough space allocated!"); + } + + uintptr_t getObjAddress() const { return ObjAddress; } +}; + +/// RelocationEntry - used to represent relocations internally in the dynamic +/// linker. +class RelocationEntry { +public: + /// SectionID - the section this relocation points to. + unsigned SectionID; + + /// Offset - offset into the section. + uint64_t Offset; + + /// RelType - relocation type. + uint32_t RelType; + + /// Addend - the relocation addend encoded in the instruction itself. Also + /// used to make a relocation section relative instead of symbol relative. + int64_t Addend; + + struct SectionPair { + uint32_t SectionA; + uint32_t SectionB; + }; + + /// SymOffset - Section offset of the relocation entry's symbol (used for GOT + /// lookup). + union { + uint64_t SymOffset; + SectionPair Sections; + }; + + /// True if this is a PCRel relocation (MachO specific). + bool IsPCRel; + + /// The size of this relocation (MachO specific). + unsigned Size; + + // ARM (MachO and COFF) specific. + bool IsTargetThumbFunc = false; + + RelocationEntry(unsigned id, uint64_t offset, uint32_t type, int64_t addend) + : SectionID(id), Offset(offset), RelType(type), Addend(addend), + SymOffset(0), IsPCRel(false), Size(0), IsTargetThumbFunc(false) {} + + RelocationEntry(unsigned id, uint64_t offset, uint32_t type, int64_t addend, + uint64_t symoffset) + : SectionID(id), Offset(offset), RelType(type), Addend(addend), + SymOffset(symoffset), IsPCRel(false), Size(0), + IsTargetThumbFunc(false) {} + + RelocationEntry(unsigned id, uint64_t offset, uint32_t type, int64_t addend, + bool IsPCRel, unsigned Size) + : SectionID(id), Offset(offset), RelType(type), Addend(addend), + SymOffset(0), IsPCRel(IsPCRel), Size(Size), IsTargetThumbFunc(false) {} + + RelocationEntry(unsigned id, uint64_t offset, uint32_t type, int64_t addend, + unsigned SectionA, uint64_t SectionAOffset, unsigned SectionB, + uint64_t SectionBOffset, bool IsPCRel, unsigned Size) + : SectionID(id), Offset(offset), RelType(type), + Addend(SectionAOffset - SectionBOffset + addend), IsPCRel(IsPCRel), + Size(Size), IsTargetThumbFunc(false) { + Sections.SectionA = SectionA; + Sections.SectionB = SectionB; + } + + RelocationEntry(unsigned id, uint64_t offset, uint32_t type, int64_t addend, + unsigned SectionA, uint64_t SectionAOffset, unsigned SectionB, + uint64_t SectionBOffset, bool IsPCRel, unsigned Size, + bool IsTargetThumbFunc) + : SectionID(id), Offset(offset), RelType(type), + Addend(SectionAOffset - SectionBOffset + addend), IsPCRel(IsPCRel), + Size(Size), IsTargetThumbFunc(IsTargetThumbFunc) { + Sections.SectionA = SectionA; + Sections.SectionB = SectionB; + } +}; + +class RelocationValueRef { +public: + unsigned SectionID = 0; + uint64_t Offset = 0; + int64_t Addend = 0; + const char *SymbolName = nullptr; + bool IsStubThumb = false; + + inline bool operator==(const RelocationValueRef &Other) const { + return SectionID == Other.SectionID && Offset == Other.Offset && + Addend == Other.Addend && SymbolName == Other.SymbolName && + IsStubThumb == Other.IsStubThumb; + } + inline bool operator<(const RelocationValueRef &Other) const { + if (SectionID != Other.SectionID) + return SectionID < Other.SectionID; + if (Offset != Other.Offset) + return Offset < Other.Offset; + if (Addend != Other.Addend) + return Addend < Other.Addend; + if (IsStubThumb != Other.IsStubThumb) + return IsStubThumb < Other.IsStubThumb; + return SymbolName < Other.SymbolName; + } +}; + +/// Symbol info for RuntimeDyld. +class SymbolTableEntry { +public: + SymbolTableEntry() = default; + + SymbolTableEntry(unsigned SectionID, uint64_t Offset, JITSymbolFlags Flags) + : Offset(Offset), SectionID(SectionID), Flags(Flags) {} + + unsigned getSectionID() const { return SectionID; } + uint64_t getOffset() const { return Offset; } + void setOffset(uint64_t NewOffset) { Offset = NewOffset; } + + JITSymbolFlags getFlags() const { return Flags; } + +private: + uint64_t Offset = 0; + unsigned SectionID = 0; + JITSymbolFlags Flags = JITSymbolFlags::None; +}; + +typedef StringMap<SymbolTableEntry> RTDyldSymbolTable; + +class RuntimeDyldImpl { + friend class RuntimeDyld::LoadedObjectInfo; +protected: + static const unsigned AbsoluteSymbolSection = ~0U; + + // The MemoryManager to load objects into. + RuntimeDyld::MemoryManager &MemMgr; + + // The symbol resolver to use for external symbols. + JITSymbolResolver &Resolver; + + // A list of all sections emitted by the dynamic linker. These sections are + // referenced in the code by means of their index in this list - SectionID. + // Because references may be kept while the list grows, use a container that + // guarantees reference stability. + typedef std::deque<SectionEntry> SectionList; + SectionList Sections; + + typedef unsigned SID; // Type for SectionIDs +#define RTDYLD_INVALID_SECTION_ID ((RuntimeDyldImpl::SID)(-1)) + + // Keep a map of sections from object file to the SectionID which + // references it. + typedef std::map<SectionRef, unsigned> ObjSectionToIDMap; + + // A global symbol table for symbols from all loaded modules. + RTDyldSymbolTable GlobalSymbolTable; + + // Keep a map of common symbols to their info pairs + typedef std::vector<SymbolRef> CommonSymbolList; + + // For each symbol, keep a list of relocations based on it. Anytime + // its address is reassigned (the JIT re-compiled the function, e.g.), + // the relocations get re-resolved. + // The symbol (or section) the relocation is sourced from is the Key + // in the relocation list where it's stored. + typedef SmallVector<RelocationEntry, 64> RelocationList; + // Relocations to sections already loaded. Indexed by SectionID which is the + // source of the address. The target where the address will be written is + // SectionID/Offset in the relocation itself. + std::unordered_map<unsigned, RelocationList> Relocations; + + // Relocations to external symbols that are not yet resolved. Symbols are + // external when they aren't found in the global symbol table of all loaded + // modules. This map is indexed by symbol name. + StringMap<RelocationList> ExternalSymbolRelocations; + + + typedef std::map<RelocationValueRef, uintptr_t> StubMap; + + Triple::ArchType Arch; + bool IsTargetLittleEndian; + bool IsMipsO32ABI; + bool IsMipsN32ABI; + bool IsMipsN64ABI; + + // True if all sections should be passed to the memory manager, false if only + // sections containing relocations should be. Defaults to 'false'. + bool ProcessAllSections; + + // This mutex prevents simultaneously loading objects from two different + // threads. This keeps us from having to protect individual data structures + // and guarantees that section allocation requests to the memory manager + // won't be interleaved between modules. It is also used in mapSectionAddress + // and resolveRelocations to protect write access to internal data structures. + // + // loadObject may be called on the same thread during the handling of of + // processRelocations, and that's OK. The handling of the relocation lists + // is written in such a way as to work correctly if new elements are added to + // the end of the list while the list is being processed. + sys::Mutex lock; + + using NotifyStubEmittedFunction = + RuntimeDyld::NotifyStubEmittedFunction; + NotifyStubEmittedFunction NotifyStubEmitted; + + virtual unsigned getMaxStubSize() const = 0; + virtual unsigned getStubAlignment() = 0; + + bool HasError; + std::string ErrorStr; + + void writeInt16BE(uint8_t *Addr, uint16_t Value) { + llvm::support::endian::write<uint16_t, llvm::support::unaligned>( + Addr, Value, IsTargetLittleEndian ? support::little : support::big); + } + + void writeInt32BE(uint8_t *Addr, uint32_t Value) { + llvm::support::endian::write<uint32_t, llvm::support::unaligned>( + Addr, Value, IsTargetLittleEndian ? support::little : support::big); + } + + void writeInt64BE(uint8_t *Addr, uint64_t Value) { + llvm::support::endian::write<uint64_t, llvm::support::unaligned>( + Addr, Value, IsTargetLittleEndian ? support::little : support::big); + } + + virtual void setMipsABI(const ObjectFile &Obj) { + IsMipsO32ABI = false; + IsMipsN32ABI = false; + IsMipsN64ABI = false; + } + + /// Endian-aware read Read the least significant Size bytes from Src. + uint64_t readBytesUnaligned(uint8_t *Src, unsigned Size) const; + + /// Endian-aware write. Write the least significant Size bytes from Value to + /// Dst. + void writeBytesUnaligned(uint64_t Value, uint8_t *Dst, unsigned Size) const; + + /// Generate JITSymbolFlags from a libObject symbol. + virtual Expected<JITSymbolFlags> getJITSymbolFlags(const SymbolRef &Sym); + + /// Modify the given target address based on the given symbol flags. + /// This can be used by subclasses to tweak addresses based on symbol flags, + /// For example: the MachO/ARM target uses it to set the low bit if the target + /// is a thumb symbol. + virtual uint64_t modifyAddressBasedOnFlags(uint64_t Addr, + JITSymbolFlags Flags) const { + return Addr; + } + + /// Given the common symbols discovered in the object file, emit a + /// new section for them and update the symbol mappings in the object and + /// symbol table. + Error emitCommonSymbols(const ObjectFile &Obj, + CommonSymbolList &CommonSymbols, uint64_t CommonSize, + uint32_t CommonAlign); + + /// Emits section data from the object file to the MemoryManager. + /// \param IsCode if it's true then allocateCodeSection() will be + /// used for emits, else allocateDataSection() will be used. + /// \return SectionID. + Expected<unsigned> emitSection(const ObjectFile &Obj, + const SectionRef &Section, + bool IsCode); + + /// Find Section in LocalSections. If the secton is not found - emit + /// it and store in LocalSections. + /// \param IsCode if it's true then allocateCodeSection() will be + /// used for emmits, else allocateDataSection() will be used. + /// \return SectionID. + Expected<unsigned> findOrEmitSection(const ObjectFile &Obj, + const SectionRef &Section, bool IsCode, + ObjSectionToIDMap &LocalSections); + + // Add a relocation entry that uses the given section. + void addRelocationForSection(const RelocationEntry &RE, unsigned SectionID); + + // Add a relocation entry that uses the given symbol. This symbol may + // be found in the global symbol table, or it may be external. + void addRelocationForSymbol(const RelocationEntry &RE, StringRef SymbolName); + + /// Emits long jump instruction to Addr. + /// \return Pointer to the memory area for emitting target address. + uint8_t *createStubFunction(uint8_t *Addr, unsigned AbiVariant = 0); + + /// Resolves relocations from Relocs list with address from Value. + void resolveRelocationList(const RelocationList &Relocs, uint64_t Value); + + /// A object file specific relocation resolver + /// \param RE The relocation to be resolved + /// \param Value Target symbol address to apply the relocation action + virtual void resolveRelocation(const RelocationEntry &RE, uint64_t Value) = 0; + + /// Parses one or more object file relocations (some object files use + /// relocation pairs) and stores it to Relocations or SymbolRelocations + /// (this depends on the object file type). + /// \return Iterator to the next relocation that needs to be parsed. + virtual Expected<relocation_iterator> + processRelocationRef(unsigned SectionID, relocation_iterator RelI, + const ObjectFile &Obj, ObjSectionToIDMap &ObjSectionToID, + StubMap &Stubs) = 0; + + void applyExternalSymbolRelocations( + const StringMap<JITEvaluatedSymbol> ExternalSymbolMap); + + /// Resolve relocations to external symbols. + Error resolveExternalSymbols(); + + // Compute an upper bound of the memory that is required to load all + // sections + Error computeTotalAllocSize(const ObjectFile &Obj, + uint64_t &CodeSize, uint32_t &CodeAlign, + uint64_t &RODataSize, uint32_t &RODataAlign, + uint64_t &RWDataSize, uint32_t &RWDataAlign); + + // Compute GOT size + unsigned computeGOTSize(const ObjectFile &Obj); + + // Compute the stub buffer size required for a section + unsigned computeSectionStubBufSize(const ObjectFile &Obj, + const SectionRef &Section); + + // Implementation of the generic part of the loadObject algorithm. + Expected<ObjSectionToIDMap> loadObjectImpl(const object::ObjectFile &Obj); + + // Return size of Global Offset Table (GOT) entry + virtual size_t getGOTEntrySize() { return 0; } + + // Return true if the relocation R may require allocating a GOT entry. + virtual bool relocationNeedsGot(const RelocationRef &R) const { + return false; + } + + // Return true if the relocation R may require allocating a stub. + virtual bool relocationNeedsStub(const RelocationRef &R) const { + return true; // Conservative answer + } + +public: + RuntimeDyldImpl(RuntimeDyld::MemoryManager &MemMgr, + JITSymbolResolver &Resolver) + : MemMgr(MemMgr), Resolver(Resolver), + ProcessAllSections(false), HasError(false) { + } + + virtual ~RuntimeDyldImpl(); + + void setProcessAllSections(bool ProcessAllSections) { + this->ProcessAllSections = ProcessAllSections; + } + + virtual std::unique_ptr<RuntimeDyld::LoadedObjectInfo> + loadObject(const object::ObjectFile &Obj) = 0; + + uint64_t getSectionLoadAddress(unsigned SectionID) const { + return Sections[SectionID].getLoadAddress(); + } + + uint8_t *getSectionAddress(unsigned SectionID) const { + return Sections[SectionID].getAddress(); + } + + StringRef getSectionContent(unsigned SectionID) const { + return StringRef(reinterpret_cast<char *>(Sections[SectionID].getAddress()), + Sections[SectionID].getStubOffset() + getMaxStubSize()); + } + + uint8_t* getSymbolLocalAddress(StringRef Name) const { + // FIXME: Just look up as a function for now. Overly simple of course. + // Work in progress. + RTDyldSymbolTable::const_iterator pos = GlobalSymbolTable.find(Name); + if (pos == GlobalSymbolTable.end()) + return nullptr; + const auto &SymInfo = pos->second; + // Absolute symbols do not have a local address. + if (SymInfo.getSectionID() == AbsoluteSymbolSection) + return nullptr; + return getSectionAddress(SymInfo.getSectionID()) + SymInfo.getOffset(); + } + + unsigned getSymbolSectionID(StringRef Name) const { + auto GSTItr = GlobalSymbolTable.find(Name); + if (GSTItr == GlobalSymbolTable.end()) + return ~0U; + return GSTItr->second.getSectionID(); + } + + JITEvaluatedSymbol getSymbol(StringRef Name) const { + // FIXME: Just look up as a function for now. Overly simple of course. + // Work in progress. + RTDyldSymbolTable::const_iterator pos = GlobalSymbolTable.find(Name); + if (pos == GlobalSymbolTable.end()) + return nullptr; + const auto &SymEntry = pos->second; + uint64_t SectionAddr = 0; + if (SymEntry.getSectionID() != AbsoluteSymbolSection) + SectionAddr = getSectionLoadAddress(SymEntry.getSectionID()); + uint64_t TargetAddr = SectionAddr + SymEntry.getOffset(); + + // FIXME: Have getSymbol should return the actual address and the client + // modify it based on the flags. This will require clients to be + // aware of the target architecture, which we should build + // infrastructure for. + TargetAddr = modifyAddressBasedOnFlags(TargetAddr, SymEntry.getFlags()); + return JITEvaluatedSymbol(TargetAddr, SymEntry.getFlags()); + } + + std::map<StringRef, JITEvaluatedSymbol> getSymbolTable() const { + std::map<StringRef, JITEvaluatedSymbol> Result; + + for (auto &KV : GlobalSymbolTable) { + auto SectionID = KV.second.getSectionID(); + uint64_t SectionAddr = 0; + if (SectionID != AbsoluteSymbolSection) + SectionAddr = getSectionLoadAddress(SectionID); + Result[KV.first()] = + JITEvaluatedSymbol(SectionAddr + KV.second.getOffset(), KV.second.getFlags()); + } + + return Result; + } + + void resolveRelocations(); + + void resolveLocalRelocations(); + + static void finalizeAsync( + std::unique_ptr<RuntimeDyldImpl> This, unique_function<void(object::OwningBinary<object::ObjectFile>, std::unique_ptr<RuntimeDyld::LoadedObjectInfo>, Error)> - OnEmitted, + OnEmitted, object::OwningBinary<object::ObjectFile> O, std::unique_ptr<RuntimeDyld::LoadedObjectInfo> Info); - - void reassignSectionAddress(unsigned SectionID, uint64_t Addr); - - void mapSectionAddress(const void *LocalAddress, uint64_t TargetAddress); - - // Is the linker in an error state? - bool hasError() { return HasError; } - - // Mark the error condition as handled and continue. - void clearError() { HasError = false; } - - // Get the error message. - StringRef getErrorString() { return ErrorStr; } - - virtual bool isCompatibleFile(const ObjectFile &Obj) const = 0; - - void setNotifyStubEmitted(NotifyStubEmittedFunction NotifyStubEmitted) { - this->NotifyStubEmitted = std::move(NotifyStubEmitted); - } - - virtual void registerEHFrames(); - - void deregisterEHFrames(); - - virtual Error finalizeLoad(const ObjectFile &ObjImg, - ObjSectionToIDMap &SectionMap) { - return Error::success(); - } -}; - -} // end namespace llvm - -#endif + + void reassignSectionAddress(unsigned SectionID, uint64_t Addr); + + void mapSectionAddress(const void *LocalAddress, uint64_t TargetAddress); + + // Is the linker in an error state? + bool hasError() { return HasError; } + + // Mark the error condition as handled and continue. + void clearError() { HasError = false; } + + // Get the error message. + StringRef getErrorString() { return ErrorStr; } + + virtual bool isCompatibleFile(const ObjectFile &Obj) const = 0; + + void setNotifyStubEmitted(NotifyStubEmittedFunction NotifyStubEmitted) { + this->NotifyStubEmitted = std::move(NotifyStubEmitted); + } + + virtual void registerEHFrames(); + + void deregisterEHFrames(); + + virtual Error finalizeLoad(const ObjectFile &ObjImg, + ObjSectionToIDMap &SectionMap) { + return Error::success(); + } +}; + +} // end namespace llvm + +#endif diff --git a/contrib/libs/llvm12/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.cpp b/contrib/libs/llvm12/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.cpp index 0602681e30..9ca76602ea 100644 --- a/contrib/libs/llvm12/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.cpp +++ b/contrib/libs/llvm12/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.cpp @@ -1,382 +1,382 @@ -//===-- RuntimeDyldMachO.cpp - Run-time dynamic linker for MC-JIT -*- C++ -*-=// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// Implementation of the MC-JIT runtime dynamic linker. -// -//===----------------------------------------------------------------------===// - -#include "RuntimeDyldMachO.h" -#include "Targets/RuntimeDyldMachOAArch64.h" -#include "Targets/RuntimeDyldMachOARM.h" -#include "Targets/RuntimeDyldMachOI386.h" -#include "Targets/RuntimeDyldMachOX86_64.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/StringRef.h" - -using namespace llvm; -using namespace llvm::object; - -#define DEBUG_TYPE "dyld" - -namespace { - -class LoadedMachOObjectInfo final - : public LoadedObjectInfoHelper<LoadedMachOObjectInfo, - RuntimeDyld::LoadedObjectInfo> { -public: - LoadedMachOObjectInfo(RuntimeDyldImpl &RTDyld, - ObjSectionToIDMap ObjSecToIDMap) - : LoadedObjectInfoHelper(RTDyld, std::move(ObjSecToIDMap)) {} - - OwningBinary<ObjectFile> - getObjectForDebug(const ObjectFile &Obj) const override { - return OwningBinary<ObjectFile>(); - } -}; - -} - -namespace llvm { - -int64_t RuntimeDyldMachO::memcpyAddend(const RelocationEntry &RE) const { - unsigned NumBytes = 1 << RE.Size; - uint8_t *Src = Sections[RE.SectionID].getAddress() + RE.Offset; - - return static_cast<int64_t>(readBytesUnaligned(Src, NumBytes)); -} - -Expected<relocation_iterator> -RuntimeDyldMachO::processScatteredVANILLA( - unsigned SectionID, relocation_iterator RelI, - const ObjectFile &BaseObjT, - RuntimeDyldMachO::ObjSectionToIDMap &ObjSectionToID, - bool TargetIsLocalThumbFunc) { - const MachOObjectFile &Obj = - static_cast<const MachOObjectFile&>(BaseObjT); - MachO::any_relocation_info RE = - Obj.getRelocation(RelI->getRawDataRefImpl()); - - SectionEntry &Section = Sections[SectionID]; - uint32_t RelocType = Obj.getAnyRelocationType(RE); - bool IsPCRel = Obj.getAnyRelocationPCRel(RE); - unsigned Size = Obj.getAnyRelocationLength(RE); - uint64_t Offset = RelI->getOffset(); - uint8_t *LocalAddress = Section.getAddressWithOffset(Offset); - unsigned NumBytes = 1 << Size; - int64_t Addend = readBytesUnaligned(LocalAddress, NumBytes); - - unsigned SymbolBaseAddr = Obj.getScatteredRelocationValue(RE); - section_iterator TargetSI = getSectionByAddress(Obj, SymbolBaseAddr); - assert(TargetSI != Obj.section_end() && "Can't find section for symbol"); - uint64_t SectionBaseAddr = TargetSI->getAddress(); - SectionRef TargetSection = *TargetSI; - bool IsCode = TargetSection.isText(); - uint32_t TargetSectionID = ~0U; - if (auto TargetSectionIDOrErr = - findOrEmitSection(Obj, TargetSection, IsCode, ObjSectionToID)) - TargetSectionID = *TargetSectionIDOrErr; - else - return TargetSectionIDOrErr.takeError(); - - Addend -= SectionBaseAddr; - RelocationEntry R(SectionID, Offset, RelocType, Addend, IsPCRel, Size); - R.IsTargetThumbFunc = TargetIsLocalThumbFunc; - - addRelocationForSection(R, TargetSectionID); - - return ++RelI; -} - - -Expected<RelocationValueRef> -RuntimeDyldMachO::getRelocationValueRef( - const ObjectFile &BaseTObj, const relocation_iterator &RI, - const RelocationEntry &RE, ObjSectionToIDMap &ObjSectionToID) { - - const MachOObjectFile &Obj = - static_cast<const MachOObjectFile &>(BaseTObj); - MachO::any_relocation_info RelInfo = - Obj.getRelocation(RI->getRawDataRefImpl()); - RelocationValueRef Value; - - bool IsExternal = Obj.getPlainRelocationExternal(RelInfo); - if (IsExternal) { - symbol_iterator Symbol = RI->getSymbol(); - StringRef TargetName; - if (auto TargetNameOrErr = Symbol->getName()) - TargetName = *TargetNameOrErr; - else - return TargetNameOrErr.takeError(); - RTDyldSymbolTable::const_iterator SI = - GlobalSymbolTable.find(TargetName.data()); - if (SI != GlobalSymbolTable.end()) { - const auto &SymInfo = SI->second; - Value.SectionID = SymInfo.getSectionID(); - Value.Offset = SymInfo.getOffset() + RE.Addend; - } else { - Value.SymbolName = TargetName.data(); - Value.Offset = RE.Addend; - } - } else { - SectionRef Sec = Obj.getAnyRelocationSection(RelInfo); - bool IsCode = Sec.isText(); - if (auto SectionIDOrErr = findOrEmitSection(Obj, Sec, IsCode, - ObjSectionToID)) - Value.SectionID = *SectionIDOrErr; - else - return SectionIDOrErr.takeError(); - uint64_t Addr = Sec.getAddress(); - Value.Offset = RE.Addend - Addr; - } - - return Value; -} - -void RuntimeDyldMachO::makeValueAddendPCRel(RelocationValueRef &Value, - const relocation_iterator &RI, - unsigned OffsetToNextPC) { - auto &O = *cast<MachOObjectFile>(RI->getObject()); - section_iterator SecI = O.getRelocationRelocatedSection(RI); - Value.Offset += RI->getOffset() + OffsetToNextPC + SecI->getAddress(); -} - -void RuntimeDyldMachO::dumpRelocationToResolve(const RelocationEntry &RE, - uint64_t Value) const { - const SectionEntry &Section = Sections[RE.SectionID]; - uint8_t *LocalAddress = Section.getAddress() + RE.Offset; - uint64_t FinalAddress = Section.getLoadAddress() + RE.Offset; - - dbgs() << "resolveRelocation Section: " << RE.SectionID - << " LocalAddress: " << format("%p", LocalAddress) - << " FinalAddress: " << format("0x%016" PRIx64, FinalAddress) - << " Value: " << format("0x%016" PRIx64, Value) << " Addend: " << RE.Addend - << " isPCRel: " << RE.IsPCRel << " MachoType: " << RE.RelType - << " Size: " << (1 << RE.Size) << "\n"; -} - -section_iterator -RuntimeDyldMachO::getSectionByAddress(const MachOObjectFile &Obj, - uint64_t Addr) { - section_iterator SI = Obj.section_begin(); - section_iterator SE = Obj.section_end(); - - for (; SI != SE; ++SI) { - uint64_t SAddr = SI->getAddress(); - uint64_t SSize = SI->getSize(); - if ((Addr >= SAddr) && (Addr < SAddr + SSize)) - return SI; - } - - return SE; -} - - -// Populate __pointers section. -Error RuntimeDyldMachO::populateIndirectSymbolPointersSection( - const MachOObjectFile &Obj, - const SectionRef &PTSection, - unsigned PTSectionID) { - assert(!Obj.is64Bit() && - "Pointer table section not supported in 64-bit MachO."); - - MachO::dysymtab_command DySymTabCmd = Obj.getDysymtabLoadCommand(); - MachO::section Sec32 = Obj.getSection(PTSection.getRawDataRefImpl()); - uint32_t PTSectionSize = Sec32.size; - unsigned FirstIndirectSymbol = Sec32.reserved1; - const unsigned PTEntrySize = 4; - unsigned NumPTEntries = PTSectionSize / PTEntrySize; - unsigned PTEntryOffset = 0; - - assert((PTSectionSize % PTEntrySize) == 0 && - "Pointers section does not contain a whole number of stubs?"); - - LLVM_DEBUG(dbgs() << "Populating pointer table section " - << Sections[PTSectionID].getName() << ", Section ID " - << PTSectionID << ", " << NumPTEntries << " entries, " - << PTEntrySize << " bytes each:\n"); - - for (unsigned i = 0; i < NumPTEntries; ++i) { - unsigned SymbolIndex = - Obj.getIndirectSymbolTableEntry(DySymTabCmd, FirstIndirectSymbol + i); - symbol_iterator SI = Obj.getSymbolByIndex(SymbolIndex); - StringRef IndirectSymbolName; - if (auto IndirectSymbolNameOrErr = SI->getName()) - IndirectSymbolName = *IndirectSymbolNameOrErr; - else - return IndirectSymbolNameOrErr.takeError(); - LLVM_DEBUG(dbgs() << " " << IndirectSymbolName << ": index " << SymbolIndex - << ", PT offset: " << PTEntryOffset << "\n"); - RelocationEntry RE(PTSectionID, PTEntryOffset, - MachO::GENERIC_RELOC_VANILLA, 0, false, 2); - addRelocationForSymbol(RE, IndirectSymbolName); - PTEntryOffset += PTEntrySize; - } - return Error::success(); -} - -bool RuntimeDyldMachO::isCompatibleFile(const object::ObjectFile &Obj) const { - return Obj.isMachO(); -} - -template <typename Impl> -Error -RuntimeDyldMachOCRTPBase<Impl>::finalizeLoad(const ObjectFile &Obj, - ObjSectionToIDMap &SectionMap) { - unsigned EHFrameSID = RTDYLD_INVALID_SECTION_ID; - unsigned TextSID = RTDYLD_INVALID_SECTION_ID; - unsigned ExceptTabSID = RTDYLD_INVALID_SECTION_ID; - - for (const auto &Section : Obj.sections()) { - StringRef Name; - if (Expected<StringRef> NameOrErr = Section.getName()) - Name = *NameOrErr; - else - consumeError(NameOrErr.takeError()); - - // Force emission of the __text, __eh_frame, and __gcc_except_tab sections - // if they're present. Otherwise call down to the impl to handle other - // sections that have already been emitted. - if (Name == "__text") { - if (auto TextSIDOrErr = findOrEmitSection(Obj, Section, true, SectionMap)) - TextSID = *TextSIDOrErr; - else - return TextSIDOrErr.takeError(); - } else if (Name == "__eh_frame") { - if (auto EHFrameSIDOrErr = findOrEmitSection(Obj, Section, false, - SectionMap)) - EHFrameSID = *EHFrameSIDOrErr; - else - return EHFrameSIDOrErr.takeError(); - } else if (Name == "__gcc_except_tab") { - if (auto ExceptTabSIDOrErr = findOrEmitSection(Obj, Section, true, - SectionMap)) - ExceptTabSID = *ExceptTabSIDOrErr; - else - return ExceptTabSIDOrErr.takeError(); - } else { - auto I = SectionMap.find(Section); - if (I != SectionMap.end()) - if (auto Err = impl().finalizeSection(Obj, I->second, Section)) - return Err; - } - } - UnregisteredEHFrameSections.push_back( - EHFrameRelatedSections(EHFrameSID, TextSID, ExceptTabSID)); - - return Error::success(); -} - -template <typename Impl> -unsigned char *RuntimeDyldMachOCRTPBase<Impl>::processFDE(uint8_t *P, - int64_t DeltaForText, - int64_t DeltaForEH) { - typedef typename Impl::TargetPtrT TargetPtrT; - - LLVM_DEBUG(dbgs() << "Processing FDE: Delta for text: " << DeltaForText - << ", Delta for EH: " << DeltaForEH << "\n"); - uint32_t Length = readBytesUnaligned(P, 4); - P += 4; - uint8_t *Ret = P + Length; - uint32_t Offset = readBytesUnaligned(P, 4); - if (Offset == 0) // is a CIE - return Ret; - - P += 4; - TargetPtrT FDELocation = readBytesUnaligned(P, sizeof(TargetPtrT)); - TargetPtrT NewLocation = FDELocation - DeltaForText; - writeBytesUnaligned(NewLocation, P, sizeof(TargetPtrT)); - - P += sizeof(TargetPtrT); - - // Skip the FDE address range - P += sizeof(TargetPtrT); - - uint8_t Augmentationsize = *P; - P += 1; - if (Augmentationsize != 0) { - TargetPtrT LSDA = readBytesUnaligned(P, sizeof(TargetPtrT)); - TargetPtrT NewLSDA = LSDA - DeltaForEH; - writeBytesUnaligned(NewLSDA, P, sizeof(TargetPtrT)); - } - - return Ret; -} - -static int64_t computeDelta(SectionEntry *A, SectionEntry *B) { - int64_t ObjDistance = static_cast<int64_t>(A->getObjAddress()) - - static_cast<int64_t>(B->getObjAddress()); - int64_t MemDistance = A->getLoadAddress() - B->getLoadAddress(); - return ObjDistance - MemDistance; -} - -template <typename Impl> -void RuntimeDyldMachOCRTPBase<Impl>::registerEHFrames() { - - for (int i = 0, e = UnregisteredEHFrameSections.size(); i != e; ++i) { - EHFrameRelatedSections &SectionInfo = UnregisteredEHFrameSections[i]; - if (SectionInfo.EHFrameSID == RTDYLD_INVALID_SECTION_ID || - SectionInfo.TextSID == RTDYLD_INVALID_SECTION_ID) - continue; - SectionEntry *Text = &Sections[SectionInfo.TextSID]; - SectionEntry *EHFrame = &Sections[SectionInfo.EHFrameSID]; - SectionEntry *ExceptTab = nullptr; - if (SectionInfo.ExceptTabSID != RTDYLD_INVALID_SECTION_ID) - ExceptTab = &Sections[SectionInfo.ExceptTabSID]; - - int64_t DeltaForText = computeDelta(Text, EHFrame); - int64_t DeltaForEH = 0; - if (ExceptTab) - DeltaForEH = computeDelta(ExceptTab, EHFrame); - - uint8_t *P = EHFrame->getAddress(); - uint8_t *End = P + EHFrame->getSize(); - while (P != End) { - P = processFDE(P, DeltaForText, DeltaForEH); - } - - MemMgr.registerEHFrames(EHFrame->getAddress(), EHFrame->getLoadAddress(), - EHFrame->getSize()); - } - UnregisteredEHFrameSections.clear(); -} - -std::unique_ptr<RuntimeDyldMachO> -RuntimeDyldMachO::create(Triple::ArchType Arch, - RuntimeDyld::MemoryManager &MemMgr, - JITSymbolResolver &Resolver) { - switch (Arch) { - default: - llvm_unreachable("Unsupported target for RuntimeDyldMachO."); - break; - case Triple::arm: - return std::make_unique<RuntimeDyldMachOARM>(MemMgr, Resolver); - case Triple::aarch64: - return std::make_unique<RuntimeDyldMachOAArch64>(MemMgr, Resolver); - case Triple::aarch64_32: - return std::make_unique<RuntimeDyldMachOAArch64>(MemMgr, Resolver); - case Triple::x86: - return std::make_unique<RuntimeDyldMachOI386>(MemMgr, Resolver); - case Triple::x86_64: - return std::make_unique<RuntimeDyldMachOX86_64>(MemMgr, Resolver); - } -} - -std::unique_ptr<RuntimeDyld::LoadedObjectInfo> -RuntimeDyldMachO::loadObject(const object::ObjectFile &O) { - if (auto ObjSectionToIDOrErr = loadObjectImpl(O)) - return std::make_unique<LoadedMachOObjectInfo>(*this, - *ObjSectionToIDOrErr); - else { - HasError = true; - raw_string_ostream ErrStream(ErrorStr); - logAllUnhandledErrors(ObjSectionToIDOrErr.takeError(), ErrStream); - return nullptr; - } -} - -} // end namespace llvm +//===-- RuntimeDyldMachO.cpp - Run-time dynamic linker for MC-JIT -*- C++ -*-=// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Implementation of the MC-JIT runtime dynamic linker. +// +//===----------------------------------------------------------------------===// + +#include "RuntimeDyldMachO.h" +#include "Targets/RuntimeDyldMachOAArch64.h" +#include "Targets/RuntimeDyldMachOARM.h" +#include "Targets/RuntimeDyldMachOI386.h" +#include "Targets/RuntimeDyldMachOX86_64.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringRef.h" + +using namespace llvm; +using namespace llvm::object; + +#define DEBUG_TYPE "dyld" + +namespace { + +class LoadedMachOObjectInfo final + : public LoadedObjectInfoHelper<LoadedMachOObjectInfo, + RuntimeDyld::LoadedObjectInfo> { +public: + LoadedMachOObjectInfo(RuntimeDyldImpl &RTDyld, + ObjSectionToIDMap ObjSecToIDMap) + : LoadedObjectInfoHelper(RTDyld, std::move(ObjSecToIDMap)) {} + + OwningBinary<ObjectFile> + getObjectForDebug(const ObjectFile &Obj) const override { + return OwningBinary<ObjectFile>(); + } +}; + +} + +namespace llvm { + +int64_t RuntimeDyldMachO::memcpyAddend(const RelocationEntry &RE) const { + unsigned NumBytes = 1 << RE.Size; + uint8_t *Src = Sections[RE.SectionID].getAddress() + RE.Offset; + + return static_cast<int64_t>(readBytesUnaligned(Src, NumBytes)); +} + +Expected<relocation_iterator> +RuntimeDyldMachO::processScatteredVANILLA( + unsigned SectionID, relocation_iterator RelI, + const ObjectFile &BaseObjT, + RuntimeDyldMachO::ObjSectionToIDMap &ObjSectionToID, + bool TargetIsLocalThumbFunc) { + const MachOObjectFile &Obj = + static_cast<const MachOObjectFile&>(BaseObjT); + MachO::any_relocation_info RE = + Obj.getRelocation(RelI->getRawDataRefImpl()); + + SectionEntry &Section = Sections[SectionID]; + uint32_t RelocType = Obj.getAnyRelocationType(RE); + bool IsPCRel = Obj.getAnyRelocationPCRel(RE); + unsigned Size = Obj.getAnyRelocationLength(RE); + uint64_t Offset = RelI->getOffset(); + uint8_t *LocalAddress = Section.getAddressWithOffset(Offset); + unsigned NumBytes = 1 << Size; + int64_t Addend = readBytesUnaligned(LocalAddress, NumBytes); + + unsigned SymbolBaseAddr = Obj.getScatteredRelocationValue(RE); + section_iterator TargetSI = getSectionByAddress(Obj, SymbolBaseAddr); + assert(TargetSI != Obj.section_end() && "Can't find section for symbol"); + uint64_t SectionBaseAddr = TargetSI->getAddress(); + SectionRef TargetSection = *TargetSI; + bool IsCode = TargetSection.isText(); + uint32_t TargetSectionID = ~0U; + if (auto TargetSectionIDOrErr = + findOrEmitSection(Obj, TargetSection, IsCode, ObjSectionToID)) + TargetSectionID = *TargetSectionIDOrErr; + else + return TargetSectionIDOrErr.takeError(); + + Addend -= SectionBaseAddr; + RelocationEntry R(SectionID, Offset, RelocType, Addend, IsPCRel, Size); + R.IsTargetThumbFunc = TargetIsLocalThumbFunc; + + addRelocationForSection(R, TargetSectionID); + + return ++RelI; +} + + +Expected<RelocationValueRef> +RuntimeDyldMachO::getRelocationValueRef( + const ObjectFile &BaseTObj, const relocation_iterator &RI, + const RelocationEntry &RE, ObjSectionToIDMap &ObjSectionToID) { + + const MachOObjectFile &Obj = + static_cast<const MachOObjectFile &>(BaseTObj); + MachO::any_relocation_info RelInfo = + Obj.getRelocation(RI->getRawDataRefImpl()); + RelocationValueRef Value; + + bool IsExternal = Obj.getPlainRelocationExternal(RelInfo); + if (IsExternal) { + symbol_iterator Symbol = RI->getSymbol(); + StringRef TargetName; + if (auto TargetNameOrErr = Symbol->getName()) + TargetName = *TargetNameOrErr; + else + return TargetNameOrErr.takeError(); + RTDyldSymbolTable::const_iterator SI = + GlobalSymbolTable.find(TargetName.data()); + if (SI != GlobalSymbolTable.end()) { + const auto &SymInfo = SI->second; + Value.SectionID = SymInfo.getSectionID(); + Value.Offset = SymInfo.getOffset() + RE.Addend; + } else { + Value.SymbolName = TargetName.data(); + Value.Offset = RE.Addend; + } + } else { + SectionRef Sec = Obj.getAnyRelocationSection(RelInfo); + bool IsCode = Sec.isText(); + if (auto SectionIDOrErr = findOrEmitSection(Obj, Sec, IsCode, + ObjSectionToID)) + Value.SectionID = *SectionIDOrErr; + else + return SectionIDOrErr.takeError(); + uint64_t Addr = Sec.getAddress(); + Value.Offset = RE.Addend - Addr; + } + + return Value; +} + +void RuntimeDyldMachO::makeValueAddendPCRel(RelocationValueRef &Value, + const relocation_iterator &RI, + unsigned OffsetToNextPC) { + auto &O = *cast<MachOObjectFile>(RI->getObject()); + section_iterator SecI = O.getRelocationRelocatedSection(RI); + Value.Offset += RI->getOffset() + OffsetToNextPC + SecI->getAddress(); +} + +void RuntimeDyldMachO::dumpRelocationToResolve(const RelocationEntry &RE, + uint64_t Value) const { + const SectionEntry &Section = Sections[RE.SectionID]; + uint8_t *LocalAddress = Section.getAddress() + RE.Offset; + uint64_t FinalAddress = Section.getLoadAddress() + RE.Offset; + + dbgs() << "resolveRelocation Section: " << RE.SectionID + << " LocalAddress: " << format("%p", LocalAddress) + << " FinalAddress: " << format("0x%016" PRIx64, FinalAddress) + << " Value: " << format("0x%016" PRIx64, Value) << " Addend: " << RE.Addend + << " isPCRel: " << RE.IsPCRel << " MachoType: " << RE.RelType + << " Size: " << (1 << RE.Size) << "\n"; +} + +section_iterator +RuntimeDyldMachO::getSectionByAddress(const MachOObjectFile &Obj, + uint64_t Addr) { + section_iterator SI = Obj.section_begin(); + section_iterator SE = Obj.section_end(); + + for (; SI != SE; ++SI) { + uint64_t SAddr = SI->getAddress(); + uint64_t SSize = SI->getSize(); + if ((Addr >= SAddr) && (Addr < SAddr + SSize)) + return SI; + } + + return SE; +} + + +// Populate __pointers section. +Error RuntimeDyldMachO::populateIndirectSymbolPointersSection( + const MachOObjectFile &Obj, + const SectionRef &PTSection, + unsigned PTSectionID) { + assert(!Obj.is64Bit() && + "Pointer table section not supported in 64-bit MachO."); + + MachO::dysymtab_command DySymTabCmd = Obj.getDysymtabLoadCommand(); + MachO::section Sec32 = Obj.getSection(PTSection.getRawDataRefImpl()); + uint32_t PTSectionSize = Sec32.size; + unsigned FirstIndirectSymbol = Sec32.reserved1; + const unsigned PTEntrySize = 4; + unsigned NumPTEntries = PTSectionSize / PTEntrySize; + unsigned PTEntryOffset = 0; + + assert((PTSectionSize % PTEntrySize) == 0 && + "Pointers section does not contain a whole number of stubs?"); + + LLVM_DEBUG(dbgs() << "Populating pointer table section " + << Sections[PTSectionID].getName() << ", Section ID " + << PTSectionID << ", " << NumPTEntries << " entries, " + << PTEntrySize << " bytes each:\n"); + + for (unsigned i = 0; i < NumPTEntries; ++i) { + unsigned SymbolIndex = + Obj.getIndirectSymbolTableEntry(DySymTabCmd, FirstIndirectSymbol + i); + symbol_iterator SI = Obj.getSymbolByIndex(SymbolIndex); + StringRef IndirectSymbolName; + if (auto IndirectSymbolNameOrErr = SI->getName()) + IndirectSymbolName = *IndirectSymbolNameOrErr; + else + return IndirectSymbolNameOrErr.takeError(); + LLVM_DEBUG(dbgs() << " " << IndirectSymbolName << ": index " << SymbolIndex + << ", PT offset: " << PTEntryOffset << "\n"); + RelocationEntry RE(PTSectionID, PTEntryOffset, + MachO::GENERIC_RELOC_VANILLA, 0, false, 2); + addRelocationForSymbol(RE, IndirectSymbolName); + PTEntryOffset += PTEntrySize; + } + return Error::success(); +} + +bool RuntimeDyldMachO::isCompatibleFile(const object::ObjectFile &Obj) const { + return Obj.isMachO(); +} + +template <typename Impl> +Error +RuntimeDyldMachOCRTPBase<Impl>::finalizeLoad(const ObjectFile &Obj, + ObjSectionToIDMap &SectionMap) { + unsigned EHFrameSID = RTDYLD_INVALID_SECTION_ID; + unsigned TextSID = RTDYLD_INVALID_SECTION_ID; + unsigned ExceptTabSID = RTDYLD_INVALID_SECTION_ID; + + for (const auto &Section : Obj.sections()) { + StringRef Name; + if (Expected<StringRef> NameOrErr = Section.getName()) + Name = *NameOrErr; + else + consumeError(NameOrErr.takeError()); + + // Force emission of the __text, __eh_frame, and __gcc_except_tab sections + // if they're present. Otherwise call down to the impl to handle other + // sections that have already been emitted. + if (Name == "__text") { + if (auto TextSIDOrErr = findOrEmitSection(Obj, Section, true, SectionMap)) + TextSID = *TextSIDOrErr; + else + return TextSIDOrErr.takeError(); + } else if (Name == "__eh_frame") { + if (auto EHFrameSIDOrErr = findOrEmitSection(Obj, Section, false, + SectionMap)) + EHFrameSID = *EHFrameSIDOrErr; + else + return EHFrameSIDOrErr.takeError(); + } else if (Name == "__gcc_except_tab") { + if (auto ExceptTabSIDOrErr = findOrEmitSection(Obj, Section, true, + SectionMap)) + ExceptTabSID = *ExceptTabSIDOrErr; + else + return ExceptTabSIDOrErr.takeError(); + } else { + auto I = SectionMap.find(Section); + if (I != SectionMap.end()) + if (auto Err = impl().finalizeSection(Obj, I->second, Section)) + return Err; + } + } + UnregisteredEHFrameSections.push_back( + EHFrameRelatedSections(EHFrameSID, TextSID, ExceptTabSID)); + + return Error::success(); +} + +template <typename Impl> +unsigned char *RuntimeDyldMachOCRTPBase<Impl>::processFDE(uint8_t *P, + int64_t DeltaForText, + int64_t DeltaForEH) { + typedef typename Impl::TargetPtrT TargetPtrT; + + LLVM_DEBUG(dbgs() << "Processing FDE: Delta for text: " << DeltaForText + << ", Delta for EH: " << DeltaForEH << "\n"); + uint32_t Length = readBytesUnaligned(P, 4); + P += 4; + uint8_t *Ret = P + Length; + uint32_t Offset = readBytesUnaligned(P, 4); + if (Offset == 0) // is a CIE + return Ret; + + P += 4; + TargetPtrT FDELocation = readBytesUnaligned(P, sizeof(TargetPtrT)); + TargetPtrT NewLocation = FDELocation - DeltaForText; + writeBytesUnaligned(NewLocation, P, sizeof(TargetPtrT)); + + P += sizeof(TargetPtrT); + + // Skip the FDE address range + P += sizeof(TargetPtrT); + + uint8_t Augmentationsize = *P; + P += 1; + if (Augmentationsize != 0) { + TargetPtrT LSDA = readBytesUnaligned(P, sizeof(TargetPtrT)); + TargetPtrT NewLSDA = LSDA - DeltaForEH; + writeBytesUnaligned(NewLSDA, P, sizeof(TargetPtrT)); + } + + return Ret; +} + +static int64_t computeDelta(SectionEntry *A, SectionEntry *B) { + int64_t ObjDistance = static_cast<int64_t>(A->getObjAddress()) - + static_cast<int64_t>(B->getObjAddress()); + int64_t MemDistance = A->getLoadAddress() - B->getLoadAddress(); + return ObjDistance - MemDistance; +} + +template <typename Impl> +void RuntimeDyldMachOCRTPBase<Impl>::registerEHFrames() { + + for (int i = 0, e = UnregisteredEHFrameSections.size(); i != e; ++i) { + EHFrameRelatedSections &SectionInfo = UnregisteredEHFrameSections[i]; + if (SectionInfo.EHFrameSID == RTDYLD_INVALID_SECTION_ID || + SectionInfo.TextSID == RTDYLD_INVALID_SECTION_ID) + continue; + SectionEntry *Text = &Sections[SectionInfo.TextSID]; + SectionEntry *EHFrame = &Sections[SectionInfo.EHFrameSID]; + SectionEntry *ExceptTab = nullptr; + if (SectionInfo.ExceptTabSID != RTDYLD_INVALID_SECTION_ID) + ExceptTab = &Sections[SectionInfo.ExceptTabSID]; + + int64_t DeltaForText = computeDelta(Text, EHFrame); + int64_t DeltaForEH = 0; + if (ExceptTab) + DeltaForEH = computeDelta(ExceptTab, EHFrame); + + uint8_t *P = EHFrame->getAddress(); + uint8_t *End = P + EHFrame->getSize(); + while (P != End) { + P = processFDE(P, DeltaForText, DeltaForEH); + } + + MemMgr.registerEHFrames(EHFrame->getAddress(), EHFrame->getLoadAddress(), + EHFrame->getSize()); + } + UnregisteredEHFrameSections.clear(); +} + +std::unique_ptr<RuntimeDyldMachO> +RuntimeDyldMachO::create(Triple::ArchType Arch, + RuntimeDyld::MemoryManager &MemMgr, + JITSymbolResolver &Resolver) { + switch (Arch) { + default: + llvm_unreachable("Unsupported target for RuntimeDyldMachO."); + break; + case Triple::arm: + return std::make_unique<RuntimeDyldMachOARM>(MemMgr, Resolver); + case Triple::aarch64: + return std::make_unique<RuntimeDyldMachOAArch64>(MemMgr, Resolver); + case Triple::aarch64_32: + return std::make_unique<RuntimeDyldMachOAArch64>(MemMgr, Resolver); + case Triple::x86: + return std::make_unique<RuntimeDyldMachOI386>(MemMgr, Resolver); + case Triple::x86_64: + return std::make_unique<RuntimeDyldMachOX86_64>(MemMgr, Resolver); + } +} + +std::unique_ptr<RuntimeDyld::LoadedObjectInfo> +RuntimeDyldMachO::loadObject(const object::ObjectFile &O) { + if (auto ObjSectionToIDOrErr = loadObjectImpl(O)) + return std::make_unique<LoadedMachOObjectInfo>(*this, + *ObjSectionToIDOrErr); + else { + HasError = true; + raw_string_ostream ErrStream(ErrorStr); + logAllUnhandledErrors(ObjSectionToIDOrErr.takeError(), ErrStream); + return nullptr; + } +} + +} // end namespace llvm diff --git a/contrib/libs/llvm12/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.h b/contrib/libs/llvm12/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.h index f73e988bdf..650e7b79fb 100644 --- a/contrib/libs/llvm12/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.h +++ b/contrib/libs/llvm12/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.h @@ -1,167 +1,167 @@ -//===-- RuntimeDyldMachO.h - Run-time dynamic linker for MC-JIT ---*- C++ -*-=// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// MachO support for MC-JIT runtime dynamic linker. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_RUNTIMEDYLDMACHO_H -#define LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_RUNTIMEDYLDMACHO_H - -#include "RuntimeDyldImpl.h" -#include "llvm/Object/MachO.h" -#include "llvm/Support/Format.h" - -#define DEBUG_TYPE "dyld" - -using namespace llvm; -using namespace llvm::object; - -namespace llvm { -class RuntimeDyldMachO : public RuntimeDyldImpl { -protected: - struct SectionOffsetPair { - unsigned SectionID; - uint64_t Offset; - }; - - struct EHFrameRelatedSections { - EHFrameRelatedSections() - : EHFrameSID(RTDYLD_INVALID_SECTION_ID), - TextSID(RTDYLD_INVALID_SECTION_ID), - ExceptTabSID(RTDYLD_INVALID_SECTION_ID) {} - - EHFrameRelatedSections(SID EH, SID T, SID Ex) - : EHFrameSID(EH), TextSID(T), ExceptTabSID(Ex) {} - SID EHFrameSID; - SID TextSID; - SID ExceptTabSID; - }; - - // When a module is loaded we save the SectionID of the EH frame section - // in a table until we receive a request to register all unregistered - // EH frame sections with the memory manager. - SmallVector<EHFrameRelatedSections, 2> UnregisteredEHFrameSections; - - RuntimeDyldMachO(RuntimeDyld::MemoryManager &MemMgr, - JITSymbolResolver &Resolver) - : RuntimeDyldImpl(MemMgr, Resolver) {} - - /// This convenience method uses memcpy to extract a contiguous addend (the - /// addend size and offset are taken from the corresponding fields of the RE). - int64_t memcpyAddend(const RelocationEntry &RE) const; - - /// Given a relocation_iterator for a non-scattered relocation, construct a - /// RelocationEntry and fill in the common fields. The 'Addend' field is *not* - /// filled in, since immediate encodings are highly target/opcode specific. - /// For targets/opcodes with simple, contiguous immediates (e.g. X86) the - /// memcpyAddend method can be used to read the immediate. - RelocationEntry getRelocationEntry(unsigned SectionID, - const ObjectFile &BaseTObj, - const relocation_iterator &RI) const { - const MachOObjectFile &Obj = - static_cast<const MachOObjectFile &>(BaseTObj); - MachO::any_relocation_info RelInfo = - Obj.getRelocation(RI->getRawDataRefImpl()); - - bool IsPCRel = Obj.getAnyRelocationPCRel(RelInfo); - unsigned Size = Obj.getAnyRelocationLength(RelInfo); - uint64_t Offset = RI->getOffset(); - MachO::RelocationInfoType RelType = - static_cast<MachO::RelocationInfoType>(Obj.getAnyRelocationType(RelInfo)); - - return RelocationEntry(SectionID, Offset, RelType, 0, IsPCRel, Size); - } - - /// Process a scattered vanilla relocation. - Expected<relocation_iterator> - processScatteredVANILLA(unsigned SectionID, relocation_iterator RelI, - const ObjectFile &BaseObjT, - RuntimeDyldMachO::ObjSectionToIDMap &ObjSectionToID, - bool TargetIsLocalThumbFunc = false); - - /// Construct a RelocationValueRef representing the relocation target. - /// For Symbols in known sections, this will return a RelocationValueRef - /// representing a (SectionID, Offset) pair. - /// For Symbols whose section is not known, this will return a - /// (SymbolName, Offset) pair, where the Offset is taken from the instruction - /// immediate (held in RE.Addend). - /// In both cases the Addend field is *NOT* fixed up to be PC-relative. That - /// should be done by the caller where appropriate by calling makePCRel on - /// the RelocationValueRef. - Expected<RelocationValueRef> - getRelocationValueRef(const ObjectFile &BaseTObj, - const relocation_iterator &RI, - const RelocationEntry &RE, - ObjSectionToIDMap &ObjSectionToID); - - /// Make the RelocationValueRef addend PC-relative. - void makeValueAddendPCRel(RelocationValueRef &Value, - const relocation_iterator &RI, - unsigned OffsetToNextPC); - - /// Dump information about the relocation entry (RE) and resolved value. - void dumpRelocationToResolve(const RelocationEntry &RE, uint64_t Value) const; - - // Return a section iterator for the section containing the given address. - static section_iterator getSectionByAddress(const MachOObjectFile &Obj, - uint64_t Addr); - - - // Populate __pointers section. - Error populateIndirectSymbolPointersSection(const MachOObjectFile &Obj, - const SectionRef &PTSection, - unsigned PTSectionID); - -public: - - /// Create a RuntimeDyldMachO instance for the given target architecture. - static std::unique_ptr<RuntimeDyldMachO> - create(Triple::ArchType Arch, - RuntimeDyld::MemoryManager &MemMgr, - JITSymbolResolver &Resolver); - - std::unique_ptr<RuntimeDyld::LoadedObjectInfo> - loadObject(const object::ObjectFile &O) override; - - SectionEntry &getSection(unsigned SectionID) { return Sections[SectionID]; } - - bool isCompatibleFile(const object::ObjectFile &Obj) const override; -}; - -/// RuntimeDyldMachOTarget - Templated base class for generic MachO linker -/// algorithms and data structures. -/// -/// Concrete, target specific sub-classes can be accessed via the impl() -/// methods. (i.e. the RuntimeDyldMachO hierarchy uses the Curiously -/// Recurring Template Idiom). Concrete subclasses for each target -/// can be found in ./Targets. -template <typename Impl> -class RuntimeDyldMachOCRTPBase : public RuntimeDyldMachO { -private: - Impl &impl() { return static_cast<Impl &>(*this); } - const Impl &impl() const { return static_cast<const Impl &>(*this); } - - unsigned char *processFDE(uint8_t *P, int64_t DeltaForText, - int64_t DeltaForEH); - -public: - RuntimeDyldMachOCRTPBase(RuntimeDyld::MemoryManager &MemMgr, - JITSymbolResolver &Resolver) - : RuntimeDyldMachO(MemMgr, Resolver) {} - - Error finalizeLoad(const ObjectFile &Obj, - ObjSectionToIDMap &SectionMap) override; - void registerEHFrames() override; -}; - -} // end namespace llvm - -#undef DEBUG_TYPE - -#endif +//===-- RuntimeDyldMachO.h - Run-time dynamic linker for MC-JIT ---*- C++ -*-=// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// MachO support for MC-JIT runtime dynamic linker. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_RUNTIMEDYLDMACHO_H +#define LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_RUNTIMEDYLDMACHO_H + +#include "RuntimeDyldImpl.h" +#include "llvm/Object/MachO.h" +#include "llvm/Support/Format.h" + +#define DEBUG_TYPE "dyld" + +using namespace llvm; +using namespace llvm::object; + +namespace llvm { +class RuntimeDyldMachO : public RuntimeDyldImpl { +protected: + struct SectionOffsetPair { + unsigned SectionID; + uint64_t Offset; + }; + + struct EHFrameRelatedSections { + EHFrameRelatedSections() + : EHFrameSID(RTDYLD_INVALID_SECTION_ID), + TextSID(RTDYLD_INVALID_SECTION_ID), + ExceptTabSID(RTDYLD_INVALID_SECTION_ID) {} + + EHFrameRelatedSections(SID EH, SID T, SID Ex) + : EHFrameSID(EH), TextSID(T), ExceptTabSID(Ex) {} + SID EHFrameSID; + SID TextSID; + SID ExceptTabSID; + }; + + // When a module is loaded we save the SectionID of the EH frame section + // in a table until we receive a request to register all unregistered + // EH frame sections with the memory manager. + SmallVector<EHFrameRelatedSections, 2> UnregisteredEHFrameSections; + + RuntimeDyldMachO(RuntimeDyld::MemoryManager &MemMgr, + JITSymbolResolver &Resolver) + : RuntimeDyldImpl(MemMgr, Resolver) {} + + /// This convenience method uses memcpy to extract a contiguous addend (the + /// addend size and offset are taken from the corresponding fields of the RE). + int64_t memcpyAddend(const RelocationEntry &RE) const; + + /// Given a relocation_iterator for a non-scattered relocation, construct a + /// RelocationEntry and fill in the common fields. The 'Addend' field is *not* + /// filled in, since immediate encodings are highly target/opcode specific. + /// For targets/opcodes with simple, contiguous immediates (e.g. X86) the + /// memcpyAddend method can be used to read the immediate. + RelocationEntry getRelocationEntry(unsigned SectionID, + const ObjectFile &BaseTObj, + const relocation_iterator &RI) const { + const MachOObjectFile &Obj = + static_cast<const MachOObjectFile &>(BaseTObj); + MachO::any_relocation_info RelInfo = + Obj.getRelocation(RI->getRawDataRefImpl()); + + bool IsPCRel = Obj.getAnyRelocationPCRel(RelInfo); + unsigned Size = Obj.getAnyRelocationLength(RelInfo); + uint64_t Offset = RI->getOffset(); + MachO::RelocationInfoType RelType = + static_cast<MachO::RelocationInfoType>(Obj.getAnyRelocationType(RelInfo)); + + return RelocationEntry(SectionID, Offset, RelType, 0, IsPCRel, Size); + } + + /// Process a scattered vanilla relocation. + Expected<relocation_iterator> + processScatteredVANILLA(unsigned SectionID, relocation_iterator RelI, + const ObjectFile &BaseObjT, + RuntimeDyldMachO::ObjSectionToIDMap &ObjSectionToID, + bool TargetIsLocalThumbFunc = false); + + /// Construct a RelocationValueRef representing the relocation target. + /// For Symbols in known sections, this will return a RelocationValueRef + /// representing a (SectionID, Offset) pair. + /// For Symbols whose section is not known, this will return a + /// (SymbolName, Offset) pair, where the Offset is taken from the instruction + /// immediate (held in RE.Addend). + /// In both cases the Addend field is *NOT* fixed up to be PC-relative. That + /// should be done by the caller where appropriate by calling makePCRel on + /// the RelocationValueRef. + Expected<RelocationValueRef> + getRelocationValueRef(const ObjectFile &BaseTObj, + const relocation_iterator &RI, + const RelocationEntry &RE, + ObjSectionToIDMap &ObjSectionToID); + + /// Make the RelocationValueRef addend PC-relative. + void makeValueAddendPCRel(RelocationValueRef &Value, + const relocation_iterator &RI, + unsigned OffsetToNextPC); + + /// Dump information about the relocation entry (RE) and resolved value. + void dumpRelocationToResolve(const RelocationEntry &RE, uint64_t Value) const; + + // Return a section iterator for the section containing the given address. + static section_iterator getSectionByAddress(const MachOObjectFile &Obj, + uint64_t Addr); + + + // Populate __pointers section. + Error populateIndirectSymbolPointersSection(const MachOObjectFile &Obj, + const SectionRef &PTSection, + unsigned PTSectionID); + +public: + + /// Create a RuntimeDyldMachO instance for the given target architecture. + static std::unique_ptr<RuntimeDyldMachO> + create(Triple::ArchType Arch, + RuntimeDyld::MemoryManager &MemMgr, + JITSymbolResolver &Resolver); + + std::unique_ptr<RuntimeDyld::LoadedObjectInfo> + loadObject(const object::ObjectFile &O) override; + + SectionEntry &getSection(unsigned SectionID) { return Sections[SectionID]; } + + bool isCompatibleFile(const object::ObjectFile &Obj) const override; +}; + +/// RuntimeDyldMachOTarget - Templated base class for generic MachO linker +/// algorithms and data structures. +/// +/// Concrete, target specific sub-classes can be accessed via the impl() +/// methods. (i.e. the RuntimeDyldMachO hierarchy uses the Curiously +/// Recurring Template Idiom). Concrete subclasses for each target +/// can be found in ./Targets. +template <typename Impl> +class RuntimeDyldMachOCRTPBase : public RuntimeDyldMachO { +private: + Impl &impl() { return static_cast<Impl &>(*this); } + const Impl &impl() const { return static_cast<const Impl &>(*this); } + + unsigned char *processFDE(uint8_t *P, int64_t DeltaForText, + int64_t DeltaForEH); + +public: + RuntimeDyldMachOCRTPBase(RuntimeDyld::MemoryManager &MemMgr, + JITSymbolResolver &Resolver) + : RuntimeDyldMachO(MemMgr, Resolver) {} + + Error finalizeLoad(const ObjectFile &Obj, + ObjSectionToIDMap &SectionMap) override; + void registerEHFrames() override; +}; + +} // end namespace llvm + +#undef DEBUG_TYPE + +#endif diff --git a/contrib/libs/llvm12/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldCOFFAArch64.h b/contrib/libs/llvm12/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldCOFFAArch64.h index 9c93200334..14510e56b3 100644 --- a/contrib/libs/llvm12/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldCOFFAArch64.h +++ b/contrib/libs/llvm12/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldCOFFAArch64.h @@ -1,376 +1,376 @@ -//===-- RuntimeDyldCOFFAArch64.h --- COFF/AArch64 specific code ---*- C++ -//-*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// COFF AArch64 support for MC-JIT runtime dynamic linker. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDCOFFAARCH64_H -#define LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDCOFFAARCH64_H - -#include "../RuntimeDyldCOFF.h" -#include "llvm/BinaryFormat/COFF.h" -#include "llvm/Object/COFF.h" -#include "llvm/Support/Endian.h" - -#define DEBUG_TYPE "dyld" - -using namespace llvm::support::endian; - -namespace llvm { - -// This relocation type is used for handling long branch instruction -// throught the Stub. -enum InternalRelocationType : unsigned { - INTERNAL_REL_ARM64_LONG_BRANCH26 = 0x111, -}; - -static void add16(uint8_t *p, int16_t v) { write16le(p, read16le(p) + v); } -static void or32le(void *P, int32_t V) { write32le(P, read32le(P) | V); } - -static void write32AArch64Imm(uint8_t *T, uint64_t imm, uint32_t rangeLimit) { - uint32_t orig = read32le(T); - orig &= ~(0xFFF << 10); - write32le(T, orig | ((imm & (0xFFF >> rangeLimit)) << 10)); -} - -static void write32AArch64Ldr(uint8_t *T, uint64_t imm) { - uint32_t orig = read32le(T); - uint32_t size = orig >> 30; - // 0x04000000 indicates SIMD/FP registers - // 0x00800000 indicates 128 bit - if ((orig & 0x04800000) == 0x04800000) - size += 4; - if ((imm & ((1 << size) - 1)) != 0) - assert(0 && "misaligned ldr/str offset"); - write32AArch64Imm(T, imm >> size, size); -} - -static void write32AArch64Addr(void *T, uint64_t s, uint64_t p, int shift) { - uint64_t Imm = (s >> shift) - (p >> shift); - uint32_t ImmLo = (Imm & 0x3) << 29; - uint32_t ImmHi = (Imm & 0x1FFFFC) << 3; - uint64_t Mask = (0x3 << 29) | (0x1FFFFC << 3); - write32le(T, (read32le(T) & ~Mask) | ImmLo | ImmHi); -} - -class RuntimeDyldCOFFAArch64 : public RuntimeDyldCOFF { - -private: - // When a module is loaded we save the SectionID of the unwind - // sections in a table until we receive a request to register all - // unregisteredEH frame sections with the memory manager. - SmallVector<SID, 2> UnregisteredEHFrameSections; - SmallVector<SID, 2> RegisteredEHFrameSections; - uint64_t ImageBase; - - // Fake an __ImageBase pointer by returning the section with the lowest adress - uint64_t getImageBase() { - if (!ImageBase) { - ImageBase = std::numeric_limits<uint64_t>::max(); - for (const SectionEntry &Section : Sections) - // The Sections list may contain sections that weren't loaded for - // whatever reason: they may be debug sections, and ProcessAllSections - // is false, or they may be sections that contain 0 bytes. If the - // section isn't loaded, the load address will be 0, and it should not - // be included in the ImageBase calculation. - if (Section.getLoadAddress() != 0) - ImageBase = std::min(ImageBase, Section.getLoadAddress()); - } - return ImageBase; - } - -public: - RuntimeDyldCOFFAArch64(RuntimeDyld::MemoryManager &MM, - JITSymbolResolver &Resolver) - : RuntimeDyldCOFF(MM, Resolver, 8, COFF::IMAGE_REL_ARM64_ADDR64), - ImageBase(0) {} - - unsigned getStubAlignment() override { return 8; } - - unsigned getMaxStubSize() const override { return 20; } - - std::tuple<uint64_t, uint64_t, uint64_t> - generateRelocationStub(unsigned SectionID, StringRef TargetName, - uint64_t Offset, uint64_t RelType, uint64_t Addend, - StubMap &Stubs) { - uintptr_t StubOffset; - SectionEntry &Section = Sections[SectionID]; - - RelocationValueRef OriginalRelValueRef; - OriginalRelValueRef.SectionID = SectionID; - OriginalRelValueRef.Offset = Offset; - OriginalRelValueRef.Addend = Addend; - OriginalRelValueRef.SymbolName = TargetName.data(); - - auto Stub = Stubs.find(OriginalRelValueRef); - if (Stub == Stubs.end()) { - LLVM_DEBUG(dbgs() << " Create a new stub function for " - << TargetName.data() << "\n"); - - StubOffset = Section.getStubOffset(); - Stubs[OriginalRelValueRef] = StubOffset; - createStubFunction(Section.getAddressWithOffset(StubOffset)); - Section.advanceStubOffset(getMaxStubSize()); - } else { - LLVM_DEBUG(dbgs() << " Stub function found for " << TargetName.data() - << "\n"); - StubOffset = Stub->second; - } - - // Resolve original relocation to stub function. - const RelocationEntry RE(SectionID, Offset, RelType, Addend); - resolveRelocation(RE, Section.getLoadAddressWithOffset(StubOffset)); - - // adjust relocation info so resolution writes to the stub function - // Here an internal relocation type is used for resolving long branch via - // stub instruction. - Addend = 0; - Offset = StubOffset; - RelType = INTERNAL_REL_ARM64_LONG_BRANCH26; - - return std::make_tuple(Offset, RelType, Addend); - } - - Expected<object::relocation_iterator> - processRelocationRef(unsigned SectionID, object::relocation_iterator RelI, - const object::ObjectFile &Obj, - ObjSectionToIDMap &ObjSectionToID, - StubMap &Stubs) override { - - auto Symbol = RelI->getSymbol(); - if (Symbol == Obj.symbol_end()) - report_fatal_error("Unknown symbol in relocation"); - - Expected<StringRef> TargetNameOrErr = Symbol->getName(); - if (!TargetNameOrErr) - return TargetNameOrErr.takeError(); - StringRef TargetName = *TargetNameOrErr; - - auto SectionOrErr = Symbol->getSection(); - if (!SectionOrErr) - return SectionOrErr.takeError(); - auto Section = *SectionOrErr; - - uint64_t RelType = RelI->getType(); - uint64_t Offset = RelI->getOffset(); - - // If there is no section, this must be an external reference. - bool IsExtern = Section == Obj.section_end(); - - // Determine the Addend used to adjust the relocation value. - uint64_t Addend = 0; - SectionEntry &AddendSection = Sections[SectionID]; - uintptr_t ObjTarget = AddendSection.getObjAddress() + Offset; - uint8_t *Displacement = (uint8_t *)ObjTarget; - - unsigned TargetSectionID = -1; - uint64_t TargetOffset = -1; - - if (TargetName.startswith(getImportSymbolPrefix())) { - TargetSectionID = SectionID; - TargetOffset = getDLLImportOffset(SectionID, Stubs, TargetName); - TargetName = StringRef(); - IsExtern = false; - } else if (!IsExtern) { - if (auto TargetSectionIDOrErr = findOrEmitSection( - Obj, *Section, Section->isText(), ObjSectionToID)) - TargetSectionID = *TargetSectionIDOrErr; - else - return TargetSectionIDOrErr.takeError(); - - TargetOffset = getSymbolOffset(*Symbol); - } - - switch (RelType) { - case COFF::IMAGE_REL_ARM64_ADDR32: - case COFF::IMAGE_REL_ARM64_ADDR32NB: - case COFF::IMAGE_REL_ARM64_REL32: - case COFF::IMAGE_REL_ARM64_SECREL: - Addend = read32le(Displacement); - break; - case COFF::IMAGE_REL_ARM64_BRANCH26: { - uint32_t orig = read32le(Displacement); - Addend = (orig & 0x03FFFFFF) << 2; - - if (IsExtern) - std::tie(Offset, RelType, Addend) = generateRelocationStub( - SectionID, TargetName, Offset, RelType, Addend, Stubs); - break; - } - case COFF::IMAGE_REL_ARM64_BRANCH19: { - uint32_t orig = read32le(Displacement); - Addend = (orig & 0x00FFFFE0) >> 3; - break; - } - case COFF::IMAGE_REL_ARM64_BRANCH14: { - uint32_t orig = read32le(Displacement); - Addend = (orig & 0x000FFFE0) >> 3; - break; - } - case COFF::IMAGE_REL_ARM64_REL21: - case COFF::IMAGE_REL_ARM64_PAGEBASE_REL21: { - uint32_t orig = read32le(Displacement); - Addend = ((orig >> 29) & 0x3) | ((orig >> 3) & 0x1FFFFC); - break; - } - case COFF::IMAGE_REL_ARM64_PAGEOFFSET_12L: - case COFF::IMAGE_REL_ARM64_PAGEOFFSET_12A: { - uint32_t orig = read32le(Displacement); - Addend = ((orig >> 10) & 0xFFF); - break; - } - case COFF::IMAGE_REL_ARM64_ADDR64: { - Addend = read64le(Displacement); - break; - } - default: - break; - } - -#if !defined(NDEBUG) - SmallString<32> RelTypeName; - RelI->getTypeName(RelTypeName); - - LLVM_DEBUG(dbgs() << "\t\tIn Section " << SectionID << " Offset " << Offset - << " RelType: " << RelTypeName << " TargetName: " - << TargetName << " Addend " << Addend << "\n"); -#endif - - if (IsExtern) { - RelocationEntry RE(SectionID, Offset, RelType, Addend); - addRelocationForSymbol(RE, TargetName); - } else { - RelocationEntry RE(SectionID, Offset, RelType, TargetOffset + Addend); - addRelocationForSection(RE, TargetSectionID); - } - return ++RelI; - } - - void resolveRelocation(const RelocationEntry &RE, uint64_t Value) override { - const auto Section = Sections[RE.SectionID]; - uint8_t *Target = Section.getAddressWithOffset(RE.Offset); - uint64_t FinalAddress = Section.getLoadAddressWithOffset(RE.Offset); - - switch (RE.RelType) { - default: - llvm_unreachable("unsupported relocation type"); - case COFF::IMAGE_REL_ARM64_ABSOLUTE: { - // This relocation is ignored. - break; - } - case COFF::IMAGE_REL_ARM64_PAGEBASE_REL21: { - // The page base of the target, for ADRP instruction. - Value += RE.Addend; - write32AArch64Addr(Target, Value, FinalAddress, 12); - break; - } - case COFF::IMAGE_REL_ARM64_REL21: { - // The 12-bit relative displacement to the target, for instruction ADR - Value += RE.Addend; - write32AArch64Addr(Target, Value, FinalAddress, 0); - break; - } - case COFF::IMAGE_REL_ARM64_PAGEOFFSET_12A: { - // The 12-bit page offset of the target, - // for instructions ADD/ADDS (immediate) with zero shift. - Value += RE.Addend; - write32AArch64Imm(Target, Value & 0xFFF, 0); - break; - } - case COFF::IMAGE_REL_ARM64_PAGEOFFSET_12L: { - // The 12-bit page offset of the target, - // for instruction LDR (indexed, unsigned immediate). - Value += RE.Addend; - write32AArch64Ldr(Target, Value & 0xFFF); - break; - } - case COFF::IMAGE_REL_ARM64_ADDR32: { - // The 32-bit VA of the target. - uint32_t VA = Value + RE.Addend; - write32le(Target, VA); - break; - } - case COFF::IMAGE_REL_ARM64_ADDR32NB: { - // The target's 32-bit RVA. - uint64_t RVA = Value + RE.Addend - getImageBase(); - write32le(Target, RVA); - break; - } - case INTERNAL_REL_ARM64_LONG_BRANCH26: { - // Encode the immadiate value for generated Stub instruction (MOVZ) - or32le(Target + 12, ((Value + RE.Addend) & 0xFFFF) << 5); - or32le(Target + 8, ((Value + RE.Addend) & 0xFFFF0000) >> 11); - or32le(Target + 4, ((Value + RE.Addend) & 0xFFFF00000000) >> 27); - or32le(Target + 0, ((Value + RE.Addend) & 0xFFFF000000000000) >> 43); - break; - } - case COFF::IMAGE_REL_ARM64_BRANCH26: { - // The 26-bit relative displacement to the target, for B and BL - // instructions. - uint64_t PCRelVal = Value + RE.Addend - FinalAddress; - assert(isInt<28>(PCRelVal) && "Branch target is out of range."); - write32le(Target, (read32le(Target) & ~(0x03FFFFFF)) | - (PCRelVal & 0x0FFFFFFC) >> 2); - break; - } - case COFF::IMAGE_REL_ARM64_BRANCH19: { - // The 19-bit offset to the relocation target, - // for conditional B instruction. - uint64_t PCRelVal = Value + RE.Addend - FinalAddress; - assert(isInt<21>(PCRelVal) && "Branch target is out of range."); - write32le(Target, (read32le(Target) & ~(0x00FFFFE0)) | - (PCRelVal & 0x001FFFFC) << 3); - break; - } - case COFF::IMAGE_REL_ARM64_BRANCH14: { - // The 14-bit offset to the relocation target, - // for instructions TBZ and TBNZ. - uint64_t PCRelVal = Value + RE.Addend - FinalAddress; - assert(isInt<16>(PCRelVal) && "Branch target is out of range."); - write32le(Target, (read32le(Target) & ~(0x000FFFE0)) | - (PCRelVal & 0x0000FFFC) << 3); - break; - } - case COFF::IMAGE_REL_ARM64_ADDR64: { - // The 64-bit VA of the relocation target. - write64le(Target, Value + RE.Addend); - break; - } - case COFF::IMAGE_REL_ARM64_SECTION: { - // 16-bit section index of the section that contains the target. - assert(static_cast<uint32_t>(RE.SectionID) <= UINT16_MAX && - "relocation overflow"); - add16(Target, RE.SectionID); - break; - } - case COFF::IMAGE_REL_ARM64_SECREL: { - // 32-bit offset of the target from the beginning of its section. - assert(static_cast<int64_t>(RE.Addend) <= INT32_MAX && - "Relocation overflow"); - assert(static_cast<int64_t>(RE.Addend) >= INT32_MIN && - "Relocation underflow"); - write32le(Target, RE.Addend); - break; - } - case COFF::IMAGE_REL_ARM64_REL32: { - // The 32-bit relative address from the byte following the relocation. - uint64_t Result = Value - FinalAddress - 4; - write32le(Target, Result + RE.Addend); - break; - } - } - } - - void registerEHFrames() override {} -}; - -} // End namespace llvm - -#endif +//===-- RuntimeDyldCOFFAArch64.h --- COFF/AArch64 specific code ---*- C++ +//-*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// COFF AArch64 support for MC-JIT runtime dynamic linker. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDCOFFAARCH64_H +#define LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDCOFFAARCH64_H + +#include "../RuntimeDyldCOFF.h" +#include "llvm/BinaryFormat/COFF.h" +#include "llvm/Object/COFF.h" +#include "llvm/Support/Endian.h" + +#define DEBUG_TYPE "dyld" + +using namespace llvm::support::endian; + +namespace llvm { + +// This relocation type is used for handling long branch instruction +// throught the Stub. +enum InternalRelocationType : unsigned { + INTERNAL_REL_ARM64_LONG_BRANCH26 = 0x111, +}; + +static void add16(uint8_t *p, int16_t v) { write16le(p, read16le(p) + v); } +static void or32le(void *P, int32_t V) { write32le(P, read32le(P) | V); } + +static void write32AArch64Imm(uint8_t *T, uint64_t imm, uint32_t rangeLimit) { + uint32_t orig = read32le(T); + orig &= ~(0xFFF << 10); + write32le(T, orig | ((imm & (0xFFF >> rangeLimit)) << 10)); +} + +static void write32AArch64Ldr(uint8_t *T, uint64_t imm) { + uint32_t orig = read32le(T); + uint32_t size = orig >> 30; + // 0x04000000 indicates SIMD/FP registers + // 0x00800000 indicates 128 bit + if ((orig & 0x04800000) == 0x04800000) + size += 4; + if ((imm & ((1 << size) - 1)) != 0) + assert(0 && "misaligned ldr/str offset"); + write32AArch64Imm(T, imm >> size, size); +} + +static void write32AArch64Addr(void *T, uint64_t s, uint64_t p, int shift) { + uint64_t Imm = (s >> shift) - (p >> shift); + uint32_t ImmLo = (Imm & 0x3) << 29; + uint32_t ImmHi = (Imm & 0x1FFFFC) << 3; + uint64_t Mask = (0x3 << 29) | (0x1FFFFC << 3); + write32le(T, (read32le(T) & ~Mask) | ImmLo | ImmHi); +} + +class RuntimeDyldCOFFAArch64 : public RuntimeDyldCOFF { + +private: + // When a module is loaded we save the SectionID of the unwind + // sections in a table until we receive a request to register all + // unregisteredEH frame sections with the memory manager. + SmallVector<SID, 2> UnregisteredEHFrameSections; + SmallVector<SID, 2> RegisteredEHFrameSections; + uint64_t ImageBase; + + // Fake an __ImageBase pointer by returning the section with the lowest adress + uint64_t getImageBase() { + if (!ImageBase) { + ImageBase = std::numeric_limits<uint64_t>::max(); + for (const SectionEntry &Section : Sections) + // The Sections list may contain sections that weren't loaded for + // whatever reason: they may be debug sections, and ProcessAllSections + // is false, or they may be sections that contain 0 bytes. If the + // section isn't loaded, the load address will be 0, and it should not + // be included in the ImageBase calculation. + if (Section.getLoadAddress() != 0) + ImageBase = std::min(ImageBase, Section.getLoadAddress()); + } + return ImageBase; + } + +public: + RuntimeDyldCOFFAArch64(RuntimeDyld::MemoryManager &MM, + JITSymbolResolver &Resolver) + : RuntimeDyldCOFF(MM, Resolver, 8, COFF::IMAGE_REL_ARM64_ADDR64), + ImageBase(0) {} + + unsigned getStubAlignment() override { return 8; } + + unsigned getMaxStubSize() const override { return 20; } + + std::tuple<uint64_t, uint64_t, uint64_t> + generateRelocationStub(unsigned SectionID, StringRef TargetName, + uint64_t Offset, uint64_t RelType, uint64_t Addend, + StubMap &Stubs) { + uintptr_t StubOffset; + SectionEntry &Section = Sections[SectionID]; + + RelocationValueRef OriginalRelValueRef; + OriginalRelValueRef.SectionID = SectionID; + OriginalRelValueRef.Offset = Offset; + OriginalRelValueRef.Addend = Addend; + OriginalRelValueRef.SymbolName = TargetName.data(); + + auto Stub = Stubs.find(OriginalRelValueRef); + if (Stub == Stubs.end()) { + LLVM_DEBUG(dbgs() << " Create a new stub function for " + << TargetName.data() << "\n"); + + StubOffset = Section.getStubOffset(); + Stubs[OriginalRelValueRef] = StubOffset; + createStubFunction(Section.getAddressWithOffset(StubOffset)); + Section.advanceStubOffset(getMaxStubSize()); + } else { + LLVM_DEBUG(dbgs() << " Stub function found for " << TargetName.data() + << "\n"); + StubOffset = Stub->second; + } + + // Resolve original relocation to stub function. + const RelocationEntry RE(SectionID, Offset, RelType, Addend); + resolveRelocation(RE, Section.getLoadAddressWithOffset(StubOffset)); + + // adjust relocation info so resolution writes to the stub function + // Here an internal relocation type is used for resolving long branch via + // stub instruction. + Addend = 0; + Offset = StubOffset; + RelType = INTERNAL_REL_ARM64_LONG_BRANCH26; + + return std::make_tuple(Offset, RelType, Addend); + } + + Expected<object::relocation_iterator> + processRelocationRef(unsigned SectionID, object::relocation_iterator RelI, + const object::ObjectFile &Obj, + ObjSectionToIDMap &ObjSectionToID, + StubMap &Stubs) override { + + auto Symbol = RelI->getSymbol(); + if (Symbol == Obj.symbol_end()) + report_fatal_error("Unknown symbol in relocation"); + + Expected<StringRef> TargetNameOrErr = Symbol->getName(); + if (!TargetNameOrErr) + return TargetNameOrErr.takeError(); + StringRef TargetName = *TargetNameOrErr; + + auto SectionOrErr = Symbol->getSection(); + if (!SectionOrErr) + return SectionOrErr.takeError(); + auto Section = *SectionOrErr; + + uint64_t RelType = RelI->getType(); + uint64_t Offset = RelI->getOffset(); + + // If there is no section, this must be an external reference. + bool IsExtern = Section == Obj.section_end(); + + // Determine the Addend used to adjust the relocation value. + uint64_t Addend = 0; + SectionEntry &AddendSection = Sections[SectionID]; + uintptr_t ObjTarget = AddendSection.getObjAddress() + Offset; + uint8_t *Displacement = (uint8_t *)ObjTarget; + + unsigned TargetSectionID = -1; + uint64_t TargetOffset = -1; + + if (TargetName.startswith(getImportSymbolPrefix())) { + TargetSectionID = SectionID; + TargetOffset = getDLLImportOffset(SectionID, Stubs, TargetName); + TargetName = StringRef(); + IsExtern = false; + } else if (!IsExtern) { + if (auto TargetSectionIDOrErr = findOrEmitSection( + Obj, *Section, Section->isText(), ObjSectionToID)) + TargetSectionID = *TargetSectionIDOrErr; + else + return TargetSectionIDOrErr.takeError(); + + TargetOffset = getSymbolOffset(*Symbol); + } + + switch (RelType) { + case COFF::IMAGE_REL_ARM64_ADDR32: + case COFF::IMAGE_REL_ARM64_ADDR32NB: + case COFF::IMAGE_REL_ARM64_REL32: + case COFF::IMAGE_REL_ARM64_SECREL: + Addend = read32le(Displacement); + break; + case COFF::IMAGE_REL_ARM64_BRANCH26: { + uint32_t orig = read32le(Displacement); + Addend = (orig & 0x03FFFFFF) << 2; + + if (IsExtern) + std::tie(Offset, RelType, Addend) = generateRelocationStub( + SectionID, TargetName, Offset, RelType, Addend, Stubs); + break; + } + case COFF::IMAGE_REL_ARM64_BRANCH19: { + uint32_t orig = read32le(Displacement); + Addend = (orig & 0x00FFFFE0) >> 3; + break; + } + case COFF::IMAGE_REL_ARM64_BRANCH14: { + uint32_t orig = read32le(Displacement); + Addend = (orig & 0x000FFFE0) >> 3; + break; + } + case COFF::IMAGE_REL_ARM64_REL21: + case COFF::IMAGE_REL_ARM64_PAGEBASE_REL21: { + uint32_t orig = read32le(Displacement); + Addend = ((orig >> 29) & 0x3) | ((orig >> 3) & 0x1FFFFC); + break; + } + case COFF::IMAGE_REL_ARM64_PAGEOFFSET_12L: + case COFF::IMAGE_REL_ARM64_PAGEOFFSET_12A: { + uint32_t orig = read32le(Displacement); + Addend = ((orig >> 10) & 0xFFF); + break; + } + case COFF::IMAGE_REL_ARM64_ADDR64: { + Addend = read64le(Displacement); + break; + } + default: + break; + } + +#if !defined(NDEBUG) + SmallString<32> RelTypeName; + RelI->getTypeName(RelTypeName); + + LLVM_DEBUG(dbgs() << "\t\tIn Section " << SectionID << " Offset " << Offset + << " RelType: " << RelTypeName << " TargetName: " + << TargetName << " Addend " << Addend << "\n"); +#endif + + if (IsExtern) { + RelocationEntry RE(SectionID, Offset, RelType, Addend); + addRelocationForSymbol(RE, TargetName); + } else { + RelocationEntry RE(SectionID, Offset, RelType, TargetOffset + Addend); + addRelocationForSection(RE, TargetSectionID); + } + return ++RelI; + } + + void resolveRelocation(const RelocationEntry &RE, uint64_t Value) override { + const auto Section = Sections[RE.SectionID]; + uint8_t *Target = Section.getAddressWithOffset(RE.Offset); + uint64_t FinalAddress = Section.getLoadAddressWithOffset(RE.Offset); + + switch (RE.RelType) { + default: + llvm_unreachable("unsupported relocation type"); + case COFF::IMAGE_REL_ARM64_ABSOLUTE: { + // This relocation is ignored. + break; + } + case COFF::IMAGE_REL_ARM64_PAGEBASE_REL21: { + // The page base of the target, for ADRP instruction. + Value += RE.Addend; + write32AArch64Addr(Target, Value, FinalAddress, 12); + break; + } + case COFF::IMAGE_REL_ARM64_REL21: { + // The 12-bit relative displacement to the target, for instruction ADR + Value += RE.Addend; + write32AArch64Addr(Target, Value, FinalAddress, 0); + break; + } + case COFF::IMAGE_REL_ARM64_PAGEOFFSET_12A: { + // The 12-bit page offset of the target, + // for instructions ADD/ADDS (immediate) with zero shift. + Value += RE.Addend; + write32AArch64Imm(Target, Value & 0xFFF, 0); + break; + } + case COFF::IMAGE_REL_ARM64_PAGEOFFSET_12L: { + // The 12-bit page offset of the target, + // for instruction LDR (indexed, unsigned immediate). + Value += RE.Addend; + write32AArch64Ldr(Target, Value & 0xFFF); + break; + } + case COFF::IMAGE_REL_ARM64_ADDR32: { + // The 32-bit VA of the target. + uint32_t VA = Value + RE.Addend; + write32le(Target, VA); + break; + } + case COFF::IMAGE_REL_ARM64_ADDR32NB: { + // The target's 32-bit RVA. + uint64_t RVA = Value + RE.Addend - getImageBase(); + write32le(Target, RVA); + break; + } + case INTERNAL_REL_ARM64_LONG_BRANCH26: { + // Encode the immadiate value for generated Stub instruction (MOVZ) + or32le(Target + 12, ((Value + RE.Addend) & 0xFFFF) << 5); + or32le(Target + 8, ((Value + RE.Addend) & 0xFFFF0000) >> 11); + or32le(Target + 4, ((Value + RE.Addend) & 0xFFFF00000000) >> 27); + or32le(Target + 0, ((Value + RE.Addend) & 0xFFFF000000000000) >> 43); + break; + } + case COFF::IMAGE_REL_ARM64_BRANCH26: { + // The 26-bit relative displacement to the target, for B and BL + // instructions. + uint64_t PCRelVal = Value + RE.Addend - FinalAddress; + assert(isInt<28>(PCRelVal) && "Branch target is out of range."); + write32le(Target, (read32le(Target) & ~(0x03FFFFFF)) | + (PCRelVal & 0x0FFFFFFC) >> 2); + break; + } + case COFF::IMAGE_REL_ARM64_BRANCH19: { + // The 19-bit offset to the relocation target, + // for conditional B instruction. + uint64_t PCRelVal = Value + RE.Addend - FinalAddress; + assert(isInt<21>(PCRelVal) && "Branch target is out of range."); + write32le(Target, (read32le(Target) & ~(0x00FFFFE0)) | + (PCRelVal & 0x001FFFFC) << 3); + break; + } + case COFF::IMAGE_REL_ARM64_BRANCH14: { + // The 14-bit offset to the relocation target, + // for instructions TBZ and TBNZ. + uint64_t PCRelVal = Value + RE.Addend - FinalAddress; + assert(isInt<16>(PCRelVal) && "Branch target is out of range."); + write32le(Target, (read32le(Target) & ~(0x000FFFE0)) | + (PCRelVal & 0x0000FFFC) << 3); + break; + } + case COFF::IMAGE_REL_ARM64_ADDR64: { + // The 64-bit VA of the relocation target. + write64le(Target, Value + RE.Addend); + break; + } + case COFF::IMAGE_REL_ARM64_SECTION: { + // 16-bit section index of the section that contains the target. + assert(static_cast<uint32_t>(RE.SectionID) <= UINT16_MAX && + "relocation overflow"); + add16(Target, RE.SectionID); + break; + } + case COFF::IMAGE_REL_ARM64_SECREL: { + // 32-bit offset of the target from the beginning of its section. + assert(static_cast<int64_t>(RE.Addend) <= INT32_MAX && + "Relocation overflow"); + assert(static_cast<int64_t>(RE.Addend) >= INT32_MIN && + "Relocation underflow"); + write32le(Target, RE.Addend); + break; + } + case COFF::IMAGE_REL_ARM64_REL32: { + // The 32-bit relative address from the byte following the relocation. + uint64_t Result = Value - FinalAddress - 4; + write32le(Target, Result + RE.Addend); + break; + } + } + } + + void registerEHFrames() override {} +}; + +} // End namespace llvm + +#endif diff --git a/contrib/libs/llvm12/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldCOFFI386.h b/contrib/libs/llvm12/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldCOFFI386.h index 8d3f0a5b5c..03c38260be 100644 --- a/contrib/libs/llvm12/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldCOFFI386.h +++ b/contrib/libs/llvm12/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldCOFFI386.h @@ -1,228 +1,228 @@ -//===--- RuntimeDyldCOFFI386.h --- COFF/X86_64 specific code ---*- C++ --*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// COFF x86 support for MC-JIT runtime dynamic linker. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDCOFFI386_H -#define LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDCOFFI386_H - -#include "../RuntimeDyldCOFF.h" -#include "llvm/BinaryFormat/COFF.h" -#include "llvm/Object/COFF.h" - -#define DEBUG_TYPE "dyld" - -namespace llvm { - -class RuntimeDyldCOFFI386 : public RuntimeDyldCOFF { -public: - RuntimeDyldCOFFI386(RuntimeDyld::MemoryManager &MM, - JITSymbolResolver &Resolver) - : RuntimeDyldCOFF(MM, Resolver, 4, COFF::IMAGE_REL_I386_DIR32) {} - - unsigned getMaxStubSize() const override { - return 8; // 2-byte jmp instruction + 32-bit relative address + 2 byte pad - } - - unsigned getStubAlignment() override { return 1; } - - Expected<object::relocation_iterator> - processRelocationRef(unsigned SectionID, - object::relocation_iterator RelI, - const object::ObjectFile &Obj, - ObjSectionToIDMap &ObjSectionToID, - StubMap &Stubs) override { - - auto Symbol = RelI->getSymbol(); - if (Symbol == Obj.symbol_end()) - report_fatal_error("Unknown symbol in relocation"); - - Expected<StringRef> TargetNameOrErr = Symbol->getName(); - if (!TargetNameOrErr) - return TargetNameOrErr.takeError(); - StringRef TargetName = *TargetNameOrErr; - - auto SectionOrErr = Symbol->getSection(); - if (!SectionOrErr) - return SectionOrErr.takeError(); - auto Section = *SectionOrErr; - bool IsExtern = Section == Obj.section_end(); - - uint64_t RelType = RelI->getType(); - uint64_t Offset = RelI->getOffset(); - - unsigned TargetSectionID = -1; - uint64_t TargetOffset = -1; - if (TargetName.startswith(getImportSymbolPrefix())) { - TargetSectionID = SectionID; - TargetOffset = getDLLImportOffset(SectionID, Stubs, TargetName, true); - TargetName = StringRef(); - IsExtern = false; - } else if (!IsExtern) { - if (auto TargetSectionIDOrErr = findOrEmitSection( - Obj, *Section, Section->isText(), ObjSectionToID)) - TargetSectionID = *TargetSectionIDOrErr; - else - return TargetSectionIDOrErr.takeError(); - if (RelType != COFF::IMAGE_REL_I386_SECTION) - TargetOffset = getSymbolOffset(*Symbol); - } - - // Determine the Addend used to adjust the relocation value. - uint64_t Addend = 0; - SectionEntry &AddendSection = Sections[SectionID]; - uintptr_t ObjTarget = AddendSection.getObjAddress() + Offset; - uint8_t *Displacement = (uint8_t *)ObjTarget; - - switch (RelType) { - case COFF::IMAGE_REL_I386_DIR32: - case COFF::IMAGE_REL_I386_DIR32NB: - case COFF::IMAGE_REL_I386_SECREL: - case COFF::IMAGE_REL_I386_REL32: { - Addend = readBytesUnaligned(Displacement, 4); - break; - } - default: - break; - } - -#if !defined(NDEBUG) - SmallString<32> RelTypeName; - RelI->getTypeName(RelTypeName); -#endif - LLVM_DEBUG(dbgs() << "\t\tIn Section " << SectionID << " Offset " << Offset - << " RelType: " << RelTypeName << " TargetName: " - << TargetName << " Addend " << Addend << "\n"); - - if (IsExtern) { - RelocationEntry RE(SectionID, Offset, RelType, 0, -1, 0, 0, 0, false, 0); - addRelocationForSymbol(RE, TargetName); - } else { - - switch (RelType) { - case COFF::IMAGE_REL_I386_ABSOLUTE: - // This relocation is ignored. - break; - case COFF::IMAGE_REL_I386_DIR32: - case COFF::IMAGE_REL_I386_DIR32NB: - case COFF::IMAGE_REL_I386_REL32: { - RelocationEntry RE = - RelocationEntry(SectionID, Offset, RelType, Addend, TargetSectionID, - TargetOffset, 0, 0, false, 0); - addRelocationForSection(RE, TargetSectionID); - break; - } - case COFF::IMAGE_REL_I386_SECTION: { - RelocationEntry RE = - RelocationEntry(TargetSectionID, Offset, RelType, 0); - addRelocationForSection(RE, TargetSectionID); - break; - } - case COFF::IMAGE_REL_I386_SECREL: { - RelocationEntry RE = - RelocationEntry(SectionID, Offset, RelType, TargetOffset + Addend); - addRelocationForSection(RE, TargetSectionID); - break; - } - default: - llvm_unreachable("unsupported relocation type"); - } - } - - return ++RelI; - } - - void resolveRelocation(const RelocationEntry &RE, uint64_t Value) override { - const auto Section = Sections[RE.SectionID]; - uint8_t *Target = Section.getAddressWithOffset(RE.Offset); - - switch (RE.RelType) { - case COFF::IMAGE_REL_I386_ABSOLUTE: - // This relocation is ignored. - break; - case COFF::IMAGE_REL_I386_DIR32: { - // The target's 32-bit VA. - uint64_t Result = - RE.Sections.SectionA == static_cast<uint32_t>(-1) - ? Value - : Sections[RE.Sections.SectionA].getLoadAddressWithOffset( - RE.Addend); - assert(Result <= UINT32_MAX && "relocation overflow"); - LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE.Offset - << " RelType: IMAGE_REL_I386_DIR32" - << " TargetSection: " << RE.Sections.SectionA - << " Value: " << format("0x%08" PRIx32, Result) - << '\n'); - writeBytesUnaligned(Result, Target, 4); - break; - } - case COFF::IMAGE_REL_I386_DIR32NB: { - // The target's 32-bit RVA. - // NOTE: use Section[0].getLoadAddress() as an approximation of ImageBase - uint64_t Result = - Sections[RE.Sections.SectionA].getLoadAddressWithOffset(RE.Addend) - - Sections[0].getLoadAddress(); - assert(Result <= UINT32_MAX && "relocation overflow"); - LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE.Offset - << " RelType: IMAGE_REL_I386_DIR32NB" - << " TargetSection: " << RE.Sections.SectionA - << " Value: " << format("0x%08" PRIx32, Result) - << '\n'); - writeBytesUnaligned(Result, Target, 4); - break; - } - case COFF::IMAGE_REL_I386_REL32: { - // 32-bit relative displacement to the target. - uint64_t Result = RE.Sections.SectionA == static_cast<uint32_t>(-1) - ? Value - : Sections[RE.Sections.SectionA].getLoadAddress(); - Result = Result - Section.getLoadAddress() + RE.Addend - 4 - RE.Offset; - assert(static_cast<int64_t>(Result) <= INT32_MAX && - "relocation overflow"); - assert(static_cast<int64_t>(Result) >= INT32_MIN && - "relocation underflow"); - LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE.Offset - << " RelType: IMAGE_REL_I386_REL32" - << " TargetSection: " << RE.Sections.SectionA - << " Value: " << format("0x%08" PRIx32, Result) - << '\n'); - writeBytesUnaligned(Result, Target, 4); - break; - } - case COFF::IMAGE_REL_I386_SECTION: - // 16-bit section index of the section that contains the target. - assert(static_cast<uint32_t>(RE.SectionID) <= UINT16_MAX && - "relocation overflow"); - LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE.Offset - << " RelType: IMAGE_REL_I386_SECTION Value: " - << RE.SectionID << '\n'); - writeBytesUnaligned(RE.SectionID, Target, 2); - break; - case COFF::IMAGE_REL_I386_SECREL: - // 32-bit offset of the target from the beginning of its section. - assert(static_cast<uint64_t>(RE.Addend) <= UINT32_MAX && - "relocation overflow"); - LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE.Offset - << " RelType: IMAGE_REL_I386_SECREL Value: " - << RE.Addend << '\n'); - writeBytesUnaligned(RE.Addend, Target, 4); - break; - default: - llvm_unreachable("unsupported relocation type"); - } - } - - void registerEHFrames() override {} -}; - -} - -#endif - +//===--- RuntimeDyldCOFFI386.h --- COFF/X86_64 specific code ---*- C++ --*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// COFF x86 support for MC-JIT runtime dynamic linker. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDCOFFI386_H +#define LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDCOFFI386_H + +#include "../RuntimeDyldCOFF.h" +#include "llvm/BinaryFormat/COFF.h" +#include "llvm/Object/COFF.h" + +#define DEBUG_TYPE "dyld" + +namespace llvm { + +class RuntimeDyldCOFFI386 : public RuntimeDyldCOFF { +public: + RuntimeDyldCOFFI386(RuntimeDyld::MemoryManager &MM, + JITSymbolResolver &Resolver) + : RuntimeDyldCOFF(MM, Resolver, 4, COFF::IMAGE_REL_I386_DIR32) {} + + unsigned getMaxStubSize() const override { + return 8; // 2-byte jmp instruction + 32-bit relative address + 2 byte pad + } + + unsigned getStubAlignment() override { return 1; } + + Expected<object::relocation_iterator> + processRelocationRef(unsigned SectionID, + object::relocation_iterator RelI, + const object::ObjectFile &Obj, + ObjSectionToIDMap &ObjSectionToID, + StubMap &Stubs) override { + + auto Symbol = RelI->getSymbol(); + if (Symbol == Obj.symbol_end()) + report_fatal_error("Unknown symbol in relocation"); + + Expected<StringRef> TargetNameOrErr = Symbol->getName(); + if (!TargetNameOrErr) + return TargetNameOrErr.takeError(); + StringRef TargetName = *TargetNameOrErr; + + auto SectionOrErr = Symbol->getSection(); + if (!SectionOrErr) + return SectionOrErr.takeError(); + auto Section = *SectionOrErr; + bool IsExtern = Section == Obj.section_end(); + + uint64_t RelType = RelI->getType(); + uint64_t Offset = RelI->getOffset(); + + unsigned TargetSectionID = -1; + uint64_t TargetOffset = -1; + if (TargetName.startswith(getImportSymbolPrefix())) { + TargetSectionID = SectionID; + TargetOffset = getDLLImportOffset(SectionID, Stubs, TargetName, true); + TargetName = StringRef(); + IsExtern = false; + } else if (!IsExtern) { + if (auto TargetSectionIDOrErr = findOrEmitSection( + Obj, *Section, Section->isText(), ObjSectionToID)) + TargetSectionID = *TargetSectionIDOrErr; + else + return TargetSectionIDOrErr.takeError(); + if (RelType != COFF::IMAGE_REL_I386_SECTION) + TargetOffset = getSymbolOffset(*Symbol); + } + + // Determine the Addend used to adjust the relocation value. + uint64_t Addend = 0; + SectionEntry &AddendSection = Sections[SectionID]; + uintptr_t ObjTarget = AddendSection.getObjAddress() + Offset; + uint8_t *Displacement = (uint8_t *)ObjTarget; + + switch (RelType) { + case COFF::IMAGE_REL_I386_DIR32: + case COFF::IMAGE_REL_I386_DIR32NB: + case COFF::IMAGE_REL_I386_SECREL: + case COFF::IMAGE_REL_I386_REL32: { + Addend = readBytesUnaligned(Displacement, 4); + break; + } + default: + break; + } + +#if !defined(NDEBUG) + SmallString<32> RelTypeName; + RelI->getTypeName(RelTypeName); +#endif + LLVM_DEBUG(dbgs() << "\t\tIn Section " << SectionID << " Offset " << Offset + << " RelType: " << RelTypeName << " TargetName: " + << TargetName << " Addend " << Addend << "\n"); + + if (IsExtern) { + RelocationEntry RE(SectionID, Offset, RelType, 0, -1, 0, 0, 0, false, 0); + addRelocationForSymbol(RE, TargetName); + } else { + + switch (RelType) { + case COFF::IMAGE_REL_I386_ABSOLUTE: + // This relocation is ignored. + break; + case COFF::IMAGE_REL_I386_DIR32: + case COFF::IMAGE_REL_I386_DIR32NB: + case COFF::IMAGE_REL_I386_REL32: { + RelocationEntry RE = + RelocationEntry(SectionID, Offset, RelType, Addend, TargetSectionID, + TargetOffset, 0, 0, false, 0); + addRelocationForSection(RE, TargetSectionID); + break; + } + case COFF::IMAGE_REL_I386_SECTION: { + RelocationEntry RE = + RelocationEntry(TargetSectionID, Offset, RelType, 0); + addRelocationForSection(RE, TargetSectionID); + break; + } + case COFF::IMAGE_REL_I386_SECREL: { + RelocationEntry RE = + RelocationEntry(SectionID, Offset, RelType, TargetOffset + Addend); + addRelocationForSection(RE, TargetSectionID); + break; + } + default: + llvm_unreachable("unsupported relocation type"); + } + } + + return ++RelI; + } + + void resolveRelocation(const RelocationEntry &RE, uint64_t Value) override { + const auto Section = Sections[RE.SectionID]; + uint8_t *Target = Section.getAddressWithOffset(RE.Offset); + + switch (RE.RelType) { + case COFF::IMAGE_REL_I386_ABSOLUTE: + // This relocation is ignored. + break; + case COFF::IMAGE_REL_I386_DIR32: { + // The target's 32-bit VA. + uint64_t Result = + RE.Sections.SectionA == static_cast<uint32_t>(-1) + ? Value + : Sections[RE.Sections.SectionA].getLoadAddressWithOffset( + RE.Addend); + assert(Result <= UINT32_MAX && "relocation overflow"); + LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE.Offset + << " RelType: IMAGE_REL_I386_DIR32" + << " TargetSection: " << RE.Sections.SectionA + << " Value: " << format("0x%08" PRIx32, Result) + << '\n'); + writeBytesUnaligned(Result, Target, 4); + break; + } + case COFF::IMAGE_REL_I386_DIR32NB: { + // The target's 32-bit RVA. + // NOTE: use Section[0].getLoadAddress() as an approximation of ImageBase + uint64_t Result = + Sections[RE.Sections.SectionA].getLoadAddressWithOffset(RE.Addend) - + Sections[0].getLoadAddress(); + assert(Result <= UINT32_MAX && "relocation overflow"); + LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE.Offset + << " RelType: IMAGE_REL_I386_DIR32NB" + << " TargetSection: " << RE.Sections.SectionA + << " Value: " << format("0x%08" PRIx32, Result) + << '\n'); + writeBytesUnaligned(Result, Target, 4); + break; + } + case COFF::IMAGE_REL_I386_REL32: { + // 32-bit relative displacement to the target. + uint64_t Result = RE.Sections.SectionA == static_cast<uint32_t>(-1) + ? Value + : Sections[RE.Sections.SectionA].getLoadAddress(); + Result = Result - Section.getLoadAddress() + RE.Addend - 4 - RE.Offset; + assert(static_cast<int64_t>(Result) <= INT32_MAX && + "relocation overflow"); + assert(static_cast<int64_t>(Result) >= INT32_MIN && + "relocation underflow"); + LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE.Offset + << " RelType: IMAGE_REL_I386_REL32" + << " TargetSection: " << RE.Sections.SectionA + << " Value: " << format("0x%08" PRIx32, Result) + << '\n'); + writeBytesUnaligned(Result, Target, 4); + break; + } + case COFF::IMAGE_REL_I386_SECTION: + // 16-bit section index of the section that contains the target. + assert(static_cast<uint32_t>(RE.SectionID) <= UINT16_MAX && + "relocation overflow"); + LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE.Offset + << " RelType: IMAGE_REL_I386_SECTION Value: " + << RE.SectionID << '\n'); + writeBytesUnaligned(RE.SectionID, Target, 2); + break; + case COFF::IMAGE_REL_I386_SECREL: + // 32-bit offset of the target from the beginning of its section. + assert(static_cast<uint64_t>(RE.Addend) <= UINT32_MAX && + "relocation overflow"); + LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE.Offset + << " RelType: IMAGE_REL_I386_SECREL Value: " + << RE.Addend << '\n'); + writeBytesUnaligned(RE.Addend, Target, 4); + break; + default: + llvm_unreachable("unsupported relocation type"); + } + } + + void registerEHFrames() override {} +}; + +} + +#endif + diff --git a/contrib/libs/llvm12/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldCOFFThumb.h b/contrib/libs/llvm12/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldCOFFThumb.h index 7fdb552908..721f2b1482 100644 --- a/contrib/libs/llvm12/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldCOFFThumb.h +++ b/contrib/libs/llvm12/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldCOFFThumb.h @@ -1,326 +1,326 @@ -//===--- RuntimeDyldCOFFThumb.h --- COFF/Thumb specific code ---*- C++ --*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// COFF thumb support for MC-JIT runtime dynamic linker. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDCOFFTHUMB_H -#define LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDCOFFTHUMB_H - -#include "../RuntimeDyldCOFF.h" -#include "llvm/BinaryFormat/COFF.h" -#include "llvm/Object/COFF.h" - -#define DEBUG_TYPE "dyld" - -namespace llvm { - -static bool isThumbFunc(object::symbol_iterator Symbol, - const object::ObjectFile &Obj, - object::section_iterator Section) { - Expected<object::SymbolRef::Type> SymTypeOrErr = Symbol->getType(); - if (!SymTypeOrErr) { - std::string Buf; - raw_string_ostream OS(Buf); - logAllUnhandledErrors(SymTypeOrErr.takeError(), OS); - OS.flush(); - report_fatal_error(Buf); - } - - if (*SymTypeOrErr != object::SymbolRef::ST_Function) - return false; - - // We check the IMAGE_SCN_MEM_16BIT flag in the section of the symbol to tell - // if it's thumb or not - return cast<object::COFFObjectFile>(Obj) - .getCOFFSection(*Section) - ->Characteristics & - COFF::IMAGE_SCN_MEM_16BIT; -} - -class RuntimeDyldCOFFThumb : public RuntimeDyldCOFF { -public: - RuntimeDyldCOFFThumb(RuntimeDyld::MemoryManager &MM, - JITSymbolResolver &Resolver) - : RuntimeDyldCOFF(MM, Resolver, 4, COFF::IMAGE_REL_ARM_ADDR32) {} - - unsigned getMaxStubSize() const override { - return 16; // 8-byte load instructions, 4-byte jump, 4-byte padding - } - - unsigned getStubAlignment() override { return 1; } - - Expected<object::relocation_iterator> - processRelocationRef(unsigned SectionID, - object::relocation_iterator RelI, - const object::ObjectFile &Obj, - ObjSectionToIDMap &ObjSectionToID, - StubMap &Stubs) override { - auto Symbol = RelI->getSymbol(); - if (Symbol == Obj.symbol_end()) - report_fatal_error("Unknown symbol in relocation"); - - Expected<StringRef> TargetNameOrErr = Symbol->getName(); - if (!TargetNameOrErr) - return TargetNameOrErr.takeError(); - StringRef TargetName = *TargetNameOrErr; - - auto SectionOrErr = Symbol->getSection(); - if (!SectionOrErr) - return SectionOrErr.takeError(); - auto Section = *SectionOrErr; - - uint64_t RelType = RelI->getType(); - uint64_t Offset = RelI->getOffset(); - - // Determine the Addend used to adjust the relocation value. - uint64_t Addend = 0; - SectionEntry &AddendSection = Sections[SectionID]; - uintptr_t ObjTarget = AddendSection.getObjAddress() + Offset; - uint8_t *Displacement = (uint8_t *)ObjTarget; - - switch (RelType) { - case COFF::IMAGE_REL_ARM_ADDR32: - case COFF::IMAGE_REL_ARM_ADDR32NB: - case COFF::IMAGE_REL_ARM_SECREL: - Addend = readBytesUnaligned(Displacement, 4); - break; - default: - break; - } - -#if !defined(NDEBUG) - SmallString<32> RelTypeName; - RelI->getTypeName(RelTypeName); -#endif - LLVM_DEBUG(dbgs() << "\t\tIn Section " << SectionID << " Offset " << Offset - << " RelType: " << RelTypeName << " TargetName: " - << TargetName << " Addend " << Addend << "\n"); - - bool IsExtern = Section == Obj.section_end(); - unsigned TargetSectionID = -1; - uint64_t TargetOffset = -1; - - if (TargetName.startswith(getImportSymbolPrefix())) { - TargetSectionID = SectionID; - TargetOffset = getDLLImportOffset(SectionID, Stubs, TargetName, true); - TargetName = StringRef(); - IsExtern = false; - } else if (!IsExtern) { - if (auto TargetSectionIDOrErr = - findOrEmitSection(Obj, *Section, Section->isText(), ObjSectionToID)) - TargetSectionID = *TargetSectionIDOrErr; - else - return TargetSectionIDOrErr.takeError(); - if (RelType != COFF::IMAGE_REL_ARM_SECTION) - TargetOffset = getSymbolOffset(*Symbol); - } - - if (IsExtern) { - RelocationEntry RE(SectionID, Offset, RelType, 0, -1, 0, 0, 0, false, 0); - addRelocationForSymbol(RE, TargetName); - } else { - - // We need to find out if the relocation is relative to a thumb function - // so that we include the ISA selection bit when resolve the relocation - bool IsTargetThumbFunc = isThumbFunc(Symbol, Obj, Section); - - switch (RelType) { - default: llvm_unreachable("unsupported relocation type"); - case COFF::IMAGE_REL_ARM_ABSOLUTE: - // This relocation is ignored. - break; - case COFF::IMAGE_REL_ARM_ADDR32: { - RelocationEntry RE = - RelocationEntry(SectionID, Offset, RelType, Addend, TargetSectionID, - TargetOffset, 0, 0, false, 0, IsTargetThumbFunc); - addRelocationForSection(RE, TargetSectionID); - break; - } - case COFF::IMAGE_REL_ARM_ADDR32NB: { - RelocationEntry RE = - RelocationEntry(SectionID, Offset, RelType, Addend, TargetSectionID, - TargetOffset, 0, 0, false, 0); - addRelocationForSection(RE, TargetSectionID); - break; - } - case COFF::IMAGE_REL_ARM_SECTION: { - RelocationEntry RE = - RelocationEntry(TargetSectionID, Offset, RelType, 0); - addRelocationForSection(RE, TargetSectionID); - break; - } - case COFF::IMAGE_REL_ARM_SECREL: { - RelocationEntry RE = - RelocationEntry(SectionID, Offset, RelType, TargetOffset + Addend); - addRelocationForSection(RE, TargetSectionID); - break; - } - case COFF::IMAGE_REL_ARM_MOV32T: { - RelocationEntry RE = - RelocationEntry(SectionID, Offset, RelType, Addend, TargetSectionID, - TargetOffset, 0, 0, false, 0, IsTargetThumbFunc); - addRelocationForSection(RE, TargetSectionID); - break; - } - case COFF::IMAGE_REL_ARM_BRANCH20T: - case COFF::IMAGE_REL_ARM_BRANCH24T: - case COFF::IMAGE_REL_ARM_BLX23T: { - RelocationEntry RE = RelocationEntry(SectionID, Offset, RelType, - TargetOffset + Addend, true, 0); - addRelocationForSection(RE, TargetSectionID); - break; - } - } - } - - return ++RelI; - } - - void resolveRelocation(const RelocationEntry &RE, uint64_t Value) override { - const auto Section = Sections[RE.SectionID]; - uint8_t *Target = Section.getAddressWithOffset(RE.Offset); - int ISASelectionBit = RE.IsTargetThumbFunc ? 1 : 0; - - switch (RE.RelType) { - default: llvm_unreachable("unsupported relocation type"); - case COFF::IMAGE_REL_ARM_ABSOLUTE: - // This relocation is ignored. - break; - case COFF::IMAGE_REL_ARM_ADDR32: { - // The target's 32-bit VA. - uint64_t Result = - RE.Sections.SectionA == static_cast<uint32_t>(-1) - ? Value - : Sections[RE.Sections.SectionA].getLoadAddressWithOffset(RE.Addend); - Result |= ISASelectionBit; - assert(Result <= UINT32_MAX && "relocation overflow"); - LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE.Offset - << " RelType: IMAGE_REL_ARM_ADDR32" - << " TargetSection: " << RE.Sections.SectionA - << " Value: " << format("0x%08" PRIx32, Result) - << '\n'); - writeBytesUnaligned(Result, Target, 4); - break; - } - case COFF::IMAGE_REL_ARM_ADDR32NB: { - // The target's 32-bit RVA. - // NOTE: use Section[0].getLoadAddress() as an approximation of ImageBase - uint64_t Result = Sections[RE.Sections.SectionA].getLoadAddress() - - Sections[0].getLoadAddress() + RE.Addend; - assert(Result <= UINT32_MAX && "relocation overflow"); - LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE.Offset - << " RelType: IMAGE_REL_ARM_ADDR32NB" - << " TargetSection: " << RE.Sections.SectionA - << " Value: " << format("0x%08" PRIx32, Result) - << '\n'); - Result |= ISASelectionBit; - writeBytesUnaligned(Result, Target, 4); - break; - } - case COFF::IMAGE_REL_ARM_SECTION: - // 16-bit section index of the section that contains the target. - assert(static_cast<uint32_t>(RE.SectionID) <= UINT16_MAX && - "relocation overflow"); - LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE.Offset - << " RelType: IMAGE_REL_ARM_SECTION Value: " - << RE.SectionID << '\n'); - writeBytesUnaligned(RE.SectionID, Target, 2); - break; - case COFF::IMAGE_REL_ARM_SECREL: - // 32-bit offset of the target from the beginning of its section. - assert(static_cast<uint64_t>(RE.Addend) <= UINT32_MAX && - "relocation overflow"); - LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE.Offset - << " RelType: IMAGE_REL_ARM_SECREL Value: " << RE.Addend - << '\n'); - writeBytesUnaligned(RE.Addend, Target, 2); - break; - case COFF::IMAGE_REL_ARM_MOV32T: { - // 32-bit VA of the target applied to a contiguous MOVW+MOVT pair. - uint64_t Result = - Sections[RE.Sections.SectionA].getLoadAddressWithOffset(RE.Addend); - assert(Result <= UINT32_MAX && "relocation overflow"); - LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE.Offset - << " RelType: IMAGE_REL_ARM_MOV32T" - << " TargetSection: " << RE.Sections.SectionA - << " Value: " << format("0x%08" PRIx32, Result) - << '\n'); - - // MOVW(T3): |11110|i|10|0|1|0|0|imm4|0|imm3|Rd|imm8| - // imm32 = zext imm4:i:imm3:imm8 - // MOVT(T1): |11110|i|10|1|1|0|0|imm4|0|imm3|Rd|imm8| - // imm16 = imm4:i:imm3:imm8 - - auto EncodeImmediate = [](uint8_t *Bytes, uint16_t Immediate) { - Bytes[0] |= ((Immediate & 0xf000) >> 12); - Bytes[1] |= ((Immediate & 0x0800) >> 11); - Bytes[2] |= ((Immediate & 0x00ff) >> 0); - Bytes[3] |= (((Immediate & 0x0700) >> 8) << 4); - }; - - EncodeImmediate(&Target[0], - (static_cast<uint32_t>(Result) >> 00) | ISASelectionBit); - EncodeImmediate(&Target[4], static_cast<uint32_t>(Result) >> 16); - break; - } - case COFF::IMAGE_REL_ARM_BRANCH20T: { - // The most significant 20-bits of the signed 21-bit relative displacement - uint64_t Value = - RE.Addend - (Sections[RE.SectionID].getLoadAddress() + RE.Offset) - 4; - assert(static_cast<int64_t>(RE.Addend) <= INT32_MAX && - "relocation overflow"); - assert(static_cast<int64_t>(RE.Addend) >= INT32_MIN && - "relocation underflow"); - LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE.Offset - << " RelType: IMAGE_REL_ARM_BRANCH20T" - << " Value: " << static_cast<int32_t>(Value) << '\n'); - static_cast<void>(Value); - llvm_unreachable("unimplemented relocation"); - break; - } - case COFF::IMAGE_REL_ARM_BRANCH24T: { - // The most significant 24-bits of the signed 25-bit relative displacement - uint64_t Value = - RE.Addend - (Sections[RE.SectionID].getLoadAddress() + RE.Offset) - 4; - assert(static_cast<int64_t>(RE.Addend) <= INT32_MAX && - "relocation overflow"); - assert(static_cast<int64_t>(RE.Addend) >= INT32_MIN && - "relocation underflow"); - LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE.Offset - << " RelType: IMAGE_REL_ARM_BRANCH24T" - << " Value: " << static_cast<int32_t>(Value) << '\n'); - static_cast<void>(Value); - llvm_unreachable("unimplemented relocation"); - break; - } - case COFF::IMAGE_REL_ARM_BLX23T: { - // The most significant 24-bits of the signed 25-bit relative displacement - uint64_t Value = - RE.Addend - (Sections[RE.SectionID].getLoadAddress() + RE.Offset) - 4; - assert(static_cast<int64_t>(RE.Addend) <= INT32_MAX && - "relocation overflow"); - assert(static_cast<int64_t>(RE.Addend) >= INT32_MIN && - "relocation underflow"); - LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE.Offset - << " RelType: IMAGE_REL_ARM_BLX23T" - << " Value: " << static_cast<int32_t>(Value) << '\n'); - static_cast<void>(Value); - llvm_unreachable("unimplemented relocation"); - break; - } - } - } - - void registerEHFrames() override {} -}; - -} - -#endif +//===--- RuntimeDyldCOFFThumb.h --- COFF/Thumb specific code ---*- C++ --*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// COFF thumb support for MC-JIT runtime dynamic linker. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDCOFFTHUMB_H +#define LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDCOFFTHUMB_H + +#include "../RuntimeDyldCOFF.h" +#include "llvm/BinaryFormat/COFF.h" +#include "llvm/Object/COFF.h" + +#define DEBUG_TYPE "dyld" + +namespace llvm { + +static bool isThumbFunc(object::symbol_iterator Symbol, + const object::ObjectFile &Obj, + object::section_iterator Section) { + Expected<object::SymbolRef::Type> SymTypeOrErr = Symbol->getType(); + if (!SymTypeOrErr) { + std::string Buf; + raw_string_ostream OS(Buf); + logAllUnhandledErrors(SymTypeOrErr.takeError(), OS); + OS.flush(); + report_fatal_error(Buf); + } + + if (*SymTypeOrErr != object::SymbolRef::ST_Function) + return false; + + // We check the IMAGE_SCN_MEM_16BIT flag in the section of the symbol to tell + // if it's thumb or not + return cast<object::COFFObjectFile>(Obj) + .getCOFFSection(*Section) + ->Characteristics & + COFF::IMAGE_SCN_MEM_16BIT; +} + +class RuntimeDyldCOFFThumb : public RuntimeDyldCOFF { +public: + RuntimeDyldCOFFThumb(RuntimeDyld::MemoryManager &MM, + JITSymbolResolver &Resolver) + : RuntimeDyldCOFF(MM, Resolver, 4, COFF::IMAGE_REL_ARM_ADDR32) {} + + unsigned getMaxStubSize() const override { + return 16; // 8-byte load instructions, 4-byte jump, 4-byte padding + } + + unsigned getStubAlignment() override { return 1; } + + Expected<object::relocation_iterator> + processRelocationRef(unsigned SectionID, + object::relocation_iterator RelI, + const object::ObjectFile &Obj, + ObjSectionToIDMap &ObjSectionToID, + StubMap &Stubs) override { + auto Symbol = RelI->getSymbol(); + if (Symbol == Obj.symbol_end()) + report_fatal_error("Unknown symbol in relocation"); + + Expected<StringRef> TargetNameOrErr = Symbol->getName(); + if (!TargetNameOrErr) + return TargetNameOrErr.takeError(); + StringRef TargetName = *TargetNameOrErr; + + auto SectionOrErr = Symbol->getSection(); + if (!SectionOrErr) + return SectionOrErr.takeError(); + auto Section = *SectionOrErr; + + uint64_t RelType = RelI->getType(); + uint64_t Offset = RelI->getOffset(); + + // Determine the Addend used to adjust the relocation value. + uint64_t Addend = 0; + SectionEntry &AddendSection = Sections[SectionID]; + uintptr_t ObjTarget = AddendSection.getObjAddress() + Offset; + uint8_t *Displacement = (uint8_t *)ObjTarget; + + switch (RelType) { + case COFF::IMAGE_REL_ARM_ADDR32: + case COFF::IMAGE_REL_ARM_ADDR32NB: + case COFF::IMAGE_REL_ARM_SECREL: + Addend = readBytesUnaligned(Displacement, 4); + break; + default: + break; + } + +#if !defined(NDEBUG) + SmallString<32> RelTypeName; + RelI->getTypeName(RelTypeName); +#endif + LLVM_DEBUG(dbgs() << "\t\tIn Section " << SectionID << " Offset " << Offset + << " RelType: " << RelTypeName << " TargetName: " + << TargetName << " Addend " << Addend << "\n"); + + bool IsExtern = Section == Obj.section_end(); + unsigned TargetSectionID = -1; + uint64_t TargetOffset = -1; + + if (TargetName.startswith(getImportSymbolPrefix())) { + TargetSectionID = SectionID; + TargetOffset = getDLLImportOffset(SectionID, Stubs, TargetName, true); + TargetName = StringRef(); + IsExtern = false; + } else if (!IsExtern) { + if (auto TargetSectionIDOrErr = + findOrEmitSection(Obj, *Section, Section->isText(), ObjSectionToID)) + TargetSectionID = *TargetSectionIDOrErr; + else + return TargetSectionIDOrErr.takeError(); + if (RelType != COFF::IMAGE_REL_ARM_SECTION) + TargetOffset = getSymbolOffset(*Symbol); + } + + if (IsExtern) { + RelocationEntry RE(SectionID, Offset, RelType, 0, -1, 0, 0, 0, false, 0); + addRelocationForSymbol(RE, TargetName); + } else { + + // We need to find out if the relocation is relative to a thumb function + // so that we include the ISA selection bit when resolve the relocation + bool IsTargetThumbFunc = isThumbFunc(Symbol, Obj, Section); + + switch (RelType) { + default: llvm_unreachable("unsupported relocation type"); + case COFF::IMAGE_REL_ARM_ABSOLUTE: + // This relocation is ignored. + break; + case COFF::IMAGE_REL_ARM_ADDR32: { + RelocationEntry RE = + RelocationEntry(SectionID, Offset, RelType, Addend, TargetSectionID, + TargetOffset, 0, 0, false, 0, IsTargetThumbFunc); + addRelocationForSection(RE, TargetSectionID); + break; + } + case COFF::IMAGE_REL_ARM_ADDR32NB: { + RelocationEntry RE = + RelocationEntry(SectionID, Offset, RelType, Addend, TargetSectionID, + TargetOffset, 0, 0, false, 0); + addRelocationForSection(RE, TargetSectionID); + break; + } + case COFF::IMAGE_REL_ARM_SECTION: { + RelocationEntry RE = + RelocationEntry(TargetSectionID, Offset, RelType, 0); + addRelocationForSection(RE, TargetSectionID); + break; + } + case COFF::IMAGE_REL_ARM_SECREL: { + RelocationEntry RE = + RelocationEntry(SectionID, Offset, RelType, TargetOffset + Addend); + addRelocationForSection(RE, TargetSectionID); + break; + } + case COFF::IMAGE_REL_ARM_MOV32T: { + RelocationEntry RE = + RelocationEntry(SectionID, Offset, RelType, Addend, TargetSectionID, + TargetOffset, 0, 0, false, 0, IsTargetThumbFunc); + addRelocationForSection(RE, TargetSectionID); + break; + } + case COFF::IMAGE_REL_ARM_BRANCH20T: + case COFF::IMAGE_REL_ARM_BRANCH24T: + case COFF::IMAGE_REL_ARM_BLX23T: { + RelocationEntry RE = RelocationEntry(SectionID, Offset, RelType, + TargetOffset + Addend, true, 0); + addRelocationForSection(RE, TargetSectionID); + break; + } + } + } + + return ++RelI; + } + + void resolveRelocation(const RelocationEntry &RE, uint64_t Value) override { + const auto Section = Sections[RE.SectionID]; + uint8_t *Target = Section.getAddressWithOffset(RE.Offset); + int ISASelectionBit = RE.IsTargetThumbFunc ? 1 : 0; + + switch (RE.RelType) { + default: llvm_unreachable("unsupported relocation type"); + case COFF::IMAGE_REL_ARM_ABSOLUTE: + // This relocation is ignored. + break; + case COFF::IMAGE_REL_ARM_ADDR32: { + // The target's 32-bit VA. + uint64_t Result = + RE.Sections.SectionA == static_cast<uint32_t>(-1) + ? Value + : Sections[RE.Sections.SectionA].getLoadAddressWithOffset(RE.Addend); + Result |= ISASelectionBit; + assert(Result <= UINT32_MAX && "relocation overflow"); + LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE.Offset + << " RelType: IMAGE_REL_ARM_ADDR32" + << " TargetSection: " << RE.Sections.SectionA + << " Value: " << format("0x%08" PRIx32, Result) + << '\n'); + writeBytesUnaligned(Result, Target, 4); + break; + } + case COFF::IMAGE_REL_ARM_ADDR32NB: { + // The target's 32-bit RVA. + // NOTE: use Section[0].getLoadAddress() as an approximation of ImageBase + uint64_t Result = Sections[RE.Sections.SectionA].getLoadAddress() - + Sections[0].getLoadAddress() + RE.Addend; + assert(Result <= UINT32_MAX && "relocation overflow"); + LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE.Offset + << " RelType: IMAGE_REL_ARM_ADDR32NB" + << " TargetSection: " << RE.Sections.SectionA + << " Value: " << format("0x%08" PRIx32, Result) + << '\n'); + Result |= ISASelectionBit; + writeBytesUnaligned(Result, Target, 4); + break; + } + case COFF::IMAGE_REL_ARM_SECTION: + // 16-bit section index of the section that contains the target. + assert(static_cast<uint32_t>(RE.SectionID) <= UINT16_MAX && + "relocation overflow"); + LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE.Offset + << " RelType: IMAGE_REL_ARM_SECTION Value: " + << RE.SectionID << '\n'); + writeBytesUnaligned(RE.SectionID, Target, 2); + break; + case COFF::IMAGE_REL_ARM_SECREL: + // 32-bit offset of the target from the beginning of its section. + assert(static_cast<uint64_t>(RE.Addend) <= UINT32_MAX && + "relocation overflow"); + LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE.Offset + << " RelType: IMAGE_REL_ARM_SECREL Value: " << RE.Addend + << '\n'); + writeBytesUnaligned(RE.Addend, Target, 2); + break; + case COFF::IMAGE_REL_ARM_MOV32T: { + // 32-bit VA of the target applied to a contiguous MOVW+MOVT pair. + uint64_t Result = + Sections[RE.Sections.SectionA].getLoadAddressWithOffset(RE.Addend); + assert(Result <= UINT32_MAX && "relocation overflow"); + LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE.Offset + << " RelType: IMAGE_REL_ARM_MOV32T" + << " TargetSection: " << RE.Sections.SectionA + << " Value: " << format("0x%08" PRIx32, Result) + << '\n'); + + // MOVW(T3): |11110|i|10|0|1|0|0|imm4|0|imm3|Rd|imm8| + // imm32 = zext imm4:i:imm3:imm8 + // MOVT(T1): |11110|i|10|1|1|0|0|imm4|0|imm3|Rd|imm8| + // imm16 = imm4:i:imm3:imm8 + + auto EncodeImmediate = [](uint8_t *Bytes, uint16_t Immediate) { + Bytes[0] |= ((Immediate & 0xf000) >> 12); + Bytes[1] |= ((Immediate & 0x0800) >> 11); + Bytes[2] |= ((Immediate & 0x00ff) >> 0); + Bytes[3] |= (((Immediate & 0x0700) >> 8) << 4); + }; + + EncodeImmediate(&Target[0], + (static_cast<uint32_t>(Result) >> 00) | ISASelectionBit); + EncodeImmediate(&Target[4], static_cast<uint32_t>(Result) >> 16); + break; + } + case COFF::IMAGE_REL_ARM_BRANCH20T: { + // The most significant 20-bits of the signed 21-bit relative displacement + uint64_t Value = + RE.Addend - (Sections[RE.SectionID].getLoadAddress() + RE.Offset) - 4; + assert(static_cast<int64_t>(RE.Addend) <= INT32_MAX && + "relocation overflow"); + assert(static_cast<int64_t>(RE.Addend) >= INT32_MIN && + "relocation underflow"); + LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE.Offset + << " RelType: IMAGE_REL_ARM_BRANCH20T" + << " Value: " << static_cast<int32_t>(Value) << '\n'); + static_cast<void>(Value); + llvm_unreachable("unimplemented relocation"); + break; + } + case COFF::IMAGE_REL_ARM_BRANCH24T: { + // The most significant 24-bits of the signed 25-bit relative displacement + uint64_t Value = + RE.Addend - (Sections[RE.SectionID].getLoadAddress() + RE.Offset) - 4; + assert(static_cast<int64_t>(RE.Addend) <= INT32_MAX && + "relocation overflow"); + assert(static_cast<int64_t>(RE.Addend) >= INT32_MIN && + "relocation underflow"); + LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE.Offset + << " RelType: IMAGE_REL_ARM_BRANCH24T" + << " Value: " << static_cast<int32_t>(Value) << '\n'); + static_cast<void>(Value); + llvm_unreachable("unimplemented relocation"); + break; + } + case COFF::IMAGE_REL_ARM_BLX23T: { + // The most significant 24-bits of the signed 25-bit relative displacement + uint64_t Value = + RE.Addend - (Sections[RE.SectionID].getLoadAddress() + RE.Offset) - 4; + assert(static_cast<int64_t>(RE.Addend) <= INT32_MAX && + "relocation overflow"); + assert(static_cast<int64_t>(RE.Addend) >= INT32_MIN && + "relocation underflow"); + LLVM_DEBUG(dbgs() << "\t\tOffset: " << RE.Offset + << " RelType: IMAGE_REL_ARM_BLX23T" + << " Value: " << static_cast<int32_t>(Value) << '\n'); + static_cast<void>(Value); + llvm_unreachable("unimplemented relocation"); + break; + } + } + } + + void registerEHFrames() override {} +}; + +} + +#endif diff --git a/contrib/libs/llvm12/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldCOFFX86_64.h b/contrib/libs/llvm12/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldCOFFX86_64.h index 5b7acf3c5f..9df3e2e3c3 100644 --- a/contrib/libs/llvm12/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldCOFFX86_64.h +++ b/contrib/libs/llvm12/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldCOFFX86_64.h @@ -1,315 +1,315 @@ -//===-- RuntimeDyldCOFFX86_64.h --- COFF/X86_64 specific code ---*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// COFF x86_x64 support for MC-JIT runtime dynamic linker. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDCOFF86_64_H -#define LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDCOFF86_64_H - -#include "../RuntimeDyldCOFF.h" -#include "llvm/BinaryFormat/COFF.h" -#include "llvm/Object/COFF.h" - -#define DEBUG_TYPE "dyld" - -namespace llvm { - -class RuntimeDyldCOFFX86_64 : public RuntimeDyldCOFF { - -private: - // When a module is loaded we save the SectionID of the unwind - // sections in a table until we receive a request to register all - // unregisteredEH frame sections with the memory manager. - SmallVector<SID, 2> UnregisteredEHFrameSections; - SmallVector<SID, 2> RegisteredEHFrameSections; - uint64_t ImageBase; - - // Fake an __ImageBase pointer by returning the section with the lowest adress - uint64_t getImageBase() { - if (!ImageBase) { - ImageBase = std::numeric_limits<uint64_t>::max(); - for (const SectionEntry &Section : Sections) - // The Sections list may contain sections that weren't loaded for - // whatever reason: they may be debug sections, and ProcessAllSections - // is false, or they may be sections that contain 0 bytes. If the - // section isn't loaded, the load address will be 0, and it should not - // be included in the ImageBase calculation. - if (Section.getLoadAddress() != 0) - ImageBase = std::min(ImageBase, Section.getLoadAddress()); - } - return ImageBase; - } - - void write32BitOffset(uint8_t *Target, int64_t Addend, uint64_t Delta) { - uint64_t Result = Addend + Delta; - assert(Result <= UINT32_MAX && "Relocation overflow"); - writeBytesUnaligned(Result, Target, 4); - } - -public: - RuntimeDyldCOFFX86_64(RuntimeDyld::MemoryManager &MM, - JITSymbolResolver &Resolver) - : RuntimeDyldCOFF(MM, Resolver, 8, COFF::IMAGE_REL_AMD64_ADDR64), - ImageBase(0) {} - - unsigned getStubAlignment() override { return 1; } - - // 2-byte jmp instruction + 32-bit relative address + 64-bit absolute jump - unsigned getMaxStubSize() const override { return 14; } - - // The target location for the relocation is described by RE.SectionID and - // RE.Offset. RE.SectionID can be used to find the SectionEntry. Each - // SectionEntry has three members describing its location. - // SectionEntry::Address is the address at which the section has been loaded - // into memory in the current (host) process. SectionEntry::LoadAddress is - // the address that the section will have in the target process. - // SectionEntry::ObjAddress is the address of the bits for this section in the - // original emitted object image (also in the current address space). - // - // Relocations will be applied as if the section were loaded at - // SectionEntry::LoadAddress, but they will be applied at an address based - // on SectionEntry::Address. SectionEntry::ObjAddress will be used to refer - // to Target memory contents if they are required for value calculations. - // - // The Value parameter here is the load address of the symbol for the - // relocation to be applied. For relocations which refer to symbols in the - // current object Value will be the LoadAddress of the section in which - // the symbol resides (RE.Addend provides additional information about the - // symbol location). For external symbols, Value will be the address of the - // symbol in the target address space. - void resolveRelocation(const RelocationEntry &RE, uint64_t Value) override { - const SectionEntry &Section = Sections[RE.SectionID]; - uint8_t *Target = Section.getAddressWithOffset(RE.Offset); - - switch (RE.RelType) { - - case COFF::IMAGE_REL_AMD64_REL32: - case COFF::IMAGE_REL_AMD64_REL32_1: - case COFF::IMAGE_REL_AMD64_REL32_2: - case COFF::IMAGE_REL_AMD64_REL32_3: - case COFF::IMAGE_REL_AMD64_REL32_4: - case COFF::IMAGE_REL_AMD64_REL32_5: { - uint64_t FinalAddress = Section.getLoadAddressWithOffset(RE.Offset); - // Delta is the distance from the start of the reloc to the end of the - // instruction with the reloc. - uint64_t Delta = 4 + (RE.RelType - COFF::IMAGE_REL_AMD64_REL32); - Value -= FinalAddress + Delta; - uint64_t Result = Value + RE.Addend; - assert(((int64_t)Result <= INT32_MAX) && "Relocation overflow"); - assert(((int64_t)Result >= INT32_MIN) && "Relocation underflow"); - writeBytesUnaligned(Result, Target, 4); - break; - } - - case COFF::IMAGE_REL_AMD64_ADDR32NB: { - // ADDR32NB requires an offset less than 2GB from 'ImageBase'. - // The MemoryManager can make sure this is always true by forcing the - // memory layout to be: CodeSection < ReadOnlySection < ReadWriteSection. - const uint64_t ImageBase = getImageBase(); +//===-- RuntimeDyldCOFFX86_64.h --- COFF/X86_64 specific code ---*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// COFF x86_x64 support for MC-JIT runtime dynamic linker. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDCOFF86_64_H +#define LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDCOFF86_64_H + +#include "../RuntimeDyldCOFF.h" +#include "llvm/BinaryFormat/COFF.h" +#include "llvm/Object/COFF.h" + +#define DEBUG_TYPE "dyld" + +namespace llvm { + +class RuntimeDyldCOFFX86_64 : public RuntimeDyldCOFF { + +private: + // When a module is loaded we save the SectionID of the unwind + // sections in a table until we receive a request to register all + // unregisteredEH frame sections with the memory manager. + SmallVector<SID, 2> UnregisteredEHFrameSections; + SmallVector<SID, 2> RegisteredEHFrameSections; + uint64_t ImageBase; + + // Fake an __ImageBase pointer by returning the section with the lowest adress + uint64_t getImageBase() { + if (!ImageBase) { + ImageBase = std::numeric_limits<uint64_t>::max(); + for (const SectionEntry &Section : Sections) + // The Sections list may contain sections that weren't loaded for + // whatever reason: they may be debug sections, and ProcessAllSections + // is false, or they may be sections that contain 0 bytes. If the + // section isn't loaded, the load address will be 0, and it should not + // be included in the ImageBase calculation. + if (Section.getLoadAddress() != 0) + ImageBase = std::min(ImageBase, Section.getLoadAddress()); + } + return ImageBase; + } + + void write32BitOffset(uint8_t *Target, int64_t Addend, uint64_t Delta) { + uint64_t Result = Addend + Delta; + assert(Result <= UINT32_MAX && "Relocation overflow"); + writeBytesUnaligned(Result, Target, 4); + } + +public: + RuntimeDyldCOFFX86_64(RuntimeDyld::MemoryManager &MM, + JITSymbolResolver &Resolver) + : RuntimeDyldCOFF(MM, Resolver, 8, COFF::IMAGE_REL_AMD64_ADDR64), + ImageBase(0) {} + + unsigned getStubAlignment() override { return 1; } + + // 2-byte jmp instruction + 32-bit relative address + 64-bit absolute jump + unsigned getMaxStubSize() const override { return 14; } + + // The target location for the relocation is described by RE.SectionID and + // RE.Offset. RE.SectionID can be used to find the SectionEntry. Each + // SectionEntry has three members describing its location. + // SectionEntry::Address is the address at which the section has been loaded + // into memory in the current (host) process. SectionEntry::LoadAddress is + // the address that the section will have in the target process. + // SectionEntry::ObjAddress is the address of the bits for this section in the + // original emitted object image (also in the current address space). + // + // Relocations will be applied as if the section were loaded at + // SectionEntry::LoadAddress, but they will be applied at an address based + // on SectionEntry::Address. SectionEntry::ObjAddress will be used to refer + // to Target memory contents if they are required for value calculations. + // + // The Value parameter here is the load address of the symbol for the + // relocation to be applied. For relocations which refer to symbols in the + // current object Value will be the LoadAddress of the section in which + // the symbol resides (RE.Addend provides additional information about the + // symbol location). For external symbols, Value will be the address of the + // symbol in the target address space. + void resolveRelocation(const RelocationEntry &RE, uint64_t Value) override { + const SectionEntry &Section = Sections[RE.SectionID]; + uint8_t *Target = Section.getAddressWithOffset(RE.Offset); + + switch (RE.RelType) { + + case COFF::IMAGE_REL_AMD64_REL32: + case COFF::IMAGE_REL_AMD64_REL32_1: + case COFF::IMAGE_REL_AMD64_REL32_2: + case COFF::IMAGE_REL_AMD64_REL32_3: + case COFF::IMAGE_REL_AMD64_REL32_4: + case COFF::IMAGE_REL_AMD64_REL32_5: { + uint64_t FinalAddress = Section.getLoadAddressWithOffset(RE.Offset); + // Delta is the distance from the start of the reloc to the end of the + // instruction with the reloc. + uint64_t Delta = 4 + (RE.RelType - COFF::IMAGE_REL_AMD64_REL32); + Value -= FinalAddress + Delta; + uint64_t Result = Value + RE.Addend; + assert(((int64_t)Result <= INT32_MAX) && "Relocation overflow"); + assert(((int64_t)Result >= INT32_MIN) && "Relocation underflow"); + writeBytesUnaligned(Result, Target, 4); + break; + } + + case COFF::IMAGE_REL_AMD64_ADDR32NB: { + // ADDR32NB requires an offset less than 2GB from 'ImageBase'. + // The MemoryManager can make sure this is always true by forcing the + // memory layout to be: CodeSection < ReadOnlySection < ReadWriteSection. + const uint64_t ImageBase = getImageBase(); if (Value < ImageBase || ((Value - ImageBase) > UINT32_MAX)) report_fatal_error("IMAGE_REL_AMD64_ADDR32NB relocation requires an " "ordered section layout"); else { - write32BitOffset(Target, RE.Addend, Value - ImageBase); - } - break; - } - - case COFF::IMAGE_REL_AMD64_ADDR64: { - writeBytesUnaligned(Value + RE.Addend, Target, 8); - break; - } - - case COFF::IMAGE_REL_AMD64_SECREL: { - assert(static_cast<int64_t>(RE.Addend) <= INT32_MAX && "Relocation overflow"); - assert(static_cast<int64_t>(RE.Addend) >= INT32_MIN && "Relocation underflow"); - writeBytesUnaligned(RE.Addend, Target, 4); - break; - } - - default: - llvm_unreachable("Relocation type not implemented yet!"); - break; - } - } - - std::tuple<uint64_t, uint64_t, uint64_t> - generateRelocationStub(unsigned SectionID, StringRef TargetName, - uint64_t Offset, uint64_t RelType, uint64_t Addend, - StubMap &Stubs) { - uintptr_t StubOffset; - SectionEntry &Section = Sections[SectionID]; - - RelocationValueRef OriginalRelValueRef; - OriginalRelValueRef.SectionID = SectionID; - OriginalRelValueRef.Offset = Offset; - OriginalRelValueRef.Addend = Addend; - OriginalRelValueRef.SymbolName = TargetName.data(); - - auto Stub = Stubs.find(OriginalRelValueRef); - if (Stub == Stubs.end()) { - LLVM_DEBUG(dbgs() << " Create a new stub function for " - << TargetName.data() << "\n"); - - StubOffset = Section.getStubOffset(); - Stubs[OriginalRelValueRef] = StubOffset; - createStubFunction(Section.getAddressWithOffset(StubOffset)); - Section.advanceStubOffset(getMaxStubSize()); - } else { - LLVM_DEBUG(dbgs() << " Stub function found for " << TargetName.data() - << "\n"); - StubOffset = Stub->second; - } - - // FIXME: If RelType == COFF::IMAGE_REL_AMD64_ADDR32NB we should be able - // to ignore the __ImageBase requirement and just forward to the stub - // directly as an offset of this section: - // write32BitOffset(Section.getAddressWithOffset(Offset), 0, StubOffset); - // .xdata exception handler's aren't having this though. - - // Resolve original relocation to stub function. - const RelocationEntry RE(SectionID, Offset, RelType, Addend); - resolveRelocation(RE, Section.getLoadAddressWithOffset(StubOffset)); - - // adjust relocation info so resolution writes to the stub function - Addend = 0; - Offset = StubOffset + 6; - RelType = COFF::IMAGE_REL_AMD64_ADDR64; - - return std::make_tuple(Offset, RelType, Addend); - } - - Expected<object::relocation_iterator> - processRelocationRef(unsigned SectionID, - object::relocation_iterator RelI, - const object::ObjectFile &Obj, - ObjSectionToIDMap &ObjSectionToID, - StubMap &Stubs) override { - // If possible, find the symbol referred to in the relocation, - // and the section that contains it. - object::symbol_iterator Symbol = RelI->getSymbol(); - if (Symbol == Obj.symbol_end()) - report_fatal_error("Unknown symbol in relocation"); - auto SectionOrError = Symbol->getSection(); - if (!SectionOrError) - return SectionOrError.takeError(); - object::section_iterator SecI = *SectionOrError; - // If there is no section, this must be an external reference. - bool IsExtern = SecI == Obj.section_end(); - - // Determine the Addend used to adjust the relocation value. - uint64_t RelType = RelI->getType(); - uint64_t Offset = RelI->getOffset(); - uint64_t Addend = 0; - SectionEntry &Section = Sections[SectionID]; - uintptr_t ObjTarget = Section.getObjAddress() + Offset; - - Expected<StringRef> TargetNameOrErr = Symbol->getName(); - if (!TargetNameOrErr) - return TargetNameOrErr.takeError(); - - StringRef TargetName = *TargetNameOrErr; - unsigned TargetSectionID = 0; - uint64_t TargetOffset = 0; - - if (TargetName.startswith(getImportSymbolPrefix())) { - assert(IsExtern && "DLLImport not marked extern?"); - TargetSectionID = SectionID; - TargetOffset = getDLLImportOffset(SectionID, Stubs, TargetName); - TargetName = StringRef(); - IsExtern = false; - } else if (!IsExtern) { - if (auto TargetSectionIDOrErr = - findOrEmitSection(Obj, *SecI, SecI->isText(), ObjSectionToID)) - TargetSectionID = *TargetSectionIDOrErr; - else - return TargetSectionIDOrErr.takeError(); - TargetOffset = getSymbolOffset(*Symbol); - } - - switch (RelType) { - - case COFF::IMAGE_REL_AMD64_REL32: - case COFF::IMAGE_REL_AMD64_REL32_1: - case COFF::IMAGE_REL_AMD64_REL32_2: - case COFF::IMAGE_REL_AMD64_REL32_3: - case COFF::IMAGE_REL_AMD64_REL32_4: - case COFF::IMAGE_REL_AMD64_REL32_5: - case COFF::IMAGE_REL_AMD64_ADDR32NB: { - uint8_t *Displacement = (uint8_t *)ObjTarget; - Addend = readBytesUnaligned(Displacement, 4); - - if (IsExtern) - std::tie(Offset, RelType, Addend) = generateRelocationStub( - SectionID, TargetName, Offset, RelType, Addend, Stubs); - - break; - } - - case COFF::IMAGE_REL_AMD64_ADDR64: { - uint8_t *Displacement = (uint8_t *)ObjTarget; - Addend = readBytesUnaligned(Displacement, 8); - break; - } - - default: - break; - } - - LLVM_DEBUG(dbgs() << "\t\tIn Section " << SectionID << " Offset " << Offset - << " RelType: " << RelType << " TargetName: " - << TargetName << " Addend " << Addend << "\n"); - - if (IsExtern) { - RelocationEntry RE(SectionID, Offset, RelType, Addend); - addRelocationForSymbol(RE, TargetName); - } else { - RelocationEntry RE(SectionID, Offset, RelType, TargetOffset + Addend); - addRelocationForSection(RE, TargetSectionID); - } - - return ++RelI; - } - - void registerEHFrames() override { - for (auto const &EHFrameSID : UnregisteredEHFrameSections) { - uint8_t *EHFrameAddr = Sections[EHFrameSID].getAddress(); - uint64_t EHFrameLoadAddr = Sections[EHFrameSID].getLoadAddress(); - size_t EHFrameSize = Sections[EHFrameSID].getSize(); - MemMgr.registerEHFrames(EHFrameAddr, EHFrameLoadAddr, EHFrameSize); - RegisteredEHFrameSections.push_back(EHFrameSID); - } - UnregisteredEHFrameSections.clear(); - } - - Error finalizeLoad(const object::ObjectFile &Obj, - ObjSectionToIDMap &SectionMap) override { - // Look for and record the EH frame section IDs. - for (const auto &SectionPair : SectionMap) { - const object::SectionRef &Section = SectionPair.first; - Expected<StringRef> NameOrErr = Section.getName(); - if (!NameOrErr) - return NameOrErr.takeError(); - - // Note unwind info is stored in .pdata but often points to .xdata - // with an IMAGE_REL_AMD64_ADDR32NB relocation. Using a memory manager - // that keeps sections ordered in relation to __ImageBase is necessary. - if ((*NameOrErr) == ".pdata") - UnregisteredEHFrameSections.push_back(SectionPair.second); - } - return Error::success(); - } -}; - -} // end namespace llvm - -#undef DEBUG_TYPE - -#endif + write32BitOffset(Target, RE.Addend, Value - ImageBase); + } + break; + } + + case COFF::IMAGE_REL_AMD64_ADDR64: { + writeBytesUnaligned(Value + RE.Addend, Target, 8); + break; + } + + case COFF::IMAGE_REL_AMD64_SECREL: { + assert(static_cast<int64_t>(RE.Addend) <= INT32_MAX && "Relocation overflow"); + assert(static_cast<int64_t>(RE.Addend) >= INT32_MIN && "Relocation underflow"); + writeBytesUnaligned(RE.Addend, Target, 4); + break; + } + + default: + llvm_unreachable("Relocation type not implemented yet!"); + break; + } + } + + std::tuple<uint64_t, uint64_t, uint64_t> + generateRelocationStub(unsigned SectionID, StringRef TargetName, + uint64_t Offset, uint64_t RelType, uint64_t Addend, + StubMap &Stubs) { + uintptr_t StubOffset; + SectionEntry &Section = Sections[SectionID]; + + RelocationValueRef OriginalRelValueRef; + OriginalRelValueRef.SectionID = SectionID; + OriginalRelValueRef.Offset = Offset; + OriginalRelValueRef.Addend = Addend; + OriginalRelValueRef.SymbolName = TargetName.data(); + + auto Stub = Stubs.find(OriginalRelValueRef); + if (Stub == Stubs.end()) { + LLVM_DEBUG(dbgs() << " Create a new stub function for " + << TargetName.data() << "\n"); + + StubOffset = Section.getStubOffset(); + Stubs[OriginalRelValueRef] = StubOffset; + createStubFunction(Section.getAddressWithOffset(StubOffset)); + Section.advanceStubOffset(getMaxStubSize()); + } else { + LLVM_DEBUG(dbgs() << " Stub function found for " << TargetName.data() + << "\n"); + StubOffset = Stub->second; + } + + // FIXME: If RelType == COFF::IMAGE_REL_AMD64_ADDR32NB we should be able + // to ignore the __ImageBase requirement and just forward to the stub + // directly as an offset of this section: + // write32BitOffset(Section.getAddressWithOffset(Offset), 0, StubOffset); + // .xdata exception handler's aren't having this though. + + // Resolve original relocation to stub function. + const RelocationEntry RE(SectionID, Offset, RelType, Addend); + resolveRelocation(RE, Section.getLoadAddressWithOffset(StubOffset)); + + // adjust relocation info so resolution writes to the stub function + Addend = 0; + Offset = StubOffset + 6; + RelType = COFF::IMAGE_REL_AMD64_ADDR64; + + return std::make_tuple(Offset, RelType, Addend); + } + + Expected<object::relocation_iterator> + processRelocationRef(unsigned SectionID, + object::relocation_iterator RelI, + const object::ObjectFile &Obj, + ObjSectionToIDMap &ObjSectionToID, + StubMap &Stubs) override { + // If possible, find the symbol referred to in the relocation, + // and the section that contains it. + object::symbol_iterator Symbol = RelI->getSymbol(); + if (Symbol == Obj.symbol_end()) + report_fatal_error("Unknown symbol in relocation"); + auto SectionOrError = Symbol->getSection(); + if (!SectionOrError) + return SectionOrError.takeError(); + object::section_iterator SecI = *SectionOrError; + // If there is no section, this must be an external reference. + bool IsExtern = SecI == Obj.section_end(); + + // Determine the Addend used to adjust the relocation value. + uint64_t RelType = RelI->getType(); + uint64_t Offset = RelI->getOffset(); + uint64_t Addend = 0; + SectionEntry &Section = Sections[SectionID]; + uintptr_t ObjTarget = Section.getObjAddress() + Offset; + + Expected<StringRef> TargetNameOrErr = Symbol->getName(); + if (!TargetNameOrErr) + return TargetNameOrErr.takeError(); + + StringRef TargetName = *TargetNameOrErr; + unsigned TargetSectionID = 0; + uint64_t TargetOffset = 0; + + if (TargetName.startswith(getImportSymbolPrefix())) { + assert(IsExtern && "DLLImport not marked extern?"); + TargetSectionID = SectionID; + TargetOffset = getDLLImportOffset(SectionID, Stubs, TargetName); + TargetName = StringRef(); + IsExtern = false; + } else if (!IsExtern) { + if (auto TargetSectionIDOrErr = + findOrEmitSection(Obj, *SecI, SecI->isText(), ObjSectionToID)) + TargetSectionID = *TargetSectionIDOrErr; + else + return TargetSectionIDOrErr.takeError(); + TargetOffset = getSymbolOffset(*Symbol); + } + + switch (RelType) { + + case COFF::IMAGE_REL_AMD64_REL32: + case COFF::IMAGE_REL_AMD64_REL32_1: + case COFF::IMAGE_REL_AMD64_REL32_2: + case COFF::IMAGE_REL_AMD64_REL32_3: + case COFF::IMAGE_REL_AMD64_REL32_4: + case COFF::IMAGE_REL_AMD64_REL32_5: + case COFF::IMAGE_REL_AMD64_ADDR32NB: { + uint8_t *Displacement = (uint8_t *)ObjTarget; + Addend = readBytesUnaligned(Displacement, 4); + + if (IsExtern) + std::tie(Offset, RelType, Addend) = generateRelocationStub( + SectionID, TargetName, Offset, RelType, Addend, Stubs); + + break; + } + + case COFF::IMAGE_REL_AMD64_ADDR64: { + uint8_t *Displacement = (uint8_t *)ObjTarget; + Addend = readBytesUnaligned(Displacement, 8); + break; + } + + default: + break; + } + + LLVM_DEBUG(dbgs() << "\t\tIn Section " << SectionID << " Offset " << Offset + << " RelType: " << RelType << " TargetName: " + << TargetName << " Addend " << Addend << "\n"); + + if (IsExtern) { + RelocationEntry RE(SectionID, Offset, RelType, Addend); + addRelocationForSymbol(RE, TargetName); + } else { + RelocationEntry RE(SectionID, Offset, RelType, TargetOffset + Addend); + addRelocationForSection(RE, TargetSectionID); + } + + return ++RelI; + } + + void registerEHFrames() override { + for (auto const &EHFrameSID : UnregisteredEHFrameSections) { + uint8_t *EHFrameAddr = Sections[EHFrameSID].getAddress(); + uint64_t EHFrameLoadAddr = Sections[EHFrameSID].getLoadAddress(); + size_t EHFrameSize = Sections[EHFrameSID].getSize(); + MemMgr.registerEHFrames(EHFrameAddr, EHFrameLoadAddr, EHFrameSize); + RegisteredEHFrameSections.push_back(EHFrameSID); + } + UnregisteredEHFrameSections.clear(); + } + + Error finalizeLoad(const object::ObjectFile &Obj, + ObjSectionToIDMap &SectionMap) override { + // Look for and record the EH frame section IDs. + for (const auto &SectionPair : SectionMap) { + const object::SectionRef &Section = SectionPair.first; + Expected<StringRef> NameOrErr = Section.getName(); + if (!NameOrErr) + return NameOrErr.takeError(); + + // Note unwind info is stored in .pdata but often points to .xdata + // with an IMAGE_REL_AMD64_ADDR32NB relocation. Using a memory manager + // that keeps sections ordered in relation to __ImageBase is necessary. + if ((*NameOrErr) == ".pdata") + UnregisteredEHFrameSections.push_back(SectionPair.second); + } + return Error::success(); + } +}; + +} // end namespace llvm + +#undef DEBUG_TYPE + +#endif diff --git a/contrib/libs/llvm12/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldELFMips.cpp b/contrib/libs/llvm12/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldELFMips.cpp index 3819195acd..17cbe612fb 100644 --- a/contrib/libs/llvm12/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldELFMips.cpp +++ b/contrib/libs/llvm12/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldELFMips.cpp @@ -1,320 +1,320 @@ -//===-- RuntimeDyldELFMips.cpp ---- ELF/Mips specific code. -----*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "RuntimeDyldELFMips.h" -#include "llvm/BinaryFormat/ELF.h" - -#define DEBUG_TYPE "dyld" - -void RuntimeDyldELFMips::resolveRelocation(const RelocationEntry &RE, - uint64_t Value) { - const SectionEntry &Section = Sections[RE.SectionID]; - if (IsMipsO32ABI) - resolveMIPSO32Relocation(Section, RE.Offset, Value, RE.RelType, RE.Addend); - else if (IsMipsN32ABI) { - resolveMIPSN32Relocation(Section, RE.Offset, Value, RE.RelType, RE.Addend, - RE.SymOffset, RE.SectionID); - } else if (IsMipsN64ABI) - resolveMIPSN64Relocation(Section, RE.Offset, Value, RE.RelType, RE.Addend, - RE.SymOffset, RE.SectionID); - else - llvm_unreachable("Mips ABI not handled"); -} - -uint64_t RuntimeDyldELFMips::evaluateRelocation(const RelocationEntry &RE, - uint64_t Value, - uint64_t Addend) { - if (IsMipsN32ABI) { - const SectionEntry &Section = Sections[RE.SectionID]; - Value = evaluateMIPS64Relocation(Section, RE.Offset, Value, RE.RelType, - Addend, RE.SymOffset, RE.SectionID); - return Value; - } - llvm_unreachable("Not reachable"); -} - -void RuntimeDyldELFMips::applyRelocation(const RelocationEntry &RE, - uint64_t Value) { - if (IsMipsN32ABI) { - const SectionEntry &Section = Sections[RE.SectionID]; - applyMIPSRelocation(Section.getAddressWithOffset(RE.Offset), Value, - RE.RelType); - return; - } - llvm_unreachable("Not reachable"); -} - -int64_t -RuntimeDyldELFMips::evaluateMIPS32Relocation(const SectionEntry &Section, - uint64_t Offset, uint64_t Value, - uint32_t Type) { - - LLVM_DEBUG(dbgs() << "evaluateMIPS32Relocation, LocalAddress: 0x" - << format("%llx", Section.getAddressWithOffset(Offset)) - << " FinalAddress: 0x" - << format("%llx", Section.getLoadAddressWithOffset(Offset)) - << " Value: 0x" << format("%llx", Value) << " Type: 0x" - << format("%x", Type) << "\n"); - - switch (Type) { - default: - llvm_unreachable("Unknown relocation type!"); - return Value; - case ELF::R_MIPS_32: - return Value; - case ELF::R_MIPS_26: - return Value >> 2; - case ELF::R_MIPS_HI16: - // Get the higher 16-bits. Also add 1 if bit 15 is 1. - return (Value + 0x8000) >> 16; - case ELF::R_MIPS_LO16: - return Value; - case ELF::R_MIPS_PC32: { - uint32_t FinalAddress = Section.getLoadAddressWithOffset(Offset); - return Value - FinalAddress; - } - case ELF::R_MIPS_PC16: { - uint32_t FinalAddress = Section.getLoadAddressWithOffset(Offset); - return (Value - FinalAddress) >> 2; - } - case ELF::R_MIPS_PC19_S2: { - uint32_t FinalAddress = Section.getLoadAddressWithOffset(Offset); - return (Value - (FinalAddress & ~0x3)) >> 2; - } - case ELF::R_MIPS_PC21_S2: { - uint32_t FinalAddress = Section.getLoadAddressWithOffset(Offset); - return (Value - FinalAddress) >> 2; - } - case ELF::R_MIPS_PC26_S2: { - uint32_t FinalAddress = Section.getLoadAddressWithOffset(Offset); - return (Value - FinalAddress) >> 2; - } - case ELF::R_MIPS_PCHI16: { - uint32_t FinalAddress = Section.getLoadAddressWithOffset(Offset); - return (Value - FinalAddress + 0x8000) >> 16; - } - case ELF::R_MIPS_PCLO16: { - uint32_t FinalAddress = Section.getLoadAddressWithOffset(Offset); - return Value - FinalAddress; - } - } -} - -int64_t RuntimeDyldELFMips::evaluateMIPS64Relocation( - const SectionEntry &Section, uint64_t Offset, uint64_t Value, uint32_t Type, - int64_t Addend, uint64_t SymOffset, SID SectionID) { - - LLVM_DEBUG(dbgs() << "evaluateMIPS64Relocation, LocalAddress: 0x" - << format("%llx", Section.getAddressWithOffset(Offset)) - << " FinalAddress: 0x" - << format("%llx", Section.getLoadAddressWithOffset(Offset)) - << " Value: 0x" << format("%llx", Value) << " Type: 0x" - << format("%x", Type) << " Addend: 0x" - << format("%llx", Addend) - << " Offset: " << format("%llx" PRIx64, Offset) - << " SID: " << format("%d", SectionID) - << " SymOffset: " << format("%x", SymOffset) << "\n"); - - switch (Type) { - default: - llvm_unreachable("Not implemented relocation type!"); - break; - case ELF::R_MIPS_JALR: - case ELF::R_MIPS_NONE: - break; - case ELF::R_MIPS_32: - case ELF::R_MIPS_64: - return Value + Addend; - case ELF::R_MIPS_26: - return ((Value + Addend) >> 2) & 0x3ffffff; - case ELF::R_MIPS_GPREL16: { - uint64_t GOTAddr = getSectionLoadAddress(SectionToGOTMap[SectionID]); - return Value + Addend - (GOTAddr + 0x7ff0); - } - case ELF::R_MIPS_SUB: - return Value - Addend; - case ELF::R_MIPS_HI16: - // Get the higher 16-bits. Also add 1 if bit 15 is 1. - return ((Value + Addend + 0x8000) >> 16) & 0xffff; - case ELF::R_MIPS_LO16: - return (Value + Addend) & 0xffff; - case ELF::R_MIPS_HIGHER: - return ((Value + Addend + 0x80008000) >> 32) & 0xffff; - case ELF::R_MIPS_HIGHEST: - return ((Value + Addend + 0x800080008000) >> 48) & 0xffff; - case ELF::R_MIPS_CALL16: - case ELF::R_MIPS_GOT_DISP: - case ELF::R_MIPS_GOT_PAGE: { - uint8_t *LocalGOTAddr = - getSectionAddress(SectionToGOTMap[SectionID]) + SymOffset; - uint64_t GOTEntry = readBytesUnaligned(LocalGOTAddr, getGOTEntrySize()); - - Value += Addend; - if (Type == ELF::R_MIPS_GOT_PAGE) - Value = (Value + 0x8000) & ~0xffff; - - if (GOTEntry) - assert(GOTEntry == Value && - "GOT entry has two different addresses."); - else - writeBytesUnaligned(Value, LocalGOTAddr, getGOTEntrySize()); - - return (SymOffset - 0x7ff0) & 0xffff; - } - case ELF::R_MIPS_GOT_OFST: { - int64_t page = (Value + Addend + 0x8000) & ~0xffff; - return (Value + Addend - page) & 0xffff; - } - case ELF::R_MIPS_GPREL32: { - uint64_t GOTAddr = getSectionLoadAddress(SectionToGOTMap[SectionID]); - return Value + Addend - (GOTAddr + 0x7ff0); - } - case ELF::R_MIPS_PC16: { - uint64_t FinalAddress = Section.getLoadAddressWithOffset(Offset); - return ((Value + Addend - FinalAddress) >> 2) & 0xffff; - } - case ELF::R_MIPS_PC32: { - uint64_t FinalAddress = Section.getLoadAddressWithOffset(Offset); - return Value + Addend - FinalAddress; - } - case ELF::R_MIPS_PC18_S3: { - uint64_t FinalAddress = Section.getLoadAddressWithOffset(Offset); - return ((Value + Addend - (FinalAddress & ~0x7)) >> 3) & 0x3ffff; - } - case ELF::R_MIPS_PC19_S2: { - uint64_t FinalAddress = Section.getLoadAddressWithOffset(Offset); - return ((Value + Addend - (FinalAddress & ~0x3)) >> 2) & 0x7ffff; - } - case ELF::R_MIPS_PC21_S2: { - uint64_t FinalAddress = Section.getLoadAddressWithOffset(Offset); - return ((Value + Addend - FinalAddress) >> 2) & 0x1fffff; - } - case ELF::R_MIPS_PC26_S2: { - uint64_t FinalAddress = Section.getLoadAddressWithOffset(Offset); - return ((Value + Addend - FinalAddress) >> 2) & 0x3ffffff; - } - case ELF::R_MIPS_PCHI16: { - uint64_t FinalAddress = Section.getLoadAddressWithOffset(Offset); - return ((Value + Addend - FinalAddress + 0x8000) >> 16) & 0xffff; - } - case ELF::R_MIPS_PCLO16: { - uint64_t FinalAddress = Section.getLoadAddressWithOffset(Offset); - return (Value + Addend - FinalAddress) & 0xffff; - } - } - return 0; -} - -void RuntimeDyldELFMips::applyMIPSRelocation(uint8_t *TargetPtr, int64_t Value, - uint32_t Type) { - uint32_t Insn = readBytesUnaligned(TargetPtr, 4); - - switch (Type) { - default: - llvm_unreachable("Unknown relocation type!"); - break; - case ELF::R_MIPS_GPREL16: - case ELF::R_MIPS_HI16: - case ELF::R_MIPS_LO16: - case ELF::R_MIPS_HIGHER: - case ELF::R_MIPS_HIGHEST: - case ELF::R_MIPS_PC16: - case ELF::R_MIPS_PCHI16: - case ELF::R_MIPS_PCLO16: - case ELF::R_MIPS_CALL16: - case ELF::R_MIPS_GOT_DISP: - case ELF::R_MIPS_GOT_PAGE: - case ELF::R_MIPS_GOT_OFST: - Insn = (Insn & 0xffff0000) | (Value & 0x0000ffff); - writeBytesUnaligned(Insn, TargetPtr, 4); - break; - case ELF::R_MIPS_PC18_S3: - Insn = (Insn & 0xfffc0000) | (Value & 0x0003ffff); - writeBytesUnaligned(Insn, TargetPtr, 4); - break; - case ELF::R_MIPS_PC19_S2: - Insn = (Insn & 0xfff80000) | (Value & 0x0007ffff); - writeBytesUnaligned(Insn, TargetPtr, 4); - break; - case ELF::R_MIPS_PC21_S2: - Insn = (Insn & 0xffe00000) | (Value & 0x001fffff); - writeBytesUnaligned(Insn, TargetPtr, 4); - break; - case ELF::R_MIPS_26: - case ELF::R_MIPS_PC26_S2: - Insn = (Insn & 0xfc000000) | (Value & 0x03ffffff); - writeBytesUnaligned(Insn, TargetPtr, 4); - break; - case ELF::R_MIPS_32: - case ELF::R_MIPS_GPREL32: - case ELF::R_MIPS_PC32: - writeBytesUnaligned(Value & 0xffffffff, TargetPtr, 4); - break; - case ELF::R_MIPS_64: - case ELF::R_MIPS_SUB: - writeBytesUnaligned(Value, TargetPtr, 8); - break; - } -} - -void RuntimeDyldELFMips::resolveMIPSN32Relocation( - const SectionEntry &Section, uint64_t Offset, uint64_t Value, uint32_t Type, - int64_t Addend, uint64_t SymOffset, SID SectionID) { - int64_t CalculatedValue = evaluateMIPS64Relocation( - Section, Offset, Value, Type, Addend, SymOffset, SectionID); - applyMIPSRelocation(Section.getAddressWithOffset(Offset), CalculatedValue, - Type); -} - -void RuntimeDyldELFMips::resolveMIPSN64Relocation( - const SectionEntry &Section, uint64_t Offset, uint64_t Value, uint32_t Type, - int64_t Addend, uint64_t SymOffset, SID SectionID) { - uint32_t r_type = Type & 0xff; - uint32_t r_type2 = (Type >> 8) & 0xff; - uint32_t r_type3 = (Type >> 16) & 0xff; - - // RelType is used to keep information for which relocation type we are - // applying relocation. - uint32_t RelType = r_type; - int64_t CalculatedValue = evaluateMIPS64Relocation(Section, Offset, Value, - RelType, Addend, - SymOffset, SectionID); - if (r_type2 != ELF::R_MIPS_NONE) { - RelType = r_type2; - CalculatedValue = evaluateMIPS64Relocation(Section, Offset, 0, RelType, - CalculatedValue, SymOffset, - SectionID); - } - if (r_type3 != ELF::R_MIPS_NONE) { - RelType = r_type3; - CalculatedValue = evaluateMIPS64Relocation(Section, Offset, 0, RelType, - CalculatedValue, SymOffset, - SectionID); - } - applyMIPSRelocation(Section.getAddressWithOffset(Offset), CalculatedValue, - RelType); -} - -void RuntimeDyldELFMips::resolveMIPSO32Relocation(const SectionEntry &Section, - uint64_t Offset, - uint32_t Value, uint32_t Type, - int32_t Addend) { - uint8_t *TargetPtr = Section.getAddressWithOffset(Offset); - Value += Addend; - - LLVM_DEBUG(dbgs() << "resolveMIPSO32Relocation, LocalAddress: " - << Section.getAddressWithOffset(Offset) << " FinalAddress: " - << format("%p", Section.getLoadAddressWithOffset(Offset)) - << " Value: " << format("%x", Value) << " Type: " - << format("%x", Type) << " Addend: " << format("%x", Addend) - << " SymOffset: " << format("%x", Offset) << "\n"); - - Value = evaluateMIPS32Relocation(Section, Offset, Value, Type); - - applyMIPSRelocation(TargetPtr, Value, Type); -} +//===-- RuntimeDyldELFMips.cpp ---- ELF/Mips specific code. -----*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "RuntimeDyldELFMips.h" +#include "llvm/BinaryFormat/ELF.h" + +#define DEBUG_TYPE "dyld" + +void RuntimeDyldELFMips::resolveRelocation(const RelocationEntry &RE, + uint64_t Value) { + const SectionEntry &Section = Sections[RE.SectionID]; + if (IsMipsO32ABI) + resolveMIPSO32Relocation(Section, RE.Offset, Value, RE.RelType, RE.Addend); + else if (IsMipsN32ABI) { + resolveMIPSN32Relocation(Section, RE.Offset, Value, RE.RelType, RE.Addend, + RE.SymOffset, RE.SectionID); + } else if (IsMipsN64ABI) + resolveMIPSN64Relocation(Section, RE.Offset, Value, RE.RelType, RE.Addend, + RE.SymOffset, RE.SectionID); + else + llvm_unreachable("Mips ABI not handled"); +} + +uint64_t RuntimeDyldELFMips::evaluateRelocation(const RelocationEntry &RE, + uint64_t Value, + uint64_t Addend) { + if (IsMipsN32ABI) { + const SectionEntry &Section = Sections[RE.SectionID]; + Value = evaluateMIPS64Relocation(Section, RE.Offset, Value, RE.RelType, + Addend, RE.SymOffset, RE.SectionID); + return Value; + } + llvm_unreachable("Not reachable"); +} + +void RuntimeDyldELFMips::applyRelocation(const RelocationEntry &RE, + uint64_t Value) { + if (IsMipsN32ABI) { + const SectionEntry &Section = Sections[RE.SectionID]; + applyMIPSRelocation(Section.getAddressWithOffset(RE.Offset), Value, + RE.RelType); + return; + } + llvm_unreachable("Not reachable"); +} + +int64_t +RuntimeDyldELFMips::evaluateMIPS32Relocation(const SectionEntry &Section, + uint64_t Offset, uint64_t Value, + uint32_t Type) { + + LLVM_DEBUG(dbgs() << "evaluateMIPS32Relocation, LocalAddress: 0x" + << format("%llx", Section.getAddressWithOffset(Offset)) + << " FinalAddress: 0x" + << format("%llx", Section.getLoadAddressWithOffset(Offset)) + << " Value: 0x" << format("%llx", Value) << " Type: 0x" + << format("%x", Type) << "\n"); + + switch (Type) { + default: + llvm_unreachable("Unknown relocation type!"); + return Value; + case ELF::R_MIPS_32: + return Value; + case ELF::R_MIPS_26: + return Value >> 2; + case ELF::R_MIPS_HI16: + // Get the higher 16-bits. Also add 1 if bit 15 is 1. + return (Value + 0x8000) >> 16; + case ELF::R_MIPS_LO16: + return Value; + case ELF::R_MIPS_PC32: { + uint32_t FinalAddress = Section.getLoadAddressWithOffset(Offset); + return Value - FinalAddress; + } + case ELF::R_MIPS_PC16: { + uint32_t FinalAddress = Section.getLoadAddressWithOffset(Offset); + return (Value - FinalAddress) >> 2; + } + case ELF::R_MIPS_PC19_S2: { + uint32_t FinalAddress = Section.getLoadAddressWithOffset(Offset); + return (Value - (FinalAddress & ~0x3)) >> 2; + } + case ELF::R_MIPS_PC21_S2: { + uint32_t FinalAddress = Section.getLoadAddressWithOffset(Offset); + return (Value - FinalAddress) >> 2; + } + case ELF::R_MIPS_PC26_S2: { + uint32_t FinalAddress = Section.getLoadAddressWithOffset(Offset); + return (Value - FinalAddress) >> 2; + } + case ELF::R_MIPS_PCHI16: { + uint32_t FinalAddress = Section.getLoadAddressWithOffset(Offset); + return (Value - FinalAddress + 0x8000) >> 16; + } + case ELF::R_MIPS_PCLO16: { + uint32_t FinalAddress = Section.getLoadAddressWithOffset(Offset); + return Value - FinalAddress; + } + } +} + +int64_t RuntimeDyldELFMips::evaluateMIPS64Relocation( + const SectionEntry &Section, uint64_t Offset, uint64_t Value, uint32_t Type, + int64_t Addend, uint64_t SymOffset, SID SectionID) { + + LLVM_DEBUG(dbgs() << "evaluateMIPS64Relocation, LocalAddress: 0x" + << format("%llx", Section.getAddressWithOffset(Offset)) + << " FinalAddress: 0x" + << format("%llx", Section.getLoadAddressWithOffset(Offset)) + << " Value: 0x" << format("%llx", Value) << " Type: 0x" + << format("%x", Type) << " Addend: 0x" + << format("%llx", Addend) + << " Offset: " << format("%llx" PRIx64, Offset) + << " SID: " << format("%d", SectionID) + << " SymOffset: " << format("%x", SymOffset) << "\n"); + + switch (Type) { + default: + llvm_unreachable("Not implemented relocation type!"); + break; + case ELF::R_MIPS_JALR: + case ELF::R_MIPS_NONE: + break; + case ELF::R_MIPS_32: + case ELF::R_MIPS_64: + return Value + Addend; + case ELF::R_MIPS_26: + return ((Value + Addend) >> 2) & 0x3ffffff; + case ELF::R_MIPS_GPREL16: { + uint64_t GOTAddr = getSectionLoadAddress(SectionToGOTMap[SectionID]); + return Value + Addend - (GOTAddr + 0x7ff0); + } + case ELF::R_MIPS_SUB: + return Value - Addend; + case ELF::R_MIPS_HI16: + // Get the higher 16-bits. Also add 1 if bit 15 is 1. + return ((Value + Addend + 0x8000) >> 16) & 0xffff; + case ELF::R_MIPS_LO16: + return (Value + Addend) & 0xffff; + case ELF::R_MIPS_HIGHER: + return ((Value + Addend + 0x80008000) >> 32) & 0xffff; + case ELF::R_MIPS_HIGHEST: + return ((Value + Addend + 0x800080008000) >> 48) & 0xffff; + case ELF::R_MIPS_CALL16: + case ELF::R_MIPS_GOT_DISP: + case ELF::R_MIPS_GOT_PAGE: { + uint8_t *LocalGOTAddr = + getSectionAddress(SectionToGOTMap[SectionID]) + SymOffset; + uint64_t GOTEntry = readBytesUnaligned(LocalGOTAddr, getGOTEntrySize()); + + Value += Addend; + if (Type == ELF::R_MIPS_GOT_PAGE) + Value = (Value + 0x8000) & ~0xffff; + + if (GOTEntry) + assert(GOTEntry == Value && + "GOT entry has two different addresses."); + else + writeBytesUnaligned(Value, LocalGOTAddr, getGOTEntrySize()); + + return (SymOffset - 0x7ff0) & 0xffff; + } + case ELF::R_MIPS_GOT_OFST: { + int64_t page = (Value + Addend + 0x8000) & ~0xffff; + return (Value + Addend - page) & 0xffff; + } + case ELF::R_MIPS_GPREL32: { + uint64_t GOTAddr = getSectionLoadAddress(SectionToGOTMap[SectionID]); + return Value + Addend - (GOTAddr + 0x7ff0); + } + case ELF::R_MIPS_PC16: { + uint64_t FinalAddress = Section.getLoadAddressWithOffset(Offset); + return ((Value + Addend - FinalAddress) >> 2) & 0xffff; + } + case ELF::R_MIPS_PC32: { + uint64_t FinalAddress = Section.getLoadAddressWithOffset(Offset); + return Value + Addend - FinalAddress; + } + case ELF::R_MIPS_PC18_S3: { + uint64_t FinalAddress = Section.getLoadAddressWithOffset(Offset); + return ((Value + Addend - (FinalAddress & ~0x7)) >> 3) & 0x3ffff; + } + case ELF::R_MIPS_PC19_S2: { + uint64_t FinalAddress = Section.getLoadAddressWithOffset(Offset); + return ((Value + Addend - (FinalAddress & ~0x3)) >> 2) & 0x7ffff; + } + case ELF::R_MIPS_PC21_S2: { + uint64_t FinalAddress = Section.getLoadAddressWithOffset(Offset); + return ((Value + Addend - FinalAddress) >> 2) & 0x1fffff; + } + case ELF::R_MIPS_PC26_S2: { + uint64_t FinalAddress = Section.getLoadAddressWithOffset(Offset); + return ((Value + Addend - FinalAddress) >> 2) & 0x3ffffff; + } + case ELF::R_MIPS_PCHI16: { + uint64_t FinalAddress = Section.getLoadAddressWithOffset(Offset); + return ((Value + Addend - FinalAddress + 0x8000) >> 16) & 0xffff; + } + case ELF::R_MIPS_PCLO16: { + uint64_t FinalAddress = Section.getLoadAddressWithOffset(Offset); + return (Value + Addend - FinalAddress) & 0xffff; + } + } + return 0; +} + +void RuntimeDyldELFMips::applyMIPSRelocation(uint8_t *TargetPtr, int64_t Value, + uint32_t Type) { + uint32_t Insn = readBytesUnaligned(TargetPtr, 4); + + switch (Type) { + default: + llvm_unreachable("Unknown relocation type!"); + break; + case ELF::R_MIPS_GPREL16: + case ELF::R_MIPS_HI16: + case ELF::R_MIPS_LO16: + case ELF::R_MIPS_HIGHER: + case ELF::R_MIPS_HIGHEST: + case ELF::R_MIPS_PC16: + case ELF::R_MIPS_PCHI16: + case ELF::R_MIPS_PCLO16: + case ELF::R_MIPS_CALL16: + case ELF::R_MIPS_GOT_DISP: + case ELF::R_MIPS_GOT_PAGE: + case ELF::R_MIPS_GOT_OFST: + Insn = (Insn & 0xffff0000) | (Value & 0x0000ffff); + writeBytesUnaligned(Insn, TargetPtr, 4); + break; + case ELF::R_MIPS_PC18_S3: + Insn = (Insn & 0xfffc0000) | (Value & 0x0003ffff); + writeBytesUnaligned(Insn, TargetPtr, 4); + break; + case ELF::R_MIPS_PC19_S2: + Insn = (Insn & 0xfff80000) | (Value & 0x0007ffff); + writeBytesUnaligned(Insn, TargetPtr, 4); + break; + case ELF::R_MIPS_PC21_S2: + Insn = (Insn & 0xffe00000) | (Value & 0x001fffff); + writeBytesUnaligned(Insn, TargetPtr, 4); + break; + case ELF::R_MIPS_26: + case ELF::R_MIPS_PC26_S2: + Insn = (Insn & 0xfc000000) | (Value & 0x03ffffff); + writeBytesUnaligned(Insn, TargetPtr, 4); + break; + case ELF::R_MIPS_32: + case ELF::R_MIPS_GPREL32: + case ELF::R_MIPS_PC32: + writeBytesUnaligned(Value & 0xffffffff, TargetPtr, 4); + break; + case ELF::R_MIPS_64: + case ELF::R_MIPS_SUB: + writeBytesUnaligned(Value, TargetPtr, 8); + break; + } +} + +void RuntimeDyldELFMips::resolveMIPSN32Relocation( + const SectionEntry &Section, uint64_t Offset, uint64_t Value, uint32_t Type, + int64_t Addend, uint64_t SymOffset, SID SectionID) { + int64_t CalculatedValue = evaluateMIPS64Relocation( + Section, Offset, Value, Type, Addend, SymOffset, SectionID); + applyMIPSRelocation(Section.getAddressWithOffset(Offset), CalculatedValue, + Type); +} + +void RuntimeDyldELFMips::resolveMIPSN64Relocation( + const SectionEntry &Section, uint64_t Offset, uint64_t Value, uint32_t Type, + int64_t Addend, uint64_t SymOffset, SID SectionID) { + uint32_t r_type = Type & 0xff; + uint32_t r_type2 = (Type >> 8) & 0xff; + uint32_t r_type3 = (Type >> 16) & 0xff; + + // RelType is used to keep information for which relocation type we are + // applying relocation. + uint32_t RelType = r_type; + int64_t CalculatedValue = evaluateMIPS64Relocation(Section, Offset, Value, + RelType, Addend, + SymOffset, SectionID); + if (r_type2 != ELF::R_MIPS_NONE) { + RelType = r_type2; + CalculatedValue = evaluateMIPS64Relocation(Section, Offset, 0, RelType, + CalculatedValue, SymOffset, + SectionID); + } + if (r_type3 != ELF::R_MIPS_NONE) { + RelType = r_type3; + CalculatedValue = evaluateMIPS64Relocation(Section, Offset, 0, RelType, + CalculatedValue, SymOffset, + SectionID); + } + applyMIPSRelocation(Section.getAddressWithOffset(Offset), CalculatedValue, + RelType); +} + +void RuntimeDyldELFMips::resolveMIPSO32Relocation(const SectionEntry &Section, + uint64_t Offset, + uint32_t Value, uint32_t Type, + int32_t Addend) { + uint8_t *TargetPtr = Section.getAddressWithOffset(Offset); + Value += Addend; + + LLVM_DEBUG(dbgs() << "resolveMIPSO32Relocation, LocalAddress: " + << Section.getAddressWithOffset(Offset) << " FinalAddress: " + << format("%p", Section.getLoadAddressWithOffset(Offset)) + << " Value: " << format("%x", Value) << " Type: " + << format("%x", Type) << " Addend: " << format("%x", Addend) + << " SymOffset: " << format("%x", Offset) << "\n"); + + Value = evaluateMIPS32Relocation(Section, Offset, Value, Type); + + applyMIPSRelocation(TargetPtr, Value, Type); +} diff --git a/contrib/libs/llvm12/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldELFMips.h b/contrib/libs/llvm12/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldELFMips.h index eb78df19a2..14fb36f070 100644 --- a/contrib/libs/llvm12/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldELFMips.h +++ b/contrib/libs/llvm12/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldELFMips.h @@ -1,67 +1,67 @@ -//===-- RuntimeDyldELFMips.h ---- ELF/Mips specific code. -------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDELFMIPS_H -#define LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDELFMIPS_H - -#include "../RuntimeDyldELF.h" -#include <string> - -#define DEBUG_TYPE "dyld" - -namespace llvm { - -class RuntimeDyldELFMips : public RuntimeDyldELF { -public: - - typedef uint64_t TargetPtrT; - - RuntimeDyldELFMips(RuntimeDyld::MemoryManager &MM, - JITSymbolResolver &Resolver) - : RuntimeDyldELF(MM, Resolver) {} - - void resolveRelocation(const RelocationEntry &RE, uint64_t Value) override; - -protected: - void resolveMIPSO32Relocation(const SectionEntry &Section, uint64_t Offset, - uint32_t Value, uint32_t Type, int32_t Addend); - void resolveMIPSN32Relocation(const SectionEntry &Section, uint64_t Offset, - uint64_t Value, uint32_t Type, int64_t Addend, - uint64_t SymOffset, SID SectionID); - void resolveMIPSN64Relocation(const SectionEntry &Section, uint64_t Offset, - uint64_t Value, uint32_t Type, int64_t Addend, - uint64_t SymOffset, SID SectionID); - -private: - /// A object file specific relocation resolver - /// \param RE The relocation to be resolved - /// \param Value Target symbol address to apply the relocation action - uint64_t evaluateRelocation(const RelocationEntry &RE, uint64_t Value, - uint64_t Addend); - - /// A object file specific relocation resolver - /// \param RE The relocation to be resolved - /// \param Value Target symbol address to apply the relocation action - void applyRelocation(const RelocationEntry &RE, uint64_t Value); - - int64_t evaluateMIPS32Relocation(const SectionEntry &Section, uint64_t Offset, - uint64_t Value, uint32_t Type); - int64_t evaluateMIPS64Relocation(const SectionEntry &Section, - uint64_t Offset, uint64_t Value, - uint32_t Type, int64_t Addend, - uint64_t SymOffset, SID SectionID); - - void applyMIPSRelocation(uint8_t *TargetPtr, int64_t CalculatedValue, - uint32_t Type); - -}; -} - -#undef DEBUG_TYPE - -#endif +//===-- RuntimeDyldELFMips.h ---- ELF/Mips specific code. -------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDELFMIPS_H +#define LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDELFMIPS_H + +#include "../RuntimeDyldELF.h" +#include <string> + +#define DEBUG_TYPE "dyld" + +namespace llvm { + +class RuntimeDyldELFMips : public RuntimeDyldELF { +public: + + typedef uint64_t TargetPtrT; + + RuntimeDyldELFMips(RuntimeDyld::MemoryManager &MM, + JITSymbolResolver &Resolver) + : RuntimeDyldELF(MM, Resolver) {} + + void resolveRelocation(const RelocationEntry &RE, uint64_t Value) override; + +protected: + void resolveMIPSO32Relocation(const SectionEntry &Section, uint64_t Offset, + uint32_t Value, uint32_t Type, int32_t Addend); + void resolveMIPSN32Relocation(const SectionEntry &Section, uint64_t Offset, + uint64_t Value, uint32_t Type, int64_t Addend, + uint64_t SymOffset, SID SectionID); + void resolveMIPSN64Relocation(const SectionEntry &Section, uint64_t Offset, + uint64_t Value, uint32_t Type, int64_t Addend, + uint64_t SymOffset, SID SectionID); + +private: + /// A object file specific relocation resolver + /// \param RE The relocation to be resolved + /// \param Value Target symbol address to apply the relocation action + uint64_t evaluateRelocation(const RelocationEntry &RE, uint64_t Value, + uint64_t Addend); + + /// A object file specific relocation resolver + /// \param RE The relocation to be resolved + /// \param Value Target symbol address to apply the relocation action + void applyRelocation(const RelocationEntry &RE, uint64_t Value); + + int64_t evaluateMIPS32Relocation(const SectionEntry &Section, uint64_t Offset, + uint64_t Value, uint32_t Type); + int64_t evaluateMIPS64Relocation(const SectionEntry &Section, + uint64_t Offset, uint64_t Value, + uint32_t Type, int64_t Addend, + uint64_t SymOffset, SID SectionID); + + void applyMIPSRelocation(uint8_t *TargetPtr, int64_t CalculatedValue, + uint32_t Type); + +}; +} + +#undef DEBUG_TYPE + +#endif diff --git a/contrib/libs/llvm12/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOAArch64.h b/contrib/libs/llvm12/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOAArch64.h index 4a10556076..f2ee1b06d4 100644 --- a/contrib/libs/llvm12/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOAArch64.h +++ b/contrib/libs/llvm12/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOAArch64.h @@ -1,541 +1,541 @@ -//===-- RuntimeDyldMachOAArch64.h -- MachO/AArch64 specific code. -*- C++ -*-=// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDMACHOAARCH64_H -#define LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDMACHOAARCH64_H - -#include "../RuntimeDyldMachO.h" -#include "llvm/Support/Endian.h" - -#define DEBUG_TYPE "dyld" - -namespace llvm { - -class RuntimeDyldMachOAArch64 - : public RuntimeDyldMachOCRTPBase<RuntimeDyldMachOAArch64> { -public: - - typedef uint64_t TargetPtrT; - - RuntimeDyldMachOAArch64(RuntimeDyld::MemoryManager &MM, - JITSymbolResolver &Resolver) - : RuntimeDyldMachOCRTPBase(MM, Resolver) {} - - unsigned getMaxStubSize() const override { return 8; } - - unsigned getStubAlignment() override { return 8; } - - /// Extract the addend encoded in the instruction / memory location. - Expected<int64_t> decodeAddend(const RelocationEntry &RE) const { - const SectionEntry &Section = Sections[RE.SectionID]; - uint8_t *LocalAddress = Section.getAddressWithOffset(RE.Offset); - unsigned NumBytes = 1 << RE.Size; - int64_t Addend = 0; - // Verify that the relocation has the correct size and alignment. - switch (RE.RelType) { - default: { - std::string ErrMsg; - { - raw_string_ostream ErrStream(ErrMsg); - ErrStream << "Unsupported relocation type: " - << getRelocName(RE.RelType); - } - return make_error<StringError>(std::move(ErrMsg), - inconvertibleErrorCode()); - } - case MachO::ARM64_RELOC_POINTER_TO_GOT: - case MachO::ARM64_RELOC_UNSIGNED: { - if (NumBytes != 4 && NumBytes != 8) { - std::string ErrMsg; - { - raw_string_ostream ErrStream(ErrMsg); - ErrStream << "Invalid relocation size for relocation " - << getRelocName(RE.RelType); - } - return make_error<StringError>(std::move(ErrMsg), - inconvertibleErrorCode()); - } - break; - } - case MachO::ARM64_RELOC_BRANCH26: - case MachO::ARM64_RELOC_PAGE21: - case MachO::ARM64_RELOC_PAGEOFF12: - case MachO::ARM64_RELOC_GOT_LOAD_PAGE21: - case MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12: - assert(NumBytes == 4 && "Invalid relocation size."); - assert((((uintptr_t)LocalAddress & 0x3) == 0) && - "Instruction address is not aligned to 4 bytes."); - break; - } - - switch (RE.RelType) { - default: - llvm_unreachable("Unsupported relocation type!"); - case MachO::ARM64_RELOC_POINTER_TO_GOT: - case MachO::ARM64_RELOC_UNSIGNED: - // This could be an unaligned memory location. - if (NumBytes == 4) - Addend = *reinterpret_cast<support::ulittle32_t *>(LocalAddress); - else - Addend = *reinterpret_cast<support::ulittle64_t *>(LocalAddress); - break; - case MachO::ARM64_RELOC_BRANCH26: { - // Verify that the relocation points to a B/BL instruction. - auto *p = reinterpret_cast<support::aligned_ulittle32_t *>(LocalAddress); - assert(((*p & 0xFC000000) == 0x14000000 || - (*p & 0xFC000000) == 0x94000000) && - "Expected branch instruction."); - - // Get the 26 bit addend encoded in the branch instruction and sign-extend - // to 64 bit. The lower 2 bits are always zeros and are therefore implicit - // (<< 2). - Addend = (*p & 0x03FFFFFF) << 2; - Addend = SignExtend64(Addend, 28); - break; - } - case MachO::ARM64_RELOC_GOT_LOAD_PAGE21: - case MachO::ARM64_RELOC_PAGE21: { - // Verify that the relocation points to the expected adrp instruction. - auto *p = reinterpret_cast<support::aligned_ulittle32_t *>(LocalAddress); - assert((*p & 0x9F000000) == 0x90000000 && "Expected adrp instruction."); - - // Get the 21 bit addend encoded in the adrp instruction and sign-extend - // to 64 bit. The lower 12 bits (4096 byte page) are always zeros and are - // therefore implicit (<< 12). - Addend = ((*p & 0x60000000) >> 29) | ((*p & 0x01FFFFE0) >> 3) << 12; - Addend = SignExtend64(Addend, 33); - break; - } - case MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12: { - // Verify that the relocation points to one of the expected load / store - // instructions. - auto *p = reinterpret_cast<support::aligned_ulittle32_t *>(LocalAddress); - (void)p; - assert((*p & 0x3B000000) == 0x39000000 && - "Only expected load / store instructions."); - LLVM_FALLTHROUGH; - } - case MachO::ARM64_RELOC_PAGEOFF12: { - // Verify that the relocation points to one of the expected load / store - // or add / sub instructions. - auto *p = reinterpret_cast<support::aligned_ulittle32_t *>(LocalAddress); - assert((((*p & 0x3B000000) == 0x39000000) || - ((*p & 0x11C00000) == 0x11000000) ) && - "Expected load / store or add/sub instruction."); - - // Get the 12 bit addend encoded in the instruction. - Addend = (*p & 0x003FFC00) >> 10; - - // Check which instruction we are decoding to obtain the implicit shift - // factor of the instruction. - int ImplicitShift = 0; - if ((*p & 0x3B000000) == 0x39000000) { // << load / store - // For load / store instructions the size is encoded in bits 31:30. - ImplicitShift = ((*p >> 30) & 0x3); - if (ImplicitShift == 0) { - // Check if this a vector op to get the correct shift value. - if ((*p & 0x04800000) == 0x04800000) - ImplicitShift = 4; - } - } - // Compensate for implicit shift. - Addend <<= ImplicitShift; - break; - } - } - return Addend; - } - - /// Extract the addend encoded in the instruction. - void encodeAddend(uint8_t *LocalAddress, unsigned NumBytes, - MachO::RelocationInfoType RelType, int64_t Addend) const { - // Verify that the relocation has the correct alignment. - switch (RelType) { - default: - llvm_unreachable("Unsupported relocation type!"); - case MachO::ARM64_RELOC_POINTER_TO_GOT: - case MachO::ARM64_RELOC_UNSIGNED: - assert((NumBytes == 4 || NumBytes == 8) && "Invalid relocation size."); - break; - case MachO::ARM64_RELOC_BRANCH26: - case MachO::ARM64_RELOC_PAGE21: - case MachO::ARM64_RELOC_PAGEOFF12: - case MachO::ARM64_RELOC_GOT_LOAD_PAGE21: - case MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12: - assert(NumBytes == 4 && "Invalid relocation size."); - assert((((uintptr_t)LocalAddress & 0x3) == 0) && - "Instruction address is not aligned to 4 bytes."); - break; - } - - switch (RelType) { - default: - llvm_unreachable("Unsupported relocation type!"); - case MachO::ARM64_RELOC_POINTER_TO_GOT: - case MachO::ARM64_RELOC_UNSIGNED: - // This could be an unaligned memory location. - if (NumBytes == 4) - *reinterpret_cast<support::ulittle32_t *>(LocalAddress) = Addend; - else - *reinterpret_cast<support::ulittle64_t *>(LocalAddress) = Addend; - break; - case MachO::ARM64_RELOC_BRANCH26: { - auto *p = reinterpret_cast<support::aligned_ulittle32_t *>(LocalAddress); - // Verify that the relocation points to the expected branch instruction. - assert(((*p & 0xFC000000) == 0x14000000 || - (*p & 0xFC000000) == 0x94000000) && - "Expected branch instruction."); - - // Verify addend value. - assert((Addend & 0x3) == 0 && "Branch target is not aligned"); - assert(isInt<28>(Addend) && "Branch target is out of range."); - - // Encode the addend as 26 bit immediate in the branch instruction. - *p = (*p & 0xFC000000) | ((uint32_t)(Addend >> 2) & 0x03FFFFFF); - break; - } - case MachO::ARM64_RELOC_GOT_LOAD_PAGE21: - case MachO::ARM64_RELOC_PAGE21: { - // Verify that the relocation points to the expected adrp instruction. - auto *p = reinterpret_cast<support::aligned_ulittle32_t *>(LocalAddress); - assert((*p & 0x9F000000) == 0x90000000 && "Expected adrp instruction."); - - // Check that the addend fits into 21 bits (+ 12 lower bits). - assert((Addend & 0xFFF) == 0 && "ADRP target is not page aligned."); - assert(isInt<33>(Addend) && "Invalid page reloc value."); - - // Encode the addend into the instruction. - uint32_t ImmLoValue = ((uint64_t)Addend << 17) & 0x60000000; - uint32_t ImmHiValue = ((uint64_t)Addend >> 9) & 0x00FFFFE0; - *p = (*p & 0x9F00001F) | ImmHiValue | ImmLoValue; - break; - } - case MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12: { - // Verify that the relocation points to one of the expected load / store - // instructions. - auto *p = reinterpret_cast<support::aligned_ulittle32_t *>(LocalAddress); - assert((*p & 0x3B000000) == 0x39000000 && - "Only expected load / store instructions."); - (void)p; - LLVM_FALLTHROUGH; - } - case MachO::ARM64_RELOC_PAGEOFF12: { - // Verify that the relocation points to one of the expected load / store - // or add / sub instructions. - auto *p = reinterpret_cast<support::aligned_ulittle32_t *>(LocalAddress); - assert((((*p & 0x3B000000) == 0x39000000) || - ((*p & 0x11C00000) == 0x11000000) ) && - "Expected load / store or add/sub instruction."); - - // Check which instruction we are decoding to obtain the implicit shift - // factor of the instruction and verify alignment. - int ImplicitShift = 0; - if ((*p & 0x3B000000) == 0x39000000) { // << load / store - // For load / store instructions the size is encoded in bits 31:30. - ImplicitShift = ((*p >> 30) & 0x3); - switch (ImplicitShift) { - case 0: - // Check if this a vector op to get the correct shift value. - if ((*p & 0x04800000) == 0x04800000) { - ImplicitShift = 4; - assert(((Addend & 0xF) == 0) && - "128-bit LDR/STR not 16-byte aligned."); - } - break; - case 1: - assert(((Addend & 0x1) == 0) && "16-bit LDR/STR not 2-byte aligned."); - break; - case 2: - assert(((Addend & 0x3) == 0) && "32-bit LDR/STR not 4-byte aligned."); - break; - case 3: - assert(((Addend & 0x7) == 0) && "64-bit LDR/STR not 8-byte aligned."); - break; - } - } - // Compensate for implicit shift. - Addend >>= ImplicitShift; - assert(isUInt<12>(Addend) && "Addend cannot be encoded."); - - // Encode the addend into the instruction. - *p = (*p & 0xFFC003FF) | ((uint32_t)(Addend << 10) & 0x003FFC00); - break; - } - } - } - - Expected<relocation_iterator> - processRelocationRef(unsigned SectionID, relocation_iterator RelI, - const ObjectFile &BaseObjT, - ObjSectionToIDMap &ObjSectionToID, - StubMap &Stubs) override { - const MachOObjectFile &Obj = - static_cast<const MachOObjectFile &>(BaseObjT); - MachO::any_relocation_info RelInfo = - Obj.getRelocation(RelI->getRawDataRefImpl()); - - if (Obj.isRelocationScattered(RelInfo)) - return make_error<RuntimeDyldError>("Scattered relocations not supported " - "for MachO AArch64"); - - // ARM64 has an ARM64_RELOC_ADDEND relocation type that carries an explicit - // addend for the following relocation. If found: (1) store the associated - // addend, (2) consume the next relocation, and (3) use the stored addend to - // override the addend. - int64_t ExplicitAddend = 0; - if (Obj.getAnyRelocationType(RelInfo) == MachO::ARM64_RELOC_ADDEND) { - assert(!Obj.getPlainRelocationExternal(RelInfo)); - assert(!Obj.getAnyRelocationPCRel(RelInfo)); - assert(Obj.getAnyRelocationLength(RelInfo) == 2); - int64_t RawAddend = Obj.getPlainRelocationSymbolNum(RelInfo); - // Sign-extend the 24-bit to 64-bit. - ExplicitAddend = SignExtend64(RawAddend, 24); - ++RelI; - RelInfo = Obj.getRelocation(RelI->getRawDataRefImpl()); - } - - if (Obj.getAnyRelocationType(RelInfo) == MachO::ARM64_RELOC_SUBTRACTOR) - return processSubtractRelocation(SectionID, RelI, Obj, ObjSectionToID); - - RelocationEntry RE(getRelocationEntry(SectionID, Obj, RelI)); - - if (RE.RelType == MachO::ARM64_RELOC_POINTER_TO_GOT) { - bool Valid = - (RE.Size == 2 && RE.IsPCRel) || (RE.Size == 3 && !RE.IsPCRel); - if (!Valid) - return make_error<StringError>("ARM64_RELOC_POINTER_TO_GOT supports " - "32-bit pc-rel or 64-bit absolute only", - inconvertibleErrorCode()); - } - - if (auto Addend = decodeAddend(RE)) - RE.Addend = *Addend; - else - return Addend.takeError(); - - assert((ExplicitAddend == 0 || RE.Addend == 0) && "Relocation has "\ - "ARM64_RELOC_ADDEND and embedded addend in the instruction."); - if (ExplicitAddend) - RE.Addend = ExplicitAddend; - - RelocationValueRef Value; - if (auto ValueOrErr = getRelocationValueRef(Obj, RelI, RE, ObjSectionToID)) - Value = *ValueOrErr; - else - return ValueOrErr.takeError(); - - bool IsExtern = Obj.getPlainRelocationExternal(RelInfo); - if (RE.RelType == MachO::ARM64_RELOC_POINTER_TO_GOT) { - // We'll take care of the offset in processGOTRelocation. - Value.Offset = 0; - } else if (!IsExtern && RE.IsPCRel) - makeValueAddendPCRel(Value, RelI, 1 << RE.Size); - - RE.Addend = Value.Offset; - - if (RE.RelType == MachO::ARM64_RELOC_GOT_LOAD_PAGE21 || - RE.RelType == MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12 || - RE.RelType == MachO::ARM64_RELOC_POINTER_TO_GOT) - processGOTRelocation(RE, Value, Stubs); - else { - if (Value.SymbolName) - addRelocationForSymbol(RE, Value.SymbolName); - else - addRelocationForSection(RE, Value.SectionID); - } - - return ++RelI; - } - - void resolveRelocation(const RelocationEntry &RE, uint64_t Value) override { - LLVM_DEBUG(dumpRelocationToResolve(RE, Value)); - - const SectionEntry &Section = Sections[RE.SectionID]; - uint8_t *LocalAddress = Section.getAddressWithOffset(RE.Offset); - MachO::RelocationInfoType RelType = - static_cast<MachO::RelocationInfoType>(RE.RelType); - - switch (RelType) { - default: - llvm_unreachable("Invalid relocation type!"); - case MachO::ARM64_RELOC_UNSIGNED: { - assert(!RE.IsPCRel && "PCRel and ARM64_RELOC_UNSIGNED not supported"); - // Mask in the target value a byte at a time (we don't have an alignment - // guarantee for the target address, so this is safest). - if (RE.Size < 2) - llvm_unreachable("Invalid size for ARM64_RELOC_UNSIGNED"); - - encodeAddend(LocalAddress, 1 << RE.Size, RelType, Value + RE.Addend); - break; - } - - case MachO::ARM64_RELOC_POINTER_TO_GOT: { - assert(((RE.Size == 2 && RE.IsPCRel) || (RE.Size == 3 && !RE.IsPCRel)) && - "ARM64_RELOC_POINTER_TO_GOT only supports 32-bit pc-rel or 64-bit " - "absolute"); - // Addend is the GOT entry address and RE.Offset the target of the - // relocation. - uint64_t Result = - RE.IsPCRel ? (RE.Addend - RE.Offset) : (Value + RE.Addend); - encodeAddend(LocalAddress, 1 << RE.Size, RelType, Result); - break; - } - - case MachO::ARM64_RELOC_BRANCH26: { - assert(RE.IsPCRel && "not PCRel and ARM64_RELOC_BRANCH26 not supported"); - // Check if branch is in range. - uint64_t FinalAddress = Section.getLoadAddressWithOffset(RE.Offset); - int64_t PCRelVal = Value - FinalAddress + RE.Addend; - encodeAddend(LocalAddress, /*Size=*/4, RelType, PCRelVal); - break; - } - case MachO::ARM64_RELOC_GOT_LOAD_PAGE21: - case MachO::ARM64_RELOC_PAGE21: { - assert(RE.IsPCRel && "not PCRel and ARM64_RELOC_PAGE21 not supported"); - // Adjust for PC-relative relocation and offset. - uint64_t FinalAddress = Section.getLoadAddressWithOffset(RE.Offset); - int64_t PCRelVal = - ((Value + RE.Addend) & (-4096)) - (FinalAddress & (-4096)); - encodeAddend(LocalAddress, /*Size=*/4, RelType, PCRelVal); - break; - } - case MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12: - case MachO::ARM64_RELOC_PAGEOFF12: { - assert(!RE.IsPCRel && "PCRel and ARM64_RELOC_PAGEOFF21 not supported"); - // Add the offset from the symbol. - Value += RE.Addend; - // Mask out the page address and only use the lower 12 bits. - Value &= 0xFFF; - encodeAddend(LocalAddress, /*Size=*/4, RelType, Value); - break; - } - case MachO::ARM64_RELOC_SUBTRACTOR: { - uint64_t SectionABase = Sections[RE.Sections.SectionA].getLoadAddress(); - uint64_t SectionBBase = Sections[RE.Sections.SectionB].getLoadAddress(); - assert((Value == SectionABase || Value == SectionBBase) && - "Unexpected SUBTRACTOR relocation value."); - Value = SectionABase - SectionBBase + RE.Addend; - writeBytesUnaligned(Value, LocalAddress, 1 << RE.Size); - break; - } - - case MachO::ARM64_RELOC_TLVP_LOAD_PAGE21: - case MachO::ARM64_RELOC_TLVP_LOAD_PAGEOFF12: - llvm_unreachable("Relocation type not yet implemented!"); - case MachO::ARM64_RELOC_ADDEND: - llvm_unreachable("ARM64_RELOC_ADDEND should have been handeled by " - "processRelocationRef!"); - } - } - - Error finalizeSection(const ObjectFile &Obj, unsigned SectionID, - const SectionRef &Section) { - return Error::success(); - } - -private: - void processGOTRelocation(const RelocationEntry &RE, - RelocationValueRef &Value, StubMap &Stubs) { - assert((RE.RelType == MachO::ARM64_RELOC_POINTER_TO_GOT && - (RE.Size == 2 || RE.Size == 3)) || - RE.Size == 2); - SectionEntry &Section = Sections[RE.SectionID]; - StubMap::const_iterator i = Stubs.find(Value); - int64_t Offset; - if (i != Stubs.end()) - Offset = static_cast<int64_t>(i->second); - else { - // FIXME: There must be a better way to do this then to check and fix the - // alignment every time!!! - uintptr_t BaseAddress = uintptr_t(Section.getAddress()); - uintptr_t StubAlignment = getStubAlignment(); - uintptr_t StubAddress = - (BaseAddress + Section.getStubOffset() + StubAlignment - 1) & - -StubAlignment; - unsigned StubOffset = StubAddress - BaseAddress; - Stubs[Value] = StubOffset; - assert(((StubAddress % getStubAlignment()) == 0) && - "GOT entry not aligned"); - RelocationEntry GOTRE(RE.SectionID, StubOffset, - MachO::ARM64_RELOC_UNSIGNED, Value.Offset, - /*IsPCRel=*/false, /*Size=*/3); - if (Value.SymbolName) - addRelocationForSymbol(GOTRE, Value.SymbolName); - else - addRelocationForSection(GOTRE, Value.SectionID); - Section.advanceStubOffset(getMaxStubSize()); - Offset = static_cast<int64_t>(StubOffset); - } - RelocationEntry TargetRE(RE.SectionID, RE.Offset, RE.RelType, Offset, - RE.IsPCRel, RE.Size); - addRelocationForSection(TargetRE, RE.SectionID); - } - - Expected<relocation_iterator> - processSubtractRelocation(unsigned SectionID, relocation_iterator RelI, - const ObjectFile &BaseObjT, - ObjSectionToIDMap &ObjSectionToID) { - const MachOObjectFile &Obj = - static_cast<const MachOObjectFile&>(BaseObjT); - MachO::any_relocation_info RE = - Obj.getRelocation(RelI->getRawDataRefImpl()); - - unsigned Size = Obj.getAnyRelocationLength(RE); - uint64_t Offset = RelI->getOffset(); - uint8_t *LocalAddress = Sections[SectionID].getAddressWithOffset(Offset); - unsigned NumBytes = 1 << Size; - - Expected<StringRef> SubtrahendNameOrErr = RelI->getSymbol()->getName(); - if (!SubtrahendNameOrErr) - return SubtrahendNameOrErr.takeError(); - auto SubtrahendI = GlobalSymbolTable.find(*SubtrahendNameOrErr); - unsigned SectionBID = SubtrahendI->second.getSectionID(); - uint64_t SectionBOffset = SubtrahendI->second.getOffset(); - int64_t Addend = - SignExtend64(readBytesUnaligned(LocalAddress, NumBytes), NumBytes * 8); - - ++RelI; - Expected<StringRef> MinuendNameOrErr = RelI->getSymbol()->getName(); - if (!MinuendNameOrErr) - return MinuendNameOrErr.takeError(); - auto MinuendI = GlobalSymbolTable.find(*MinuendNameOrErr); - unsigned SectionAID = MinuendI->second.getSectionID(); - uint64_t SectionAOffset = MinuendI->second.getOffset(); - - RelocationEntry R(SectionID, Offset, MachO::ARM64_RELOC_SUBTRACTOR, (uint64_t)Addend, - SectionAID, SectionAOffset, SectionBID, SectionBOffset, - false, Size); - - addRelocationForSection(R, SectionAID); - - return ++RelI; - } - - static const char *getRelocName(uint32_t RelocType) { - switch (RelocType) { - case MachO::ARM64_RELOC_UNSIGNED: return "ARM64_RELOC_UNSIGNED"; - case MachO::ARM64_RELOC_SUBTRACTOR: return "ARM64_RELOC_SUBTRACTOR"; - case MachO::ARM64_RELOC_BRANCH26: return "ARM64_RELOC_BRANCH26"; - case MachO::ARM64_RELOC_PAGE21: return "ARM64_RELOC_PAGE21"; - case MachO::ARM64_RELOC_PAGEOFF12: return "ARM64_RELOC_PAGEOFF12"; - case MachO::ARM64_RELOC_GOT_LOAD_PAGE21: return "ARM64_RELOC_GOT_LOAD_PAGE21"; - case MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12: return "ARM64_RELOC_GOT_LOAD_PAGEOFF12"; - case MachO::ARM64_RELOC_POINTER_TO_GOT: return "ARM64_RELOC_POINTER_TO_GOT"; - case MachO::ARM64_RELOC_TLVP_LOAD_PAGE21: return "ARM64_RELOC_TLVP_LOAD_PAGE21"; - case MachO::ARM64_RELOC_TLVP_LOAD_PAGEOFF12: return "ARM64_RELOC_TLVP_LOAD_PAGEOFF12"; - case MachO::ARM64_RELOC_ADDEND: return "ARM64_RELOC_ADDEND"; - } - return "Unrecognized arm64 addend"; - } - -}; -} - -#undef DEBUG_TYPE - -#endif +//===-- RuntimeDyldMachOAArch64.h -- MachO/AArch64 specific code. -*- C++ -*-=// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDMACHOAARCH64_H +#define LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDMACHOAARCH64_H + +#include "../RuntimeDyldMachO.h" +#include "llvm/Support/Endian.h" + +#define DEBUG_TYPE "dyld" + +namespace llvm { + +class RuntimeDyldMachOAArch64 + : public RuntimeDyldMachOCRTPBase<RuntimeDyldMachOAArch64> { +public: + + typedef uint64_t TargetPtrT; + + RuntimeDyldMachOAArch64(RuntimeDyld::MemoryManager &MM, + JITSymbolResolver &Resolver) + : RuntimeDyldMachOCRTPBase(MM, Resolver) {} + + unsigned getMaxStubSize() const override { return 8; } + + unsigned getStubAlignment() override { return 8; } + + /// Extract the addend encoded in the instruction / memory location. + Expected<int64_t> decodeAddend(const RelocationEntry &RE) const { + const SectionEntry &Section = Sections[RE.SectionID]; + uint8_t *LocalAddress = Section.getAddressWithOffset(RE.Offset); + unsigned NumBytes = 1 << RE.Size; + int64_t Addend = 0; + // Verify that the relocation has the correct size and alignment. + switch (RE.RelType) { + default: { + std::string ErrMsg; + { + raw_string_ostream ErrStream(ErrMsg); + ErrStream << "Unsupported relocation type: " + << getRelocName(RE.RelType); + } + return make_error<StringError>(std::move(ErrMsg), + inconvertibleErrorCode()); + } + case MachO::ARM64_RELOC_POINTER_TO_GOT: + case MachO::ARM64_RELOC_UNSIGNED: { + if (NumBytes != 4 && NumBytes != 8) { + std::string ErrMsg; + { + raw_string_ostream ErrStream(ErrMsg); + ErrStream << "Invalid relocation size for relocation " + << getRelocName(RE.RelType); + } + return make_error<StringError>(std::move(ErrMsg), + inconvertibleErrorCode()); + } + break; + } + case MachO::ARM64_RELOC_BRANCH26: + case MachO::ARM64_RELOC_PAGE21: + case MachO::ARM64_RELOC_PAGEOFF12: + case MachO::ARM64_RELOC_GOT_LOAD_PAGE21: + case MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12: + assert(NumBytes == 4 && "Invalid relocation size."); + assert((((uintptr_t)LocalAddress & 0x3) == 0) && + "Instruction address is not aligned to 4 bytes."); + break; + } + + switch (RE.RelType) { + default: + llvm_unreachable("Unsupported relocation type!"); + case MachO::ARM64_RELOC_POINTER_TO_GOT: + case MachO::ARM64_RELOC_UNSIGNED: + // This could be an unaligned memory location. + if (NumBytes == 4) + Addend = *reinterpret_cast<support::ulittle32_t *>(LocalAddress); + else + Addend = *reinterpret_cast<support::ulittle64_t *>(LocalAddress); + break; + case MachO::ARM64_RELOC_BRANCH26: { + // Verify that the relocation points to a B/BL instruction. + auto *p = reinterpret_cast<support::aligned_ulittle32_t *>(LocalAddress); + assert(((*p & 0xFC000000) == 0x14000000 || + (*p & 0xFC000000) == 0x94000000) && + "Expected branch instruction."); + + // Get the 26 bit addend encoded in the branch instruction and sign-extend + // to 64 bit. The lower 2 bits are always zeros and are therefore implicit + // (<< 2). + Addend = (*p & 0x03FFFFFF) << 2; + Addend = SignExtend64(Addend, 28); + break; + } + case MachO::ARM64_RELOC_GOT_LOAD_PAGE21: + case MachO::ARM64_RELOC_PAGE21: { + // Verify that the relocation points to the expected adrp instruction. + auto *p = reinterpret_cast<support::aligned_ulittle32_t *>(LocalAddress); + assert((*p & 0x9F000000) == 0x90000000 && "Expected adrp instruction."); + + // Get the 21 bit addend encoded in the adrp instruction and sign-extend + // to 64 bit. The lower 12 bits (4096 byte page) are always zeros and are + // therefore implicit (<< 12). + Addend = ((*p & 0x60000000) >> 29) | ((*p & 0x01FFFFE0) >> 3) << 12; + Addend = SignExtend64(Addend, 33); + break; + } + case MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12: { + // Verify that the relocation points to one of the expected load / store + // instructions. + auto *p = reinterpret_cast<support::aligned_ulittle32_t *>(LocalAddress); + (void)p; + assert((*p & 0x3B000000) == 0x39000000 && + "Only expected load / store instructions."); + LLVM_FALLTHROUGH; + } + case MachO::ARM64_RELOC_PAGEOFF12: { + // Verify that the relocation points to one of the expected load / store + // or add / sub instructions. + auto *p = reinterpret_cast<support::aligned_ulittle32_t *>(LocalAddress); + assert((((*p & 0x3B000000) == 0x39000000) || + ((*p & 0x11C00000) == 0x11000000) ) && + "Expected load / store or add/sub instruction."); + + // Get the 12 bit addend encoded in the instruction. + Addend = (*p & 0x003FFC00) >> 10; + + // Check which instruction we are decoding to obtain the implicit shift + // factor of the instruction. + int ImplicitShift = 0; + if ((*p & 0x3B000000) == 0x39000000) { // << load / store + // For load / store instructions the size is encoded in bits 31:30. + ImplicitShift = ((*p >> 30) & 0x3); + if (ImplicitShift == 0) { + // Check if this a vector op to get the correct shift value. + if ((*p & 0x04800000) == 0x04800000) + ImplicitShift = 4; + } + } + // Compensate for implicit shift. + Addend <<= ImplicitShift; + break; + } + } + return Addend; + } + + /// Extract the addend encoded in the instruction. + void encodeAddend(uint8_t *LocalAddress, unsigned NumBytes, + MachO::RelocationInfoType RelType, int64_t Addend) const { + // Verify that the relocation has the correct alignment. + switch (RelType) { + default: + llvm_unreachable("Unsupported relocation type!"); + case MachO::ARM64_RELOC_POINTER_TO_GOT: + case MachO::ARM64_RELOC_UNSIGNED: + assert((NumBytes == 4 || NumBytes == 8) && "Invalid relocation size."); + break; + case MachO::ARM64_RELOC_BRANCH26: + case MachO::ARM64_RELOC_PAGE21: + case MachO::ARM64_RELOC_PAGEOFF12: + case MachO::ARM64_RELOC_GOT_LOAD_PAGE21: + case MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12: + assert(NumBytes == 4 && "Invalid relocation size."); + assert((((uintptr_t)LocalAddress & 0x3) == 0) && + "Instruction address is not aligned to 4 bytes."); + break; + } + + switch (RelType) { + default: + llvm_unreachable("Unsupported relocation type!"); + case MachO::ARM64_RELOC_POINTER_TO_GOT: + case MachO::ARM64_RELOC_UNSIGNED: + // This could be an unaligned memory location. + if (NumBytes == 4) + *reinterpret_cast<support::ulittle32_t *>(LocalAddress) = Addend; + else + *reinterpret_cast<support::ulittle64_t *>(LocalAddress) = Addend; + break; + case MachO::ARM64_RELOC_BRANCH26: { + auto *p = reinterpret_cast<support::aligned_ulittle32_t *>(LocalAddress); + // Verify that the relocation points to the expected branch instruction. + assert(((*p & 0xFC000000) == 0x14000000 || + (*p & 0xFC000000) == 0x94000000) && + "Expected branch instruction."); + + // Verify addend value. + assert((Addend & 0x3) == 0 && "Branch target is not aligned"); + assert(isInt<28>(Addend) && "Branch target is out of range."); + + // Encode the addend as 26 bit immediate in the branch instruction. + *p = (*p & 0xFC000000) | ((uint32_t)(Addend >> 2) & 0x03FFFFFF); + break; + } + case MachO::ARM64_RELOC_GOT_LOAD_PAGE21: + case MachO::ARM64_RELOC_PAGE21: { + // Verify that the relocation points to the expected adrp instruction. + auto *p = reinterpret_cast<support::aligned_ulittle32_t *>(LocalAddress); + assert((*p & 0x9F000000) == 0x90000000 && "Expected adrp instruction."); + + // Check that the addend fits into 21 bits (+ 12 lower bits). + assert((Addend & 0xFFF) == 0 && "ADRP target is not page aligned."); + assert(isInt<33>(Addend) && "Invalid page reloc value."); + + // Encode the addend into the instruction. + uint32_t ImmLoValue = ((uint64_t)Addend << 17) & 0x60000000; + uint32_t ImmHiValue = ((uint64_t)Addend >> 9) & 0x00FFFFE0; + *p = (*p & 0x9F00001F) | ImmHiValue | ImmLoValue; + break; + } + case MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12: { + // Verify that the relocation points to one of the expected load / store + // instructions. + auto *p = reinterpret_cast<support::aligned_ulittle32_t *>(LocalAddress); + assert((*p & 0x3B000000) == 0x39000000 && + "Only expected load / store instructions."); + (void)p; + LLVM_FALLTHROUGH; + } + case MachO::ARM64_RELOC_PAGEOFF12: { + // Verify that the relocation points to one of the expected load / store + // or add / sub instructions. + auto *p = reinterpret_cast<support::aligned_ulittle32_t *>(LocalAddress); + assert((((*p & 0x3B000000) == 0x39000000) || + ((*p & 0x11C00000) == 0x11000000) ) && + "Expected load / store or add/sub instruction."); + + // Check which instruction we are decoding to obtain the implicit shift + // factor of the instruction and verify alignment. + int ImplicitShift = 0; + if ((*p & 0x3B000000) == 0x39000000) { // << load / store + // For load / store instructions the size is encoded in bits 31:30. + ImplicitShift = ((*p >> 30) & 0x3); + switch (ImplicitShift) { + case 0: + // Check if this a vector op to get the correct shift value. + if ((*p & 0x04800000) == 0x04800000) { + ImplicitShift = 4; + assert(((Addend & 0xF) == 0) && + "128-bit LDR/STR not 16-byte aligned."); + } + break; + case 1: + assert(((Addend & 0x1) == 0) && "16-bit LDR/STR not 2-byte aligned."); + break; + case 2: + assert(((Addend & 0x3) == 0) && "32-bit LDR/STR not 4-byte aligned."); + break; + case 3: + assert(((Addend & 0x7) == 0) && "64-bit LDR/STR not 8-byte aligned."); + break; + } + } + // Compensate for implicit shift. + Addend >>= ImplicitShift; + assert(isUInt<12>(Addend) && "Addend cannot be encoded."); + + // Encode the addend into the instruction. + *p = (*p & 0xFFC003FF) | ((uint32_t)(Addend << 10) & 0x003FFC00); + break; + } + } + } + + Expected<relocation_iterator> + processRelocationRef(unsigned SectionID, relocation_iterator RelI, + const ObjectFile &BaseObjT, + ObjSectionToIDMap &ObjSectionToID, + StubMap &Stubs) override { + const MachOObjectFile &Obj = + static_cast<const MachOObjectFile &>(BaseObjT); + MachO::any_relocation_info RelInfo = + Obj.getRelocation(RelI->getRawDataRefImpl()); + + if (Obj.isRelocationScattered(RelInfo)) + return make_error<RuntimeDyldError>("Scattered relocations not supported " + "for MachO AArch64"); + + // ARM64 has an ARM64_RELOC_ADDEND relocation type that carries an explicit + // addend for the following relocation. If found: (1) store the associated + // addend, (2) consume the next relocation, and (3) use the stored addend to + // override the addend. + int64_t ExplicitAddend = 0; + if (Obj.getAnyRelocationType(RelInfo) == MachO::ARM64_RELOC_ADDEND) { + assert(!Obj.getPlainRelocationExternal(RelInfo)); + assert(!Obj.getAnyRelocationPCRel(RelInfo)); + assert(Obj.getAnyRelocationLength(RelInfo) == 2); + int64_t RawAddend = Obj.getPlainRelocationSymbolNum(RelInfo); + // Sign-extend the 24-bit to 64-bit. + ExplicitAddend = SignExtend64(RawAddend, 24); + ++RelI; + RelInfo = Obj.getRelocation(RelI->getRawDataRefImpl()); + } + + if (Obj.getAnyRelocationType(RelInfo) == MachO::ARM64_RELOC_SUBTRACTOR) + return processSubtractRelocation(SectionID, RelI, Obj, ObjSectionToID); + + RelocationEntry RE(getRelocationEntry(SectionID, Obj, RelI)); + + if (RE.RelType == MachO::ARM64_RELOC_POINTER_TO_GOT) { + bool Valid = + (RE.Size == 2 && RE.IsPCRel) || (RE.Size == 3 && !RE.IsPCRel); + if (!Valid) + return make_error<StringError>("ARM64_RELOC_POINTER_TO_GOT supports " + "32-bit pc-rel or 64-bit absolute only", + inconvertibleErrorCode()); + } + + if (auto Addend = decodeAddend(RE)) + RE.Addend = *Addend; + else + return Addend.takeError(); + + assert((ExplicitAddend == 0 || RE.Addend == 0) && "Relocation has "\ + "ARM64_RELOC_ADDEND and embedded addend in the instruction."); + if (ExplicitAddend) + RE.Addend = ExplicitAddend; + + RelocationValueRef Value; + if (auto ValueOrErr = getRelocationValueRef(Obj, RelI, RE, ObjSectionToID)) + Value = *ValueOrErr; + else + return ValueOrErr.takeError(); + + bool IsExtern = Obj.getPlainRelocationExternal(RelInfo); + if (RE.RelType == MachO::ARM64_RELOC_POINTER_TO_GOT) { + // We'll take care of the offset in processGOTRelocation. + Value.Offset = 0; + } else if (!IsExtern && RE.IsPCRel) + makeValueAddendPCRel(Value, RelI, 1 << RE.Size); + + RE.Addend = Value.Offset; + + if (RE.RelType == MachO::ARM64_RELOC_GOT_LOAD_PAGE21 || + RE.RelType == MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12 || + RE.RelType == MachO::ARM64_RELOC_POINTER_TO_GOT) + processGOTRelocation(RE, Value, Stubs); + else { + if (Value.SymbolName) + addRelocationForSymbol(RE, Value.SymbolName); + else + addRelocationForSection(RE, Value.SectionID); + } + + return ++RelI; + } + + void resolveRelocation(const RelocationEntry &RE, uint64_t Value) override { + LLVM_DEBUG(dumpRelocationToResolve(RE, Value)); + + const SectionEntry &Section = Sections[RE.SectionID]; + uint8_t *LocalAddress = Section.getAddressWithOffset(RE.Offset); + MachO::RelocationInfoType RelType = + static_cast<MachO::RelocationInfoType>(RE.RelType); + + switch (RelType) { + default: + llvm_unreachable("Invalid relocation type!"); + case MachO::ARM64_RELOC_UNSIGNED: { + assert(!RE.IsPCRel && "PCRel and ARM64_RELOC_UNSIGNED not supported"); + // Mask in the target value a byte at a time (we don't have an alignment + // guarantee for the target address, so this is safest). + if (RE.Size < 2) + llvm_unreachable("Invalid size for ARM64_RELOC_UNSIGNED"); + + encodeAddend(LocalAddress, 1 << RE.Size, RelType, Value + RE.Addend); + break; + } + + case MachO::ARM64_RELOC_POINTER_TO_GOT: { + assert(((RE.Size == 2 && RE.IsPCRel) || (RE.Size == 3 && !RE.IsPCRel)) && + "ARM64_RELOC_POINTER_TO_GOT only supports 32-bit pc-rel or 64-bit " + "absolute"); + // Addend is the GOT entry address and RE.Offset the target of the + // relocation. + uint64_t Result = + RE.IsPCRel ? (RE.Addend - RE.Offset) : (Value + RE.Addend); + encodeAddend(LocalAddress, 1 << RE.Size, RelType, Result); + break; + } + + case MachO::ARM64_RELOC_BRANCH26: { + assert(RE.IsPCRel && "not PCRel and ARM64_RELOC_BRANCH26 not supported"); + // Check if branch is in range. + uint64_t FinalAddress = Section.getLoadAddressWithOffset(RE.Offset); + int64_t PCRelVal = Value - FinalAddress + RE.Addend; + encodeAddend(LocalAddress, /*Size=*/4, RelType, PCRelVal); + break; + } + case MachO::ARM64_RELOC_GOT_LOAD_PAGE21: + case MachO::ARM64_RELOC_PAGE21: { + assert(RE.IsPCRel && "not PCRel and ARM64_RELOC_PAGE21 not supported"); + // Adjust for PC-relative relocation and offset. + uint64_t FinalAddress = Section.getLoadAddressWithOffset(RE.Offset); + int64_t PCRelVal = + ((Value + RE.Addend) & (-4096)) - (FinalAddress & (-4096)); + encodeAddend(LocalAddress, /*Size=*/4, RelType, PCRelVal); + break; + } + case MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12: + case MachO::ARM64_RELOC_PAGEOFF12: { + assert(!RE.IsPCRel && "PCRel and ARM64_RELOC_PAGEOFF21 not supported"); + // Add the offset from the symbol. + Value += RE.Addend; + // Mask out the page address and only use the lower 12 bits. + Value &= 0xFFF; + encodeAddend(LocalAddress, /*Size=*/4, RelType, Value); + break; + } + case MachO::ARM64_RELOC_SUBTRACTOR: { + uint64_t SectionABase = Sections[RE.Sections.SectionA].getLoadAddress(); + uint64_t SectionBBase = Sections[RE.Sections.SectionB].getLoadAddress(); + assert((Value == SectionABase || Value == SectionBBase) && + "Unexpected SUBTRACTOR relocation value."); + Value = SectionABase - SectionBBase + RE.Addend; + writeBytesUnaligned(Value, LocalAddress, 1 << RE.Size); + break; + } + + case MachO::ARM64_RELOC_TLVP_LOAD_PAGE21: + case MachO::ARM64_RELOC_TLVP_LOAD_PAGEOFF12: + llvm_unreachable("Relocation type not yet implemented!"); + case MachO::ARM64_RELOC_ADDEND: + llvm_unreachable("ARM64_RELOC_ADDEND should have been handeled by " + "processRelocationRef!"); + } + } + + Error finalizeSection(const ObjectFile &Obj, unsigned SectionID, + const SectionRef &Section) { + return Error::success(); + } + +private: + void processGOTRelocation(const RelocationEntry &RE, + RelocationValueRef &Value, StubMap &Stubs) { + assert((RE.RelType == MachO::ARM64_RELOC_POINTER_TO_GOT && + (RE.Size == 2 || RE.Size == 3)) || + RE.Size == 2); + SectionEntry &Section = Sections[RE.SectionID]; + StubMap::const_iterator i = Stubs.find(Value); + int64_t Offset; + if (i != Stubs.end()) + Offset = static_cast<int64_t>(i->second); + else { + // FIXME: There must be a better way to do this then to check and fix the + // alignment every time!!! + uintptr_t BaseAddress = uintptr_t(Section.getAddress()); + uintptr_t StubAlignment = getStubAlignment(); + uintptr_t StubAddress = + (BaseAddress + Section.getStubOffset() + StubAlignment - 1) & + -StubAlignment; + unsigned StubOffset = StubAddress - BaseAddress; + Stubs[Value] = StubOffset; + assert(((StubAddress % getStubAlignment()) == 0) && + "GOT entry not aligned"); + RelocationEntry GOTRE(RE.SectionID, StubOffset, + MachO::ARM64_RELOC_UNSIGNED, Value.Offset, + /*IsPCRel=*/false, /*Size=*/3); + if (Value.SymbolName) + addRelocationForSymbol(GOTRE, Value.SymbolName); + else + addRelocationForSection(GOTRE, Value.SectionID); + Section.advanceStubOffset(getMaxStubSize()); + Offset = static_cast<int64_t>(StubOffset); + } + RelocationEntry TargetRE(RE.SectionID, RE.Offset, RE.RelType, Offset, + RE.IsPCRel, RE.Size); + addRelocationForSection(TargetRE, RE.SectionID); + } + + Expected<relocation_iterator> + processSubtractRelocation(unsigned SectionID, relocation_iterator RelI, + const ObjectFile &BaseObjT, + ObjSectionToIDMap &ObjSectionToID) { + const MachOObjectFile &Obj = + static_cast<const MachOObjectFile&>(BaseObjT); + MachO::any_relocation_info RE = + Obj.getRelocation(RelI->getRawDataRefImpl()); + + unsigned Size = Obj.getAnyRelocationLength(RE); + uint64_t Offset = RelI->getOffset(); + uint8_t *LocalAddress = Sections[SectionID].getAddressWithOffset(Offset); + unsigned NumBytes = 1 << Size; + + Expected<StringRef> SubtrahendNameOrErr = RelI->getSymbol()->getName(); + if (!SubtrahendNameOrErr) + return SubtrahendNameOrErr.takeError(); + auto SubtrahendI = GlobalSymbolTable.find(*SubtrahendNameOrErr); + unsigned SectionBID = SubtrahendI->second.getSectionID(); + uint64_t SectionBOffset = SubtrahendI->second.getOffset(); + int64_t Addend = + SignExtend64(readBytesUnaligned(LocalAddress, NumBytes), NumBytes * 8); + + ++RelI; + Expected<StringRef> MinuendNameOrErr = RelI->getSymbol()->getName(); + if (!MinuendNameOrErr) + return MinuendNameOrErr.takeError(); + auto MinuendI = GlobalSymbolTable.find(*MinuendNameOrErr); + unsigned SectionAID = MinuendI->second.getSectionID(); + uint64_t SectionAOffset = MinuendI->second.getOffset(); + + RelocationEntry R(SectionID, Offset, MachO::ARM64_RELOC_SUBTRACTOR, (uint64_t)Addend, + SectionAID, SectionAOffset, SectionBID, SectionBOffset, + false, Size); + + addRelocationForSection(R, SectionAID); + + return ++RelI; + } + + static const char *getRelocName(uint32_t RelocType) { + switch (RelocType) { + case MachO::ARM64_RELOC_UNSIGNED: return "ARM64_RELOC_UNSIGNED"; + case MachO::ARM64_RELOC_SUBTRACTOR: return "ARM64_RELOC_SUBTRACTOR"; + case MachO::ARM64_RELOC_BRANCH26: return "ARM64_RELOC_BRANCH26"; + case MachO::ARM64_RELOC_PAGE21: return "ARM64_RELOC_PAGE21"; + case MachO::ARM64_RELOC_PAGEOFF12: return "ARM64_RELOC_PAGEOFF12"; + case MachO::ARM64_RELOC_GOT_LOAD_PAGE21: return "ARM64_RELOC_GOT_LOAD_PAGE21"; + case MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12: return "ARM64_RELOC_GOT_LOAD_PAGEOFF12"; + case MachO::ARM64_RELOC_POINTER_TO_GOT: return "ARM64_RELOC_POINTER_TO_GOT"; + case MachO::ARM64_RELOC_TLVP_LOAD_PAGE21: return "ARM64_RELOC_TLVP_LOAD_PAGE21"; + case MachO::ARM64_RELOC_TLVP_LOAD_PAGEOFF12: return "ARM64_RELOC_TLVP_LOAD_PAGEOFF12"; + case MachO::ARM64_RELOC_ADDEND: return "ARM64_RELOC_ADDEND"; + } + return "Unrecognized arm64 addend"; + } + +}; +} + +#undef DEBUG_TYPE + +#endif diff --git a/contrib/libs/llvm12/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOARM.h b/contrib/libs/llvm12/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOARM.h index 672c2871ab..a76958a9e2 100644 --- a/contrib/libs/llvm12/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOARM.h +++ b/contrib/libs/llvm12/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOARM.h @@ -1,432 +1,432 @@ -//===----- RuntimeDyldMachOARM.h ---- MachO/ARM specific code. ----*- C++ -*-=// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDMACHOARM_H -#define LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDMACHOARM_H - -#include "../RuntimeDyldMachO.h" -#include <string> - -#define DEBUG_TYPE "dyld" - -namespace llvm { - -class RuntimeDyldMachOARM - : public RuntimeDyldMachOCRTPBase<RuntimeDyldMachOARM> { -private: - typedef RuntimeDyldMachOCRTPBase<RuntimeDyldMachOARM> ParentT; - -public: - - typedef uint32_t TargetPtrT; - - RuntimeDyldMachOARM(RuntimeDyld::MemoryManager &MM, - JITSymbolResolver &Resolver) - : RuntimeDyldMachOCRTPBase(MM, Resolver) {} - - unsigned getMaxStubSize() const override { return 8; } - - unsigned getStubAlignment() override { return 4; } - - Expected<JITSymbolFlags> getJITSymbolFlags(const SymbolRef &SR) override { - auto Flags = RuntimeDyldImpl::getJITSymbolFlags(SR); - if (!Flags) - return Flags.takeError(); - Flags->getTargetFlags() = ARMJITSymbolFlags::fromObjectSymbol(SR); - return Flags; - } - - uint64_t modifyAddressBasedOnFlags(uint64_t Addr, - JITSymbolFlags Flags) const override { - if (Flags.getTargetFlags() & ARMJITSymbolFlags::Thumb) - Addr |= 0x1; - return Addr; - } - - bool isAddrTargetThumb(unsigned SectionID, uint64_t Offset) { - auto TargetObjAddr = Sections[SectionID].getObjAddress() + Offset; - for (auto &KV : GlobalSymbolTable) { - auto &Entry = KV.second; - auto SymbolObjAddr = - Sections[Entry.getSectionID()].getObjAddress() + Entry.getOffset(); - if (TargetObjAddr == SymbolObjAddr) - return (Entry.getFlags().getTargetFlags() & ARMJITSymbolFlags::Thumb); - } - return false; - } - - Expected<int64_t> decodeAddend(const RelocationEntry &RE) const { - const SectionEntry &Section = Sections[RE.SectionID]; - uint8_t *LocalAddress = Section.getAddressWithOffset(RE.Offset); - - switch (RE.RelType) { - default: - return memcpyAddend(RE); - case MachO::ARM_RELOC_BR24: { - uint32_t Temp = readBytesUnaligned(LocalAddress, 4); - Temp &= 0x00ffffff; // Mask out the opcode. - // Now we've got the shifted immediate, shift by 2, sign extend and ret. - return SignExtend32<26>(Temp << 2); - } - - case MachO::ARM_THUMB_RELOC_BR22: { - // This is a pair of instructions whose operands combine to provide 22 - // bits of displacement: - // Encoding for high bits 1111 0XXX XXXX XXXX - // Encoding for low bits 1111 1XXX XXXX XXXX - uint16_t HighInsn = readBytesUnaligned(LocalAddress, 2); - if ((HighInsn & 0xf800) != 0xf000) - return make_error<StringError>("Unrecognized thumb branch encoding " - "(BR22 high bits)", - inconvertibleErrorCode()); - - uint16_t LowInsn = readBytesUnaligned(LocalAddress + 2, 2); - if ((LowInsn & 0xf800) != 0xf800) - return make_error<StringError>("Unrecognized thumb branch encoding " - "(BR22 low bits)", - inconvertibleErrorCode()); - - return SignExtend64<23>(((HighInsn & 0x7ff) << 12) | - ((LowInsn & 0x7ff) << 1)); - } - } - } - - Expected<relocation_iterator> - processRelocationRef(unsigned SectionID, relocation_iterator RelI, - const ObjectFile &BaseObjT, - ObjSectionToIDMap &ObjSectionToID, - StubMap &Stubs) override { - const MachOObjectFile &Obj = - static_cast<const MachOObjectFile &>(BaseObjT); - MachO::any_relocation_info RelInfo = - Obj.getRelocation(RelI->getRawDataRefImpl()); - uint32_t RelType = Obj.getAnyRelocationType(RelInfo); - - // Set to true for thumb functions in this (or previous) TUs. - // Will be used to set the TargetIsThumbFunc member on the relocation entry. - bool TargetIsLocalThumbFunc = false; - if (Obj.getPlainRelocationExternal(RelInfo)) { - auto Symbol = RelI->getSymbol(); - StringRef TargetName; - if (auto TargetNameOrErr = Symbol->getName()) - TargetName = *TargetNameOrErr; - else - return TargetNameOrErr.takeError(); - - // If the target is external but the value doesn't have a name then we've - // converted the value to a section/offset pair, but we still need to set - // the IsTargetThumbFunc bit, so look the value up in the globla symbol table. - auto EntryItr = GlobalSymbolTable.find(TargetName); - if (EntryItr != GlobalSymbolTable.end()) { - TargetIsLocalThumbFunc = - EntryItr->second.getFlags().getTargetFlags() & - ARMJITSymbolFlags::Thumb; - } - } - - if (Obj.isRelocationScattered(RelInfo)) { - if (RelType == MachO::ARM_RELOC_HALF_SECTDIFF) - return processHALFSECTDIFFRelocation(SectionID, RelI, Obj, - ObjSectionToID); - else if (RelType == MachO::GENERIC_RELOC_VANILLA) - return processScatteredVANILLA(SectionID, RelI, Obj, ObjSectionToID, - TargetIsLocalThumbFunc); - else - return ++RelI; - } - - // Sanity check relocation type. - switch (RelType) { - UNIMPLEMENTED_RELOC(MachO::ARM_RELOC_PAIR); - UNIMPLEMENTED_RELOC(MachO::ARM_RELOC_SECTDIFF); - UNIMPLEMENTED_RELOC(MachO::ARM_RELOC_LOCAL_SECTDIFF); - UNIMPLEMENTED_RELOC(MachO::ARM_RELOC_PB_LA_PTR); - UNIMPLEMENTED_RELOC(MachO::ARM_THUMB_32BIT_BRANCH); - UNIMPLEMENTED_RELOC(MachO::ARM_RELOC_HALF); - default: - if (RelType > MachO::ARM_RELOC_HALF_SECTDIFF) - return make_error<RuntimeDyldError>(("MachO ARM relocation type " + - Twine(RelType) + - " is out of range").str()); - break; - } - - RelocationEntry RE(getRelocationEntry(SectionID, Obj, RelI)); - if (auto AddendOrErr = decodeAddend(RE)) - RE.Addend = *AddendOrErr; - else - return AddendOrErr.takeError(); - RE.IsTargetThumbFunc = TargetIsLocalThumbFunc; - - RelocationValueRef Value; - if (auto ValueOrErr = getRelocationValueRef(Obj, RelI, RE, ObjSectionToID)) - Value = *ValueOrErr; - else - return ValueOrErr.takeError(); - - // If this is a branch from a thumb function (BR22) then make sure we mark - // the value as being a thumb stub: we don't want to mix it up with an ARM - // stub targeting the same function. - if (RE.RelType == MachO::ARM_THUMB_RELOC_BR22) - Value.IsStubThumb = true; - - if (RE.IsPCRel) - makeValueAddendPCRel(Value, RelI, - (RE.RelType == MachO::ARM_THUMB_RELOC_BR22) ? 4 : 8); - - // If this is a non-external branch target check whether Value points to a - // thumb func. - if (!Value.SymbolName && (RelType == MachO::ARM_RELOC_BR24 || - RelType == MachO::ARM_THUMB_RELOC_BR22)) - RE.IsTargetThumbFunc = isAddrTargetThumb(Value.SectionID, Value.Offset); - - if (RE.RelType == MachO::ARM_RELOC_BR24 || - RE.RelType == MachO::ARM_THUMB_RELOC_BR22) - processBranchRelocation(RE, Value, Stubs); - else { - RE.Addend = Value.Offset; - if (Value.SymbolName) - addRelocationForSymbol(RE, Value.SymbolName); - else - addRelocationForSection(RE, Value.SectionID); - } - - return ++RelI; - } - - void resolveRelocation(const RelocationEntry &RE, uint64_t Value) override { - LLVM_DEBUG(dumpRelocationToResolve(RE, Value)); - const SectionEntry &Section = Sections[RE.SectionID]; - uint8_t *LocalAddress = Section.getAddressWithOffset(RE.Offset); - - // If the relocation is PC-relative, the value to be encoded is the - // pointer difference. - if (RE.IsPCRel) { - uint64_t FinalAddress = Section.getLoadAddressWithOffset(RE.Offset); - Value -= FinalAddress; - // ARM PCRel relocations have an effective-PC offset of two instructions - // (four bytes in Thumb mode, 8 bytes in ARM mode). - Value -= (RE.RelType == MachO::ARM_THUMB_RELOC_BR22) ? 4 : 8; - } - - switch (RE.RelType) { - case MachO::ARM_THUMB_RELOC_BR22: { - Value += RE.Addend; - uint16_t HighInsn = readBytesUnaligned(LocalAddress, 2); - assert((HighInsn & 0xf800) == 0xf000 && - "Unrecognized thumb branch encoding (BR22 high bits)"); - HighInsn = (HighInsn & 0xf800) | ((Value >> 12) & 0x7ff); - - uint16_t LowInsn = readBytesUnaligned(LocalAddress + 2, 2); - assert((LowInsn & 0xf800) == 0xf800 && - "Unrecognized thumb branch encoding (BR22 low bits)"); - LowInsn = (LowInsn & 0xf800) | ((Value >> 1) & 0x7ff); - - writeBytesUnaligned(HighInsn, LocalAddress, 2); - writeBytesUnaligned(LowInsn, LocalAddress + 2, 2); - break; - } - - case MachO::ARM_RELOC_VANILLA: - if (RE.IsTargetThumbFunc) - Value |= 0x01; - writeBytesUnaligned(Value + RE.Addend, LocalAddress, 1 << RE.Size); - break; - case MachO::ARM_RELOC_BR24: { - // Mask the value into the target address. We know instructions are - // 32-bit aligned, so we can do it all at once. - Value += RE.Addend; - // The low two bits of the value are not encoded. - Value >>= 2; - // Mask the value to 24 bits. - uint64_t FinalValue = Value & 0xffffff; - // FIXME: If the destination is a Thumb function (and the instruction - // is a non-predicated BL instruction), we need to change it to a BLX - // instruction instead. - - // Insert the value into the instruction. - uint32_t Temp = readBytesUnaligned(LocalAddress, 4); - writeBytesUnaligned((Temp & ~0xffffff) | FinalValue, LocalAddress, 4); - - break; - } - case MachO::ARM_RELOC_HALF_SECTDIFF: { - uint64_t SectionABase = Sections[RE.Sections.SectionA].getLoadAddress(); - uint64_t SectionBBase = Sections[RE.Sections.SectionB].getLoadAddress(); - assert((Value == SectionABase || Value == SectionBBase) && - "Unexpected HALFSECTDIFF relocation value."); - Value = SectionABase - SectionBBase + RE.Addend; - if (RE.Size & 0x1) // :upper16: - Value = (Value >> 16); - - bool IsThumb = RE.Size & 0x2; - - Value &= 0xffff; - - uint32_t Insn = readBytesUnaligned(LocalAddress, 4); - - if (IsThumb) - Insn = (Insn & 0x8f00fbf0) | ((Value & 0xf000) >> 12) | - ((Value & 0x0800) >> 1) | ((Value & 0x0700) << 20) | - ((Value & 0x00ff) << 16); - else - Insn = (Insn & 0xfff0f000) | ((Value & 0xf000) << 4) | (Value & 0x0fff); - writeBytesUnaligned(Insn, LocalAddress, 4); - break; - } - - default: - llvm_unreachable("Invalid relocation type"); - } - } - - Error finalizeSection(const ObjectFile &Obj, unsigned SectionID, - const SectionRef &Section) { - StringRef Name; - if (Expected<StringRef> NameOrErr = Section.getName()) - Name = *NameOrErr; - else - consumeError(NameOrErr.takeError()); - - if (Name == "__nl_symbol_ptr") - return populateIndirectSymbolPointersSection(cast<MachOObjectFile>(Obj), - Section, SectionID); - return Error::success(); - } - -private: - - void processBranchRelocation(const RelocationEntry &RE, - const RelocationValueRef &Value, - StubMap &Stubs) { - // This is an ARM branch relocation, need to use a stub function. - // Look up for existing stub. - SectionEntry &Section = Sections[RE.SectionID]; - RuntimeDyldMachO::StubMap::const_iterator i = Stubs.find(Value); - uint8_t *Addr; - if (i != Stubs.end()) { - Addr = Section.getAddressWithOffset(i->second); - } else { - // Create a new stub function. - assert(Section.getStubOffset() % 4 == 0 && "Misaligned stub"); - Stubs[Value] = Section.getStubOffset(); - uint32_t StubOpcode = 0; - if (RE.RelType == MachO::ARM_RELOC_BR24) - StubOpcode = 0xe51ff004; // ldr pc, [pc, #-4] - else if (RE.RelType == MachO::ARM_THUMB_RELOC_BR22) - StubOpcode = 0xf000f8df; // ldr pc, [pc] - else - llvm_unreachable("Unrecognized relocation"); - Addr = Section.getAddressWithOffset(Section.getStubOffset()); - writeBytesUnaligned(StubOpcode, Addr, 4); - uint8_t *StubTargetAddr = Addr + 4; - RelocationEntry StubRE( - RE.SectionID, StubTargetAddr - Section.getAddress(), - MachO::GENERIC_RELOC_VANILLA, Value.Offset, false, 2); - StubRE.IsTargetThumbFunc = RE.IsTargetThumbFunc; - if (Value.SymbolName) - addRelocationForSymbol(StubRE, Value.SymbolName); - else - addRelocationForSection(StubRE, Value.SectionID); - Section.advanceStubOffset(getMaxStubSize()); - } - RelocationEntry TargetRE(RE.SectionID, RE.Offset, RE.RelType, 0, - RE.IsPCRel, RE.Size); - resolveRelocation(TargetRE, (uint64_t)Addr); - } - - Expected<relocation_iterator> - processHALFSECTDIFFRelocation(unsigned SectionID, relocation_iterator RelI, - const ObjectFile &BaseTObj, - ObjSectionToIDMap &ObjSectionToID) { - const MachOObjectFile &MachO = - static_cast<const MachOObjectFile&>(BaseTObj); - MachO::any_relocation_info RE = - MachO.getRelocation(RelI->getRawDataRefImpl()); - - // For a half-diff relocation the length bits actually record whether this - // is a movw/movt, and whether this is arm or thumb. - // Bit 0 indicates movw (b0 == 0) or movt (b0 == 1). - // Bit 1 indicates arm (b1 == 0) or thumb (b1 == 1). - unsigned HalfDiffKindBits = MachO.getAnyRelocationLength(RE); - bool IsThumb = HalfDiffKindBits & 0x2; - - SectionEntry &Section = Sections[SectionID]; - uint32_t RelocType = MachO.getAnyRelocationType(RE); - bool IsPCRel = MachO.getAnyRelocationPCRel(RE); - uint64_t Offset = RelI->getOffset(); - uint8_t *LocalAddress = Section.getAddressWithOffset(Offset); - int64_t Immediate = readBytesUnaligned(LocalAddress, 4); // Copy the whole instruction out. - - if (IsThumb) - Immediate = ((Immediate & 0x0000000f) << 12) | - ((Immediate & 0x00000400) << 1) | - ((Immediate & 0x70000000) >> 20) | - ((Immediate & 0x00ff0000) >> 16); - else - Immediate = ((Immediate >> 4) & 0xf000) | (Immediate & 0xfff); - - ++RelI; - MachO::any_relocation_info RE2 = - MachO.getRelocation(RelI->getRawDataRefImpl()); - uint32_t AddrA = MachO.getScatteredRelocationValue(RE); - section_iterator SAI = getSectionByAddress(MachO, AddrA); - assert(SAI != MachO.section_end() && "Can't find section for address A"); - uint64_t SectionABase = SAI->getAddress(); - uint64_t SectionAOffset = AddrA - SectionABase; - SectionRef SectionA = *SAI; - bool IsCode = SectionA.isText(); - uint32_t SectionAID = ~0U; - if (auto SectionAIDOrErr = - findOrEmitSection(MachO, SectionA, IsCode, ObjSectionToID)) - SectionAID = *SectionAIDOrErr; - else - return SectionAIDOrErr.takeError(); - - uint32_t AddrB = MachO.getScatteredRelocationValue(RE2); - section_iterator SBI = getSectionByAddress(MachO, AddrB); - assert(SBI != MachO.section_end() && "Can't find section for address B"); - uint64_t SectionBBase = SBI->getAddress(); - uint64_t SectionBOffset = AddrB - SectionBBase; - SectionRef SectionB = *SBI; - uint32_t SectionBID = ~0U; - if (auto SectionBIDOrErr = - findOrEmitSection(MachO, SectionB, IsCode, ObjSectionToID)) - SectionBID = *SectionBIDOrErr; - else - return SectionBIDOrErr.takeError(); - - uint32_t OtherHalf = MachO.getAnyRelocationAddress(RE2) & 0xffff; - unsigned Shift = (HalfDiffKindBits & 0x1) ? 16 : 0; - uint32_t FullImmVal = (Immediate << Shift) | (OtherHalf << (16 - Shift)); - int64_t Addend = FullImmVal - (AddrA - AddrB); - - // addend = Encoded - Expected - // = Encoded - (AddrA - AddrB) - - LLVM_DEBUG(dbgs() << "Found SECTDIFF: AddrA: " << AddrA - << ", AddrB: " << AddrB << ", Addend: " << Addend - << ", SectionA ID: " << SectionAID << ", SectionAOffset: " - << SectionAOffset << ", SectionB ID: " << SectionBID - << ", SectionBOffset: " << SectionBOffset << "\n"); - RelocationEntry R(SectionID, Offset, RelocType, Addend, SectionAID, - SectionAOffset, SectionBID, SectionBOffset, IsPCRel, - HalfDiffKindBits); - - addRelocationForSection(R, SectionAID); - - return ++RelI; - } - -}; -} - -#undef DEBUG_TYPE - -#endif +//===----- RuntimeDyldMachOARM.h ---- MachO/ARM specific code. ----*- C++ -*-=// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDMACHOARM_H +#define LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDMACHOARM_H + +#include "../RuntimeDyldMachO.h" +#include <string> + +#define DEBUG_TYPE "dyld" + +namespace llvm { + +class RuntimeDyldMachOARM + : public RuntimeDyldMachOCRTPBase<RuntimeDyldMachOARM> { +private: + typedef RuntimeDyldMachOCRTPBase<RuntimeDyldMachOARM> ParentT; + +public: + + typedef uint32_t TargetPtrT; + + RuntimeDyldMachOARM(RuntimeDyld::MemoryManager &MM, + JITSymbolResolver &Resolver) + : RuntimeDyldMachOCRTPBase(MM, Resolver) {} + + unsigned getMaxStubSize() const override { return 8; } + + unsigned getStubAlignment() override { return 4; } + + Expected<JITSymbolFlags> getJITSymbolFlags(const SymbolRef &SR) override { + auto Flags = RuntimeDyldImpl::getJITSymbolFlags(SR); + if (!Flags) + return Flags.takeError(); + Flags->getTargetFlags() = ARMJITSymbolFlags::fromObjectSymbol(SR); + return Flags; + } + + uint64_t modifyAddressBasedOnFlags(uint64_t Addr, + JITSymbolFlags Flags) const override { + if (Flags.getTargetFlags() & ARMJITSymbolFlags::Thumb) + Addr |= 0x1; + return Addr; + } + + bool isAddrTargetThumb(unsigned SectionID, uint64_t Offset) { + auto TargetObjAddr = Sections[SectionID].getObjAddress() + Offset; + for (auto &KV : GlobalSymbolTable) { + auto &Entry = KV.second; + auto SymbolObjAddr = + Sections[Entry.getSectionID()].getObjAddress() + Entry.getOffset(); + if (TargetObjAddr == SymbolObjAddr) + return (Entry.getFlags().getTargetFlags() & ARMJITSymbolFlags::Thumb); + } + return false; + } + + Expected<int64_t> decodeAddend(const RelocationEntry &RE) const { + const SectionEntry &Section = Sections[RE.SectionID]; + uint8_t *LocalAddress = Section.getAddressWithOffset(RE.Offset); + + switch (RE.RelType) { + default: + return memcpyAddend(RE); + case MachO::ARM_RELOC_BR24: { + uint32_t Temp = readBytesUnaligned(LocalAddress, 4); + Temp &= 0x00ffffff; // Mask out the opcode. + // Now we've got the shifted immediate, shift by 2, sign extend and ret. + return SignExtend32<26>(Temp << 2); + } + + case MachO::ARM_THUMB_RELOC_BR22: { + // This is a pair of instructions whose operands combine to provide 22 + // bits of displacement: + // Encoding for high bits 1111 0XXX XXXX XXXX + // Encoding for low bits 1111 1XXX XXXX XXXX + uint16_t HighInsn = readBytesUnaligned(LocalAddress, 2); + if ((HighInsn & 0xf800) != 0xf000) + return make_error<StringError>("Unrecognized thumb branch encoding " + "(BR22 high bits)", + inconvertibleErrorCode()); + + uint16_t LowInsn = readBytesUnaligned(LocalAddress + 2, 2); + if ((LowInsn & 0xf800) != 0xf800) + return make_error<StringError>("Unrecognized thumb branch encoding " + "(BR22 low bits)", + inconvertibleErrorCode()); + + return SignExtend64<23>(((HighInsn & 0x7ff) << 12) | + ((LowInsn & 0x7ff) << 1)); + } + } + } + + Expected<relocation_iterator> + processRelocationRef(unsigned SectionID, relocation_iterator RelI, + const ObjectFile &BaseObjT, + ObjSectionToIDMap &ObjSectionToID, + StubMap &Stubs) override { + const MachOObjectFile &Obj = + static_cast<const MachOObjectFile &>(BaseObjT); + MachO::any_relocation_info RelInfo = + Obj.getRelocation(RelI->getRawDataRefImpl()); + uint32_t RelType = Obj.getAnyRelocationType(RelInfo); + + // Set to true for thumb functions in this (or previous) TUs. + // Will be used to set the TargetIsThumbFunc member on the relocation entry. + bool TargetIsLocalThumbFunc = false; + if (Obj.getPlainRelocationExternal(RelInfo)) { + auto Symbol = RelI->getSymbol(); + StringRef TargetName; + if (auto TargetNameOrErr = Symbol->getName()) + TargetName = *TargetNameOrErr; + else + return TargetNameOrErr.takeError(); + + // If the target is external but the value doesn't have a name then we've + // converted the value to a section/offset pair, but we still need to set + // the IsTargetThumbFunc bit, so look the value up in the globla symbol table. + auto EntryItr = GlobalSymbolTable.find(TargetName); + if (EntryItr != GlobalSymbolTable.end()) { + TargetIsLocalThumbFunc = + EntryItr->second.getFlags().getTargetFlags() & + ARMJITSymbolFlags::Thumb; + } + } + + if (Obj.isRelocationScattered(RelInfo)) { + if (RelType == MachO::ARM_RELOC_HALF_SECTDIFF) + return processHALFSECTDIFFRelocation(SectionID, RelI, Obj, + ObjSectionToID); + else if (RelType == MachO::GENERIC_RELOC_VANILLA) + return processScatteredVANILLA(SectionID, RelI, Obj, ObjSectionToID, + TargetIsLocalThumbFunc); + else + return ++RelI; + } + + // Sanity check relocation type. + switch (RelType) { + UNIMPLEMENTED_RELOC(MachO::ARM_RELOC_PAIR); + UNIMPLEMENTED_RELOC(MachO::ARM_RELOC_SECTDIFF); + UNIMPLEMENTED_RELOC(MachO::ARM_RELOC_LOCAL_SECTDIFF); + UNIMPLEMENTED_RELOC(MachO::ARM_RELOC_PB_LA_PTR); + UNIMPLEMENTED_RELOC(MachO::ARM_THUMB_32BIT_BRANCH); + UNIMPLEMENTED_RELOC(MachO::ARM_RELOC_HALF); + default: + if (RelType > MachO::ARM_RELOC_HALF_SECTDIFF) + return make_error<RuntimeDyldError>(("MachO ARM relocation type " + + Twine(RelType) + + " is out of range").str()); + break; + } + + RelocationEntry RE(getRelocationEntry(SectionID, Obj, RelI)); + if (auto AddendOrErr = decodeAddend(RE)) + RE.Addend = *AddendOrErr; + else + return AddendOrErr.takeError(); + RE.IsTargetThumbFunc = TargetIsLocalThumbFunc; + + RelocationValueRef Value; + if (auto ValueOrErr = getRelocationValueRef(Obj, RelI, RE, ObjSectionToID)) + Value = *ValueOrErr; + else + return ValueOrErr.takeError(); + + // If this is a branch from a thumb function (BR22) then make sure we mark + // the value as being a thumb stub: we don't want to mix it up with an ARM + // stub targeting the same function. + if (RE.RelType == MachO::ARM_THUMB_RELOC_BR22) + Value.IsStubThumb = true; + + if (RE.IsPCRel) + makeValueAddendPCRel(Value, RelI, + (RE.RelType == MachO::ARM_THUMB_RELOC_BR22) ? 4 : 8); + + // If this is a non-external branch target check whether Value points to a + // thumb func. + if (!Value.SymbolName && (RelType == MachO::ARM_RELOC_BR24 || + RelType == MachO::ARM_THUMB_RELOC_BR22)) + RE.IsTargetThumbFunc = isAddrTargetThumb(Value.SectionID, Value.Offset); + + if (RE.RelType == MachO::ARM_RELOC_BR24 || + RE.RelType == MachO::ARM_THUMB_RELOC_BR22) + processBranchRelocation(RE, Value, Stubs); + else { + RE.Addend = Value.Offset; + if (Value.SymbolName) + addRelocationForSymbol(RE, Value.SymbolName); + else + addRelocationForSection(RE, Value.SectionID); + } + + return ++RelI; + } + + void resolveRelocation(const RelocationEntry &RE, uint64_t Value) override { + LLVM_DEBUG(dumpRelocationToResolve(RE, Value)); + const SectionEntry &Section = Sections[RE.SectionID]; + uint8_t *LocalAddress = Section.getAddressWithOffset(RE.Offset); + + // If the relocation is PC-relative, the value to be encoded is the + // pointer difference. + if (RE.IsPCRel) { + uint64_t FinalAddress = Section.getLoadAddressWithOffset(RE.Offset); + Value -= FinalAddress; + // ARM PCRel relocations have an effective-PC offset of two instructions + // (four bytes in Thumb mode, 8 bytes in ARM mode). + Value -= (RE.RelType == MachO::ARM_THUMB_RELOC_BR22) ? 4 : 8; + } + + switch (RE.RelType) { + case MachO::ARM_THUMB_RELOC_BR22: { + Value += RE.Addend; + uint16_t HighInsn = readBytesUnaligned(LocalAddress, 2); + assert((HighInsn & 0xf800) == 0xf000 && + "Unrecognized thumb branch encoding (BR22 high bits)"); + HighInsn = (HighInsn & 0xf800) | ((Value >> 12) & 0x7ff); + + uint16_t LowInsn = readBytesUnaligned(LocalAddress + 2, 2); + assert((LowInsn & 0xf800) == 0xf800 && + "Unrecognized thumb branch encoding (BR22 low bits)"); + LowInsn = (LowInsn & 0xf800) | ((Value >> 1) & 0x7ff); + + writeBytesUnaligned(HighInsn, LocalAddress, 2); + writeBytesUnaligned(LowInsn, LocalAddress + 2, 2); + break; + } + + case MachO::ARM_RELOC_VANILLA: + if (RE.IsTargetThumbFunc) + Value |= 0x01; + writeBytesUnaligned(Value + RE.Addend, LocalAddress, 1 << RE.Size); + break; + case MachO::ARM_RELOC_BR24: { + // Mask the value into the target address. We know instructions are + // 32-bit aligned, so we can do it all at once. + Value += RE.Addend; + // The low two bits of the value are not encoded. + Value >>= 2; + // Mask the value to 24 bits. + uint64_t FinalValue = Value & 0xffffff; + // FIXME: If the destination is a Thumb function (and the instruction + // is a non-predicated BL instruction), we need to change it to a BLX + // instruction instead. + + // Insert the value into the instruction. + uint32_t Temp = readBytesUnaligned(LocalAddress, 4); + writeBytesUnaligned((Temp & ~0xffffff) | FinalValue, LocalAddress, 4); + + break; + } + case MachO::ARM_RELOC_HALF_SECTDIFF: { + uint64_t SectionABase = Sections[RE.Sections.SectionA].getLoadAddress(); + uint64_t SectionBBase = Sections[RE.Sections.SectionB].getLoadAddress(); + assert((Value == SectionABase || Value == SectionBBase) && + "Unexpected HALFSECTDIFF relocation value."); + Value = SectionABase - SectionBBase + RE.Addend; + if (RE.Size & 0x1) // :upper16: + Value = (Value >> 16); + + bool IsThumb = RE.Size & 0x2; + + Value &= 0xffff; + + uint32_t Insn = readBytesUnaligned(LocalAddress, 4); + + if (IsThumb) + Insn = (Insn & 0x8f00fbf0) | ((Value & 0xf000) >> 12) | + ((Value & 0x0800) >> 1) | ((Value & 0x0700) << 20) | + ((Value & 0x00ff) << 16); + else + Insn = (Insn & 0xfff0f000) | ((Value & 0xf000) << 4) | (Value & 0x0fff); + writeBytesUnaligned(Insn, LocalAddress, 4); + break; + } + + default: + llvm_unreachable("Invalid relocation type"); + } + } + + Error finalizeSection(const ObjectFile &Obj, unsigned SectionID, + const SectionRef &Section) { + StringRef Name; + if (Expected<StringRef> NameOrErr = Section.getName()) + Name = *NameOrErr; + else + consumeError(NameOrErr.takeError()); + + if (Name == "__nl_symbol_ptr") + return populateIndirectSymbolPointersSection(cast<MachOObjectFile>(Obj), + Section, SectionID); + return Error::success(); + } + +private: + + void processBranchRelocation(const RelocationEntry &RE, + const RelocationValueRef &Value, + StubMap &Stubs) { + // This is an ARM branch relocation, need to use a stub function. + // Look up for existing stub. + SectionEntry &Section = Sections[RE.SectionID]; + RuntimeDyldMachO::StubMap::const_iterator i = Stubs.find(Value); + uint8_t *Addr; + if (i != Stubs.end()) { + Addr = Section.getAddressWithOffset(i->second); + } else { + // Create a new stub function. + assert(Section.getStubOffset() % 4 == 0 && "Misaligned stub"); + Stubs[Value] = Section.getStubOffset(); + uint32_t StubOpcode = 0; + if (RE.RelType == MachO::ARM_RELOC_BR24) + StubOpcode = 0xe51ff004; // ldr pc, [pc, #-4] + else if (RE.RelType == MachO::ARM_THUMB_RELOC_BR22) + StubOpcode = 0xf000f8df; // ldr pc, [pc] + else + llvm_unreachable("Unrecognized relocation"); + Addr = Section.getAddressWithOffset(Section.getStubOffset()); + writeBytesUnaligned(StubOpcode, Addr, 4); + uint8_t *StubTargetAddr = Addr + 4; + RelocationEntry StubRE( + RE.SectionID, StubTargetAddr - Section.getAddress(), + MachO::GENERIC_RELOC_VANILLA, Value.Offset, false, 2); + StubRE.IsTargetThumbFunc = RE.IsTargetThumbFunc; + if (Value.SymbolName) + addRelocationForSymbol(StubRE, Value.SymbolName); + else + addRelocationForSection(StubRE, Value.SectionID); + Section.advanceStubOffset(getMaxStubSize()); + } + RelocationEntry TargetRE(RE.SectionID, RE.Offset, RE.RelType, 0, + RE.IsPCRel, RE.Size); + resolveRelocation(TargetRE, (uint64_t)Addr); + } + + Expected<relocation_iterator> + processHALFSECTDIFFRelocation(unsigned SectionID, relocation_iterator RelI, + const ObjectFile &BaseTObj, + ObjSectionToIDMap &ObjSectionToID) { + const MachOObjectFile &MachO = + static_cast<const MachOObjectFile&>(BaseTObj); + MachO::any_relocation_info RE = + MachO.getRelocation(RelI->getRawDataRefImpl()); + + // For a half-diff relocation the length bits actually record whether this + // is a movw/movt, and whether this is arm or thumb. + // Bit 0 indicates movw (b0 == 0) or movt (b0 == 1). + // Bit 1 indicates arm (b1 == 0) or thumb (b1 == 1). + unsigned HalfDiffKindBits = MachO.getAnyRelocationLength(RE); + bool IsThumb = HalfDiffKindBits & 0x2; + + SectionEntry &Section = Sections[SectionID]; + uint32_t RelocType = MachO.getAnyRelocationType(RE); + bool IsPCRel = MachO.getAnyRelocationPCRel(RE); + uint64_t Offset = RelI->getOffset(); + uint8_t *LocalAddress = Section.getAddressWithOffset(Offset); + int64_t Immediate = readBytesUnaligned(LocalAddress, 4); // Copy the whole instruction out. + + if (IsThumb) + Immediate = ((Immediate & 0x0000000f) << 12) | + ((Immediate & 0x00000400) << 1) | + ((Immediate & 0x70000000) >> 20) | + ((Immediate & 0x00ff0000) >> 16); + else + Immediate = ((Immediate >> 4) & 0xf000) | (Immediate & 0xfff); + + ++RelI; + MachO::any_relocation_info RE2 = + MachO.getRelocation(RelI->getRawDataRefImpl()); + uint32_t AddrA = MachO.getScatteredRelocationValue(RE); + section_iterator SAI = getSectionByAddress(MachO, AddrA); + assert(SAI != MachO.section_end() && "Can't find section for address A"); + uint64_t SectionABase = SAI->getAddress(); + uint64_t SectionAOffset = AddrA - SectionABase; + SectionRef SectionA = *SAI; + bool IsCode = SectionA.isText(); + uint32_t SectionAID = ~0U; + if (auto SectionAIDOrErr = + findOrEmitSection(MachO, SectionA, IsCode, ObjSectionToID)) + SectionAID = *SectionAIDOrErr; + else + return SectionAIDOrErr.takeError(); + + uint32_t AddrB = MachO.getScatteredRelocationValue(RE2); + section_iterator SBI = getSectionByAddress(MachO, AddrB); + assert(SBI != MachO.section_end() && "Can't find section for address B"); + uint64_t SectionBBase = SBI->getAddress(); + uint64_t SectionBOffset = AddrB - SectionBBase; + SectionRef SectionB = *SBI; + uint32_t SectionBID = ~0U; + if (auto SectionBIDOrErr = + findOrEmitSection(MachO, SectionB, IsCode, ObjSectionToID)) + SectionBID = *SectionBIDOrErr; + else + return SectionBIDOrErr.takeError(); + + uint32_t OtherHalf = MachO.getAnyRelocationAddress(RE2) & 0xffff; + unsigned Shift = (HalfDiffKindBits & 0x1) ? 16 : 0; + uint32_t FullImmVal = (Immediate << Shift) | (OtherHalf << (16 - Shift)); + int64_t Addend = FullImmVal - (AddrA - AddrB); + + // addend = Encoded - Expected + // = Encoded - (AddrA - AddrB) + + LLVM_DEBUG(dbgs() << "Found SECTDIFF: AddrA: " << AddrA + << ", AddrB: " << AddrB << ", Addend: " << Addend + << ", SectionA ID: " << SectionAID << ", SectionAOffset: " + << SectionAOffset << ", SectionB ID: " << SectionBID + << ", SectionBOffset: " << SectionBOffset << "\n"); + RelocationEntry R(SectionID, Offset, RelocType, Addend, SectionAID, + SectionAOffset, SectionBID, SectionBOffset, IsPCRel, + HalfDiffKindBits); + + addRelocationForSection(R, SectionAID); + + return ++RelI; + } + +}; +} + +#undef DEBUG_TYPE + +#endif diff --git a/contrib/libs/llvm12/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOI386.h b/contrib/libs/llvm12/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOI386.h index 7c3ab7cf1a..523deb29b7 100644 --- a/contrib/libs/llvm12/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOI386.h +++ b/contrib/libs/llvm12/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOI386.h @@ -1,251 +1,251 @@ -//===---- RuntimeDyldMachOI386.h ---- MachO/I386 specific code. ---*- C++ -*-=// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDMACHOI386_H -#define LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDMACHOI386_H - -#include "../RuntimeDyldMachO.h" -#include <string> - -#define DEBUG_TYPE "dyld" - -namespace llvm { - -class RuntimeDyldMachOI386 - : public RuntimeDyldMachOCRTPBase<RuntimeDyldMachOI386> { -public: - - typedef uint32_t TargetPtrT; - - RuntimeDyldMachOI386(RuntimeDyld::MemoryManager &MM, - JITSymbolResolver &Resolver) - : RuntimeDyldMachOCRTPBase(MM, Resolver) {} - - unsigned getMaxStubSize() const override { return 0; } - - unsigned getStubAlignment() override { return 1; } - - Expected<relocation_iterator> - processRelocationRef(unsigned SectionID, relocation_iterator RelI, - const ObjectFile &BaseObjT, - ObjSectionToIDMap &ObjSectionToID, - StubMap &Stubs) override { - const MachOObjectFile &Obj = - static_cast<const MachOObjectFile &>(BaseObjT); - MachO::any_relocation_info RelInfo = - Obj.getRelocation(RelI->getRawDataRefImpl()); - uint32_t RelType = Obj.getAnyRelocationType(RelInfo); - - if (Obj.isRelocationScattered(RelInfo)) { - if (RelType == MachO::GENERIC_RELOC_SECTDIFF || - RelType == MachO::GENERIC_RELOC_LOCAL_SECTDIFF) - return processSECTDIFFRelocation(SectionID, RelI, Obj, - ObjSectionToID); - else if (RelType == MachO::GENERIC_RELOC_VANILLA) - return processScatteredVANILLA(SectionID, RelI, Obj, ObjSectionToID); - return make_error<RuntimeDyldError>(("Unhandled I386 scattered relocation " - "type: " + Twine(RelType)).str()); - } - - switch (RelType) { - UNIMPLEMENTED_RELOC(MachO::GENERIC_RELOC_PAIR); - UNIMPLEMENTED_RELOC(MachO::GENERIC_RELOC_PB_LA_PTR); - UNIMPLEMENTED_RELOC(MachO::GENERIC_RELOC_TLV); - default: - if (RelType > MachO::GENERIC_RELOC_TLV) - return make_error<RuntimeDyldError>(("MachO I386 relocation type " + - Twine(RelType) + - " is out of range").str()); - break; - } - - RelocationEntry RE(getRelocationEntry(SectionID, Obj, RelI)); - RE.Addend = memcpyAddend(RE); - RelocationValueRef Value; - if (auto ValueOrErr = getRelocationValueRef(Obj, RelI, RE, ObjSectionToID)) - Value = *ValueOrErr; - else - return ValueOrErr.takeError(); - - // Addends for external, PC-rel relocations on i386 point back to the zero - // offset. Calculate the final offset from the relocation target instead. - // This allows us to use the same logic for both external and internal - // relocations in resolveI386RelocationRef. - // bool IsExtern = Obj.getPlainRelocationExternal(RelInfo); - // if (IsExtern && RE.IsPCRel) { - // uint64_t RelocAddr = 0; - // RelI->getAddress(RelocAddr); - // Value.Addend += RelocAddr + 4; - // } - if (RE.IsPCRel) - makeValueAddendPCRel(Value, RelI, 1 << RE.Size); - - RE.Addend = Value.Offset; - - if (Value.SymbolName) - addRelocationForSymbol(RE, Value.SymbolName); - else - addRelocationForSection(RE, Value.SectionID); - - return ++RelI; - } - - void resolveRelocation(const RelocationEntry &RE, uint64_t Value) override { - LLVM_DEBUG(dumpRelocationToResolve(RE, Value)); - - const SectionEntry &Section = Sections[RE.SectionID]; - uint8_t *LocalAddress = Section.getAddressWithOffset(RE.Offset); - - if (RE.IsPCRel) { - uint64_t FinalAddress = Section.getLoadAddressWithOffset(RE.Offset); - Value -= FinalAddress + 4; // see MachOX86_64::resolveRelocation. - } - - switch (RE.RelType) { - case MachO::GENERIC_RELOC_VANILLA: - writeBytesUnaligned(Value + RE.Addend, LocalAddress, 1 << RE.Size); - break; - case MachO::GENERIC_RELOC_SECTDIFF: - case MachO::GENERIC_RELOC_LOCAL_SECTDIFF: { - uint64_t SectionABase = Sections[RE.Sections.SectionA].getLoadAddress(); - uint64_t SectionBBase = Sections[RE.Sections.SectionB].getLoadAddress(); - assert((Value == SectionABase || Value == SectionBBase) && - "Unexpected SECTDIFF relocation value."); - Value = SectionABase - SectionBBase + RE.Addend; - writeBytesUnaligned(Value, LocalAddress, 1 << RE.Size); - break; - } - default: - llvm_unreachable("Invalid relocation type!"); - } - } - - Error finalizeSection(const ObjectFile &Obj, unsigned SectionID, - const SectionRef &Section) { - StringRef Name; - if (Expected<StringRef> NameOrErr = Section.getName()) - Name = *NameOrErr; - else - consumeError(NameOrErr.takeError()); - - if (Name == "__jump_table") - return populateJumpTable(cast<MachOObjectFile>(Obj), Section, SectionID); - else if (Name == "__pointers") - return populateIndirectSymbolPointersSection(cast<MachOObjectFile>(Obj), - Section, SectionID); - return Error::success(); - } - -private: - Expected<relocation_iterator> - processSECTDIFFRelocation(unsigned SectionID, relocation_iterator RelI, - const ObjectFile &BaseObjT, - ObjSectionToIDMap &ObjSectionToID) { - const MachOObjectFile &Obj = - static_cast<const MachOObjectFile&>(BaseObjT); - MachO::any_relocation_info RE = - Obj.getRelocation(RelI->getRawDataRefImpl()); - - SectionEntry &Section = Sections[SectionID]; - uint32_t RelocType = Obj.getAnyRelocationType(RE); - bool IsPCRel = Obj.getAnyRelocationPCRel(RE); - unsigned Size = Obj.getAnyRelocationLength(RE); - uint64_t Offset = RelI->getOffset(); - uint8_t *LocalAddress = Section.getAddressWithOffset(Offset); - unsigned NumBytes = 1 << Size; - uint64_t Addend = readBytesUnaligned(LocalAddress, NumBytes); - - ++RelI; - MachO::any_relocation_info RE2 = - Obj.getRelocation(RelI->getRawDataRefImpl()); - - uint32_t AddrA = Obj.getScatteredRelocationValue(RE); - section_iterator SAI = getSectionByAddress(Obj, AddrA); - assert(SAI != Obj.section_end() && "Can't find section for address A"); - uint64_t SectionABase = SAI->getAddress(); - uint64_t SectionAOffset = AddrA - SectionABase; - SectionRef SectionA = *SAI; - bool IsCode = SectionA.isText(); - uint32_t SectionAID = ~0U; - if (auto SectionAIDOrErr = - findOrEmitSection(Obj, SectionA, IsCode, ObjSectionToID)) - SectionAID = *SectionAIDOrErr; - else - return SectionAIDOrErr.takeError(); - - uint32_t AddrB = Obj.getScatteredRelocationValue(RE2); - section_iterator SBI = getSectionByAddress(Obj, AddrB); - assert(SBI != Obj.section_end() && "Can't find section for address B"); - uint64_t SectionBBase = SBI->getAddress(); - uint64_t SectionBOffset = AddrB - SectionBBase; - SectionRef SectionB = *SBI; - uint32_t SectionBID = ~0U; - if (auto SectionBIDOrErr = - findOrEmitSection(Obj, SectionB, IsCode, ObjSectionToID)) - SectionBID = *SectionBIDOrErr; - else - return SectionBIDOrErr.takeError(); - - // Compute the addend 'C' from the original expression 'A - B + C'. - Addend -= AddrA - AddrB; - - LLVM_DEBUG(dbgs() << "Found SECTDIFF: AddrA: " << AddrA - << ", AddrB: " << AddrB << ", Addend: " << Addend - << ", SectionA ID: " << SectionAID << ", SectionAOffset: " - << SectionAOffset << ", SectionB ID: " << SectionBID - << ", SectionBOffset: " << SectionBOffset << "\n"); - RelocationEntry R(SectionID, Offset, RelocType, Addend, SectionAID, - SectionAOffset, SectionBID, SectionBOffset, - IsPCRel, Size); - - addRelocationForSection(R, SectionAID); - - return ++RelI; - } - - // Populate stubs in __jump_table section. - Error populateJumpTable(const MachOObjectFile &Obj, - const SectionRef &JTSection, - unsigned JTSectionID) { - MachO::dysymtab_command DySymTabCmd = Obj.getDysymtabLoadCommand(); - MachO::section Sec32 = Obj.getSection(JTSection.getRawDataRefImpl()); - uint32_t JTSectionSize = Sec32.size; - unsigned FirstIndirectSymbol = Sec32.reserved1; - unsigned JTEntrySize = Sec32.reserved2; - unsigned NumJTEntries = JTSectionSize / JTEntrySize; - uint8_t *JTSectionAddr = getSectionAddress(JTSectionID); - unsigned JTEntryOffset = 0; - - if (JTSectionSize % JTEntrySize != 0) - return make_error<RuntimeDyldError>("Jump-table section does not contain " - "a whole number of stubs?"); - - for (unsigned i = 0; i < NumJTEntries; ++i) { - unsigned SymbolIndex = - Obj.getIndirectSymbolTableEntry(DySymTabCmd, FirstIndirectSymbol + i); - symbol_iterator SI = Obj.getSymbolByIndex(SymbolIndex); - Expected<StringRef> IndirectSymbolName = SI->getName(); - if (!IndirectSymbolName) - return IndirectSymbolName.takeError(); - uint8_t *JTEntryAddr = JTSectionAddr + JTEntryOffset; - createStubFunction(JTEntryAddr); - RelocationEntry RE(JTSectionID, JTEntryOffset + 1, - MachO::GENERIC_RELOC_VANILLA, 0, true, 2); - addRelocationForSymbol(RE, *IndirectSymbolName); - JTEntryOffset += JTEntrySize; - } - - return Error::success(); - } - -}; -} - -#undef DEBUG_TYPE - -#endif +//===---- RuntimeDyldMachOI386.h ---- MachO/I386 specific code. ---*- C++ -*-=// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDMACHOI386_H +#define LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDMACHOI386_H + +#include "../RuntimeDyldMachO.h" +#include <string> + +#define DEBUG_TYPE "dyld" + +namespace llvm { + +class RuntimeDyldMachOI386 + : public RuntimeDyldMachOCRTPBase<RuntimeDyldMachOI386> { +public: + + typedef uint32_t TargetPtrT; + + RuntimeDyldMachOI386(RuntimeDyld::MemoryManager &MM, + JITSymbolResolver &Resolver) + : RuntimeDyldMachOCRTPBase(MM, Resolver) {} + + unsigned getMaxStubSize() const override { return 0; } + + unsigned getStubAlignment() override { return 1; } + + Expected<relocation_iterator> + processRelocationRef(unsigned SectionID, relocation_iterator RelI, + const ObjectFile &BaseObjT, + ObjSectionToIDMap &ObjSectionToID, + StubMap &Stubs) override { + const MachOObjectFile &Obj = + static_cast<const MachOObjectFile &>(BaseObjT); + MachO::any_relocation_info RelInfo = + Obj.getRelocation(RelI->getRawDataRefImpl()); + uint32_t RelType = Obj.getAnyRelocationType(RelInfo); + + if (Obj.isRelocationScattered(RelInfo)) { + if (RelType == MachO::GENERIC_RELOC_SECTDIFF || + RelType == MachO::GENERIC_RELOC_LOCAL_SECTDIFF) + return processSECTDIFFRelocation(SectionID, RelI, Obj, + ObjSectionToID); + else if (RelType == MachO::GENERIC_RELOC_VANILLA) + return processScatteredVANILLA(SectionID, RelI, Obj, ObjSectionToID); + return make_error<RuntimeDyldError>(("Unhandled I386 scattered relocation " + "type: " + Twine(RelType)).str()); + } + + switch (RelType) { + UNIMPLEMENTED_RELOC(MachO::GENERIC_RELOC_PAIR); + UNIMPLEMENTED_RELOC(MachO::GENERIC_RELOC_PB_LA_PTR); + UNIMPLEMENTED_RELOC(MachO::GENERIC_RELOC_TLV); + default: + if (RelType > MachO::GENERIC_RELOC_TLV) + return make_error<RuntimeDyldError>(("MachO I386 relocation type " + + Twine(RelType) + + " is out of range").str()); + break; + } + + RelocationEntry RE(getRelocationEntry(SectionID, Obj, RelI)); + RE.Addend = memcpyAddend(RE); + RelocationValueRef Value; + if (auto ValueOrErr = getRelocationValueRef(Obj, RelI, RE, ObjSectionToID)) + Value = *ValueOrErr; + else + return ValueOrErr.takeError(); + + // Addends for external, PC-rel relocations on i386 point back to the zero + // offset. Calculate the final offset from the relocation target instead. + // This allows us to use the same logic for both external and internal + // relocations in resolveI386RelocationRef. + // bool IsExtern = Obj.getPlainRelocationExternal(RelInfo); + // if (IsExtern && RE.IsPCRel) { + // uint64_t RelocAddr = 0; + // RelI->getAddress(RelocAddr); + // Value.Addend += RelocAddr + 4; + // } + if (RE.IsPCRel) + makeValueAddendPCRel(Value, RelI, 1 << RE.Size); + + RE.Addend = Value.Offset; + + if (Value.SymbolName) + addRelocationForSymbol(RE, Value.SymbolName); + else + addRelocationForSection(RE, Value.SectionID); + + return ++RelI; + } + + void resolveRelocation(const RelocationEntry &RE, uint64_t Value) override { + LLVM_DEBUG(dumpRelocationToResolve(RE, Value)); + + const SectionEntry &Section = Sections[RE.SectionID]; + uint8_t *LocalAddress = Section.getAddressWithOffset(RE.Offset); + + if (RE.IsPCRel) { + uint64_t FinalAddress = Section.getLoadAddressWithOffset(RE.Offset); + Value -= FinalAddress + 4; // see MachOX86_64::resolveRelocation. + } + + switch (RE.RelType) { + case MachO::GENERIC_RELOC_VANILLA: + writeBytesUnaligned(Value + RE.Addend, LocalAddress, 1 << RE.Size); + break; + case MachO::GENERIC_RELOC_SECTDIFF: + case MachO::GENERIC_RELOC_LOCAL_SECTDIFF: { + uint64_t SectionABase = Sections[RE.Sections.SectionA].getLoadAddress(); + uint64_t SectionBBase = Sections[RE.Sections.SectionB].getLoadAddress(); + assert((Value == SectionABase || Value == SectionBBase) && + "Unexpected SECTDIFF relocation value."); + Value = SectionABase - SectionBBase + RE.Addend; + writeBytesUnaligned(Value, LocalAddress, 1 << RE.Size); + break; + } + default: + llvm_unreachable("Invalid relocation type!"); + } + } + + Error finalizeSection(const ObjectFile &Obj, unsigned SectionID, + const SectionRef &Section) { + StringRef Name; + if (Expected<StringRef> NameOrErr = Section.getName()) + Name = *NameOrErr; + else + consumeError(NameOrErr.takeError()); + + if (Name == "__jump_table") + return populateJumpTable(cast<MachOObjectFile>(Obj), Section, SectionID); + else if (Name == "__pointers") + return populateIndirectSymbolPointersSection(cast<MachOObjectFile>(Obj), + Section, SectionID); + return Error::success(); + } + +private: + Expected<relocation_iterator> + processSECTDIFFRelocation(unsigned SectionID, relocation_iterator RelI, + const ObjectFile &BaseObjT, + ObjSectionToIDMap &ObjSectionToID) { + const MachOObjectFile &Obj = + static_cast<const MachOObjectFile&>(BaseObjT); + MachO::any_relocation_info RE = + Obj.getRelocation(RelI->getRawDataRefImpl()); + + SectionEntry &Section = Sections[SectionID]; + uint32_t RelocType = Obj.getAnyRelocationType(RE); + bool IsPCRel = Obj.getAnyRelocationPCRel(RE); + unsigned Size = Obj.getAnyRelocationLength(RE); + uint64_t Offset = RelI->getOffset(); + uint8_t *LocalAddress = Section.getAddressWithOffset(Offset); + unsigned NumBytes = 1 << Size; + uint64_t Addend = readBytesUnaligned(LocalAddress, NumBytes); + + ++RelI; + MachO::any_relocation_info RE2 = + Obj.getRelocation(RelI->getRawDataRefImpl()); + + uint32_t AddrA = Obj.getScatteredRelocationValue(RE); + section_iterator SAI = getSectionByAddress(Obj, AddrA); + assert(SAI != Obj.section_end() && "Can't find section for address A"); + uint64_t SectionABase = SAI->getAddress(); + uint64_t SectionAOffset = AddrA - SectionABase; + SectionRef SectionA = *SAI; + bool IsCode = SectionA.isText(); + uint32_t SectionAID = ~0U; + if (auto SectionAIDOrErr = + findOrEmitSection(Obj, SectionA, IsCode, ObjSectionToID)) + SectionAID = *SectionAIDOrErr; + else + return SectionAIDOrErr.takeError(); + + uint32_t AddrB = Obj.getScatteredRelocationValue(RE2); + section_iterator SBI = getSectionByAddress(Obj, AddrB); + assert(SBI != Obj.section_end() && "Can't find section for address B"); + uint64_t SectionBBase = SBI->getAddress(); + uint64_t SectionBOffset = AddrB - SectionBBase; + SectionRef SectionB = *SBI; + uint32_t SectionBID = ~0U; + if (auto SectionBIDOrErr = + findOrEmitSection(Obj, SectionB, IsCode, ObjSectionToID)) + SectionBID = *SectionBIDOrErr; + else + return SectionBIDOrErr.takeError(); + + // Compute the addend 'C' from the original expression 'A - B + C'. + Addend -= AddrA - AddrB; + + LLVM_DEBUG(dbgs() << "Found SECTDIFF: AddrA: " << AddrA + << ", AddrB: " << AddrB << ", Addend: " << Addend + << ", SectionA ID: " << SectionAID << ", SectionAOffset: " + << SectionAOffset << ", SectionB ID: " << SectionBID + << ", SectionBOffset: " << SectionBOffset << "\n"); + RelocationEntry R(SectionID, Offset, RelocType, Addend, SectionAID, + SectionAOffset, SectionBID, SectionBOffset, + IsPCRel, Size); + + addRelocationForSection(R, SectionAID); + + return ++RelI; + } + + // Populate stubs in __jump_table section. + Error populateJumpTable(const MachOObjectFile &Obj, + const SectionRef &JTSection, + unsigned JTSectionID) { + MachO::dysymtab_command DySymTabCmd = Obj.getDysymtabLoadCommand(); + MachO::section Sec32 = Obj.getSection(JTSection.getRawDataRefImpl()); + uint32_t JTSectionSize = Sec32.size; + unsigned FirstIndirectSymbol = Sec32.reserved1; + unsigned JTEntrySize = Sec32.reserved2; + unsigned NumJTEntries = JTSectionSize / JTEntrySize; + uint8_t *JTSectionAddr = getSectionAddress(JTSectionID); + unsigned JTEntryOffset = 0; + + if (JTSectionSize % JTEntrySize != 0) + return make_error<RuntimeDyldError>("Jump-table section does not contain " + "a whole number of stubs?"); + + for (unsigned i = 0; i < NumJTEntries; ++i) { + unsigned SymbolIndex = + Obj.getIndirectSymbolTableEntry(DySymTabCmd, FirstIndirectSymbol + i); + symbol_iterator SI = Obj.getSymbolByIndex(SymbolIndex); + Expected<StringRef> IndirectSymbolName = SI->getName(); + if (!IndirectSymbolName) + return IndirectSymbolName.takeError(); + uint8_t *JTEntryAddr = JTSectionAddr + JTEntryOffset; + createStubFunction(JTEntryAddr); + RelocationEntry RE(JTSectionID, JTEntryOffset + 1, + MachO::GENERIC_RELOC_VANILLA, 0, true, 2); + addRelocationForSymbol(RE, *IndirectSymbolName); + JTEntryOffset += JTEntrySize; + } + + return Error::success(); + } + +}; +} + +#undef DEBUG_TYPE + +#endif diff --git a/contrib/libs/llvm12/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOX86_64.h b/contrib/libs/llvm12/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOX86_64.h index d4b016cc57..28febbdb94 100644 --- a/contrib/libs/llvm12/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOX86_64.h +++ b/contrib/libs/llvm12/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOX86_64.h @@ -1,239 +1,239 @@ -//===-- RuntimeDyldMachOX86_64.h ---- MachO/X86_64 specific code. -*- C++ -*-=// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDMACHOX86_64_H -#define LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDMACHOX86_64_H - -#include "../RuntimeDyldMachO.h" -#include <string> - -#define DEBUG_TYPE "dyld" - -namespace llvm { - -class RuntimeDyldMachOX86_64 - : public RuntimeDyldMachOCRTPBase<RuntimeDyldMachOX86_64> { -public: - - typedef uint64_t TargetPtrT; - - RuntimeDyldMachOX86_64(RuntimeDyld::MemoryManager &MM, - JITSymbolResolver &Resolver) - : RuntimeDyldMachOCRTPBase(MM, Resolver) {} - - unsigned getMaxStubSize() const override { return 8; } - - unsigned getStubAlignment() override { return 8; } - - Expected<relocation_iterator> - processRelocationRef(unsigned SectionID, relocation_iterator RelI, - const ObjectFile &BaseObjT, - ObjSectionToIDMap &ObjSectionToID, - StubMap &Stubs) override { - const MachOObjectFile &Obj = - static_cast<const MachOObjectFile &>(BaseObjT); - MachO::any_relocation_info RelInfo = - Obj.getRelocation(RelI->getRawDataRefImpl()); - uint32_t RelType = Obj.getAnyRelocationType(RelInfo); - - if (RelType == MachO::X86_64_RELOC_SUBTRACTOR) - return processSubtractRelocation(SectionID, RelI, Obj, ObjSectionToID); - - assert(!Obj.isRelocationScattered(RelInfo) && - "Scattered relocations not supported on X86_64"); - - RelocationEntry RE(getRelocationEntry(SectionID, Obj, RelI)); - RE.Addend = memcpyAddend(RE); - RelocationValueRef Value; - if (auto ValueOrErr = getRelocationValueRef(Obj, RelI, RE, ObjSectionToID)) - Value = *ValueOrErr; - else - return ValueOrErr.takeError(); - - bool IsExtern = Obj.getPlainRelocationExternal(RelInfo); - if (!IsExtern && RE.IsPCRel) - makeValueAddendPCRel(Value, RelI, 1 << RE.Size); - - switch (RelType) { - UNIMPLEMENTED_RELOC(MachO::X86_64_RELOC_TLV); - default: - if (RelType > MachO::X86_64_RELOC_TLV) - return make_error<RuntimeDyldError>(("MachO X86_64 relocation type " + - Twine(RelType) + - " is out of range").str()); - break; - } - - if (RE.RelType == MachO::X86_64_RELOC_GOT || - RE.RelType == MachO::X86_64_RELOC_GOT_LOAD) - processGOTRelocation(RE, Value, Stubs); - else { - RE.Addend = Value.Offset; - if (Value.SymbolName) - addRelocationForSymbol(RE, Value.SymbolName); - else - addRelocationForSection(RE, Value.SectionID); - } - - return ++RelI; - } - - void resolveRelocation(const RelocationEntry &RE, uint64_t Value) override { - LLVM_DEBUG(dumpRelocationToResolve(RE, Value)); - const SectionEntry &Section = Sections[RE.SectionID]; - uint8_t *LocalAddress = Section.getAddressWithOffset(RE.Offset); - - // If the relocation is PC-relative, the value to be encoded is the - // pointer difference. - if (RE.IsPCRel) { - // FIXME: It seems this value needs to be adjusted by 4 for an effective - // PC address. Is that expected? Only for branches, perhaps? - uint64_t FinalAddress = Section.getLoadAddressWithOffset(RE.Offset); - Value -= FinalAddress + 4; - } - - switch (RE.RelType) { - default: - llvm_unreachable("Invalid relocation type!"); - case MachO::X86_64_RELOC_SIGNED_1: - case MachO::X86_64_RELOC_SIGNED_2: - case MachO::X86_64_RELOC_SIGNED_4: - case MachO::X86_64_RELOC_SIGNED: - case MachO::X86_64_RELOC_UNSIGNED: - case MachO::X86_64_RELOC_BRANCH: - writeBytesUnaligned(Value + RE.Addend, LocalAddress, 1 << RE.Size); - break; - case MachO::X86_64_RELOC_SUBTRACTOR: { - uint64_t SectionABase = Sections[RE.Sections.SectionA].getLoadAddress(); - uint64_t SectionBBase = Sections[RE.Sections.SectionB].getLoadAddress(); - assert((Value == SectionABase || Value == SectionBBase) && - "Unexpected SUBTRACTOR relocation value."); - Value = SectionABase - SectionBBase + RE.Addend; - writeBytesUnaligned(Value, LocalAddress, 1 << RE.Size); - break; - } - } - } - - Error finalizeSection(const ObjectFile &Obj, unsigned SectionID, - const SectionRef &Section) { - return Error::success(); - } - -private: - void processGOTRelocation(const RelocationEntry &RE, - RelocationValueRef &Value, StubMap &Stubs) { - SectionEntry &Section = Sections[RE.SectionID]; - assert(RE.IsPCRel); - assert(RE.Size == 2); - Value.Offset -= RE.Addend; - RuntimeDyldMachO::StubMap::const_iterator i = Stubs.find(Value); - uint8_t *Addr; - if (i != Stubs.end()) { - Addr = Section.getAddressWithOffset(i->second); - } else { - Stubs[Value] = Section.getStubOffset(); - uint8_t *GOTEntry = Section.getAddressWithOffset(Section.getStubOffset()); - RelocationEntry GOTRE(RE.SectionID, Section.getStubOffset(), - MachO::X86_64_RELOC_UNSIGNED, Value.Offset, false, - 3); - if (Value.SymbolName) - addRelocationForSymbol(GOTRE, Value.SymbolName); - else - addRelocationForSection(GOTRE, Value.SectionID); - Section.advanceStubOffset(8); - Addr = GOTEntry; - } - RelocationEntry TargetRE(RE.SectionID, RE.Offset, - MachO::X86_64_RELOC_UNSIGNED, RE.Addend, true, 2); - resolveRelocation(TargetRE, (uint64_t)Addr); - } - - Expected<relocation_iterator> - processSubtractRelocation(unsigned SectionID, relocation_iterator RelI, - const MachOObjectFile &BaseObj, - ObjSectionToIDMap &ObjSectionToID) { - const MachOObjectFile &Obj = - static_cast<const MachOObjectFile&>(BaseObj); - MachO::any_relocation_info RE = - Obj.getRelocation(RelI->getRawDataRefImpl()); - - unsigned Size = Obj.getAnyRelocationLength(RE); - uint64_t Offset = RelI->getOffset(); - uint8_t *LocalAddress = Sections[SectionID].getAddressWithOffset(Offset); - unsigned NumBytes = 1 << Size; - int64_t Addend = - SignExtend64(readBytesUnaligned(LocalAddress, NumBytes), NumBytes * 8); - - unsigned SectionBID = ~0U; - uint64_t SectionBOffset = 0; - - MachO::any_relocation_info RelInfo = - Obj.getRelocation(RelI->getRawDataRefImpl()); - - bool AIsExternal = BaseObj.getPlainRelocationExternal(RelInfo); - - if (AIsExternal) { - Expected<StringRef> SubtrahendNameOrErr = RelI->getSymbol()->getName(); - if (!SubtrahendNameOrErr) - return SubtrahendNameOrErr.takeError(); - auto SubtrahendI = GlobalSymbolTable.find(*SubtrahendNameOrErr); - SectionBID = SubtrahendI->second.getSectionID(); - SectionBOffset = SubtrahendI->second.getOffset(); - } else { - SectionRef SecB = Obj.getAnyRelocationSection(RelInfo); - bool IsCode = SecB.isText(); - Expected<unsigned> SectionBIDOrErr = - findOrEmitSection(Obj, SecB, IsCode, ObjSectionToID); - if (!SectionBIDOrErr) - return SectionBIDOrErr.takeError(); - SectionBID = *SectionBIDOrErr; - Addend += SecB.getAddress(); - } - - ++RelI; - - unsigned SectionAID = ~0U; - uint64_t SectionAOffset = 0; - - RelInfo = Obj.getRelocation(RelI->getRawDataRefImpl()); - - bool BIsExternal = BaseObj.getPlainRelocationExternal(RelInfo); - if (BIsExternal) { - Expected<StringRef> MinuendNameOrErr = RelI->getSymbol()->getName(); - if (!MinuendNameOrErr) - return MinuendNameOrErr.takeError(); - auto MinuendI = GlobalSymbolTable.find(*MinuendNameOrErr); - SectionAID = MinuendI->second.getSectionID(); - SectionAOffset = MinuendI->second.getOffset(); - } else { - SectionRef SecA = Obj.getAnyRelocationSection(RelInfo); - bool IsCode = SecA.isText(); - Expected<unsigned> SectionAIDOrErr = - findOrEmitSection(Obj, SecA, IsCode, ObjSectionToID); - if (!SectionAIDOrErr) - return SectionAIDOrErr.takeError(); - SectionAID = *SectionAIDOrErr; - Addend -= SecA.getAddress(); - } - - RelocationEntry R(SectionID, Offset, MachO::X86_64_RELOC_SUBTRACTOR, (uint64_t)Addend, - SectionAID, SectionAOffset, SectionBID, SectionBOffset, - false, Size); - - addRelocationForSection(R, SectionAID); - - return ++RelI; - } - -}; -} - -#undef DEBUG_TYPE - -#endif +//===-- RuntimeDyldMachOX86_64.h ---- MachO/X86_64 specific code. -*- C++ -*-=// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDMACHOX86_64_H +#define LLVM_LIB_EXECUTIONENGINE_RUNTIMEDYLD_TARGETS_RUNTIMEDYLDMACHOX86_64_H + +#include "../RuntimeDyldMachO.h" +#include <string> + +#define DEBUG_TYPE "dyld" + +namespace llvm { + +class RuntimeDyldMachOX86_64 + : public RuntimeDyldMachOCRTPBase<RuntimeDyldMachOX86_64> { +public: + + typedef uint64_t TargetPtrT; + + RuntimeDyldMachOX86_64(RuntimeDyld::MemoryManager &MM, + JITSymbolResolver &Resolver) + : RuntimeDyldMachOCRTPBase(MM, Resolver) {} + + unsigned getMaxStubSize() const override { return 8; } + + unsigned getStubAlignment() override { return 8; } + + Expected<relocation_iterator> + processRelocationRef(unsigned SectionID, relocation_iterator RelI, + const ObjectFile &BaseObjT, + ObjSectionToIDMap &ObjSectionToID, + StubMap &Stubs) override { + const MachOObjectFile &Obj = + static_cast<const MachOObjectFile &>(BaseObjT); + MachO::any_relocation_info RelInfo = + Obj.getRelocation(RelI->getRawDataRefImpl()); + uint32_t RelType = Obj.getAnyRelocationType(RelInfo); + + if (RelType == MachO::X86_64_RELOC_SUBTRACTOR) + return processSubtractRelocation(SectionID, RelI, Obj, ObjSectionToID); + + assert(!Obj.isRelocationScattered(RelInfo) && + "Scattered relocations not supported on X86_64"); + + RelocationEntry RE(getRelocationEntry(SectionID, Obj, RelI)); + RE.Addend = memcpyAddend(RE); + RelocationValueRef Value; + if (auto ValueOrErr = getRelocationValueRef(Obj, RelI, RE, ObjSectionToID)) + Value = *ValueOrErr; + else + return ValueOrErr.takeError(); + + bool IsExtern = Obj.getPlainRelocationExternal(RelInfo); + if (!IsExtern && RE.IsPCRel) + makeValueAddendPCRel(Value, RelI, 1 << RE.Size); + + switch (RelType) { + UNIMPLEMENTED_RELOC(MachO::X86_64_RELOC_TLV); + default: + if (RelType > MachO::X86_64_RELOC_TLV) + return make_error<RuntimeDyldError>(("MachO X86_64 relocation type " + + Twine(RelType) + + " is out of range").str()); + break; + } + + if (RE.RelType == MachO::X86_64_RELOC_GOT || + RE.RelType == MachO::X86_64_RELOC_GOT_LOAD) + processGOTRelocation(RE, Value, Stubs); + else { + RE.Addend = Value.Offset; + if (Value.SymbolName) + addRelocationForSymbol(RE, Value.SymbolName); + else + addRelocationForSection(RE, Value.SectionID); + } + + return ++RelI; + } + + void resolveRelocation(const RelocationEntry &RE, uint64_t Value) override { + LLVM_DEBUG(dumpRelocationToResolve(RE, Value)); + const SectionEntry &Section = Sections[RE.SectionID]; + uint8_t *LocalAddress = Section.getAddressWithOffset(RE.Offset); + + // If the relocation is PC-relative, the value to be encoded is the + // pointer difference. + if (RE.IsPCRel) { + // FIXME: It seems this value needs to be adjusted by 4 for an effective + // PC address. Is that expected? Only for branches, perhaps? + uint64_t FinalAddress = Section.getLoadAddressWithOffset(RE.Offset); + Value -= FinalAddress + 4; + } + + switch (RE.RelType) { + default: + llvm_unreachable("Invalid relocation type!"); + case MachO::X86_64_RELOC_SIGNED_1: + case MachO::X86_64_RELOC_SIGNED_2: + case MachO::X86_64_RELOC_SIGNED_4: + case MachO::X86_64_RELOC_SIGNED: + case MachO::X86_64_RELOC_UNSIGNED: + case MachO::X86_64_RELOC_BRANCH: + writeBytesUnaligned(Value + RE.Addend, LocalAddress, 1 << RE.Size); + break; + case MachO::X86_64_RELOC_SUBTRACTOR: { + uint64_t SectionABase = Sections[RE.Sections.SectionA].getLoadAddress(); + uint64_t SectionBBase = Sections[RE.Sections.SectionB].getLoadAddress(); + assert((Value == SectionABase || Value == SectionBBase) && + "Unexpected SUBTRACTOR relocation value."); + Value = SectionABase - SectionBBase + RE.Addend; + writeBytesUnaligned(Value, LocalAddress, 1 << RE.Size); + break; + } + } + } + + Error finalizeSection(const ObjectFile &Obj, unsigned SectionID, + const SectionRef &Section) { + return Error::success(); + } + +private: + void processGOTRelocation(const RelocationEntry &RE, + RelocationValueRef &Value, StubMap &Stubs) { + SectionEntry &Section = Sections[RE.SectionID]; + assert(RE.IsPCRel); + assert(RE.Size == 2); + Value.Offset -= RE.Addend; + RuntimeDyldMachO::StubMap::const_iterator i = Stubs.find(Value); + uint8_t *Addr; + if (i != Stubs.end()) { + Addr = Section.getAddressWithOffset(i->second); + } else { + Stubs[Value] = Section.getStubOffset(); + uint8_t *GOTEntry = Section.getAddressWithOffset(Section.getStubOffset()); + RelocationEntry GOTRE(RE.SectionID, Section.getStubOffset(), + MachO::X86_64_RELOC_UNSIGNED, Value.Offset, false, + 3); + if (Value.SymbolName) + addRelocationForSymbol(GOTRE, Value.SymbolName); + else + addRelocationForSection(GOTRE, Value.SectionID); + Section.advanceStubOffset(8); + Addr = GOTEntry; + } + RelocationEntry TargetRE(RE.SectionID, RE.Offset, + MachO::X86_64_RELOC_UNSIGNED, RE.Addend, true, 2); + resolveRelocation(TargetRE, (uint64_t)Addr); + } + + Expected<relocation_iterator> + processSubtractRelocation(unsigned SectionID, relocation_iterator RelI, + const MachOObjectFile &BaseObj, + ObjSectionToIDMap &ObjSectionToID) { + const MachOObjectFile &Obj = + static_cast<const MachOObjectFile&>(BaseObj); + MachO::any_relocation_info RE = + Obj.getRelocation(RelI->getRawDataRefImpl()); + + unsigned Size = Obj.getAnyRelocationLength(RE); + uint64_t Offset = RelI->getOffset(); + uint8_t *LocalAddress = Sections[SectionID].getAddressWithOffset(Offset); + unsigned NumBytes = 1 << Size; + int64_t Addend = + SignExtend64(readBytesUnaligned(LocalAddress, NumBytes), NumBytes * 8); + + unsigned SectionBID = ~0U; + uint64_t SectionBOffset = 0; + + MachO::any_relocation_info RelInfo = + Obj.getRelocation(RelI->getRawDataRefImpl()); + + bool AIsExternal = BaseObj.getPlainRelocationExternal(RelInfo); + + if (AIsExternal) { + Expected<StringRef> SubtrahendNameOrErr = RelI->getSymbol()->getName(); + if (!SubtrahendNameOrErr) + return SubtrahendNameOrErr.takeError(); + auto SubtrahendI = GlobalSymbolTable.find(*SubtrahendNameOrErr); + SectionBID = SubtrahendI->second.getSectionID(); + SectionBOffset = SubtrahendI->second.getOffset(); + } else { + SectionRef SecB = Obj.getAnyRelocationSection(RelInfo); + bool IsCode = SecB.isText(); + Expected<unsigned> SectionBIDOrErr = + findOrEmitSection(Obj, SecB, IsCode, ObjSectionToID); + if (!SectionBIDOrErr) + return SectionBIDOrErr.takeError(); + SectionBID = *SectionBIDOrErr; + Addend += SecB.getAddress(); + } + + ++RelI; + + unsigned SectionAID = ~0U; + uint64_t SectionAOffset = 0; + + RelInfo = Obj.getRelocation(RelI->getRawDataRefImpl()); + + bool BIsExternal = BaseObj.getPlainRelocationExternal(RelInfo); + if (BIsExternal) { + Expected<StringRef> MinuendNameOrErr = RelI->getSymbol()->getName(); + if (!MinuendNameOrErr) + return MinuendNameOrErr.takeError(); + auto MinuendI = GlobalSymbolTable.find(*MinuendNameOrErr); + SectionAID = MinuendI->second.getSectionID(); + SectionAOffset = MinuendI->second.getOffset(); + } else { + SectionRef SecA = Obj.getAnyRelocationSection(RelInfo); + bool IsCode = SecA.isText(); + Expected<unsigned> SectionAIDOrErr = + findOrEmitSection(Obj, SecA, IsCode, ObjSectionToID); + if (!SectionAIDOrErr) + return SectionAIDOrErr.takeError(); + SectionAID = *SectionAIDOrErr; + Addend -= SecA.getAddress(); + } + + RelocationEntry R(SectionID, Offset, MachO::X86_64_RELOC_SUBTRACTOR, (uint64_t)Addend, + SectionAID, SectionAOffset, SectionBID, SectionBOffset, + false, Size); + + addRelocationForSection(R, SectionAID); + + return ++RelI; + } + +}; +} + +#undef DEBUG_TYPE + +#endif diff --git a/contrib/libs/llvm12/lib/ExecutionEngine/RuntimeDyld/ya.make b/contrib/libs/llvm12/lib/ExecutionEngine/RuntimeDyld/ya.make index 7861e98ab1..44d7dea118 100644 --- a/contrib/libs/llvm12/lib/ExecutionEngine/RuntimeDyld/ya.make +++ b/contrib/libs/llvm12/lib/ExecutionEngine/RuntimeDyld/ya.make @@ -1,42 +1,42 @@ -# Generated by devtools/yamaker. - -LIBRARY() - +# Generated by devtools/yamaker. + +LIBRARY() + OWNER( orivej g:cpp-contrib ) - + LICENSE(Apache-2.0 WITH LLVM-exception) LICENSE_TEXTS(.yandex_meta/licenses.list.txt) -PEERDIR( +PEERDIR( contrib/libs/llvm12 contrib/libs/llvm12/include contrib/libs/llvm12/lib/IR contrib/libs/llvm12/lib/MC contrib/libs/llvm12/lib/Object contrib/libs/llvm12/lib/Support -) - +) + ADDINCL( contrib/libs/llvm12/lib/ExecutionEngine/RuntimeDyld ) - -NO_COMPILER_WARNINGS() - -NO_UTIL() - -SRCS( - JITSymbol.cpp - RTDyldMemoryManager.cpp - RuntimeDyld.cpp - RuntimeDyldCOFF.cpp - RuntimeDyldChecker.cpp - RuntimeDyldELF.cpp - RuntimeDyldMachO.cpp - Targets/RuntimeDyldELFMips.cpp -) - -END() + +NO_COMPILER_WARNINGS() + +NO_UTIL() + +SRCS( + JITSymbol.cpp + RTDyldMemoryManager.cpp + RuntimeDyld.cpp + RuntimeDyldCOFF.cpp + RuntimeDyldChecker.cpp + RuntimeDyldELF.cpp + RuntimeDyldMachO.cpp + Targets/RuntimeDyldELFMips.cpp +) + +END() diff --git a/contrib/libs/llvm12/lib/ExecutionEngine/SectionMemoryManager.cpp b/contrib/libs/llvm12/lib/ExecutionEngine/SectionMemoryManager.cpp index 537cc508b3..6690dd07d9 100644 --- a/contrib/libs/llvm12/lib/ExecutionEngine/SectionMemoryManager.cpp +++ b/contrib/libs/llvm12/lib/ExecutionEngine/SectionMemoryManager.cpp @@ -1,117 +1,117 @@ -//===- SectionMemoryManager.cpp - Memory manager for MCJIT/RtDyld *- C++ -*-==// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file implements the section-based memory manager used by the MCJIT -// execution engine and RuntimeDyld -// -//===----------------------------------------------------------------------===// - -#include "llvm/ExecutionEngine/SectionMemoryManager.h" -#include "llvm/Config/config.h" -#include "llvm/Support/MathExtras.h" -#include "llvm/Support/Process.h" - -namespace llvm { - -uint8_t *SectionMemoryManager::allocateDataSection(uintptr_t Size, - unsigned Alignment, - unsigned SectionID, - StringRef SectionName, - bool IsReadOnly) { - if (IsReadOnly) - return allocateSection(SectionMemoryManager::AllocationPurpose::ROData, - Size, Alignment); - return allocateSection(SectionMemoryManager::AllocationPurpose::RWData, Size, - Alignment); -} - -uint8_t *SectionMemoryManager::allocateCodeSection(uintptr_t Size, - unsigned Alignment, - unsigned SectionID, - StringRef SectionName) { - return allocateSection(SectionMemoryManager::AllocationPurpose::Code, Size, - Alignment); -} - -uint8_t *SectionMemoryManager::allocateSection( - SectionMemoryManager::AllocationPurpose Purpose, uintptr_t Size, - unsigned Alignment) { - if (!Alignment) - Alignment = 16; - - assert(!(Alignment & (Alignment - 1)) && "Alignment must be a power of two."); - - uintptr_t RequiredSize = Alignment * ((Size + Alignment - 1) / Alignment + 1); - uintptr_t Addr = 0; - - MemoryGroup &MemGroup = [&]() -> MemoryGroup & { - switch (Purpose) { - case AllocationPurpose::Code: - return CodeMem; - case AllocationPurpose::ROData: - return RODataMem; - case AllocationPurpose::RWData: - return RWDataMem; - } - llvm_unreachable("Unknown SectionMemoryManager::AllocationPurpose"); - }(); - - // Look in the list of free memory regions and use a block there if one - // is available. - for (FreeMemBlock &FreeMB : MemGroup.FreeMem) { - if (FreeMB.Free.allocatedSize() >= RequiredSize) { - Addr = (uintptr_t)FreeMB.Free.base(); - uintptr_t EndOfBlock = Addr + FreeMB.Free.allocatedSize(); - // Align the address. - Addr = (Addr + Alignment - 1) & ~(uintptr_t)(Alignment - 1); - - if (FreeMB.PendingPrefixIndex == (unsigned)-1) { - // The part of the block we're giving out to the user is now pending - MemGroup.PendingMem.push_back(sys::MemoryBlock((void *)Addr, Size)); - - // Remember this pending block, such that future allocations can just - // modify it rather than creating a new one - FreeMB.PendingPrefixIndex = MemGroup.PendingMem.size() - 1; - } else { - sys::MemoryBlock &PendingMB = - MemGroup.PendingMem[FreeMB.PendingPrefixIndex]; - PendingMB = sys::MemoryBlock(PendingMB.base(), - Addr + Size - (uintptr_t)PendingMB.base()); - } - - // Remember how much free space is now left in this block - FreeMB.Free = - sys::MemoryBlock((void *)(Addr + Size), EndOfBlock - Addr - Size); - return (uint8_t *)Addr; - } - } - - // No pre-allocated free block was large enough. Allocate a new memory region. - // Note that all sections get allocated as read-write. The permissions will - // be updated later based on memory group. - // - // FIXME: It would be useful to define a default allocation size (or add - // it as a constructor parameter) to minimize the number of allocations. - // - // FIXME: Initialize the Near member for each memory group to avoid - // interleaving. - std::error_code ec; - sys::MemoryBlock MB = MMapper.allocateMappedMemory( - Purpose, RequiredSize, &MemGroup.Near, - sys::Memory::MF_READ | sys::Memory::MF_WRITE, ec); - if (ec) { - // FIXME: Add error propagation to the interface. - return nullptr; - } - - // Save this address as the basis for our next request - MemGroup.Near = MB; - +//===- SectionMemoryManager.cpp - Memory manager for MCJIT/RtDyld *- C++ -*-==// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements the section-based memory manager used by the MCJIT +// execution engine and RuntimeDyld +// +//===----------------------------------------------------------------------===// + +#include "llvm/ExecutionEngine/SectionMemoryManager.h" +#include "llvm/Config/config.h" +#include "llvm/Support/MathExtras.h" +#include "llvm/Support/Process.h" + +namespace llvm { + +uint8_t *SectionMemoryManager::allocateDataSection(uintptr_t Size, + unsigned Alignment, + unsigned SectionID, + StringRef SectionName, + bool IsReadOnly) { + if (IsReadOnly) + return allocateSection(SectionMemoryManager::AllocationPurpose::ROData, + Size, Alignment); + return allocateSection(SectionMemoryManager::AllocationPurpose::RWData, Size, + Alignment); +} + +uint8_t *SectionMemoryManager::allocateCodeSection(uintptr_t Size, + unsigned Alignment, + unsigned SectionID, + StringRef SectionName) { + return allocateSection(SectionMemoryManager::AllocationPurpose::Code, Size, + Alignment); +} + +uint8_t *SectionMemoryManager::allocateSection( + SectionMemoryManager::AllocationPurpose Purpose, uintptr_t Size, + unsigned Alignment) { + if (!Alignment) + Alignment = 16; + + assert(!(Alignment & (Alignment - 1)) && "Alignment must be a power of two."); + + uintptr_t RequiredSize = Alignment * ((Size + Alignment - 1) / Alignment + 1); + uintptr_t Addr = 0; + + MemoryGroup &MemGroup = [&]() -> MemoryGroup & { + switch (Purpose) { + case AllocationPurpose::Code: + return CodeMem; + case AllocationPurpose::ROData: + return RODataMem; + case AllocationPurpose::RWData: + return RWDataMem; + } + llvm_unreachable("Unknown SectionMemoryManager::AllocationPurpose"); + }(); + + // Look in the list of free memory regions and use a block there if one + // is available. + for (FreeMemBlock &FreeMB : MemGroup.FreeMem) { + if (FreeMB.Free.allocatedSize() >= RequiredSize) { + Addr = (uintptr_t)FreeMB.Free.base(); + uintptr_t EndOfBlock = Addr + FreeMB.Free.allocatedSize(); + // Align the address. + Addr = (Addr + Alignment - 1) & ~(uintptr_t)(Alignment - 1); + + if (FreeMB.PendingPrefixIndex == (unsigned)-1) { + // The part of the block we're giving out to the user is now pending + MemGroup.PendingMem.push_back(sys::MemoryBlock((void *)Addr, Size)); + + // Remember this pending block, such that future allocations can just + // modify it rather than creating a new one + FreeMB.PendingPrefixIndex = MemGroup.PendingMem.size() - 1; + } else { + sys::MemoryBlock &PendingMB = + MemGroup.PendingMem[FreeMB.PendingPrefixIndex]; + PendingMB = sys::MemoryBlock(PendingMB.base(), + Addr + Size - (uintptr_t)PendingMB.base()); + } + + // Remember how much free space is now left in this block + FreeMB.Free = + sys::MemoryBlock((void *)(Addr + Size), EndOfBlock - Addr - Size); + return (uint8_t *)Addr; + } + } + + // No pre-allocated free block was large enough. Allocate a new memory region. + // Note that all sections get allocated as read-write. The permissions will + // be updated later based on memory group. + // + // FIXME: It would be useful to define a default allocation size (or add + // it as a constructor parameter) to minimize the number of allocations. + // + // FIXME: Initialize the Near member for each memory group to avoid + // interleaving. + std::error_code ec; + sys::MemoryBlock MB = MMapper.allocateMappedMemory( + Purpose, RequiredSize, &MemGroup.Near, + sys::Memory::MF_READ | sys::Memory::MF_WRITE, ec); + if (ec) { + // FIXME: Add error propagation to the interface. + return nullptr; + } + + // Save this address as the basis for our next request + MemGroup.Near = MB; + // Copy the address to all the other groups, if they have not // been initialized. if (CodeMem.Near.base() == 0) @@ -121,153 +121,153 @@ uint8_t *SectionMemoryManager::allocateSection( if (RWDataMem.Near.base() == 0) RWDataMem.Near = MB; - // Remember that we allocated this memory - MemGroup.AllocatedMem.push_back(MB); - Addr = (uintptr_t)MB.base(); - uintptr_t EndOfBlock = Addr + MB.allocatedSize(); - - // Align the address. - Addr = (Addr + Alignment - 1) & ~(uintptr_t)(Alignment - 1); - - // The part of the block we're giving out to the user is now pending - MemGroup.PendingMem.push_back(sys::MemoryBlock((void *)Addr, Size)); - - // The allocateMappedMemory may allocate much more memory than we need. In - // this case, we store the unused memory as a free memory block. - unsigned FreeSize = EndOfBlock - Addr - Size; - if (FreeSize > 16) { - FreeMemBlock FreeMB; - FreeMB.Free = sys::MemoryBlock((void *)(Addr + Size), FreeSize); - FreeMB.PendingPrefixIndex = (unsigned)-1; - MemGroup.FreeMem.push_back(FreeMB); - } - - // Return aligned address - return (uint8_t *)Addr; -} - -bool SectionMemoryManager::finalizeMemory(std::string *ErrMsg) { - // FIXME: Should in-progress permissions be reverted if an error occurs? - std::error_code ec; - - // Make code memory executable. - ec = applyMemoryGroupPermissions(CodeMem, - sys::Memory::MF_READ | sys::Memory::MF_EXEC); - if (ec) { - if (ErrMsg) { - *ErrMsg = ec.message(); - } - return true; - } - - // Make read-only data memory read-only. + // Remember that we allocated this memory + MemGroup.AllocatedMem.push_back(MB); + Addr = (uintptr_t)MB.base(); + uintptr_t EndOfBlock = Addr + MB.allocatedSize(); + + // Align the address. + Addr = (Addr + Alignment - 1) & ~(uintptr_t)(Alignment - 1); + + // The part of the block we're giving out to the user is now pending + MemGroup.PendingMem.push_back(sys::MemoryBlock((void *)Addr, Size)); + + // The allocateMappedMemory may allocate much more memory than we need. In + // this case, we store the unused memory as a free memory block. + unsigned FreeSize = EndOfBlock - Addr - Size; + if (FreeSize > 16) { + FreeMemBlock FreeMB; + FreeMB.Free = sys::MemoryBlock((void *)(Addr + Size), FreeSize); + FreeMB.PendingPrefixIndex = (unsigned)-1; + MemGroup.FreeMem.push_back(FreeMB); + } + + // Return aligned address + return (uint8_t *)Addr; +} + +bool SectionMemoryManager::finalizeMemory(std::string *ErrMsg) { + // FIXME: Should in-progress permissions be reverted if an error occurs? + std::error_code ec; + + // Make code memory executable. + ec = applyMemoryGroupPermissions(CodeMem, + sys::Memory::MF_READ | sys::Memory::MF_EXEC); + if (ec) { + if (ErrMsg) { + *ErrMsg = ec.message(); + } + return true; + } + + // Make read-only data memory read-only. ec = applyMemoryGroupPermissions(RODataMem, sys::Memory::MF_READ); - if (ec) { - if (ErrMsg) { - *ErrMsg = ec.message(); - } - return true; - } - - // Read-write data memory already has the correct permissions - - // Some platforms with separate data cache and instruction cache require - // explicit cache flush, otherwise JIT code manipulations (like resolved - // relocations) will get to the data cache but not to the instruction cache. - invalidateInstructionCache(); - - return false; -} - -static sys::MemoryBlock trimBlockToPageSize(sys::MemoryBlock M) { - static const size_t PageSize = sys::Process::getPageSizeEstimate(); - - size_t StartOverlap = - (PageSize - ((uintptr_t)M.base() % PageSize)) % PageSize; - - size_t TrimmedSize = M.allocatedSize(); - TrimmedSize -= StartOverlap; - TrimmedSize -= TrimmedSize % PageSize; - - sys::MemoryBlock Trimmed((void *)((uintptr_t)M.base() + StartOverlap), - TrimmedSize); - - assert(((uintptr_t)Trimmed.base() % PageSize) == 0); - assert((Trimmed.allocatedSize() % PageSize) == 0); - assert(M.base() <= Trimmed.base() && - Trimmed.allocatedSize() <= M.allocatedSize()); - - return Trimmed; -} - -std::error_code -SectionMemoryManager::applyMemoryGroupPermissions(MemoryGroup &MemGroup, - unsigned Permissions) { - for (sys::MemoryBlock &MB : MemGroup.PendingMem) - if (std::error_code EC = MMapper.protectMappedMemory(MB, Permissions)) - return EC; - - MemGroup.PendingMem.clear(); - - // Now go through free blocks and trim any of them that don't span the entire - // page because one of the pending blocks may have overlapped it. - for (FreeMemBlock &FreeMB : MemGroup.FreeMem) { - FreeMB.Free = trimBlockToPageSize(FreeMB.Free); - // We cleared the PendingMem list, so all these pointers are now invalid - FreeMB.PendingPrefixIndex = (unsigned)-1; - } - - // Remove all blocks which are now empty + if (ec) { + if (ErrMsg) { + *ErrMsg = ec.message(); + } + return true; + } + + // Read-write data memory already has the correct permissions + + // Some platforms with separate data cache and instruction cache require + // explicit cache flush, otherwise JIT code manipulations (like resolved + // relocations) will get to the data cache but not to the instruction cache. + invalidateInstructionCache(); + + return false; +} + +static sys::MemoryBlock trimBlockToPageSize(sys::MemoryBlock M) { + static const size_t PageSize = sys::Process::getPageSizeEstimate(); + + size_t StartOverlap = + (PageSize - ((uintptr_t)M.base() % PageSize)) % PageSize; + + size_t TrimmedSize = M.allocatedSize(); + TrimmedSize -= StartOverlap; + TrimmedSize -= TrimmedSize % PageSize; + + sys::MemoryBlock Trimmed((void *)((uintptr_t)M.base() + StartOverlap), + TrimmedSize); + + assert(((uintptr_t)Trimmed.base() % PageSize) == 0); + assert((Trimmed.allocatedSize() % PageSize) == 0); + assert(M.base() <= Trimmed.base() && + Trimmed.allocatedSize() <= M.allocatedSize()); + + return Trimmed; +} + +std::error_code +SectionMemoryManager::applyMemoryGroupPermissions(MemoryGroup &MemGroup, + unsigned Permissions) { + for (sys::MemoryBlock &MB : MemGroup.PendingMem) + if (std::error_code EC = MMapper.protectMappedMemory(MB, Permissions)) + return EC; + + MemGroup.PendingMem.clear(); + + // Now go through free blocks and trim any of them that don't span the entire + // page because one of the pending blocks may have overlapped it. + for (FreeMemBlock &FreeMB : MemGroup.FreeMem) { + FreeMB.Free = trimBlockToPageSize(FreeMB.Free); + // We cleared the PendingMem list, so all these pointers are now invalid + FreeMB.PendingPrefixIndex = (unsigned)-1; + } + + // Remove all blocks which are now empty erase_if(MemGroup.FreeMem, [](FreeMemBlock &FreeMB) { return FreeMB.Free.allocatedSize() == 0; }); - - return std::error_code(); -} - -void SectionMemoryManager::invalidateInstructionCache() { - for (sys::MemoryBlock &Block : CodeMem.PendingMem) - sys::Memory::InvalidateInstructionCache(Block.base(), - Block.allocatedSize()); -} - -SectionMemoryManager::~SectionMemoryManager() { - for (MemoryGroup *Group : {&CodeMem, &RWDataMem, &RODataMem}) { - for (sys::MemoryBlock &Block : Group->AllocatedMem) - MMapper.releaseMappedMemory(Block); - } -} - -SectionMemoryManager::MemoryMapper::~MemoryMapper() {} - -void SectionMemoryManager::anchor() {} - -namespace { -// Trivial implementation of SectionMemoryManager::MemoryMapper that just calls -// into sys::Memory. -class DefaultMMapper final : public SectionMemoryManager::MemoryMapper { -public: - sys::MemoryBlock - allocateMappedMemory(SectionMemoryManager::AllocationPurpose Purpose, - size_t NumBytes, const sys::MemoryBlock *const NearBlock, - unsigned Flags, std::error_code &EC) override { - return sys::Memory::allocateMappedMemory(NumBytes, NearBlock, Flags, EC); - } - - std::error_code protectMappedMemory(const sys::MemoryBlock &Block, - unsigned Flags) override { - return sys::Memory::protectMappedMemory(Block, Flags); - } - - std::error_code releaseMappedMemory(sys::MemoryBlock &M) override { - return sys::Memory::releaseMappedMemory(M); - } -}; - -DefaultMMapper DefaultMMapperInstance; -} // namespace - -SectionMemoryManager::SectionMemoryManager(MemoryMapper *MM) - : MMapper(MM ? *MM : DefaultMMapperInstance) {} - -} // namespace llvm + + return std::error_code(); +} + +void SectionMemoryManager::invalidateInstructionCache() { + for (sys::MemoryBlock &Block : CodeMem.PendingMem) + sys::Memory::InvalidateInstructionCache(Block.base(), + Block.allocatedSize()); +} + +SectionMemoryManager::~SectionMemoryManager() { + for (MemoryGroup *Group : {&CodeMem, &RWDataMem, &RODataMem}) { + for (sys::MemoryBlock &Block : Group->AllocatedMem) + MMapper.releaseMappedMemory(Block); + } +} + +SectionMemoryManager::MemoryMapper::~MemoryMapper() {} + +void SectionMemoryManager::anchor() {} + +namespace { +// Trivial implementation of SectionMemoryManager::MemoryMapper that just calls +// into sys::Memory. +class DefaultMMapper final : public SectionMemoryManager::MemoryMapper { +public: + sys::MemoryBlock + allocateMappedMemory(SectionMemoryManager::AllocationPurpose Purpose, + size_t NumBytes, const sys::MemoryBlock *const NearBlock, + unsigned Flags, std::error_code &EC) override { + return sys::Memory::allocateMappedMemory(NumBytes, NearBlock, Flags, EC); + } + + std::error_code protectMappedMemory(const sys::MemoryBlock &Block, + unsigned Flags) override { + return sys::Memory::protectMappedMemory(Block, Flags); + } + + std::error_code releaseMappedMemory(sys::MemoryBlock &M) override { + return sys::Memory::releaseMappedMemory(M); + } +}; + +DefaultMMapper DefaultMMapperInstance; +} // namespace + +SectionMemoryManager::SectionMemoryManager(MemoryMapper *MM) + : MMapper(MM ? *MM : DefaultMMapperInstance) {} + +} // namespace llvm diff --git a/contrib/libs/llvm12/lib/ExecutionEngine/TargetSelect.cpp b/contrib/libs/llvm12/lib/ExecutionEngine/TargetSelect.cpp index 6caece2816..28ea04be1a 100644 --- a/contrib/libs/llvm12/lib/ExecutionEngine/TargetSelect.cpp +++ b/contrib/libs/llvm12/lib/ExecutionEngine/TargetSelect.cpp @@ -1,96 +1,96 @@ -//===-- TargetSelect.cpp - Target Chooser Code ----------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This just asks the TargetRegistry for the appropriate target to use, and -// allows the user to specify a specific one on the commandline with -march=x, -// -mcpu=y, and -mattr=a,-b,+c. Clients should initialize targets prior to -// calling selectTarget(). -// -//===----------------------------------------------------------------------===// - -#include "llvm/ADT/Triple.h" -#include "llvm/ExecutionEngine/ExecutionEngine.h" -#include "llvm/IR/Module.h" -#include "llvm/MC/SubtargetFeature.h" -#include "llvm/Support/Host.h" -#include "llvm/Support/TargetRegistry.h" -#include "llvm/Target/TargetMachine.h" - -using namespace llvm; - -TargetMachine *EngineBuilder::selectTarget() { - Triple TT; - - // MCJIT can generate code for remote targets, but the old JIT and Interpreter - // must use the host architecture. - if (WhichEngine != EngineKind::Interpreter && M) - TT.setTriple(M->getTargetTriple()); - - return selectTarget(TT, MArch, MCPU, MAttrs); -} - -/// selectTarget - Pick a target either via -march or by guessing the native -/// arch. Add any CPU features specified via -mcpu or -mattr. -TargetMachine *EngineBuilder::selectTarget(const Triple &TargetTriple, - StringRef MArch, - StringRef MCPU, - const SmallVectorImpl<std::string>& MAttrs) { - Triple TheTriple(TargetTriple); - if (TheTriple.getTriple().empty()) - TheTriple.setTriple(sys::getProcessTriple()); - - // Adjust the triple to match what the user requested. - const Target *TheTarget = nullptr; - if (!MArch.empty()) { - auto I = find_if(TargetRegistry::targets(), - [&](const Target &T) { return MArch == T.getName(); }); - - if (I == TargetRegistry::targets().end()) { - if (ErrorStr) - *ErrorStr = "No available targets are compatible with this -march, " - "see -version for the available targets.\n"; - return nullptr; - } - - TheTarget = &*I; - - // Adjust the triple to match (if known), otherwise stick with the - // requested/host triple. - Triple::ArchType Type = Triple::getArchTypeForLLVMName(MArch); - if (Type != Triple::UnknownArch) - TheTriple.setArch(Type); - } else { - std::string Error; - TheTarget = TargetRegistry::lookupTarget(TheTriple.getTriple(), Error); - if (!TheTarget) { - if (ErrorStr) - *ErrorStr = Error; - return nullptr; - } - } - - // Package up features to be passed to target/subtarget - std::string FeaturesStr; - if (!MAttrs.empty()) { - SubtargetFeatures Features; - for (unsigned i = 0; i != MAttrs.size(); ++i) - Features.AddFeature(MAttrs[i]); - FeaturesStr = Features.getString(); - } - - // Allocate a target... - TargetMachine *Target = - TheTarget->createTargetMachine(TheTriple.getTriple(), MCPU, FeaturesStr, - Options, RelocModel, CMModel, OptLevel, - /*JIT*/ true); - Target->Options.EmulatedTLS = EmulatedTLS; - Target->Options.ExplicitEmulatedTLS = true; - - assert(Target && "Could not allocate target machine!"); - return Target; -} +//===-- TargetSelect.cpp - Target Chooser Code ----------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This just asks the TargetRegistry for the appropriate target to use, and +// allows the user to specify a specific one on the commandline with -march=x, +// -mcpu=y, and -mattr=a,-b,+c. Clients should initialize targets prior to +// calling selectTarget(). +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/Triple.h" +#include "llvm/ExecutionEngine/ExecutionEngine.h" +#include "llvm/IR/Module.h" +#include "llvm/MC/SubtargetFeature.h" +#include "llvm/Support/Host.h" +#include "llvm/Support/TargetRegistry.h" +#include "llvm/Target/TargetMachine.h" + +using namespace llvm; + +TargetMachine *EngineBuilder::selectTarget() { + Triple TT; + + // MCJIT can generate code for remote targets, but the old JIT and Interpreter + // must use the host architecture. + if (WhichEngine != EngineKind::Interpreter && M) + TT.setTriple(M->getTargetTriple()); + + return selectTarget(TT, MArch, MCPU, MAttrs); +} + +/// selectTarget - Pick a target either via -march or by guessing the native +/// arch. Add any CPU features specified via -mcpu or -mattr. +TargetMachine *EngineBuilder::selectTarget(const Triple &TargetTriple, + StringRef MArch, + StringRef MCPU, + const SmallVectorImpl<std::string>& MAttrs) { + Triple TheTriple(TargetTriple); + if (TheTriple.getTriple().empty()) + TheTriple.setTriple(sys::getProcessTriple()); + + // Adjust the triple to match what the user requested. + const Target *TheTarget = nullptr; + if (!MArch.empty()) { + auto I = find_if(TargetRegistry::targets(), + [&](const Target &T) { return MArch == T.getName(); }); + + if (I == TargetRegistry::targets().end()) { + if (ErrorStr) + *ErrorStr = "No available targets are compatible with this -march, " + "see -version for the available targets.\n"; + return nullptr; + } + + TheTarget = &*I; + + // Adjust the triple to match (if known), otherwise stick with the + // requested/host triple. + Triple::ArchType Type = Triple::getArchTypeForLLVMName(MArch); + if (Type != Triple::UnknownArch) + TheTriple.setArch(Type); + } else { + std::string Error; + TheTarget = TargetRegistry::lookupTarget(TheTriple.getTriple(), Error); + if (!TheTarget) { + if (ErrorStr) + *ErrorStr = Error; + return nullptr; + } + } + + // Package up features to be passed to target/subtarget + std::string FeaturesStr; + if (!MAttrs.empty()) { + SubtargetFeatures Features; + for (unsigned i = 0; i != MAttrs.size(); ++i) + Features.AddFeature(MAttrs[i]); + FeaturesStr = Features.getString(); + } + + // Allocate a target... + TargetMachine *Target = + TheTarget->createTargetMachine(TheTriple.getTriple(), MCPU, FeaturesStr, + Options, RelocModel, CMModel, OptLevel, + /*JIT*/ true); + Target->Options.EmulatedTLS = EmulatedTLS; + Target->Options.ExplicitEmulatedTLS = true; + + assert(Target && "Could not allocate target machine!"); + return Target; +} diff --git a/contrib/libs/llvm12/lib/ExecutionEngine/ya.make b/contrib/libs/llvm12/lib/ExecutionEngine/ya.make index 8b69533069..38849572cb 100644 --- a/contrib/libs/llvm12/lib/ExecutionEngine/ya.make +++ b/contrib/libs/llvm12/lib/ExecutionEngine/ya.make @@ -1,17 +1,17 @@ -# Generated by devtools/yamaker. - -LIBRARY() - +# Generated by devtools/yamaker. + +LIBRARY() + OWNER( orivej g:cpp-contrib ) - + LICENSE(Apache-2.0 WITH LLVM-exception) LICENSE_TEXTS(.yandex_meta/licenses.list.txt) -PEERDIR( +PEERDIR( contrib/libs/llvm12 contrib/libs/llvm12/include contrib/libs/llvm12/lib/ExecutionEngine/RuntimeDyld @@ -20,22 +20,22 @@ PEERDIR( contrib/libs/llvm12/lib/Object contrib/libs/llvm12/lib/Support contrib/libs/llvm12/lib/Target -) - +) + ADDINCL( contrib/libs/llvm12/lib/ExecutionEngine ) - -NO_COMPILER_WARNINGS() - -NO_UTIL() - -SRCS( - ExecutionEngine.cpp - ExecutionEngineBindings.cpp - GDBRegistrationListener.cpp - SectionMemoryManager.cpp - TargetSelect.cpp -) - -END() + +NO_COMPILER_WARNINGS() + +NO_UTIL() + +SRCS( + ExecutionEngine.cpp + ExecutionEngineBindings.cpp + GDBRegistrationListener.cpp + SectionMemoryManager.cpp + TargetSelect.cpp +) + +END() |