Put RTDyldMemoryManager into its own file, and make it linked into

libExecutionEngine. Move method implementations that aren't specific to 
allocation out of SectionMemoryManager and into RTDyldMemoryManager.

This is in preparation for exposing RTDyldMemoryManager through the C 
API.

This is a fixed version of r182407 and r182411. That first revision 
broke builds because I forgot to move the conditional includes of 
various POSIX headers from SectionMemoryManager into 
RTDyldMemoryManager. Those includes are necessary because of how 
getPointerToNamedFunction works around the glibc libc_nonshared.a thing. 
The latter revision still broke things because I forgot to include 
llvm/Config/config.h.



git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@182418 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Filip Pizlo 2013-05-21 20:24:07 +00:00
parent 50f19a906a
commit a4ea4a7203
7 changed files with 194 additions and 159 deletions

View File

@ -0,0 +1,76 @@
//===-- RTDyldMemoryManager.cpp - Memory manager for MC-JIT -----*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Interface of the runtime dynamic memory manager base class.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_EXECUTIONENGINE_RT_DYLD_MEMORY_MANAGER_H
#define LLVM_EXECUTIONENGINE_RT_DYLD_MEMORY_MANAGER_H
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/CBindingWrapping.h"
#include "llvm/Support/Memory.h"
#include "llvm-c/ExecutionEngine.h"
namespace llvm {
// RuntimeDyld clients often want to handle the memory management of
// what gets placed where. For JIT clients, this is the subset of
// JITMemoryManager required for dynamic loading of binaries.
//
// FIXME: As the RuntimeDyld fills out, additional routines will be needed
// for the varying types of objects to be allocated.
class RTDyldMemoryManager {
RTDyldMemoryManager(const RTDyldMemoryManager&) LLVM_DELETED_FUNCTION;
void operator=(const RTDyldMemoryManager&) LLVM_DELETED_FUNCTION;
public:
RTDyldMemoryManager() {}
virtual ~RTDyldMemoryManager();
/// Allocate a memory block of (at least) the given size suitable for
/// executable code. The SectionID is a unique identifier assigned by the JIT
/// engine, and optionally recorded by the memory manager to access a loaded
/// section.
virtual uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment,
unsigned SectionID) = 0;
/// Allocate a memory block of (at least) the given size suitable for data.
/// The SectionID is a unique identifier assigned by the JIT engine, and
/// optionally recorded by the memory manager to access a loaded section.
virtual uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment,
unsigned SectionID, bool IsReadOnly) = 0;
/// Register the EH frames with the runtime so that c++ exceptions work.
virtual void registerEHFrames(StringRef SectionData);
/// This method returns the address of the specified function. As such it is
/// only useful for resolving library symbols, not code generated symbols.
///
/// If \p AbortOnFailure is false and no function with the given name is
/// found, this function returns a null pointer. Otherwise, it prints a
/// message to stderr and aborts.
virtual void *getPointerToNamedFunction(const std::string &Name,
bool AbortOnFailure = true);
/// This method is called when object loading is complete and section page
/// permissions can be applied. It is up to the memory manager implementation
/// to decide whether or not to act on this method. The memory manager will
/// typically allocate all sections as read-write and then apply specific
/// permissions when this method is called. Code sections cannot be executed
/// until this function has been called. In addition, any cache coherency
/// operations needed to reliably use the memory are also performed.
///
/// Returns true if an error occurred, false otherwise.
virtual bool finalizeMemory(std::string *ErrMsg = 0) = 0;
};
} // namespace llvm
#endif // LLVM_EXECUTIONENGINE_RT_DYLD_MEMORY_MANAGER_H

View File

@ -16,6 +16,7 @@
#include "llvm/ADT/StringRef.h"
#include "llvm/ExecutionEngine/ObjectBuffer.h"
#include "llvm/ExecutionEngine/RTDyldMemoryManager.h"
#include "llvm/Support/Memory.h"
namespace llvm {
@ -23,58 +24,6 @@ namespace llvm {
class RuntimeDyldImpl;
class ObjectImage;
// RuntimeDyld clients often want to handle the memory management of
// what gets placed where. For JIT clients, this is the subset of
// JITMemoryManager required for dynamic loading of binaries.
//
// FIXME: As the RuntimeDyld fills out, additional routines will be needed
// for the varying types of objects to be allocated.
class RTDyldMemoryManager {
RTDyldMemoryManager(const RTDyldMemoryManager&) LLVM_DELETED_FUNCTION;
void operator=(const RTDyldMemoryManager&) LLVM_DELETED_FUNCTION;
public:
RTDyldMemoryManager() {}
virtual ~RTDyldMemoryManager();
/// Allocate a memory block of (at least) the given size suitable for
/// executable code. The SectionID is a unique identifier assigned by the JIT
/// engine, and optionally recorded by the memory manager to access a loaded
/// section.
virtual uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment,
unsigned SectionID) = 0;
/// Allocate a memory block of (at least) the given size suitable for data.
/// The SectionID is a unique identifier assigned by the JIT engine, and
/// optionally recorded by the memory manager to access a loaded section.
virtual uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment,
unsigned SectionID, bool IsReadOnly) = 0;
/// This method returns the address of the specified function. 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 returns a null pointer. Otherwise, it prints a
/// message to stderr and aborts.
virtual void *getPointerToNamedFunction(const std::string &Name,
bool AbortOnFailure = true) = 0;
/// This method is called when object loading is complete and section page
/// permissions can be applied. It is up to the memory manager implementation
/// to decide whether or not to act on this method. The memory manager will
/// typically allocate all sections as read-write and then apply specific
/// permissions when this method is called. Code sections cannot be executed
/// until this function has been called. In addition, any cache coherency
/// operations needed to reliably use the memory are also performed.
///
/// Returns true if an error occurred, false otherwise.
virtual bool finalizeMemory(std::string *ErrMsg = 0) = 0;
/// Register the EH frames with the runtime so that c++ exceptions work. The
/// default implementation does nothing. Look at SectionMemoryManager for one
/// that uses __register_frame.
virtual void registerEHFrames(StringRef SectionData);
};
class RuntimeDyld {
RuntimeDyld(const RuntimeDyld &) LLVM_DELETED_FUNCTION;
void operator=(const RuntimeDyld &) LLVM_DELETED_FUNCTION;

View File

@ -73,17 +73,6 @@ public:
/// \returns true if an error occurred, false otherwise.
virtual bool finalizeMemory(std::string *ErrMsg = 0);
void registerEHFrames(StringRef SectionData);
/// This method returns the address of the specified function. As such it is
/// only useful for resolving library symbols, not code generated symbols.
///
/// If \p AbortOnFailure is false and no function with the given name is
/// found, this function returns a null pointer. Otherwise, it prints a
/// message to stderr and aborts.
virtual void *getPointerToNamedFunction(const std::string &Name,
bool AbortOnFailure = true);
/// \brief Invalidate instruction cache for code sections.
///
/// Some platforms with separate data cache and instruction cache require

View File

@ -3,6 +3,7 @@
add_llvm_library(LLVMExecutionEngine
ExecutionEngine.cpp
ExecutionEngineBindings.cpp
RTDyldMemoryManager.cpp
TargetSelect.cpp
)

View File

@ -14,19 +14,8 @@
#include "llvm/Config/config.h"
#include "llvm/ExecutionEngine/SectionMemoryManager.h"
#include "llvm/Support/DynamicLibrary.h"
#include "llvm/Support/MathExtras.h"
#ifdef __linux__
// These includes used by SectionMemoryManager::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 {
uint8_t *SectionMemoryManager::allocateDataSection(uintptr_t Size,
@ -146,38 +135,6 @@ bool SectionMemoryManager::finalizeMemory(std::string *ErrMsg)
return false;
}
// Determine whether we can register EH tables.
#if (defined(__GNUC__) && !defined(__ARM_EABI__) && \
!defined(__USING_SJLJ_EXCEPTIONS__))
#define HAVE_EHTABLE_SUPPORT 1
#else
#define HAVE_EHTABLE_SUPPORT 0
#endif
#if HAVE_EHTABLE_SUPPORT
extern "C" void __register_frame(void*);
static const char *processFDE(const char *Entry) {
const char *P = Entry;
uint32_t Length = *((uint32_t*)P);
P += 4;
uint32_t Offset = *((uint32_t*)P);
if (Offset != 0)
__register_frame((void*)Entry);
return P + Length;
}
#endif
void SectionMemoryManager::registerEHFrames(StringRef SectionData) {
#if HAVE_EHTABLE_SUPPORT
const char *P = SectionData.data();
const char *End = SectionData.data() + SectionData.size();
do {
P = processFDE(P);
} while(P != End);
#endif
}
error_code SectionMemoryManager::applyMemoryGroupPermissions(MemoryGroup &MemGroup,
unsigned Permissions) {
@ -199,57 +156,6 @@ void SectionMemoryManager::invalidateInstructionCache() {
CodeMem.AllocatedMem[i].size());
}
static int jit_noop() {
return 0;
}
void *SectionMemoryManager::getPointerToNamedFunction(const std::string &Name,
bool AbortOnFailure) {
#if defined(__linux__)
//===--------------------------------------------------------------------===//
// 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 (void*)(intptr_t)&stat;
if (Name == "fstat") return (void*)(intptr_t)&fstat;
if (Name == "lstat") return (void*)(intptr_t)&lstat;
if (Name == "stat64") return (void*)(intptr_t)&stat64;
if (Name == "fstat64") return (void*)(intptr_t)&fstat64;
if (Name == "lstat64") return (void*)(intptr_t)&lstat64;
if (Name == "atexit") return (void*)(intptr_t)&atexit;
if (Name == "mknod") return (void*)(intptr_t)&mknod;
#endif // __linux__
// 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 (void*)(intptr_t)&jit_noop;
const char *NameStr = Name.c_str();
void *Ptr = sys::DynamicLibrary::SearchForAddressOfSymbol(NameStr);
if (Ptr) return Ptr;
// If it wasn't found and if it starts with an underscore ('_') character,
// try again without the underscore.
if (NameStr[0] == '_') {
Ptr = sys::DynamicLibrary::SearchForAddressOfSymbol(NameStr+1);
if (Ptr) return Ptr;
}
if (AbortOnFailure)
report_fatal_error("Program used external function '" + Name +
"' which could not be resolved!");
return 0;
}
SectionMemoryManager::~SectionMemoryManager() {
for (unsigned i = 0, e = CodeMem.AllocatedMem.size(); i != e; ++i)
sys::Memory::releaseMappedMemory(CodeMem.AllocatedMem[i]);

View File

@ -0,0 +1,116 @@
//===-- RTDyldMemoryManager.cpp - Memory manager for MC-JIT -----*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Implementation of the runtime dynamic memory manager base class.
//
//===----------------------------------------------------------------------===//
#include "llvm/Config/config.h"
#include "llvm/ExecutionEngine/RTDyldMemoryManager.h"
#include "llvm/Support/DynamicLibrary.h"
#include "llvm/Support/ErrorHandling.h"
#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() {}
// Determine whether we can register EH tables.
#if (defined(__GNUC__) && !defined(__ARM_EABI__) && \
!defined(__USING_SJLJ_EXCEPTIONS__))
#define HAVE_EHTABLE_SUPPORT 1
#else
#define HAVE_EHTABLE_SUPPORT 0
#endif
#if HAVE_EHTABLE_SUPPORT
extern "C" void __register_frame(void*);
static const char *processFDE(const char *Entry) {
const char *P = Entry;
uint32_t Length = *((uint32_t*)P);
P += 4;
uint32_t Offset = *((uint32_t*)P);
if (Offset != 0)
__register_frame((void*)Entry);
return P + Length;
}
#endif
void RTDyldMemoryManager::registerEHFrames(StringRef SectionData) {
#if HAVE_EHTABLE_SUPPORT
const char *P = SectionData.data();
const char *End = SectionData.data() + SectionData.size();
do {
P = processFDE(P);
} while(P != End);
#endif
}
static int jit_noop() {
return 0;
}
void *RTDyldMemoryManager::getPointerToNamedFunction(const std::string &Name,
bool AbortOnFailure) {
#if defined(__linux__)
//===--------------------------------------------------------------------===//
// 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 (void*)(intptr_t)&stat;
if (Name == "fstat") return (void*)(intptr_t)&fstat;
if (Name == "lstat") return (void*)(intptr_t)&lstat;
if (Name == "stat64") return (void*)(intptr_t)&stat64;
if (Name == "fstat64") return (void*)(intptr_t)&fstat64;
if (Name == "lstat64") return (void*)(intptr_t)&lstat64;
if (Name == "atexit") return (void*)(intptr_t)&atexit;
if (Name == "mknod") return (void*)(intptr_t)&mknod;
#endif // __linux__
// 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 (void*)(intptr_t)&jit_noop;
const char *NameStr = Name.c_str();
void *Ptr = sys::DynamicLibrary::SearchForAddressOfSymbol(NameStr);
if (Ptr) return Ptr;
// If it wasn't found and if it starts with an underscore ('_') character,
// try again without the underscore.
if (NameStr[0] == '_') {
Ptr = sys::DynamicLibrary::SearchForAddressOfSymbol(NameStr+1);
if (Ptr) return Ptr;
}
if (AbortOnFailure)
report_fatal_error("Program used external function '" + Name +
"' which could not be resolved!");
return 0;
}
} // namespace llvm

View File

@ -24,8 +24,6 @@ using namespace llvm;
using namespace llvm::object;
// Empty out-of-line virtual destructor as the key function.
RTDyldMemoryManager::~RTDyldMemoryManager() {}
void RTDyldMemoryManager::registerEHFrames(StringRef SectionData) {}
RuntimeDyldImpl::~RuntimeDyldImpl() {}
namespace llvm {