Path: blob/main/contrib/llvm-project/llvm/lib/ExecutionEngine/RuntimeDyld/RTDyldMemoryManager.cpp
35266 views
//===-- RTDyldMemoryManager.cpp - Memory manager for MC-JIT -----*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// Implementation of the runtime dynamic memory manager base class.9//10//===----------------------------------------------------------------------===//1112#include "llvm/Config/config.h"13#include "llvm/ExecutionEngine/RTDyldMemoryManager.h"14#include "llvm/Support/Compiler.h"15#include "llvm/Support/DynamicLibrary.h"16#include "llvm/Support/ErrorHandling.h"17#include <cstdlib>1819#ifdef __linux__20// These includes used by RTDyldMemoryManager::getPointerToNamedFunction()21// for Glibc trickery. See comments in this function for more information.22#ifdef HAVE_SYS_STAT_H23#include <sys/stat.h>24#endif25#include <fcntl.h>26#include <unistd.h>27#endif2829namespace llvm {3031RTDyldMemoryManager::~RTDyldMemoryManager() = default;3233#if defined(HAVE_REGISTER_FRAME) && defined(HAVE_DEREGISTER_FRAME) && \34!defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__)35extern "C" void __register_frame(void *);36extern "C" void __deregister_frame(void *);37#else38// The building compiler does not have __(de)register_frame but39// it may be found at runtime in a dynamically-loaded library.40// For example, this happens when building LLVM with Visual C++41// but using the MingW runtime.42static void __register_frame(void *p) {43static bool Searched = false;44static void((*rf)(void *)) = 0;4546if (!Searched) {47Searched = true;48*(void **)&rf =49llvm::sys::DynamicLibrary::SearchForAddressOfSymbol("__register_frame");50}51if (rf)52rf(p);53}5455static void __deregister_frame(void *p) {56static bool Searched = false;57static void((*df)(void *)) = 0;5859if (!Searched) {60Searched = true;61*(void **)&df = llvm::sys::DynamicLibrary::SearchForAddressOfSymbol(62"__deregister_frame");63}64if (df)65df(p);66}67#endif6869/* libgcc and libunwind __register_frame behave differently. We use the presence70* of __unw_add_dynamic_fde to detect libunwind. */71#if defined(HAVE_UNW_ADD_DYNAMIC_FDE) || defined(__APPLE__)7273static const char *processFDE(const char *Entry, bool isDeregister) {74const char *P = Entry;75uint32_t Length = *((const uint32_t *)P);76P += 4;77uint32_t Offset = *((const uint32_t *)P);78if (Offset != 0) {79if (isDeregister)80__deregister_frame(const_cast<char *>(Entry));81else82__register_frame(const_cast<char *>(Entry));83}84return P + Length;85}8687// This implementation handles frame registration for local targets.88// Memory managers for remote targets should re-implement this function89// and use the LoadAddr parameter.90void RTDyldMemoryManager::registerEHFramesInProcess(uint8_t *Addr,91size_t Size) {92// On OS X OS X __register_frame takes a single FDE as an argument.93// See http://lists.llvm.org/pipermail/llvm-dev/2013-April/061737.html94// and projects/libunwind/src/UnwindLevel1-gcc-ext.c.95const char *P = (const char *)Addr;96const char *End = P + Size;97while (P != End)98P = processFDE(P, false);99}100101void RTDyldMemoryManager::deregisterEHFramesInProcess(uint8_t *Addr,102size_t Size) {103const char *P = (const char *)Addr;104const char *End = P + Size;105while (P != End)106P = processFDE(P, true);107}108109#else110111void RTDyldMemoryManager::registerEHFramesInProcess(uint8_t *Addr,112size_t Size) {113// On Linux __register_frame takes a single argument:114// a pointer to the start of the .eh_frame section.115116// How can it find the end? Because crtendS.o is linked117// in and it has an .eh_frame section with four zero chars.118__register_frame(Addr);119}120121void RTDyldMemoryManager::deregisterEHFramesInProcess(uint8_t *Addr,122size_t Size) {123__deregister_frame(Addr);124}125126#endif127128void RTDyldMemoryManager::registerEHFrames(uint8_t *Addr, uint64_t LoadAddr,129size_t Size) {130registerEHFramesInProcess(Addr, Size);131EHFrames.push_back({Addr, Size});132}133134void RTDyldMemoryManager::deregisterEHFrames() {135for (auto &Frame : EHFrames)136deregisterEHFramesInProcess(Frame.Addr, Frame.Size);137EHFrames.clear();138}139140static int jit_noop() {141return 0;142}143144// ARM math functions are statically linked on Android from libgcc.a, but not145// available at runtime for dynamic linking. On Linux these are usually placed146// in libgcc_s.so so can be found by normal dynamic lookup.147#if defined(__BIONIC__) && defined(__arm__)148// List of functions which are statically linked on Android and can be generated149// by LLVM. This is done as a nested macro which is used once to declare the150// imported functions with ARM_MATH_DECL and once to compare them to the151// user-requested symbol in getSymbolAddress with ARM_MATH_CHECK. The test152// assumes that all functions start with __aeabi_ and getSymbolAddress must be153// modified if that changes.154#define ARM_MATH_IMPORTS(PP) \155PP(__aeabi_d2f) \156PP(__aeabi_d2iz) \157PP(__aeabi_d2lz) \158PP(__aeabi_d2uiz) \159PP(__aeabi_d2ulz) \160PP(__aeabi_dadd) \161PP(__aeabi_dcmpeq) \162PP(__aeabi_dcmpge) \163PP(__aeabi_dcmpgt) \164PP(__aeabi_dcmple) \165PP(__aeabi_dcmplt) \166PP(__aeabi_dcmpun) \167PP(__aeabi_ddiv) \168PP(__aeabi_dmul) \169PP(__aeabi_dsub) \170PP(__aeabi_f2d) \171PP(__aeabi_f2iz) \172PP(__aeabi_f2lz) \173PP(__aeabi_f2uiz) \174PP(__aeabi_f2ulz) \175PP(__aeabi_fadd) \176PP(__aeabi_fcmpeq) \177PP(__aeabi_fcmpge) \178PP(__aeabi_fcmpgt) \179PP(__aeabi_fcmple) \180PP(__aeabi_fcmplt) \181PP(__aeabi_fcmpun) \182PP(__aeabi_fdiv) \183PP(__aeabi_fmul) \184PP(__aeabi_fsub) \185PP(__aeabi_i2d) \186PP(__aeabi_i2f) \187PP(__aeabi_idiv) \188PP(__aeabi_idivmod) \189PP(__aeabi_l2d) \190PP(__aeabi_l2f) \191PP(__aeabi_lasr) \192PP(__aeabi_ldivmod) \193PP(__aeabi_llsl) \194PP(__aeabi_llsr) \195PP(__aeabi_lmul) \196PP(__aeabi_ui2d) \197PP(__aeabi_ui2f) \198PP(__aeabi_uidiv) \199PP(__aeabi_uidivmod) \200PP(__aeabi_ul2d) \201PP(__aeabi_ul2f) \202PP(__aeabi_uldivmod)203204// Declare statically linked math functions on ARM. The function declarations205// here do not have the correct prototypes for each function in206// ARM_MATH_IMPORTS, but it doesn't matter because only the symbol addresses are207// needed. In particular the __aeabi_*divmod functions do not have calling208// conventions which match any C prototype.209#define ARM_MATH_DECL(name) extern "C" void name();210ARM_MATH_IMPORTS(ARM_MATH_DECL)211#undef ARM_MATH_DECL212#endif213214#if defined(__linux__) && defined(__GLIBC__) && \215(defined(__i386__) || defined(__x86_64__))216extern "C" LLVM_ATTRIBUTE_WEAK void __morestack();217#endif218219uint64_t220RTDyldMemoryManager::getSymbolAddressInProcess(const std::string &Name) {221// This implementation assumes that the host program is the target.222// Clients generating code for a remote target should implement their own223// memory manager.224#if defined(__linux__) && defined(__GLIBC__)225//===--------------------------------------------------------------------===//226// Function stubs that are invoked instead of certain library calls227//228// Force the following functions to be linked in to anything that uses the229// JIT. This is a hack designed to work around the all-too-clever Glibc230// strategy of making these functions work differently when inlined vs. when231// not inlined, and hiding their real definitions in a separate archive file232// that the dynamic linker can't see. For more info, search for233// 'libc_nonshared.a' on Google, or read http://llvm.org/PR274.234if (Name == "stat") return (uint64_t)&stat;235if (Name == "fstat") return (uint64_t)&fstat;236if (Name == "lstat") return (uint64_t)&lstat;237if (Name == "stat64") return (uint64_t)&stat64;238if (Name == "fstat64") return (uint64_t)&fstat64;239if (Name == "lstat64") return (uint64_t)&lstat64;240if (Name == "atexit") return (uint64_t)&atexit;241if (Name == "mknod") return (uint64_t)&mknod;242243#if defined(__i386__) || defined(__x86_64__)244// __morestack lives in libgcc, a static library.245if (&__morestack && Name == "__morestack")246return (uint64_t)&__morestack;247#endif248#endif // __linux__ && __GLIBC__249250// See ARM_MATH_IMPORTS definition for explanation251#if defined(__BIONIC__) && defined(__arm__)252if (Name.compare(0, 8, "__aeabi_") == 0) {253// Check if the user has requested any of the functions listed in254// ARM_MATH_IMPORTS, and if so redirect to the statically linked symbol.255#define ARM_MATH_CHECK(fn) if (Name == #fn) return (uint64_t)&fn;256ARM_MATH_IMPORTS(ARM_MATH_CHECK)257#undef ARM_MATH_CHECK258}259#endif260261// We should not invoke parent's ctors/dtors from generated main()!262// On Mingw and Cygwin, the symbol __main is resolved to263// callee's(eg. tools/lli) one, to invoke wrong duplicated ctors264// (and register wrong callee's dtors with atexit(3)).265// We expect ExecutionEngine::runStaticConstructorsDestructors()266// is called before ExecutionEngine::runFunctionAsMain() is called.267if (Name == "__main") return (uint64_t)&jit_noop;268269const char *NameStr = Name.c_str();270271// DynamicLibrary::SearchForAddressOfSymbol expects an unmangled 'C' symbol272// name so ff we're on Darwin, strip the leading '_' off.273#ifdef __APPLE__274if (NameStr[0] == '_')275++NameStr;276#endif277278return (uint64_t)sys::DynamicLibrary::SearchForAddressOfSymbol(NameStr);279}280281void *RTDyldMemoryManager::getPointerToNamedFunction(const std::string &Name,282bool AbortOnFailure) {283uint64_t Addr = getSymbolAddress(Name);284285if (!Addr && AbortOnFailure)286report_fatal_error(Twine("Program used external function '") + Name +287"' which could not be resolved!");288289return (void*)Addr;290}291292void RTDyldMemoryManager::anchor() {}293void MCJITMemoryManager::anchor() {}294} // namespace llvm295296297