Revert a series of commits to MCJIT to get the build working in CMake

(and hopefully on Windows). The bots have been down most of the day
because of this, and it's not clear to me what all will be required to
fix it.

The commits started with r153205, then r153207, r153208, and r153221.
The first commit seems to be the real culprit, but I couldn't revert
a smaller number of patches.

When resubmitting, r153207 and r153208 should be folded into r153205,
they were simple build fixes.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@153241 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Chandler Carruth 2012-03-22 05:44:06 +00:00
parent f2f6182f6a
commit 3e29671cca
67 changed files with 1387 additions and 2040 deletions

View File

@ -47,17 +47,6 @@ public:
/// debugging, and may be turned on by default in debug mode.
virtual void setPoisonMemory(bool poison) = 0;
/// 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.
///
virtual void *getPointerToNamedFunction(const std::string &Name,
bool AbortOnFailure = true) = 0;
//===--------------------------------------------------------------------===//
// Global Offset Table Management
//===--------------------------------------------------------------------===//

View File

@ -45,9 +45,15 @@ public:
virtual uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment,
unsigned SectionID) = 0;
virtual void *getPointerToNamedFunction(const std::string &Name,
bool AbortOnFailure = true) = 0;
// Allocate ActualSize bytes, or more, for the named function. Return
// a pointer to the allocated memory and update Size to reflect how much
// memory was acutally allocated.
virtual uint8_t *startFunctionBody(const char *Name, uintptr_t &Size) = 0;
// Mark the end of the function, including how much of the allocated
// memory was actually used.
virtual void endFunctionBody(const char *Name, uint8_t *FunctionStart,
uint8_t *FunctionEnd) = 0;
};
class RuntimeDyld {

View File

@ -2,6 +2,7 @@
add_definitions(-DENABLE_X86_JIT)
add_llvm_library(LLVMJIT
Intercept.cpp
JIT.cpp
JITDwarfEmitter.cpp
JITEmitter.cpp

View File

@ -0,0 +1,162 @@
//===-- Intercept.cpp - System function interception routines -------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// If a function call occurs to an external function, the JIT is designed to use
// the dynamic loader interface to find a function to call. This is useful for
// calling system calls and library functions that are not available in LLVM.
// Some system calls, however, need to be handled specially. For this reason,
// we intercept some of them here and use our own stubs to handle them.
//
//===----------------------------------------------------------------------===//
#include "JIT.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/DynamicLibrary.h"
#include "llvm/Config/config.h"
using namespace llvm;
// AtExitHandlers - List of functions to call when the program exits,
// registered with the atexit() library function.
static std::vector<void (*)()> AtExitHandlers;
/// runAtExitHandlers - Run any functions registered by the program's
/// calls to atexit(3), which we intercept and store in
/// AtExitHandlers.
///
static void runAtExitHandlers() {
while (!AtExitHandlers.empty()) {
void (*Fn)() = AtExitHandlers.back();
AtExitHandlers.pop_back();
Fn();
}
}
//===----------------------------------------------------------------------===//
// 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 defined(__linux__)
#if defined(HAVE_SYS_STAT_H)
#include <sys/stat.h>
#endif
#include <fcntl.h>
#include <unistd.h>
/* stat functions are redirecting to __xstat with a version number. On x86-64
* linking with libc_nonshared.a and -Wl,--export-dynamic doesn't make 'stat'
* available as an exported symbol, so we have to add it explicitly.
*/
namespace {
class StatSymbols {
public:
StatSymbols() {
sys::DynamicLibrary::AddSymbol("stat", (void*)(intptr_t)stat);
sys::DynamicLibrary::AddSymbol("fstat", (void*)(intptr_t)fstat);
sys::DynamicLibrary::AddSymbol("lstat", (void*)(intptr_t)lstat);
sys::DynamicLibrary::AddSymbol("stat64", (void*)(intptr_t)stat64);
sys::DynamicLibrary::AddSymbol("\x1stat64", (void*)(intptr_t)stat64);
sys::DynamicLibrary::AddSymbol("\x1open64", (void*)(intptr_t)open64);
sys::DynamicLibrary::AddSymbol("\x1lseek64", (void*)(intptr_t)lseek64);
sys::DynamicLibrary::AddSymbol("fstat64", (void*)(intptr_t)fstat64);
sys::DynamicLibrary::AddSymbol("lstat64", (void*)(intptr_t)lstat64);
sys::DynamicLibrary::AddSymbol("atexit", (void*)(intptr_t)atexit);
sys::DynamicLibrary::AddSymbol("mknod", (void*)(intptr_t)mknod);
}
};
}
static StatSymbols initStatSymbols;
#endif // __linux__
// jit_exit - Used to intercept the "exit" library call.
static void jit_exit(int Status) {
runAtExitHandlers(); // Run atexit handlers...
exit(Status);
}
// jit_atexit - Used to intercept the "atexit" library call.
static int jit_atexit(void (*Fn)()) {
AtExitHandlers.push_back(Fn); // Take note of atexit handler...
return 0; // Always successful
}
static int jit_noop() {
return 0;
}
//===----------------------------------------------------------------------===//
//
/// getPointerToNamedFunction - This method returns the address of the specified
/// function by using the dynamic loader interface. As such it is only useful
/// for resolving library symbols, not code generated symbols.
///
void *JIT::getPointerToNamedFunction(const std::string &Name,
bool AbortOnFailure) {
if (!isSymbolSearchingDisabled()) {
// Check to see if this is one of the functions we want to intercept. Note,
// we cast to intptr_t here to silence a -pedantic warning that complains
// about casting a function pointer to a normal pointer.
if (Name == "exit") return (void*)(intptr_t)&jit_exit;
if (Name == "atexit") return (void*)(intptr_t)&jit_atexit;
// 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();
// If this is an asm specifier, skip the sentinal.
if (NameStr[0] == 1) ++NameStr;
// If it's an external function, look it up in the process image...
void *Ptr = sys::DynamicLibrary::SearchForAddressOfSymbol(NameStr);
if (Ptr) return Ptr;
// If it wasn't found and if it starts with an underscore ('_') character,
// and has an asm specifier, try again without the underscore.
if (Name[0] == 1 && NameStr[0] == '_') {
Ptr = sys::DynamicLibrary::SearchForAddressOfSymbol(NameStr+1);
if (Ptr) return Ptr;
}
// Darwin/PPC adds $LDBLStub suffixes to various symbols like printf. These
// are references to hidden visibility symbols that dlsym cannot resolve.
// If we have one of these, strip off $LDBLStub and try again.
#if defined(__APPLE__) && defined(__ppc__)
if (Name.size() > 9 && Name[Name.size()-9] == '$' &&
memcmp(&Name[Name.size()-8], "LDBLStub", 8) == 0) {
// First try turning $LDBLStub into $LDBL128. If that fails, strip it off.
// This mirrors logic in libSystemStubs.a.
std::string Prefix = std::string(Name.begin(), Name.end()-9);
if (void *Ptr = getPointerToNamedFunction(Prefix+"$LDBL128", false))
return Ptr;
if (void *Ptr = getPointerToNamedFunction(Prefix, false))
return Ptr;
}
#endif
}
/// If a LazyFunctionCreator is installed, use it to get/create the function.
if (LazyFunctionCreator)
if (void *RP = LazyFunctionCreator(Name))
return RP;
if (AbortOnFailure) {
report_fatal_error("Program used external function '"+Name+
"' which could not be resolved!");
}
return 0;
}

View File

@ -23,7 +23,6 @@
#include "llvm/CodeGen/MachineCodeInfo.h"
#include "llvm/ExecutionEngine/GenericValue.h"
#include "llvm/ExecutionEngine/JITEventListener.h"
#include "llvm/ExecutionEngine/JITMemoryManager.h"
#include "llvm/Target/TargetData.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetJITInfo.h"
@ -268,9 +267,9 @@ extern "C" {
}
JIT::JIT(Module *M, TargetMachine &tm, TargetJITInfo &tji,
JITMemoryManager *jmm, bool GVsWithCode)
: ExecutionEngine(M), TM(tm), TJI(tji), JMM(jmm),
AllocateGVsWithCode(GVsWithCode), isAlreadyCodeGenerating(false) {
JITMemoryManager *JMM, bool GVsWithCode)
: ExecutionEngine(M), TM(tm), TJI(tji), AllocateGVsWithCode(GVsWithCode),
isAlreadyCodeGenerating(false) {
setTargetData(TM.getTargetData());
jitstate = new JITState(M);
@ -712,27 +711,6 @@ void *JIT::getPointerToBasicBlock(BasicBlock *BB) {
}
}
void *JIT::getPointerToNamedFunction(const std::string &Name,
bool AbortOnFailure){
if (!isSymbolSearchingDisabled()) {
void *ptr = JMM->getPointerToNamedFunction(Name, false);
if (ptr)
return ptr;
}
/// If a LazyFunctionCreator is installed, use it to get/create the function.
if (LazyFunctionCreator)
if (void *RP = LazyFunctionCreator(Name))
return RP;
if (AbortOnFailure) {
report_fatal_error("Program used external function '"+Name+
"' which could not be resolved!");
}
return 0;
}
/// getOrEmitGlobalVariable - Return the address of the specified global
/// variable, possibly emitting it to memory if needed. This is used by the
/// Emitter.

View File

@ -58,7 +58,6 @@ class JIT : public ExecutionEngine {
TargetMachine &TM; // The current target we are compiling to
TargetJITInfo &TJI; // The JITInfo for the target we are compiling to
JITCodeEmitter *JCE; // JCE object
JITMemoryManager *JMM;
std::vector<JITEventListener*> EventListeners;
/// AllocateGVsWithCode - Some applications require that global variables and

View File

@ -314,17 +314,6 @@ namespace {
/// should allocate a separate slab.
static const size_t DefaultSizeThreshold;
/// 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.
///
virtual void *getPointerToNamedFunction(const std::string &Name,
bool AbortOnFailure = true);
void AllocateGOT();
// Testing methods.
@ -768,148 +757,6 @@ bool DefaultJITMemoryManager::CheckInvariants(std::string &ErrorStr) {
return true;
}
//===----------------------------------------------------------------------===//
// getPointerToNamedFunction() implementation.
//===----------------------------------------------------------------------===//
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/DynamicLibrary.h"
#include "llvm/Config/config.h"
// AtExitHandlers - List of functions to call when the program exits,
// registered with the atexit() library function.
static std::vector<void (*)()> AtExitHandlers;
/// runAtExitHandlers - Run any functions registered by the program's
/// calls to atexit(3), which we intercept and store in
/// AtExitHandlers.
///
static void runAtExitHandlers() {
while (!AtExitHandlers.empty()) {
void (*Fn)() = AtExitHandlers.back();
AtExitHandlers.pop_back();
Fn();
}
}
//===----------------------------------------------------------------------===//
// 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 defined(__linux__)
#if defined(HAVE_SYS_STAT_H)
#include <sys/stat.h>
#endif
#include <fcntl.h>
#include <unistd.h>
/* stat functions are redirecting to __xstat with a version number. On x86-64
* linking with libc_nonshared.a and -Wl,--export-dynamic doesn't make 'stat'
* available as an exported symbol, so we have to add it explicitly.
*/
namespace {
class StatSymbols {
public:
StatSymbols() {
sys::DynamicLibrary::AddSymbol("stat", (void*)(intptr_t)stat);
sys::DynamicLibrary::AddSymbol("fstat", (void*)(intptr_t)fstat);
sys::DynamicLibrary::AddSymbol("lstat", (void*)(intptr_t)lstat);
sys::DynamicLibrary::AddSymbol("stat64", (void*)(intptr_t)stat64);
sys::DynamicLibrary::AddSymbol("\x1stat64", (void*)(intptr_t)stat64);
sys::DynamicLibrary::AddSymbol("\x1open64", (void*)(intptr_t)open64);
sys::DynamicLibrary::AddSymbol("\x1lseek64", (void*)(intptr_t)lseek64);
sys::DynamicLibrary::AddSymbol("fstat64", (void*)(intptr_t)fstat64);
sys::DynamicLibrary::AddSymbol("lstat64", (void*)(intptr_t)lstat64);
sys::DynamicLibrary::AddSymbol("atexit", (void*)(intptr_t)atexit);
sys::DynamicLibrary::AddSymbol("mknod", (void*)(intptr_t)mknod);
}
};
}
static StatSymbols initStatSymbols;
#endif // __linux__
// jit_exit - Used to intercept the "exit" library call.
static void jit_exit(int Status) {
runAtExitHandlers(); // Run atexit handlers...
exit(Status);
}
// jit_atexit - Used to intercept the "atexit" library call.
static int jit_atexit(void (*Fn)()) {
AtExitHandlers.push_back(Fn); // Take note of atexit handler...
return 0; // Always successful
}
static int jit_noop() {
return 0;
}
//===----------------------------------------------------------------------===//
//
/// getPointerToNamedFunction - This method returns the address of the specified
/// function by using the dynamic loader interface. As such it is only useful
/// for resolving library symbols, not code generated symbols.
///
void *DefaultJITMemoryManager::getPointerToNamedFunction(const std::string &Name,
bool AbortOnFailure) {
// Check to see if this is one of the functions we want to intercept. Note,
// we cast to intptr_t here to silence a -pedantic warning that complains
// about casting a function pointer to a normal pointer.
if (Name == "exit") return (void*)(intptr_t)&jit_exit;
if (Name == "atexit") return (void*)(intptr_t)&jit_atexit;
// 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();
// If this is an asm specifier, skip the sentinal.
if (NameStr[0] == 1) ++NameStr;
// If it's an external function, look it up in the process image...
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;
}
// Darwin/PPC adds $LDBLStub suffixes to various symbols like printf. These
// are references to hidden visibility symbols that dlsym cannot resolve.
// If we have one of these, strip off $LDBLStub and try again.
#if defined(__APPLE__) && defined(__ppc__)
if (Name.size() > 9 && Name[Name.size()-9] == '$' &&
memcmp(&Name[Name.size()-8], "LDBLStub", 8) == 0) {
// First try turning $LDBLStub into $LDBL128. If that fails, strip it off.
// This mirrors logic in libSystemStubs.a.
std::string Prefix = std::string(Name.begin(), Name.end()-9);
if (void *Ptr = getPointerToNamedFunction(Prefix+"$LDBL128", false))
return Ptr;
if (void *Ptr = getPointerToNamedFunction(Prefix, false))
return Ptr;
}
#endif
if (AbortOnFailure) {
report_fatal_error("Program used external function '"+Name+
"' which could not be resolved!");
}
return 0;
}
JITMemoryManager *JITMemoryManager::CreateDefaultMemManager() {
return new DefaultJITMemoryManager();
}

View File

@ -1,4 +1,5 @@
add_llvm_library(LLVMMCJIT
MCJIT.cpp
MCJITMemoryManager.cpp
Intercept.cpp
)

View File

@ -0,0 +1,162 @@
//===-- Intercept.cpp - System function interception routines -------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// If a function call occurs to an external function, the JIT is designed to use
// the dynamic loader interface to find a function to call. This is useful for
// calling system calls and library functions that are not available in LLVM.
// Some system calls, however, need to be handled specially. For this reason,
// we intercept some of them here and use our own stubs to handle them.
//
//===----------------------------------------------------------------------===//
#include "MCJIT.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/DynamicLibrary.h"
#include "llvm/Config/config.h"
using namespace llvm;
// AtExitHandlers - List of functions to call when the program exits,
// registered with the atexit() library function.
static std::vector<void (*)()> AtExitHandlers;
/// runAtExitHandlers - Run any functions registered by the program's
/// calls to atexit(3), which we intercept and store in
/// AtExitHandlers.
///
static void runAtExitHandlers() {
while (!AtExitHandlers.empty()) {
void (*Fn)() = AtExitHandlers.back();
AtExitHandlers.pop_back();
Fn();
}
}
//===----------------------------------------------------------------------===//
// 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 defined(__linux__)
#if defined(HAVE_SYS_STAT_H)
#include <sys/stat.h>
#endif
#include <fcntl.h>
#include <unistd.h>
/* stat functions are redirecting to __xstat with a version number. On x86-64
* linking with libc_nonshared.a and -Wl,--export-dynamic doesn't make 'stat'
* available as an exported symbol, so we have to add it explicitly.
*/
namespace {
class StatSymbols {
public:
StatSymbols() {
sys::DynamicLibrary::AddSymbol("stat", (void*)(intptr_t)stat);
sys::DynamicLibrary::AddSymbol("fstat", (void*)(intptr_t)fstat);
sys::DynamicLibrary::AddSymbol("lstat", (void*)(intptr_t)lstat);
sys::DynamicLibrary::AddSymbol("stat64", (void*)(intptr_t)stat64);
sys::DynamicLibrary::AddSymbol("\x1stat64", (void*)(intptr_t)stat64);
sys::DynamicLibrary::AddSymbol("\x1open64", (void*)(intptr_t)open64);
sys::DynamicLibrary::AddSymbol("\x1lseek64", (void*)(intptr_t)lseek64);
sys::DynamicLibrary::AddSymbol("fstat64", (void*)(intptr_t)fstat64);
sys::DynamicLibrary::AddSymbol("lstat64", (void*)(intptr_t)lstat64);
sys::DynamicLibrary::AddSymbol("atexit", (void*)(intptr_t)atexit);
sys::DynamicLibrary::AddSymbol("mknod", (void*)(intptr_t)mknod);
}
};
}
static StatSymbols initStatSymbols;
#endif // __linux__
// jit_exit - Used to intercept the "exit" library call.
static void jit_exit(int Status) {
runAtExitHandlers(); // Run atexit handlers...
exit(Status);
}
// jit_atexit - Used to intercept the "atexit" library call.
static int jit_atexit(void (*Fn)()) {
AtExitHandlers.push_back(Fn); // Take note of atexit handler...
return 0; // Always successful
}
static int jit_noop() {
return 0;
}
//===----------------------------------------------------------------------===//
//
/// getPointerToNamedFunction - This method returns the address of the specified
/// function by using the dynamic loader interface. As such it is only useful
/// for resolving library symbols, not code generated symbols.
///
void *MCJIT::getPointerToNamedFunction(const std::string &Name,
bool AbortOnFailure) {
if (!isSymbolSearchingDisabled()) {
// Check to see if this is one of the functions we want to intercept. Note,
// we cast to intptr_t here to silence a -pedantic warning that complains
// about casting a function pointer to a normal pointer.
if (Name == "exit") return (void*)(intptr_t)&jit_exit;
if (Name == "atexit") return (void*)(intptr_t)&jit_atexit;
// 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();
// If this is an asm specifier, skip the sentinal.
if (NameStr[0] == 1) ++NameStr;
// If it's an external function, look it up in the process image...
void *Ptr = sys::DynamicLibrary::SearchForAddressOfSymbol(NameStr);
if (Ptr) return Ptr;
// If it wasn't found and if it starts with an underscore ('_') character,
// and has an asm specifier, try again without the underscore.
if (Name[0] == 1 && NameStr[0] == '_') {
Ptr = sys::DynamicLibrary::SearchForAddressOfSymbol(NameStr+1);
if (Ptr) return Ptr;
}
// Darwin/PPC adds $LDBLStub suffixes to various symbols like printf. These
// are references to hidden visibility symbols that dlsym cannot resolve.
// If we have one of these, strip off $LDBLStub and try again.
#if defined(__APPLE__) && defined(__ppc__)
if (Name.size() > 9 && Name[Name.size()-9] == '$' &&
memcmp(&Name[Name.size()-8], "LDBLStub", 8) == 0) {
// First try turning $LDBLStub into $LDBL128. If that fails, strip it off.
// This mirrors logic in libSystemStubs.a.
std::string Prefix = std::string(Name.begin(), Name.end()-9);
if (void *Ptr = getPointerToNamedFunction(Prefix+"$LDBL128", false))
return Ptr;
if (void *Ptr = getPointerToNamedFunction(Prefix, false))
return Ptr;
}
#endif
}
/// If a LazyFunctionCreator is installed, use it to get/create the function.
if (LazyFunctionCreator)
if (void *RP = LazyFunctionCreator(Name))
return RP;
if (AbortOnFailure) {
report_fatal_error("Program used external function '"+Name+
"' which could not be resolved!");
}
return 0;
}

View File

@ -215,23 +215,3 @@ GenericValue MCJIT::runFunction(Function *F,
llvm_unreachable("Full-featured argument passing not supported yet!");
}
void *MCJIT::getPointerToNamedFunction(const std::string &Name,
bool AbortOnFailure){
if (!isSymbolSearchingDisabled()) {
void *ptr = MemMgr->getPointerToNamedFunction(Name, false);
if (ptr)
return ptr;
}
/// If a LazyFunctionCreator is installed, use it to get/create the function.
if (LazyFunctionCreator)
if (void *RP = LazyFunctionCreator(Name))
return RP;
if (AbortOnFailure) {
report_fatal_error("Program used external function '"+Name+
"' which could not be resolved!");
}
return 0;
}

View File

@ -67,7 +67,6 @@ public:
///
virtual void *getPointerToNamedFunction(const std::string &Name,
bool AbortOnFailure = true);
/// 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.

View File

@ -33,17 +33,46 @@ public:
uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment,
unsigned SectionID) {
return JMM->allocateSpace(Size, Alignment);
return JMM->allocateDataSection(Size, Alignment, SectionID);
}
uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment,
unsigned SectionID) {
return JMM->allocateSpace(Size, Alignment);
return JMM->allocateCodeSection(Size, Alignment, SectionID);
}
virtual void *getPointerToNamedFunction(const std::string &Name,
bool AbortOnFailure = true) {
return JMM->getPointerToNamedFunction(Name, AbortOnFailure);
// Allocate ActualSize bytes, or more, for the named function. Return
// a pointer to the allocated memory and update Size to reflect how much
// memory was acutally allocated.
uint8_t *startFunctionBody(const char *Name, uintptr_t &Size) {
// FIXME: This should really reference the MCAsmInfo to get the global
// prefix.
if (Name[0] == '_') ++Name;
Function *F = M->getFunction(Name);
// Some ObjC names have a prefixed \01 in the IR. If we failed to find
// the symbol and it's of the ObjC conventions (starts with "-" or
// "+"), try prepending a \01 and see if we can find it that way.
if (!F && (Name[0] == '-' || Name[0] == '+'))
F = M->getFunction((Twine("\1") + Name).str());
assert(F && "No matching function in JIT IR Module!");
return JMM->startFunctionBody(F, Size);
}
// Mark the end of the function, including how much of the allocated
// memory was actually used.
void endFunctionBody(const char *Name, uint8_t *FunctionStart,
uint8_t *FunctionEnd) {
// FIXME: This should really reference the MCAsmInfo to get the global
// prefix.
if (Name[0] == '_') ++Name;
Function *F = M->getFunction(Name);
// Some ObjC names have a prefixed \01 in the IR. If we failed to find
// the symbol and it's of the ObjC conventions (starts with "-" or
// "+"), try prepending a \01 and see if we can find it that way.
if (!F && (Name[0] == '-' || Name[0] == '+'))
F = M->getFunction((Twine("\1") + Name).str());
assert(F && "No matching function in JIT IR Module!");
JMM->endFunctionBody(F, FunctionStart, FunctionEnd);
}
};

View File

@ -26,290 +26,45 @@ RuntimeDyldImpl::~RuntimeDyldImpl() {}
namespace llvm {
void RuntimeDyldImpl::extractFunction(StringRef Name, uint8_t *StartAddress,
uint8_t *EndAddress) {
// FIXME: DEPRECATED in favor of by-section allocation.
// Allocate memory for the function via the memory manager.
uintptr_t Size = EndAddress - StartAddress + 1;
uintptr_t AllocSize = Size;
uint8_t *Mem = MemMgr->startFunctionBody(Name.data(), AllocSize);
assert(Size >= (uint64_t)(EndAddress - StartAddress + 1) &&
"Memory manager failed to allocate enough memory!");
// Copy the function payload into the memory block.
memcpy(Mem, StartAddress, Size);
MemMgr->endFunctionBody(Name.data(), Mem, Mem + Size);
// Remember where we put it.
unsigned SectionID = Sections.size();
Sections.push_back(sys::MemoryBlock(Mem, Size));
// Default the assigned address for this symbol to wherever this
// allocated it.
SymbolTable[Name] = SymbolLoc(SectionID, 0);
DEBUG(dbgs() << " allocated to [" << Mem << ", " << Mem + Size << "]\n");
}
// Resolve the relocations for all symbols we currently know about.
void RuntimeDyldImpl::resolveRelocations() {
// First, resolve relocations assotiated with external symbols.
resolveSymbols();
// Just iterate over the sections we have and resolve all the relocations
// in them. Gross overkill, but it gets the job done.
for (int i = 0, e = Sections.size(); i != e; ++i) {
reassignSectionAddress(i, Sections[i].LoadAddress);
reassignSectionAddress(i, SectionLoadAddress[i]);
}
}
void RuntimeDyldImpl::mapSectionAddress(void *LocalAddress,
uint64_t TargetAddress) {
for (unsigned i = 0, e = Sections.size(); i != e; ++i) {
if (Sections[i].Address == LocalAddress) {
reassignSectionAddress(i, TargetAddress);
return;
}
}
llvm_unreachable("Attempting to remap address of unknown section!");
assert(SectionLocalMemToID.count(LocalAddress) &&
"Attempting to remap address of unknown section!");
unsigned SectionID = SectionLocalMemToID[LocalAddress];
reassignSectionAddress(SectionID, TargetAddress);
}
bool RuntimeDyldImpl::loadObject(const MemoryBuffer *InputBuffer) {
// FIXME: ObjectFile don't modify MemoryBuffer.
// It should use const MemoryBuffer as parameter.
ObjectFile *obj = ObjectFile::
createObjectFile(const_cast<MemoryBuffer*>(InputBuffer));
Arch = (Triple::ArchType)obj->getArch();
LocalSymbolMap LocalSymbols; // Functions and data symbols from the
// object file.
ObjSectionToIDMap LocalSections; // Used sections from the object file
error_code err;
// Parse symbols
DEBUG(dbgs() << "Parse symbols:\n");
for (symbol_iterator it = obj->begin_symbols(), itEnd = obj->end_symbols();
it != itEnd; it.increment(err)) {
if (err) break;
object::SymbolRef::Type SymType;
StringRef Name;
if ((bool)(err = it->getType(SymType))) break;
if ((bool)(err = it->getName(Name))) break;
if (SymType == object::SymbolRef::ST_Function ||
SymType == object::SymbolRef::ST_Data) {
uint64_t FileOffset;
uint32_t flags;
StringRef sData;
section_iterator sIt = obj->end_sections();
if ((bool)(err = it->getFileOffset(FileOffset))) break;
if ((bool)(err = it->getFlags(flags))) break;
if ((bool)(err = it->getSection(sIt))) break;
if (sIt == obj->end_sections()) continue;
if ((bool)(err = sIt->getContents(sData))) break;
const uint8_t* SymPtr = (const uint8_t*)InputBuffer->getBufferStart() +
(uintptr_t)FileOffset;
uintptr_t SectOffset = (uintptr_t)(SymPtr - (const uint8_t*)sData.begin());
unsigned SectionID =
findOrEmitSection(*sIt,
SymType == object::SymbolRef::ST_Function,
LocalSections);
bool isGlobal = flags & SymbolRef::SF_Global;
LocalSymbols[Name.data()] = SymbolLoc(SectionID, SectOffset);
DEBUG(dbgs() << "\tFileOffset: " << format("%p", (uintptr_t)FileOffset)
<< " flags: " << flags
<< " SID: " << SectionID
<< " Offset: " << format("%p", SectOffset));
if (isGlobal)
SymbolTable[Name] = SymbolLoc(SectionID, SectOffset);
}
DEBUG(dbgs() << "\tType: " << SymType << " Name: " << Name << "\n");
}
if (err) {
report_fatal_error(err.message());
}
// Parse and proccess relocations
DEBUG(dbgs() << "Parse relocations:\n");
for (section_iterator sIt = obj->begin_sections(),
sItEnd = obj->end_sections(); sIt != sItEnd; sIt.increment(err)) {
if (err) break;
bool isFirstRelocation = true;
unsigned SectionID = 0;
StubMap Stubs;
for (relocation_iterator it = sIt->begin_relocations(),
itEnd = sIt->end_relocations(); it != itEnd; it.increment(err)) {
if (err) break;
// If it's first relocation in this section, find its SectionID
if (isFirstRelocation) {
SectionID = findOrEmitSection(*sIt, true, LocalSections);
DEBUG(dbgs() << "\tSectionID: " << SectionID << "\n");
isFirstRelocation = false;
}
ObjRelocationInfo RI;
RI.SectionID = SectionID;
if ((bool)(err = it->getAdditionalInfo(RI.AdditionalInfo))) break;
if ((bool)(err = it->getOffset(RI.Offset))) break;
if ((bool)(err = it->getSymbol(RI.Symbol))) break;
if ((bool)(err = it->getType(RI.Type))) break;
DEBUG(dbgs() << "\t\tAddend: " << RI.AdditionalInfo
<< " Offset: " << format("%p", (uintptr_t)RI.Offset)
<< " Type: " << (uint32_t)(RI.Type & 0xffffffffL)
<< "\n");
processRelocationRef(RI, *obj, LocalSections, LocalSymbols, Stubs);
}
if (err) {
report_fatal_error(err.message());
}
}
return false;
}
unsigned RuntimeDyldImpl::emitSection(const SectionRef &Section,
bool IsCode) {
unsigned StubBufSize = 0,
StubSize = getMaxStubSize();
error_code err;
if (StubSize > 0) {
for (relocation_iterator it = Section.begin_relocations(),
itEnd = Section.end_relocations(); it != itEnd; it.increment(err))
StubBufSize += StubSize;
}
StringRef data;
uint64_t Alignment64;
if ((bool)(err = Section.getContents(data))) report_fatal_error(err.message());
if ((bool)(err = Section.getAlignment(Alignment64)))
report_fatal_error(err.message());
unsigned Alignment = (unsigned)Alignment64 & 0xffffffffL;
unsigned DataSize = data.size();
unsigned Allocate = DataSize + StubBufSize;
unsigned SectionID = Sections.size();
const char *pData = data.data();
uint8_t *Addr = IsCode
? MemMgr->allocateCodeSection(Allocate, Alignment, SectionID)
: MemMgr->allocateDataSection(Allocate, Alignment, SectionID);
memcpy(Addr, pData, DataSize);
DEBUG(dbgs() << "emitSection SectionID: " << SectionID
<< " obj addr: " << format("%p", pData)
<< " new addr: " << format("%p", Addr)
<< " DataSize: " << DataSize
<< " StubBufSize: " << StubBufSize
<< " Allocate: " << Allocate
<< "\n");
Sections.push_back(SectionEntry(Addr, Allocate, DataSize,(uintptr_t)pData));
return SectionID;
}
unsigned RuntimeDyldImpl::
findOrEmitSection(const SectionRef &Section, bool IsCode,
ObjSectionToIDMap &LocalSections) {
unsigned SectionID = 0;
ObjSectionToIDMap::iterator sIDIt = LocalSections.find(Section);
if (sIDIt != LocalSections.end())
SectionID = sIDIt->second;
else {
SectionID = emitSection(Section, IsCode);
LocalSections[Section] = SectionID;
}
return SectionID;
}
void RuntimeDyldImpl::AddRelocation(const RelocationValueRef &Value,
unsigned SectionID, uintptr_t Offset,
uint32_t RelType) {
DEBUG(dbgs() << "AddRelocation SymNamePtr: " << format("%p", Value.SymbolName)
<< " SID: " << Value.SectionID
<< " Addend: " << format("%p", Value.Addend)
<< " Offset: " << format("%p", Offset)
<< " RelType: " << format("%x", RelType)
<< "\n");
if (Value.SymbolName == 0) {
Relocations[Value.SectionID].push_back(RelocationEntry(
SectionID,
Offset,
RelType,
Value.Addend));
} else
SymbolRelocations[Value.SymbolName].push_back(RelocationEntry(
SectionID,
Offset,
RelType,
Value.Addend));
}
uint8_t *RuntimeDyldImpl::createStubFunction(uint8_t *Addr) {
// TODO: There is only ARM far stub now. We should add the Thumb stub,
// and stubs for branches Thumb - ARM and ARM - Thumb.
if (Arch == Triple::arm) {
uint32_t *StubAddr = (uint32_t*)Addr;
*StubAddr = 0xe51ff004; // ldr pc,<label>
return (uint8_t*)++StubAddr;
}
else
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. Re-apply any
// relocations referencing this section with the given address.
//
// 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.
Sections[SectionID].LoadAddress = Addr;
DEBUG(dbgs() << "Resolving relocations Section #" << SectionID
<< "\t" << format("%p", (uint8_t *)Addr)
<< "\n");
resolveRelocationList(Relocations[SectionID], Addr);
}
void RuntimeDyldImpl::resolveRelocationEntry(const RelocationEntry &RE,
uint64_t Value) {
uint8_t *Target = Sections[RE.SectionID].Address + RE.Offset;
DEBUG(dbgs() << "\tSectionID: " << RE.SectionID
<< " + " << RE.Offset << " (" << format("%p", Target) << ")"
<< " Data: " << RE.Data
<< " Addend: " << RE.Addend
<< "\n");
resolveRelocation(Target, Sections[RE.SectionID].LoadAddress + RE.Offset,
Value, RE.Data, RE.Addend);
}
void RuntimeDyldImpl::resolveRelocationList(const RelocationList &Relocs,
uint64_t Value) {
for (unsigned i = 0, e = Relocs.size(); i != e; ++i) {
resolveRelocationEntry(Relocs[i], Value);
}
}
// resolveSymbols - Resolve any relocations to the specified symbols if
// we know where it lives.
void RuntimeDyldImpl::resolveSymbols() {
StringMap<RelocationList>::iterator it = SymbolRelocations.begin(),
itEnd = SymbolRelocations.end();
for (; it != itEnd; it++) {
StringRef Name = it->first();
RelocationList &Relocs = it->second;
StringMap<SymbolLoc>::const_iterator Loc = SymbolTable.find(Name);
if (Loc == SymbolTable.end()) {
// This is an external symbol, try to get it address from
// MemoryManager.
uint8_t *Addr = (uint8_t*) MemMgr->getPointerToNamedFunction(Name.data(),
true);
DEBUG(dbgs() << "Resolving relocations Name: " << Name
<< "\t" << format("%p", Addr)
<< "\n");
resolveRelocationList(Relocs, (uintptr_t)Addr);
} else {
// Change the relocation to be section relative rather than symbol
// relative and move it to the resolved relocation list.
DEBUG(dbgs() << "Resolving symbol '" << Name << "'\n");
for (int i = 0, e = Relocs.size(); i != e; ++i) {
RelocationEntry Entry = Relocs[i];
Entry.Addend += Loc->second.second;
Relocations[Loc->second.first].push_back(Entry);
}
Relocs.clear();
}
}
}
//===----------------------------------------------------------------------===//
// RuntimeDyld class implementation
RuntimeDyld::RuntimeDyld(RTDyldMemoryManager *mm) {

View File

@ -25,58 +25,222 @@ using namespace llvm::object;
namespace llvm {
namespace {
void RuntimeDyldELF::resolveX86_64Relocation(uint8_t *LocalAddress,
uint64_t FinalAddress,
uint64_t Value,
uint32_t Type,
int64_t Addend) {
switch (Type) {
default:
llvm_unreachable("Relocation type not implemented yet!");
break;
// FIXME: this function should probably not live here...
//
// Returns the name and address of an unrelocated symbol in an ELF section
void getSymbolInfo(symbol_iterator Sym, uint64_t &Addr, StringRef &Name) {
//FIXME: error checking here required to catch corrupt ELF objects...
error_code Err = Sym->getName(Name);
uint64_t AddrInSection;
Err = Sym->getAddress(AddrInSection);
SectionRef empty_section;
section_iterator Section(empty_section);
Err = Sym->getSection(Section);
StringRef SectionContents;
Section->getContents(SectionContents);
Addr = reinterpret_cast<uint64_t>(SectionContents.data()) + AddrInSection;
}
}
bool RuntimeDyldELF::loadObject(MemoryBuffer *InputBuffer) {
if (!isCompatibleFormat(InputBuffer))
return true;
OwningPtr<ObjectFile> Obj(ObjectFile::createELFObjectFile(InputBuffer));
Arch = Obj->getArch();
// Map address in the Object file image to function names
IntervalMap<uint64_t, StringRef>::Allocator A;
IntervalMap<uint64_t, StringRef> FuncMap(A);
// This is a bit of a hack. The ObjectFile we've just loaded reports
// section addresses as 0 and doesn't provide access to the section
// offset (from which we could calculate the address. Instead,
// we're storing the address when it comes up in the ST_Debug case
// below.
//
StringMap<uint64_t> DebugSymbolMap;
symbol_iterator SymEnd = Obj->end_symbols();
error_code Err;
for (symbol_iterator Sym = Obj->begin_symbols();
Sym != SymEnd; Sym.increment(Err)) {
SymbolRef::Type Type;
Sym->getType(Type);
if (Type == SymbolRef::ST_Function) {
StringRef Name;
uint64_t Addr;
getSymbolInfo(Sym, Addr, Name);
uint64_t Size;
Err = Sym->getSize(Size);
uint8_t *Start;
uint8_t *End;
Start = reinterpret_cast<uint8_t*>(Addr);
End = reinterpret_cast<uint8_t*>(Addr + Size - 1);
extractFunction(Name, Start, End);
FuncMap.insert(Addr, Addr + Size - 1, Name);
} else if (Type == SymbolRef::ST_Debug) {
// This case helps us find section addresses
StringRef Name;
uint64_t Addr;
getSymbolInfo(Sym, Addr, Name);
DebugSymbolMap[Name] = Addr;
}
}
// Iterate through the relocations for this object
section_iterator SecEnd = Obj->end_sections();
for (section_iterator Sec = Obj->begin_sections();
Sec != SecEnd; Sec.increment(Err)) {
StringRef SecName;
uint64_t SecAddr;
Sec->getName(SecName);
// Ignore sections that aren't in our map
if (DebugSymbolMap.find(SecName) == DebugSymbolMap.end()) {
continue;
}
SecAddr = DebugSymbolMap[SecName];
relocation_iterator RelEnd = Sec->end_relocations();
for (relocation_iterator Rel = Sec->begin_relocations();
Rel != RelEnd; Rel.increment(Err)) {
uint64_t RelOffset;
uint64_t RelType;
int64_t RelAddend;
SymbolRef RelSym;
StringRef SymName;
uint64_t SymAddr;
uint64_t SymOffset;
Rel->getAddress(RelOffset);
Rel->getType(RelType);
Rel->getAdditionalInfo(RelAddend);
Rel->getSymbol(RelSym);
RelSym.getName(SymName);
RelSym.getAddress(SymAddr);
RelSym.getFileOffset(SymOffset);
// If this relocation is inside a function, we want to store the
// function name and a function-relative offset
IntervalMap<uint64_t, StringRef>::iterator ContainingFunc
= FuncMap.find(SecAddr + RelOffset);
if (ContainingFunc.valid()) {
// Re-base the relocation to make it relative to the target function
RelOffset = (SecAddr + RelOffset) - ContainingFunc.start();
Relocations[SymName].push_back(RelocationEntry(ContainingFunc.value(),
RelOffset,
RelType,
RelAddend,
true));
} else {
Relocations[SymName].push_back(RelocationEntry(SecName,
RelOffset,
RelType,
RelAddend,
false));
}
}
}
return false;
}
void RuntimeDyldELF::resolveRelocations() {
// FIXME: deprecated. should be changed to use the by-section
// allocation and relocation scheme.
// Just iterate over the symbols in our symbol table and assign their
// addresses.
StringMap<SymbolLoc>::iterator i = SymbolTable.begin();
StringMap<SymbolLoc>::iterator e = SymbolTable.end();
for (;i != e; ++i) {
assert (i->getValue().second == 0 && "non-zero offset in by-function sym!");
reassignSymbolAddress(i->getKey(),
(uint8_t*)Sections[i->getValue().first].base());
}
}
void RuntimeDyldELF::resolveX86_64Relocation(StringRef Name,
uint8_t *Addr,
const RelocationEntry &RE) {
uint8_t *TargetAddr;
if (RE.IsFunctionRelative) {
StringMap<SymbolLoc>::const_iterator Loc = SymbolTable.find(RE.Target);
assert(Loc != SymbolTable.end() && "Function for relocation not found");
TargetAddr =
reinterpret_cast<uint8_t*>(Sections[Loc->second.first].base()) +
Loc->second.second + RE.Offset;
} else {
// FIXME: Get the address of the target section and add that to RE.Offset
llvm_unreachable("Non-function relocation not implemented yet!");
}
switch (RE.Type) {
default: llvm_unreachable("Relocation type not implemented yet!");
case ELF::R_X86_64_64: {
uint64_t *Target = (uint64_t*)(LocalAddress);
*Target = Value + Addend;
uint8_t **Target = reinterpret_cast<uint8_t**>(TargetAddr);
*Target = Addr + RE.Addend;
break;
}
case ELF::R_X86_64_32:
case ELF::R_X86_64_32S: {
Value += Addend;
uint64_t Value = reinterpret_cast<uint64_t>(Addr) + RE.Addend;
// FIXME: Handle the possibility of this assertion failing
assert((Type == ELF::R_X86_64_32 && !(Value & 0xFFFFFFFF00000000ULL)) ||
(Type == ELF::R_X86_64_32S &&
assert((RE.Type == ELF::R_X86_64_32 && !(Value & 0xFFFFFFFF00000000ULL)) ||
(RE.Type == ELF::R_X86_64_32S &&
(Value & 0xFFFFFFFF00000000ULL) == 0xFFFFFFFF00000000ULL));
uint32_t TruncatedAddr = (Value & 0xFFFFFFFF);
uint32_t *Target = reinterpret_cast<uint32_t*>(LocalAddress);
uint32_t *Target = reinterpret_cast<uint32_t*>(TargetAddr);
*Target = TruncatedAddr;
break;
}
case ELF::R_X86_64_PC32: {
uint32_t *Placeholder = reinterpret_cast<uint32_t*>(LocalAddress);
int64_t RealOffset = *Placeholder + Value + Addend - FinalAddress;
assert(RealOffset <= 214783647 && RealOffset >= -214783648);
int32_t TruncOffset = (RealOffset & 0xFFFFFFFF);
uint32_t *Placeholder = reinterpret_cast<uint32_t*>(TargetAddr);
uint64_t RealOffset = *Placeholder +
reinterpret_cast<uint64_t>(Addr) +
RE.Addend - reinterpret_cast<uint64_t>(TargetAddr);
assert((RealOffset & 0xFFFFFFFF) == RealOffset);
uint32_t TruncOffset = (RealOffset & 0xFFFFFFFF);
*Placeholder = TruncOffset;
break;
}
}
}
void RuntimeDyldELF::resolveX86Relocation(uint8_t *LocalAddress,
uint32_t FinalAddress,
uint32_t Value,
uint32_t Type,
int32_t Addend) {
switch (Type) {
void RuntimeDyldELF::resolveX86Relocation(StringRef Name,
uint8_t *Addr,
const RelocationEntry &RE) {
uint8_t *TargetAddr;
if (RE.IsFunctionRelative) {
StringMap<SymbolLoc>::const_iterator Loc = SymbolTable.find(RE.Target);
assert(Loc != SymbolTable.end() && "Function for relocation not found");
TargetAddr =
reinterpret_cast<uint8_t*>(Sections[Loc->second.first].base()) +
Loc->second.second + RE.Offset;
} else {
// FIXME: Get the address of the target section and add that to RE.Offset
llvm_unreachable("Non-function relocation not implemented yet!");
}
switch (RE.Type) {
case ELF::R_386_32: {
uint32_t *Target = (uint32_t*)(LocalAddress);
*Target = Value + Addend;
uint8_t **Target = reinterpret_cast<uint8_t**>(TargetAddr);
*Target = Addr + RE.Addend;
break;
}
case ELF::R_386_PC32: {
uint32_t *Placeholder = reinterpret_cast<uint32_t*>(LocalAddress);
uint32_t RealOffset = *Placeholder + Value + Addend - FinalAddress;
uint32_t *Placeholder = reinterpret_cast<uint32_t*>(TargetAddr);
uint32_t RealOffset = *Placeholder + reinterpret_cast<uintptr_t>(Addr) +
RE.Addend - reinterpret_cast<uintptr_t>(TargetAddr);
*Placeholder = RealOffset;
break;
}
@ -84,173 +248,57 @@ void RuntimeDyldELF::resolveX86Relocation(uint8_t *LocalAddress,
// There are other relocation types, but it appears these are the
// only ones currently used by the LLVM ELF object writer
llvm_unreachable("Relocation type not implemented yet!");
break;
}
}
void RuntimeDyldELF::resolveARMRelocation(uint8_t *LocalAddress,
uint32_t FinalAddress,
uint32_t Value,
uint32_t Type,
int32_t Addend) {
// TODO: Add Thumb relocations.
uint32_t* TargetPtr = (uint32_t*)LocalAddress;
Value += Addend;
DEBUG(dbgs() << "resolveARMRelocation, LocalAddress: " << LocalAddress
<< " 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!");
// Just write 32bit value to relocation address
case ELF::R_ARM_ABS32 :
*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 :
Value = Value & 0xFFFF;
*TargetPtr |= Value & 0xFFF;
*TargetPtr |= ((Value >> 12) & 0xF) << 16;
break;
// Write last 16 bit of 32 bit value to the mov instruction.
// Last 4 bit should be shifted.
case ELF::R_ARM_MOVT_ABS :
Value = (Value >> 16) & 0xFFFF;
*TargetPtr |= Value & 0xFFF;
*TargetPtr |= ((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;
*TargetPtr &= 0xFF000000;
*TargetPtr |= RelValue;
break;
}
void RuntimeDyldELF::resolveArmRelocation(StringRef Name,
uint8_t *Addr,
const RelocationEntry &RE) {
}
void RuntimeDyldELF::resolveRelocation(uint8_t *LocalAddress,
uint64_t FinalAddress,
uint64_t Value,
uint32_t Type,
int64_t Addend) {
void RuntimeDyldELF::resolveRelocation(StringRef Name,
uint8_t *Addr,
const RelocationEntry &RE) {
switch (Arch) {
case Triple::x86_64:
resolveX86_64Relocation(LocalAddress, FinalAddress, Value, Type, Addend);
resolveX86_64Relocation(Name, Addr, RE);
break;
case Triple::x86:
resolveX86Relocation(LocalAddress, (uint32_t)(FinalAddress & 0xffffffffL),
(uint32_t)(Value & 0xffffffffL), Type,
(uint32_t)(Addend & 0xffffffffL));
resolveX86Relocation(Name, Addr, RE);
break;
case Triple::arm: // Fall through.
case Triple::thumb:
resolveARMRelocation(LocalAddress, (uint32_t)(FinalAddress & 0xffffffffL),
(uint32_t)(Value & 0xffffffffL), Type,
(uint32_t)(Addend & 0xffffffffL));
case Triple::arm:
resolveArmRelocation(Name, Addr, RE);
break;
default: llvm_unreachable("Unsupported CPU type!");
}
}
void RuntimeDyldELF::
processRelocationRef(const ObjRelocationInfo &Rel, const ObjectFile &Obj,
ObjSectionToIDMap &ObjSectionToID,
LocalSymbolMap &Symbols, StubMap &Stubs) {
void RuntimeDyldELF::reassignSymbolAddress(StringRef Name, uint8_t *Addr) {
// FIXME: deprecated. switch to reassignSectionAddress() instead.
//
// Actually moving the symbol address requires by-section mapping.
assert(Sections[SymbolTable.lookup(Name).first].base() == (void*)Addr &&
"Unable to relocate section in by-function JIT allocation model!");
uint32_t RelType = (uint32_t)(Rel.Type & 0xffffffffL);
intptr_t Addend = (intptr_t)Rel.AdditionalInfo;
RelocationValueRef Value;
StringRef TargetName;
const SymbolRef &Symbol = Rel.Symbol;
Symbol.getName(TargetName);
DEBUG(dbgs() << "\t\tRelType: " << RelType
<< " Addend: " << Addend
<< " TargetName: " << TargetName
<< "\n");
// First look the symbol in object file symbols.
LocalSymbolMap::iterator it = Symbols.find(TargetName.data());
if (it != Symbols.end()) {
Value.SectionID = it->second.first;
Value.Addend = it->second.second;
} else {
// Second look the symbol in global symbol table.
StringMap<SymbolLoc>::iterator itS = SymbolTable.find(TargetName.data());
if (itS != SymbolTable.end()) {
Value.SectionID = itS->second.first;
Value.Addend = itS->second.second;
} else {
SymbolRef::Type SymType;
Symbol.getType(SymType);
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.
section_iterator sIt = Obj.end_sections();
Symbol.getSection(sIt);
if (sIt == Obj.end_sections())
llvm_unreachable("Symbol section not found, bad object file format!");
DEBUG(dbgs() << "\t\tThis is section symbol\n");
Value.SectionID = findOrEmitSection((*sIt), true, ObjSectionToID);
Value.Addend = Addend;
break;
}
case SymbolRef::ST_Unknown: {
Value.SymbolName = TargetName.data();
Value.Addend = Addend;
break;
}
default:
llvm_unreachable("Unresolved symbol type!");
break;
}
}
RelocationList &Relocs = Relocations[Name];
for (unsigned i = 0, e = Relocs.size(); i != e; ++i) {
RelocationEntry &RE = Relocs[i];
resolveRelocation(Name, Addr, RE);
}
DEBUG(dbgs() << "\t\tRel.SectionID: " << Rel.SectionID
<< " Rel.Offset: " << Rel.Offset
<< "\n");
if (Arch == Triple::arm &&
(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.
DEBUG(dbgs() << "\t\tThis is an ARM branch relocation.");
SectionEntry &Section = Sections[Rel.SectionID];
uint8_t *Target = Section.Address + Rel.Offset;
}
// Look up for existing stub.
StubMap::const_iterator stubIt = Stubs.find(Value);
if (stubIt != Stubs.end()) {
resolveRelocation(Target, Section.LoadAddress, (uint64_t)Section.Address +
stubIt->second, RelType, 0);
DEBUG(dbgs() << " Stub function found\n");
} else {
// Create a new stub function.
DEBUG(dbgs() << " Create a new stub function\n");
Stubs[Value] = Section.StubOffset;
uint8_t *StubTargetAddr = createStubFunction(Section.Address +
Section.StubOffset);
AddRelocation(Value, Rel.SectionID,
StubTargetAddr - Section.Address, ELF::R_ARM_ABS32);
resolveRelocation(Target, Section.LoadAddress, (uint64_t)Section.Address +
Section.StubOffset, RelType, 0);
Section.StubOffset += getMaxStubSize();
}
} else
AddRelocation(Value, Rel.SectionID, Rel.Offset, RelType);
// Assign an address to a symbol name and resolve all the relocations
// associated with it.
void RuntimeDyldELF::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. Re-apply any
// relocations referencing this section with the given address.
//
// 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.
assert(0);
}
bool RuntimeDyldELF::isCompatibleFormat(const MemoryBuffer *InputBuffer) const {

View File

@ -21,42 +21,158 @@ using namespace llvm;
namespace llvm {
class RuntimeDyldELF : public RuntimeDyldImpl {
protected:
void resolveX86_64Relocation(uint8_t *LocalAddress,
uint64_t FinalAddress,
uint64_t Value,
uint32_t Type,
int64_t Addend);
// 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.
struct RelocationEntry {
// Function or section this relocation is contained in.
std::string Target;
// Offset into the target function or section for the relocation.
uint32_t Offset;
// Relocation type
uint32_t Type;
// Addend encoded in the instruction itself, if any.
int32_t Addend;
// Has the relocation been recalcuated as an offset within a function?
bool IsFunctionRelative;
// Has this relocation been resolved previously?
bool isResolved;
void resolveX86Relocation(uint8_t *LocalAddress,
uint32_t FinalAddress,
uint32_t Value,
uint32_t Type,
int32_t Addend);
RelocationEntry(StringRef t,
uint32_t offset,
uint32_t type,
int32_t addend,
bool isFunctionRelative)
: Target(t)
, Offset(offset)
, Type(type)
, Addend(addend)
, IsFunctionRelative(isFunctionRelative)
, isResolved(false) { }
};
typedef SmallVector<RelocationEntry, 4> RelocationList;
StringMap<RelocationList> Relocations;
unsigned Arch;
void resolveARMRelocation(uint8_t *LocalAddress,
uint32_t FinalAddress,
uint32_t Value,
uint32_t Type,
int32_t Addend);
void resolveRelocations();
virtual void resolveRelocation(uint8_t *LocalAddress,
uint64_t FinalAddress,
uint64_t Value,
uint32_t Type,
int64_t Addend);
void resolveX86_64Relocation(StringRef Name,
uint8_t *Addr,
const RelocationEntry &RE);
virtual void processRelocationRef(const ObjRelocationInfo &Rel,
const ObjectFile &Obj,
ObjSectionToIDMap &ObjSectionToID,
LocalSymbolMap &Symbols, StubMap &Stubs);
void resolveX86Relocation(StringRef Name,
uint8_t *Addr,
const RelocationEntry &RE);
void resolveArmRelocation(StringRef Name,
uint8_t *Addr,
const RelocationEntry &RE);
void resolveRelocation(StringRef Name,
uint8_t *Addr,
const RelocationEntry &RE);
public:
RuntimeDyldELF(RTDyldMemoryManager *mm) : RuntimeDyldImpl(mm) {}
bool loadObject(MemoryBuffer *InputBuffer);
void reassignSymbolAddress(StringRef Name, uint8_t *Addr);
void reassignSectionAddress(unsigned SectionID, uint64_t Addr);
bool isCompatibleFormat(const MemoryBuffer *InputBuffer) const;
};
} // end namespace llvm
#endif
#endif
//===-- RuntimeDyldELF.h - Run-time dynamic linker 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.
//
//===----------------------------------------------------------------------===//
//
// ELF support for MC-JIT runtime dynamic linker.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_RUNTIME_DYLD_ELF_H
#define LLVM_RUNTIME_DYLD_ELF_H
#include "RuntimeDyldImpl.h"
using namespace llvm;
namespace llvm {
class RuntimeDyldELF : public RuntimeDyldImpl {
// 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.
struct RelocationEntry {
// Function or section this relocation is contained in.
std::string Target;
// Offset into the target function or section for the relocation.
uint32_t Offset;
// Relocation type
uint32_t Type;
// Addend encoded in the instruction itself, if any.
int32_t Addend;
// Has the relocation been recalcuated as an offset within a function?
bool IsFunctionRelative;
// Has this relocation been resolved previously?
bool isResolved;
RelocationEntry(StringRef t,
uint32_t offset,
uint32_t type,
int32_t addend,
bool isFunctionRelative)
: Target(t)
, Offset(offset)
, Type(type)
, Addend(addend)
, IsFunctionRelative(isFunctionRelative)
, isResolved(false) { }
};
typedef SmallVector<RelocationEntry, 4> RelocationList;
StringMap<RelocationList> Relocations;
unsigned Arch;
void resolveRelocations();
void resolveX86_64Relocation(StringRef Name,
uint8_t *Addr,
const RelocationEntry &RE);
void resolveX86Relocation(StringRef Name,
uint8_t *Addr,
const RelocationEntry &RE);
void resolveArmRelocation(StringRef Name,
uint8_t *Addr,
const RelocationEntry &RE);
void resolveRelocation(StringRef Name,
uint8_t *Addr,
const RelocationEntry &RE);
public:
RuntimeDyldELF(RTDyldMemoryManager *mm) : RuntimeDyldImpl(mm) {}
bool loadObject(MemoryBuffer *InputBuffer);
void reassignSymbolAddress(StringRef Name, uint8_t *Addr);
void reassignSectionAddress(unsigned SectionID, uint64_t Addr);
bool isCompatibleFormat(const MemoryBuffer *InputBuffer) const;
};
} // end namespace llvm
#endif

View File

@ -15,125 +15,45 @@
#define LLVM_RUNTIME_DYLD_IMPL_H
#include "llvm/ExecutionEngine/RuntimeDyld.h"
#include "llvm/Object/ObjectFile.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/Twine.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ExecutionEngine/ExecutionEngine.h"
#include "llvm/Support/Memory.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/system_error.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/ADT/Triple.h"
#include <map>
#include "llvm/Support/Format.h"
using namespace llvm;
using namespace llvm::object;
namespace llvm {
class SectionEntry {
public:
uint8_t* Address;
size_t Size;
uint64_t LoadAddress; // For each section, the address it will be
// considered to live at for relocations. The same
// as the pointer to the above memory block for
// hosted JITs.
uintptr_t StubOffset; // It's used for architecturies with stub
// functions for far relocations like ARM.
uintptr_t ObjAddress; // Section address in object file. It's use for
// calculate MachO relocation addend
SectionEntry(uint8_t* address, size_t size, uintptr_t stubOffset,
uintptr_t objAddress)
: Address(address), Size(size), LoadAddress((uintptr_t)address),
StubOffset(stubOffset), ObjAddress(objAddress) {}
};
class RelocationEntry {
public:
unsigned SectionID; // Section the relocation is contained in.
uintptr_t Offset; // Offset into the section for the relocation.
uint32_t Data; // Relocatino data. Including type of relocation
// and another flags and parameners from
intptr_t Addend; // Addend encoded in the instruction itself, if any,
// plus the offset into the source section for
// the symbol once the relocation is resolvable.
RelocationEntry(unsigned id, uint64_t offset, uint32_t data, int64_t addend)
: SectionID(id), Offset(offset), Data(data), Addend(addend) {}
};
// Raw relocation data from object file
class ObjRelocationInfo {
public:
unsigned SectionID;
uint64_t Offset;
SymbolRef Symbol;
uint64_t Type;
int64_t AdditionalInfo;
};
class RelocationValueRef {
public:
unsigned SectionID;
intptr_t Addend;
const char *SymbolName;
RelocationValueRef(): SectionID(0), Addend(0), SymbolName(0) {}
inline bool operator==(const RelocationValueRef &Other) const {
return std::memcmp(this, &Other, sizeof(RelocationValueRef)) == 0;
}
inline bool operator <(const RelocationValueRef &Other) const {
return std::memcmp(this, &Other, sizeof(RelocationValueRef)) < 0;
}
};
class RuntimeDyldImpl {
protected:
unsigned CPUType;
unsigned CPUSubtype;
// The MemoryManager to load objects into.
RTDyldMemoryManager *MemMgr;
// A list of emmitted sections.
typedef SmallVector<SectionEntry, 64> SectionList;
SectionList Sections;
// For each section, we have a MemoryBlock of it's data.
// Indexed by SectionID.
SmallVector<sys::MemoryBlock, 32> Sections;
// For each section, the address it will be considered to live at for
// relocations. The same as the pointer to the above memory block for hosted
// JITs. Indexed by SectionID.
SmallVector<uint64_t, 32> SectionLoadAddress;
// Keep a map of sections from object file to the SectionID which
// references it.
typedef std::map<SectionRef, unsigned> ObjSectionToIDMap;
// Keep a map of starting local address to the SectionID which references it.
// Lookup function for when we assign virtual addresses.
DenseMap<void *, unsigned> SectionLocalMemToID;
// Master symbol table. As modules are loaded and external symbols are
// resolved, their addresses are stored here as a SectionID/Offset pair.
typedef std::pair<unsigned, uintptr_t> SymbolLoc;
typedef std::pair<unsigned, uint64_t> SymbolLoc;
StringMap<SymbolLoc> SymbolTable;
typedef DenseMap<const char*, SymbolLoc> LocalSymbolMap;
// 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 writen is
// SectionID/Offset in the relocation itself.
DenseMap<unsigned, RelocationList> Relocations;
// Relocations to external symbols that are not yet resolved.
// Indexed by symbol name.
StringMap<RelocationList> SymbolRelocations;
typedef std::map<RelocationValueRef, uintptr_t> StubMap;
Triple::ArchType Arch;
inline unsigned getMaxStubSize() {
if (Arch == Triple::arm || Arch == Triple::thumb)
return 8; // 32-bit instruction and 32-bit address
else
return 0;
}
bool HasError;
std::string ErrorStr;
@ -146,62 +66,17 @@ protected:
}
uint8_t *getSectionAddress(unsigned SectionID) {
return (uint8_t*)Sections[SectionID].Address;
return (uint8_t*)Sections[SectionID].base();
}
void extractFunction(StringRef Name, uint8_t *StartAddress,
uint8_t *EndAddress);
/// \brief Emits section data from the object file to the MemoryManager.
/// \param IsCode if it's true then allocateCodeSection() will be
/// used for emmits, else allocateDataSection() will be used.
/// \return SectionID.
unsigned emitSection(const SectionRef &Section, bool IsCode);
/// \brief 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.
unsigned findOrEmitSection(const SectionRef &Section, bool IsCode,
ObjSectionToIDMap &LocalSections);
/// \brief If Value.SymbolName is NULL then store relocation to the
/// Relocations, else store it in the SymbolRelocations.
void AddRelocation(const RelocationValueRef &Value, unsigned SectionID,
uintptr_t Offset, uint32_t RelType);
/// \brief Emits long jump instruction to Addr.
/// \return Pointer to the memory area for emitting target address.
uint8_t* createStubFunction(uint8_t *Addr);
/// \brief Resolves relocations from Relocs list with address from Value.
void resolveRelocationList(const RelocationList &Relocs, uint64_t Value);
void resolveRelocationEntry(const RelocationEntry &RE, uint64_t Value);
/// \brief A object file specific relocation resolver
/// \param Address Address to apply the relocation action
/// \param Value Target symbol address to apply the relocation action
/// \param Type object file specific relocation type
/// \param Addend A constant addend used to compute the value to be stored
/// into the relocatable field
virtual void resolveRelocation(uint8_t *LocalAddress,
uint64_t FinalAddress,
uint64_t Value,
uint32_t Type,
int64_t Addend) = 0;
/// \brief Parses the object file relocation and store it to Relocations
/// or SymbolRelocations. Its depend from object file type.
virtual void processRelocationRef(const ObjRelocationInfo &Rel,
const ObjectFile &Obj,
ObjSectionToIDMap &ObjSectionToID,
LocalSymbolMap &Symbols, StubMap &Stubs) = 0;
void resolveSymbols();
public:
RuntimeDyldImpl(RTDyldMemoryManager *mm) : MemMgr(mm), HasError(false) {}
virtual ~RuntimeDyldImpl();
bool loadObject(const MemoryBuffer *InputBuffer);
virtual bool loadObject(MemoryBuffer *InputBuffer) = 0;
void *getSymbolAddress(StringRef Name) {
// FIXME: Just look up as a function for now. Overly simple of course.
@ -212,9 +87,9 @@ public:
return getSectionAddress(Loc.first) + Loc.second;
}
void resolveRelocations();
virtual void resolveRelocations();
void reassignSectionAddress(unsigned SectionID, uint64_t Addr);
virtual void reassignSectionAddress(unsigned SectionID, uint64_t Addr) = 0;
void mapSectionAddress(void *LocalAddress, uint64_t TargetAddress);
@ -228,7 +103,6 @@ public:
StringRef getErrorString() { return ErrorStr; }
virtual bool isCompatibleFormat(const MemoryBuffer *InputBuffer) const = 0;
};
} // end namespace llvm

View File

@ -21,47 +21,33 @@ using namespace llvm::object;
namespace llvm {
void RuntimeDyldMachO::resolveRelocation(uint8_t *LocalAddress,
uint64_t FinalAddress,
uint64_t Value,
uint32_t Type,
int64_t Addend) {
bool isPCRel = (Type >> 24) & 1;
unsigned MachoType = (Type >> 28) & 0xf;
unsigned Size = 1 << ((Type >> 25) & 3);
DEBUG(dbgs() << "resolveRelocation LocalAddress: " << format("%p", LocalAddress)
<< " FinalAddress: " << format("%p", FinalAddress)
<< " Value: " << format("%p", Value)
<< " Addend: " << Addend
<< " isPCRel: " << isPCRel
<< " MachoType: " << MachoType
<< " Size: " << Size
<< "\n");
bool RuntimeDyldMachO::
resolveRelocation(uint8_t *LocalAddress,
uint64_t FinalAddress,
uint64_t Value,
bool isPCRel,
unsigned Type,
unsigned Size,
int64_t Addend) {
// This just dispatches to the proper target specific routine.
switch (Arch) {
switch (CPUType) {
default: llvm_unreachable("Unsupported CPU type!");
case Triple::x86_64: // Fall through.
case Triple::x86:
resolveX86_64Relocation(LocalAddress,
FinalAddress,
(uintptr_t)Value,
isPCRel,
MachoType,
Size,
Addend);
break;
case Triple::arm: // Fall through.
case Triple::thumb:
resolveARMRelocation(LocalAddress,
FinalAddress,
(uintptr_t)Value,
isPCRel,
MachoType,
Size,
Addend);
break;
case mach::CTM_x86_64:
return resolveX86_64Relocation(LocalAddress,
FinalAddress,
(uintptr_t)Value,
isPCRel,
Type,
Size,
Addend);
case mach::CTM_ARM:
return resolveARMRelocation(LocalAddress,
FinalAddress,
(uintptr_t)Value,
isPCRel,
Type,
Size,
Addend);
}
}
@ -167,83 +153,503 @@ resolveARMRelocation(uint8_t *LocalAddress,
return false;
}
void RuntimeDyldMachO::
processRelocationRef(const ObjRelocationInfo &Rel, const ObjectFile &Obj,
ObjSectionToIDMap &ObjSectionToID,
LocalSymbolMap &Symbols, StubMap &Stubs) {
bool RuntimeDyldMachO::
loadSegment32(const MachOObject *Obj,
const MachOObject::LoadCommandInfo *SegmentLCI,
const InMemoryStruct<macho::SymtabLoadCommand> &SymtabLC) {
// FIXME: This should really be combined w/ loadSegment64. Templatized
// function on the 32/64 datatypes maybe?
InMemoryStruct<macho::SegmentLoadCommand> SegmentLC;
Obj->ReadSegmentLoadCommand(*SegmentLCI, SegmentLC);
if (!SegmentLC)
return Error("unable to load segment load command");
uint32_t RelType = (uint32_t) (Rel.Type & 0xffffffffL);
RelocationValueRef Value;
SectionEntry &Section = Sections[Rel.SectionID];
uint8_t *Target = Section.Address + Rel.Offset;
bool isExtern = (RelType >> 27) & 1;
if (isExtern) {
StringRef TargetName;
const SymbolRef &Symbol = Rel.Symbol;
Symbol.getName(TargetName);
// First look the symbol in object file symbols.
LocalSymbolMap::iterator it = Symbols.find(TargetName.data());
if (it != Symbols.end()) {
Value.SectionID = it->second.first;
Value.Addend = it->second.second;
} else {
// Second look the symbol in global symbol table.
StringMap<SymbolLoc>::iterator itS = SymbolTable.find(TargetName.data());
if (itS != SymbolTable.end()) {
Value.SectionID = itS->second.first;
Value.Addend = itS->second.second;
} else
Value.SymbolName = TargetName.data();
}
} else {
error_code err;
uint8_t sIdx = static_cast<uint8_t>(RelType & 0xFF);
section_iterator sIt = Obj.begin_sections(),
sItEnd = Obj.end_sections();
for (uint8_t i = 1; i < sIdx; i++) {
error_code err;
sIt.increment(err);
if (sIt == sItEnd)
break;
}
assert(sIt != sItEnd && "No section containing relocation!");
Value.SectionID = findOrEmitSection(*sIt, true, ObjSectionToID);
Value.Addend = *(const intptr_t *)Target;
if (Value.Addend) {
// The MachO addend is offset from the current section, we need set it
// as offset from destination section
Value.Addend += Section.ObjAddress - Sections[Value.SectionID].ObjAddress;
SmallVector<unsigned, 16> SectionMap;
for (unsigned SectNum = 0; SectNum != SegmentLC->NumSections; ++SectNum) {
InMemoryStruct<macho::Section> Sect;
Obj->ReadSection(*SegmentLCI, SectNum, Sect);
if (!Sect)
return Error("unable to load section: '" + Twine(SectNum) + "'");
// Allocate memory via the MM for the section.
uint8_t *Buffer;
uint32_t SectionID = Sections.size();
if (Sect->Flags == 0x80000400)
Buffer = MemMgr->allocateCodeSection(Sect->Size, Sect->Align, SectionID);
else
Buffer = MemMgr->allocateDataSection(Sect->Size, Sect->Align, SectionID);
DEBUG(dbgs() << "Loading "
<< ((Sect->Flags == 0x80000400) ? "text" : "data")
<< " (ID #" << SectionID << ")"
<< " '" << Sect->SegmentName << ","
<< Sect->Name << "' of size " << Sect->Size
<< " to address " << Buffer << ".\n");
// Copy the payload from the object file into the allocated buffer.
uint8_t *Base = (uint8_t*)Obj->getData(SegmentLC->FileOffset,
SegmentLC->FileSize).data();
memcpy(Buffer, Base + Sect->Address, Sect->Size);
// Remember what got allocated for this SectionID.
Sections.push_back(sys::MemoryBlock(Buffer, Sect->Size));
SectionLocalMemToID[Buffer] = SectionID;
// By default, the load address of a section is its memory buffer.
SectionLoadAddress.push_back((uint64_t)Buffer);
// Keep a map of object file section numbers to corresponding SectionIDs
// while processing the file.
SectionMap.push_back(SectionID);
}
// Process the symbol table.
SmallVector<StringRef, 64> SymbolNames;
processSymbols32(Obj, SectionMap, SymbolNames, SymtabLC);
// Process the relocations for each section we're loading.
Relocations.grow(Relocations.size() + SegmentLC->NumSections);
Referrers.grow(Referrers.size() + SegmentLC->NumSections);
for (unsigned SectNum = 0; SectNum != SegmentLC->NumSections; ++SectNum) {
InMemoryStruct<macho::Section> Sect;
Obj->ReadSection(*SegmentLCI, SectNum, Sect);
if (!Sect)
return Error("unable to load section: '" + Twine(SectNum) + "'");
for (unsigned j = 0; j != Sect->NumRelocationTableEntries; ++j) {
InMemoryStruct<macho::RelocationEntry> RE;
Obj->ReadRelocationEntry(Sect->RelocationTableOffset, j, RE);
if (RE->Word0 & macho::RF_Scattered)
return Error("NOT YET IMPLEMENTED: scattered relocations.");
// Word0 of the relocation is the offset into the section where the
// relocation should be applied. We need to translate that into an
// offset into a function since that's our atom.
uint32_t Offset = RE->Word0;
bool isExtern = (RE->Word1 >> 27) & 1;
// FIXME: Get the relocation addend from the target address.
// FIXME: VERY imporant for internal relocations.
// Figure out the source symbol of the relocation. If isExtern is true,
// this relocation references the symbol table, otherwise it references
// a section in the same object, numbered from 1 through NumSections
// (SectionBases is [0, NumSections-1]).
uint32_t SourceNum = RE->Word1 & 0xffffff; // 24-bit value
if (!isExtern) {
assert(SourceNum > 0 && "Invalid relocation section number!");
unsigned SectionID = SectionMap[SourceNum - 1];
unsigned TargetID = SectionMap[SectNum];
DEBUG(dbgs() << "Internal relocation at Section #"
<< TargetID << " + " << Offset
<< " from Section #"
<< SectionID << " (Word1: "
<< format("0x%x", RE->Word1) << ")\n");
// Store the relocation information. It will get resolved when
// the section addresses are assigned.
uint32_t RelocationIndex = Relocations[SectionID].size();
Relocations[SectionID].push_back(RelocationEntry(TargetID,
Offset,
RE->Word1,
0 /*Addend*/));
Referrers[TargetID].push_back(Referrer(SectionID, RelocationIndex));
} else {
StringRef SourceName = SymbolNames[SourceNum];
// Now store the relocation information. Associate it with the source
// symbol. Just add it to the unresolved list and let the general
// path post-load resolve it if we know where the symbol is.
UnresolvedRelocations[SourceName].push_back(RelocationEntry(SectNum,
Offset,
RE->Word1,
0 /*Addend*/));
DEBUG(dbgs() << "Relocation at Section #" << SectNum << " + " << Offset
<< " from '" << SourceName << "(Word1: "
<< format("0x%x", RE->Word1) << ")\n");
}
}
}
if (Arch == Triple::arm && RelType == macho::RIT_ARM_Branch24Bit) {
// This is an ARM branch relocation, need to use a stub function.
// Resolve the addresses of any symbols that were defined in this segment.
for (int i = 0, e = SymbolNames.size(); i != e; ++i)
resolveSymbol(SymbolNames[i]);
// Look up for existing stub.
StubMap::const_iterator stubIt = Stubs.find(Value);
if (stubIt != Stubs.end())
resolveRelocation(Target, (uint64_t)Target,
(uint64_t)Section.Address + stubIt->second,
RelType, 0);
else {
// Create a new stub function.
Stubs[Value] = Section.StubOffset;
uint8_t *StubTargetAddr = createStubFunction(Section.Address +
Section.StubOffset);
AddRelocation(Value, Rel.SectionID, StubTargetAddr - Section.Address,
macho::RIT_Vanilla);
resolveRelocation(Target, (uint64_t)Target,
(uint64_t)Section.Address + Section.StubOffset,
RelType, 0);
Section.StubOffset += getMaxStubSize();
}
} else
AddRelocation(Value, Rel.SectionID, Rel.Offset, RelType);
return false;
}
bool RuntimeDyldMachO::isCompatibleFormat(const MemoryBuffer *InputBuffer) const {
bool RuntimeDyldMachO::
loadSegment64(const MachOObject *Obj,
const MachOObject::LoadCommandInfo *SegmentLCI,
const InMemoryStruct<macho::SymtabLoadCommand> &SymtabLC) {
InMemoryStruct<macho::Segment64LoadCommand> Segment64LC;
Obj->ReadSegment64LoadCommand(*SegmentLCI, Segment64LC);
if (!Segment64LC)
return Error("unable to load segment load command");
SmallVector<unsigned, 16> SectionMap;
for (unsigned SectNum = 0; SectNum != Segment64LC->NumSections; ++SectNum) {
InMemoryStruct<macho::Section64> Sect;
Obj->ReadSection64(*SegmentLCI, SectNum, Sect);
if (!Sect)
return Error("unable to load section: '" + Twine(SectNum) + "'");
// Allocate memory via the MM for the section.
uint8_t *Buffer;
uint32_t SectionID = Sections.size();
unsigned Align = 1 << Sect->Align; // .o file has log2 alignment.
if (Sect->Flags == 0x80000400)
Buffer = MemMgr->allocateCodeSection(Sect->Size, Align, SectionID);
else
Buffer = MemMgr->allocateDataSection(Sect->Size, Align, SectionID);
DEBUG(dbgs() << "Loading "
<< ((Sect->Flags == 0x80000400) ? "text" : "data")
<< " (ID #" << SectionID << ")"
<< " '" << Sect->SegmentName << ","
<< Sect->Name << "' of size " << Sect->Size
<< " (align " << Align << ")"
<< " to address " << Buffer << ".\n");
// Copy the payload from the object file into the allocated buffer.
uint8_t *Base = (uint8_t*)Obj->getData(Segment64LC->FileOffset,
Segment64LC->FileSize).data();
memcpy(Buffer, Base + Sect->Address, Sect->Size);
// Remember what got allocated for this SectionID.
Sections.push_back(sys::MemoryBlock(Buffer, Sect->Size));
SectionLocalMemToID[Buffer] = SectionID;
// By default, the load address of a section is its memory buffer.
SectionLoadAddress.push_back((uint64_t)Buffer);
// Keep a map of object file section numbers to corresponding SectionIDs
// while processing the file.
SectionMap.push_back(SectionID);
}
// Process the symbol table.
SmallVector<StringRef, 64> SymbolNames;
processSymbols64(Obj, SectionMap, SymbolNames, SymtabLC);
// Process the relocations for each section we're loading.
Relocations.grow(Relocations.size() + Segment64LC->NumSections);
Referrers.grow(Referrers.size() + Segment64LC->NumSections);
for (unsigned SectNum = 0; SectNum != Segment64LC->NumSections; ++SectNum) {
InMemoryStruct<macho::Section64> Sect;
Obj->ReadSection64(*SegmentLCI, SectNum, Sect);
if (!Sect)
return Error("unable to load section: '" + Twine(SectNum) + "'");
for (unsigned j = 0; j != Sect->NumRelocationTableEntries; ++j) {
InMemoryStruct<macho::RelocationEntry> RE;
Obj->ReadRelocationEntry(Sect->RelocationTableOffset, j, RE);
if (RE->Word0 & macho::RF_Scattered)
return Error("NOT YET IMPLEMENTED: scattered relocations.");
// Word0 of the relocation is the offset into the section where the
// relocation should be applied. We need to translate that into an
// offset into a function since that's our atom.
uint32_t Offset = RE->Word0;
bool isExtern = (RE->Word1 >> 27) & 1;
// FIXME: Get the relocation addend from the target address.
// FIXME: VERY imporant for internal relocations.
// Figure out the source symbol of the relocation. If isExtern is true,
// this relocation references the symbol table, otherwise it references
// a section in the same object, numbered from 1 through NumSections
// (SectionBases is [0, NumSections-1]).
uint32_t SourceNum = RE->Word1 & 0xffffff; // 24-bit value
if (!isExtern) {
assert(SourceNum > 0 && "Invalid relocation section number!");
unsigned SectionID = SectionMap[SourceNum - 1];
unsigned TargetID = SectionMap[SectNum];
DEBUG(dbgs() << "Internal relocation at Section #"
<< TargetID << " + " << Offset
<< " from Section #"
<< SectionID << " (Word1: "
<< format("0x%x", RE->Word1) << ")\n");
// Store the relocation information. It will get resolved when
// the section addresses are assigned.
uint32_t RelocationIndex = Relocations[SectionID].size();
Relocations[SectionID].push_back(RelocationEntry(TargetID,
Offset,
RE->Word1,
0 /*Addend*/));
Referrers[TargetID].push_back(Referrer(SectionID, RelocationIndex));
} else {
StringRef SourceName = SymbolNames[SourceNum];
// Now store the relocation information. Associate it with the source
// symbol. Just add it to the unresolved list and let the general
// path post-load resolve it if we know where the symbol is.
UnresolvedRelocations[SourceName].push_back(RelocationEntry(SectNum,
Offset,
RE->Word1,
0 /*Addend*/));
DEBUG(dbgs() << "Relocation at Section #" << SectNum << " + " << Offset
<< " from '" << SourceName << "(Word1: "
<< format("0x%x", RE->Word1) << ")\n");
}
}
}
// Resolve the addresses of any symbols that were defined in this segment.
for (int i = 0, e = SymbolNames.size(); i != e; ++i)
resolveSymbol(SymbolNames[i]);
return false;
}
bool RuntimeDyldMachO::
processSymbols32(const MachOObject *Obj,
SmallVectorImpl<unsigned> &SectionMap,
SmallVectorImpl<StringRef> &SymbolNames,
const InMemoryStruct<macho::SymtabLoadCommand> &SymtabLC) {
// FIXME: Combine w/ processSymbols64. Factor 64/32 datatype and such.
for (unsigned i = 0; i != SymtabLC->NumSymbolTableEntries; ++i) {
InMemoryStruct<macho::SymbolTableEntry> STE;
Obj->ReadSymbolTableEntry(SymtabLC->SymbolTableOffset, i, STE);
if (!STE)
return Error("unable to read symbol: '" + Twine(i) + "'");
// Get the symbol name.
StringRef Name = Obj->getStringAtIndex(STE->StringIndex);
SymbolNames.push_back(Name);
// FIXME: Check the symbol type and flags.
if (STE->Type != 0xF) // external, defined in this segment.
continue;
// Flags in the upper nibble we don't care about.
if ((STE->Flags & 0xf) != 0x0)
continue;
// Remember the symbol.
uint32_t SectionID = SectionMap[STE->SectionIndex - 1];
SymbolTable[Name] = SymbolLoc(SectionID, STE->Value);
DEBUG(dbgs() << "Symbol: '" << Name << "' @ "
<< (getSectionAddress(SectionID) + STE->Value)
<< "\n");
}
return false;
}
bool RuntimeDyldMachO::
processSymbols64(const MachOObject *Obj,
SmallVectorImpl<unsigned> &SectionMap,
SmallVectorImpl<StringRef> &SymbolNames,
const InMemoryStruct<macho::SymtabLoadCommand> &SymtabLC) {
for (unsigned i = 0; i != SymtabLC->NumSymbolTableEntries; ++i) {
InMemoryStruct<macho::Symbol64TableEntry> STE;
Obj->ReadSymbol64TableEntry(SymtabLC->SymbolTableOffset, i, STE);
if (!STE)
return Error("unable to read symbol: '" + Twine(i) + "'");
// Get the symbol name.
StringRef Name = Obj->getStringAtIndex(STE->StringIndex);
SymbolNames.push_back(Name);
// FIXME: Check the symbol type and flags.
if (STE->Type != 0xF) // external, defined in this segment.
continue;
// Flags in the upper nibble we don't care about.
if ((STE->Flags & 0xf) != 0x0)
continue;
// Remember the symbol.
uint32_t SectionID = SectionMap[STE->SectionIndex - 1];
SymbolTable[Name] = SymbolLoc(SectionID, STE->Value);
DEBUG(dbgs() << "Symbol: '" << Name << "' @ "
<< (getSectionAddress(SectionID) + STE->Value)
<< "\n");
}
return false;
}
// resolveSymbol - Resolve any relocations to the specified symbol if
// we know where it lives.
void RuntimeDyldMachO::resolveSymbol(StringRef Name) {
StringMap<SymbolLoc>::const_iterator Loc = SymbolTable.find(Name);
if (Loc == SymbolTable.end())
return;
RelocationList &Relocs = UnresolvedRelocations[Name];
DEBUG(dbgs() << "Resolving symbol '" << Name << "'\n");
for (int i = 0, e = Relocs.size(); i != e; ++i) {
// Change the relocation to be section relative rather than symbol
// relative and move it to the resolved relocation list.
RelocationEntry Entry = Relocs[i];
Entry.Addend += Loc->second.second;
uint32_t RelocationIndex = Relocations[Loc->second.first].size();
Relocations[Loc->second.first].push_back(Entry);
Referrers[Entry.SectionID].push_back(Referrer(Loc->second.first, RelocationIndex));
}
// FIXME: Keep a worklist of the relocations we've added so that we can
// resolve more selectively later.
Relocs.clear();
}
bool RuntimeDyldMachO::loadObject(MemoryBuffer *InputBuffer) {
// If the linker is in an error state, don't do anything.
if (hasError())
return true;
// Load the Mach-O wrapper object.
std::string ErrorStr;
OwningPtr<MachOObject> Obj(
MachOObject::LoadFromBuffer(InputBuffer, &ErrorStr));
if (!Obj)
return Error("unable to load object: '" + ErrorStr + "'");
// Get the CPU type information from the header.
const macho::Header &Header = Obj->getHeader();
// FIXME: Error checking that the loaded object is compatible with
// the system we're running on.
CPUType = Header.CPUType;
CPUSubtype = Header.CPUSubtype;
// Validate that the load commands match what we expect.
const MachOObject::LoadCommandInfo *SegmentLCI = 0, *SymtabLCI = 0,
*DysymtabLCI = 0;
for (unsigned i = 0; i != Header.NumLoadCommands; ++i) {
const MachOObject::LoadCommandInfo &LCI = Obj->getLoadCommandInfo(i);
switch (LCI.Command.Type) {
case macho::LCT_Segment:
case macho::LCT_Segment64:
if (SegmentLCI)
return Error("unexpected input object (multiple segments)");
SegmentLCI = &LCI;
break;
case macho::LCT_Symtab:
if (SymtabLCI)
return Error("unexpected input object (multiple symbol tables)");
SymtabLCI = &LCI;
break;
case macho::LCT_Dysymtab:
if (DysymtabLCI)
return Error("unexpected input object (multiple symbol tables)");
DysymtabLCI = &LCI;
break;
default:
return Error("unexpected input object (unexpected load command");
}
}
if (!SymtabLCI)
return Error("no symbol table found in object");
if (!SegmentLCI)
return Error("no segments found in object");
// Read and register the symbol table data.
InMemoryStruct<macho::SymtabLoadCommand> SymtabLC;
Obj->ReadSymtabLoadCommand(*SymtabLCI, SymtabLC);
if (!SymtabLC)
return Error("unable to load symbol table load command");
Obj->RegisterStringTable(*SymtabLC);
// Read the dynamic link-edit information, if present (not present in static
// objects).
if (DysymtabLCI) {
InMemoryStruct<macho::DysymtabLoadCommand> DysymtabLC;
Obj->ReadDysymtabLoadCommand(*DysymtabLCI, DysymtabLC);
if (!DysymtabLC)
return Error("unable to load dynamic link-exit load command");
// FIXME: We don't support anything interesting yet.
// if (DysymtabLC->LocalSymbolsIndex != 0)
// return Error("NOT YET IMPLEMENTED: local symbol entries");
// if (DysymtabLC->ExternalSymbolsIndex != 0)
// return Error("NOT YET IMPLEMENTED: non-external symbol entries");
// if (DysymtabLC->UndefinedSymbolsIndex != SymtabLC->NumSymbolTableEntries)
// return Error("NOT YET IMPLEMENTED: undefined symbol entries");
}
// Load the segment load command.
if (SegmentLCI->Command.Type == macho::LCT_Segment) {
if (loadSegment32(Obj.get(), SegmentLCI, SymtabLC))
return true;
} else {
if (loadSegment64(Obj.get(), SegmentLCI, SymtabLC))
return true;
}
// Assign the addresses of the sections from the object so that any
// relocations to them get set properly.
// FIXME: This is done directly from the client at the moment. We should
// default the values to the local storage, at least when the target arch
// is the same as the host arch.
return false;
}
// Assign an address to a symbol name and resolve all the relocations
// associated with it.
void RuntimeDyldMachO::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. Re-apply any
// relocations referencing this section with the given address.
//
// 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.
SectionLoadAddress[SectionID] = Addr;
RelocationList &Relocs = Relocations[SectionID];
for (unsigned i = 0, e = Relocs.size(); i != e; ++i) {
RelocationEntry &RE = Relocs[i];
uint8_t *Target = (uint8_t*)Sections[RE.SectionID].base() + RE.Offset;
uint64_t FinalTarget = (uint64_t)SectionLoadAddress[RE.SectionID] + RE.Offset;
bool isPCRel = (RE.Data >> 24) & 1;
unsigned Type = (RE.Data >> 28) & 0xf;
unsigned Size = 1 << ((RE.Data >> 25) & 3);
DEBUG(dbgs() << "Resolving relocation at Section #" << RE.SectionID
<< " + " << RE.Offset << " (" << format("%p", Target) << ")"
<< " from Section #" << SectionID << " (" << format("%p", Addr) << ")"
<< "(" << (isPCRel ? "pcrel" : "absolute")
<< ", type: " << Type << ", Size: " << Size << ", Addend: "
<< RE.Addend << ").\n");
resolveRelocation(Target,
FinalTarget,
Addr,
isPCRel,
Type,
Size,
RE.Addend);
}
ReferrerList &Refers = Referrers[SectionID];
for (unsigned i = 0, e = Refers.size(); i != e; ++i) {
Referrer &R = Refers[i];
RelocationEntry &RE = Relocations[R.SectionID][R.Index];
uint8_t *Target = (uint8_t*)Sections[RE.SectionID].base() + RE.Offset;
uint64_t FinalTarget = (uint64_t)SectionLoadAddress[RE.SectionID] + RE.Offset;
bool isPCRel = (RE.Data >> 24) & 1;
unsigned Type = (RE.Data >> 28) & 0xf;
unsigned Size = 1 << ((RE.Data >> 25) & 3);
DEBUG(dbgs() << "Resolving relocation at Section #" << RE.SectionID
<< " + " << RE.Offset << " (" << format("%p", Target) << ")"
<< " from Section #" << SectionID << " (" << format("%p", Addr) << ")"
<< "(" << (isPCRel ? "pcrel" : "absolute")
<< ", type: " << Type << ", Size: " << Size << ", Addend: "
<< RE.Addend << ").\n");
resolveRelocation(Target,
FinalTarget,
Addr,
isPCRel,
Type,
Size,
RE.Addend);
}
}
bool RuntimeDyldMachO::isKnownFormat(const MemoryBuffer *InputBuffer) {
StringRef Magic = InputBuffer->getBuffer().slice(0, 4);
if (Magic == "\xFE\xED\xFA\xCE") return true;
if (Magic == "\xCE\xFA\xED\xFE") return true;

View File

@ -25,7 +25,55 @@ using namespace llvm::object;
namespace llvm {
class RuntimeDyldMachO : public RuntimeDyldImpl {
protected:
// 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.
struct RelocationEntry {
unsigned SectionID; // Section the relocation is contained in.
uint64_t Offset; // Offset into the section for the relocation.
uint32_t Data; // Second word of the raw macho relocation entry.
int64_t Addend; // Addend encoded in the instruction itself, if any,
// plus the offset into the source section for
// the symbol once the relocation is resolvable.
RelocationEntry(unsigned id, uint64_t offset, uint32_t data, int64_t addend)
: SectionID(id), Offset(offset), Data(data), Addend(addend) {}
};
typedef SmallVector<RelocationEntry, 4> RelocationList;
// For each section, keep a list of referrers in that section that are clients
// of relocations in other sections. Whenever a relocation gets created,
// create a corresponding referrer. Whenever relocations are re-resolved,
// re-resolve the referrers' relocations as well.
struct Referrer {
unsigned SectionID; // Section whose RelocationList contains the relocation.
uint32_t Index; // Index of the RelocatonEntry in that RelocationList.
Referrer(unsigned id, uint32_t index)
: SectionID(id), Index(index) {}
};
typedef SmallVector<Referrer, 4> ReferrerList;
// Relocations to sections already loaded. Indexed by SectionID which is the
// source of the address. The target where the address will be writen is
// SectionID/Offset in the relocation itself.
IndexedMap<RelocationList> Relocations;
// Referrers corresponding to Relocations.
IndexedMap<ReferrerList> Referrers;
// Relocations to symbols that are not yet resolved. Must be external
// relocations by definition. Indexed by symbol name.
StringMap<RelocationList> UnresolvedRelocations;
bool resolveRelocation(uint8_t *LocalAddress,
uint64_t FinalAddress,
uint64_t Value,
bool isPCRel,
unsigned Type,
unsigned Size,
int64_t Addend);
bool resolveX86_64Relocation(uint8_t *LocalAddress,
uint64_t FinalAddress,
uint64_t Value,
@ -41,21 +89,35 @@ protected:
unsigned Size,
int64_t Addend);
virtual void processRelocationRef(const ObjRelocationInfo &Rel,
const ObjectFile &Obj,
ObjSectionToIDMap &ObjSectionToID,
LocalSymbolMap &Symbols, StubMap &Stubs);
bool loadSegment32(const MachOObject *Obj,
const MachOObject::LoadCommandInfo *SegmentLCI,
const InMemoryStruct<macho::SymtabLoadCommand> &SymtabLC);
bool loadSegment64(const MachOObject *Obj,
const MachOObject::LoadCommandInfo *SegmentLCI,
const InMemoryStruct<macho::SymtabLoadCommand> &SymtabLC);
bool processSymbols32(const MachOObject *Obj,
SmallVectorImpl<unsigned> &SectionMap,
SmallVectorImpl<StringRef> &SymbolNames,
const InMemoryStruct<macho::SymtabLoadCommand> &SymtabLC);
bool processSymbols64(const MachOObject *Obj,
SmallVectorImpl<unsigned> &SectionMap,
SmallVectorImpl<StringRef> &SymbolNames,
const InMemoryStruct<macho::SymtabLoadCommand> &SymtabLC);
void resolveSymbol(StringRef Name);
public:
virtual void resolveRelocation(uint8_t *LocalAddress,
uint64_t FinalAddress,
uint64_t Value,
uint32_t Type,
int64_t Addend);
RuntimeDyldMachO(RTDyldMemoryManager *mm) : RuntimeDyldImpl(mm) {}
bool isCompatibleFormat(const MemoryBuffer *InputBuffer) const;
bool loadObject(MemoryBuffer *InputBuffer);
void reassignSectionAddress(unsigned SectionID, uint64_t Addr);
static bool isKnownFormat(const MemoryBuffer *InputBuffer);
bool isCompatibleFormat(const MemoryBuffer *InputBuffer) const {
return isKnownFormat(InputBuffer);
}
};
} // end namespace llvm

View File

@ -1,37 +0,0 @@
; RUN: %lli -use-mcjit %s > /dev/null
@.LC0 = internal global [10 x i8] c"argc: %d\0A\00" ; <[10 x i8]*> [#uses=1]
declare i32 @puts(i8*)
define void @getoptions(i32* %argc) {
bb0:
ret void
}
declare i32 @printf(i8*, ...)
define i32 @main(i32 %argc, i8** %argv) {
bb0:
call i32 (i8*, ...)* @printf( i8* getelementptr ([10 x i8]* @.LC0, i64 0, i64 0), i32 %argc ) ; <i32>:0 [#uses=0]
%cast224 = bitcast i8** %argv to i8* ; <i8*> [#uses=1]
%local = alloca i8* ; <i8**> [#uses=3]
store i8* %cast224, i8** %local
%cond226 = icmp sle i32 %argc, 0 ; <i1> [#uses=1]
br i1 %cond226, label %bb3, label %bb2
bb2: ; preds = %bb2, %bb0
%cann-indvar = phi i32 [ 0, %bb0 ], [ %add1-indvar, %bb2 ] ; <i32> [#uses=2]
%add1-indvar = add i32 %cann-indvar, 1 ; <i32> [#uses=2]
%cann-indvar-idxcast = sext i32 %cann-indvar to i64 ; <i64> [#uses=1]
%CT = bitcast i8** %local to i8*** ; <i8***> [#uses=1]
%reg115 = load i8*** %CT ; <i8**> [#uses=1]
%cast235 = getelementptr i8** %reg115, i64 %cann-indvar-idxcast ; <i8**> [#uses=1]
%reg117 = load i8** %cast235 ; <i8*> [#uses=1]
%reg236 = call i32 @puts( i8* %reg117 ) ; <i32> [#uses=0]
%cond239 = icmp slt i32 %add1-indvar, %argc ; <i1> [#uses=1]
br i1 %cond239, label %bb2, label %bb3
bb3: ; preds = %bb2, %bb0
%cast243 = bitcast i8** %local to i32* ; <i32*> [#uses=1]
call void @getoptions( i32* %cast243 )
ret i32 0
}

View File

@ -1,13 +0,0 @@
; RUN: %lli -use-mcjit %s > /dev/null
define i32 @foo(i32 %X, i32 %Y, double %A) {
%cond212 = fcmp une double %A, 1.000000e+00 ; <i1> [#uses=1]
%cast110 = zext i1 %cond212 to i32 ; <i32> [#uses=1]
ret i32 %cast110
}
define i32 @main() {
%reg212 = call i32 @foo( i32 0, i32 1, double 1.000000e+00 ) ; <i32> [#uses=1]
ret i32 %reg212
}

View File

@ -1,20 +0,0 @@
; RUN: %lli -use-mcjit %s > /dev/null
define i32 @main() {
call i32 @mylog( i32 4 ) ; <i32>:1 [#uses=0]
ret i32 0
}
define internal i32 @mylog(i32 %num) {
bb0:
br label %bb2
bb2: ; preds = %bb2, %bb0
%reg112 = phi i32 [ 10, %bb2 ], [ 1, %bb0 ] ; <i32> [#uses=1]
%cann-indvar = phi i32 [ %cann-indvar, %bb2 ], [ 0, %bb0 ] ; <i32> [#uses=1]
%reg114 = add i32 %reg112, 1 ; <i32> [#uses=2]
%cond222 = icmp slt i32 %reg114, %num ; <i1> [#uses=1]
br i1 %cond222, label %bb2, label %bb3
bb3: ; preds = %bb2
ret i32 %reg114
}

View File

@ -1,12 +0,0 @@
; RUN: %lli -use-mcjit %s > /dev/null
define i32 @main() {
; <label>:0
br label %Loop
Loop: ; preds = %Loop, %0
%X = phi i32 [ 0, %0 ], [ 1, %Loop ] ; <i32> [#uses=1]
br i1 true, label %Out, label %Loop
Out: ; preds = %Loop
ret i32 %X
}

View File

@ -1,11 +0,0 @@
; RUN: %lli -use-mcjit %s > /dev/null
; We were accidentally inverting the signedness of right shifts. Whoops.
define i32 @main() {
%X = ashr i32 -1, 16 ; <i32> [#uses=1]
%Y = ashr i32 %X, 16 ; <i32> [#uses=1]
%Z = add i32 %Y, 1 ; <i32> [#uses=1]
ret i32 %Z
}

View File

@ -1,10 +0,0 @@
; RUN: %lli -use-mcjit %s > /dev/null
define i32 @main() {
%X = fadd double 0.000000e+00, 1.000000e+00 ; <double> [#uses=1]
%Y = fsub double 0.000000e+00, 1.000000e+00 ; <double> [#uses=2]
%Z = fcmp oeq double %X, %Y ; <i1> [#uses=0]
fadd double %Y, 0.000000e+00 ; <double>:1 [#uses=0]
ret i32 0
}

View File

@ -1,17 +0,0 @@
; RUN: %lli -use-mcjit %s > /dev/null
define i32 @bar(i8* %X) {
; pointer should be 4 byte aligned!
%P = alloca double ; <double*> [#uses=1]
%R = ptrtoint double* %P to i32 ; <i32> [#uses=1]
%A = and i32 %R, 3 ; <i32> [#uses=1]
ret i32 %A
}
define i32 @main() {
%SP = alloca i8 ; <i8*> [#uses=1]
%X = add i32 0, 0 ; <i32> [#uses=1]
alloca i8, i32 %X ; <i8*>:1 [#uses=0]
call i32 @bar( i8* %SP ) ; <i32>:2 [#uses=1]
ret i32 %2
}

View File

@ -1,19 +0,0 @@
; This testcase should return with an exit code of 1.
;
; RUN: not %lli -use-mcjit %s
@test = global i64 0 ; <i64*> [#uses=1]
define internal i64 @test.upgrd.1() {
%tmp.0 = load i64* @test ; <i64> [#uses=1]
%tmp.1 = add i64 %tmp.0, 1 ; <i64> [#uses=1]
ret i64 %tmp.1
}
define i32 @main() {
%L = call i64 @test.upgrd.1( ) ; <i64> [#uses=1]
%I = trunc i64 %L to i32 ; <i32> [#uses=1]
ret i32 %I
}

View File

@ -1,11 +0,0 @@
; RUN: %lli -use-mcjit %s test
declare i32 @puts(i8*)
define i32 @main(i32 %argc.1, i8** %argv.1) {
%tmp.5 = getelementptr i8** %argv.1, i64 1 ; <i8**> [#uses=1]
%tmp.6 = load i8** %tmp.5 ; <i8*> [#uses=1]
%tmp.0 = call i32 @puts( i8* %tmp.6 ) ; <i32> [#uses=0]
ret i32 0
}

View File

@ -1,15 +0,0 @@
; RUN: %lli -use-mcjit %s > /dev/null
target datalayout = "e-p:32:32"
define i32 @main() {
entry:
br label %endif
then: ; No predecessors!
br label %endif
endif: ; preds = %then, %entry
%x = phi i32 [ 4, %entry ], [ 27, %then ] ; <i32> [#uses=0]
%result = phi i32 [ 32, %then ], [ 0, %entry ] ; <i32> [#uses=0]
ret i32 0
}

View File

@ -1,19 +0,0 @@
; RUN: %lli -use-mcjit %s > /dev/null
; Testcase distilled from 256.bzip2.
target datalayout = "e-p:32:32"
define i32 @main() {
entry:
br label %loopentry.0
loopentry.0: ; preds = %loopentry.0, %entry
%h.0 = phi i32 [ %tmp.2, %loopentry.0 ], [ -1, %entry ] ; <i32> [#uses=1]
%tmp.2 = add i32 %h.0, 1 ; <i32> [#uses=3]
%tmp.4 = icmp ne i32 %tmp.2, 0 ; <i1> [#uses=1]
br i1 %tmp.4, label %loopentry.0, label %loopentry.1
loopentry.1: ; preds = %loopentry.0
%h.1 = phi i32 [ %tmp.2, %loopentry.0 ] ; <i32> [#uses=1]
ret i32 %h.1
}

View File

@ -1,17 +0,0 @@
; RUN: %lli -use-mcjit %s > /dev/null
; Testcase distilled from 256.bzip2.
target datalayout = "e-p:32:32"
define i32 @main() {
entry:
%X = add i32 1, -1 ; <i32> [#uses=3]
br label %Next
Next: ; preds = %entry
%A = phi i32 [ %X, %entry ] ; <i32> [#uses=0]
%B = phi i32 [ %X, %entry ] ; <i32> [#uses=0]
%C = phi i32 [ %X, %entry ] ; <i32> [#uses=1]
ret i32 %C
}

View File

@ -1,11 +0,0 @@
; RUN: %lli -use-mcjit %s > /dev/null
; This testcase failed to work because two variable sized allocas confused the
; local register allocator.
define i32 @main(i32 %X) {
%A = alloca i32, i32 %X ; <i32*> [#uses=0]
%B = alloca float, i32 %X ; <float*> [#uses=0]
ret i32 0
}

View File

@ -1,21 +0,0 @@
; RUN: %lli -use-mcjit %s > /dev/null
;
; Regression Test: EnvironmentTest.ll
;
; Description:
; This is a regression test that verifies that the JIT passes the
; environment to the main() function.
;
declare i32 @strlen(i8*)
define i32 @main(i32 %argc.1, i8** %argv.1, i8** %envp.1) {
%tmp.2 = load i8** %envp.1 ; <i8*> [#uses=1]
%tmp.3 = call i32 @strlen( i8* %tmp.2 ) ; <i32> [#uses=1]
%T = icmp eq i32 %tmp.3, 0 ; <i1> [#uses=1]
%R = zext i1 %T to i32 ; <i32> [#uses=1]
ret i32 %R
}

View File

@ -1,34 +0,0 @@
; RUN: %lli -use-mcjit %s > /dev/null
; This testcase exposes a bug in the local register allocator where it runs out
; of registers (due to too many overlapping live ranges), but then attempts to
; use the ESP register (which is not allocatable) to hold a value.
define i32 @main(i32 %A) {
; ESP gets used again...
%Ap2 = alloca i32, i32 %A ; <i32*> [#uses=11]
; Produce lots of overlapping live ranges
%B = add i32 %A, 1 ; <i32> [#uses=1]
%C = add i32 %A, 2 ; <i32> [#uses=1]
%D = add i32 %A, 3 ; <i32> [#uses=1]
%E = add i32 %A, 4 ; <i32> [#uses=1]
%F = add i32 %A, 5 ; <i32> [#uses=1]
%G = add i32 %A, 6 ; <i32> [#uses=1]
%H = add i32 %A, 7 ; <i32> [#uses=1]
%I = add i32 %A, 8 ; <i32> [#uses=1]
%J = add i32 %A, 9 ; <i32> [#uses=1]
%K = add i32 %A, 10 ; <i32> [#uses=1]
; Uses of all of the values
store i32 %A, i32* %Ap2
store i32 %B, i32* %Ap2
store i32 %C, i32* %Ap2
store i32 %D, i32* %Ap2
store i32 %E, i32* %Ap2
store i32 %F, i32* %Ap2
store i32 %G, i32* %Ap2
store i32 %H, i32* %Ap2
store i32 %I, i32* %Ap2
store i32 %J, i32* %Ap2
store i32 %K, i32* %Ap2
ret i32 0
}

View File

@ -1,23 +0,0 @@
; RUN: %lli -use-mcjit %s > /dev/null
@A = global i32 0 ; <i32*> [#uses=1]
define i32 @main() {
%Ret = call i32 @test( i1 true, i32 0 ) ; <i32> [#uses=1]
ret i32 %Ret
}
define i32 @test(i1 %c, i32 %A) {
br i1 %c, label %Taken1, label %NotTaken
Cont: ; preds = %Taken1, %NotTaken
%V = phi i32 [ 0, %NotTaken ], [ sub (i32 ptrtoint (i32* @A to i32), i32 1234), %Taken1 ] ; <i32> [#uses=0]
ret i32 0
NotTaken: ; preds = %0
br label %Cont
Taken1: ; preds = %0
%B = icmp eq i32 %A, 0 ; <i1> [#uses=1]
br i1 %B, label %Cont, label %ExitError
ExitError: ; preds = %Taken1
ret i32 12
}

View File

@ -1,22 +0,0 @@
; PR672
; RUN: %lli -use-mcjit %s
; XFAIL: mcjit-ia32
define i32 @main() {
%f = bitcast i32 (i32, i32*, i32)* @check_tail to i32* ; <i32*> [#uses=1]
%res = tail call fastcc i32 @check_tail( i32 10, i32* %f, i32 10 ) ; <i32> [#uses=1]
ret i32 %res
}
define fastcc i32 @check_tail(i32 %x, i32* %f, i32 %g) {
%tmp1 = icmp sgt i32 %x, 0 ; <i1> [#uses=1]
br i1 %tmp1, label %if-then, label %if-else
if-then: ; preds = %0
%fun_ptr = bitcast i32* %f to i32 (i32, i32*, i32)* ; <i32 (i32, i32*, i32)*> [#uses=1]
%arg1 = add i32 %x, -1 ; <i32> [#uses=1]
%res = tail call fastcc i32 %fun_ptr( i32 %arg1, i32* %f, i32 %g ) ; <i32> [#uses=1]
ret i32 %res
if-else: ; preds = %0
ret i32 %x
}

View File

@ -1,19 +0,0 @@
; RUN: %lli -use-mcjit -force-interpreter %s
; PR1836
define i32 @main() {
entry:
%retval = alloca i32 ; <i32*> [#uses=2]
%tmp = alloca i32 ; <i32*> [#uses=2]
%x = alloca i75, align 16 ; <i75*> [#uses=1]
%"alloca point" = bitcast i32 0 to i32 ; <i32> [#uses=0]
store i75 999, i75* %x, align 16
store i32 0, i32* %tmp, align 4
%tmp1 = load i32* %tmp, align 4 ; <i32> [#uses=1]
store i32 %tmp1, i32* %retval, align 4
br label %return
return: ; preds = %entry
%retval2 = load i32* %retval ; <i32> [#uses=1]
ret i32 %retval2
}

View File

@ -1,59 +0,0 @@
; RUN: %lli -use-mcjit -force-interpreter=true %s | grep 1
target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:32:32"
target triple = "i686-pc-linux-gnu"
@.str = internal constant [10 x i8] c"MSB = %d\0A\00" ; <[10 x i8]*> [#uses=1]
define i65 @foo(i65 %x) {
entry:
%x_addr = alloca i65 ; <i65*> [#uses=2]
%retval = alloca i65 ; <i65*> [#uses=2]
%tmp = alloca i65 ; <i65*> [#uses=2]
%"alloca point" = bitcast i65 0 to i65 ; <i65> [#uses=0]
store i65 %x, i65* %x_addr
%tmp1 = load i65* %x_addr, align 4 ; <i65> [#uses=1]
%tmp2 = ashr i65 %tmp1, 65 ; <i65> [#uses=1]
store i65 %tmp2, i65* %tmp, align 4
%tmp3 = load i65* %tmp, align 4 ; <i65> [#uses=1]
store i65 %tmp3, i65* %retval, align 4
br label %return
return: ; preds = %entry
%retval4 = load i65* %retval ; <i65> [#uses=1]
ret i65 %retval4
}
define i32 @main() {
entry:
%retval = alloca i32 ; <i32*> [#uses=1]
%iftmp.0 = alloca i32 ; <i32*> [#uses=3]
%"alloca point" = bitcast i32 0 to i32 ; <i32> [#uses=0]
%tmp = call i65 @foo( i65 -9 ) ; <i65> [#uses=1]
%tmp1 = lshr i65 %tmp, 64 ; <i65> [#uses=1]
%tmp2 = xor i65 %tmp1, 1 ; <i65> [#uses=1]
%tmp3 = and i65 %tmp2, 1 ; <i65> [#uses=1]
%tmp34 = trunc i65 %tmp3 to i8 ; <i8> [#uses=1]
%toBool = icmp ne i8 %tmp34, 0 ; <i1> [#uses=1]
br i1 %toBool, label %cond_true, label %cond_false
cond_true: ; preds = %entry
store i32 0, i32* %iftmp.0, align 4
br label %cond_next
cond_false: ; preds = %entry
store i32 1, i32* %iftmp.0, align 4
br label %cond_next
cond_next: ; preds = %cond_false, %cond_true
%tmp5 = getelementptr [10 x i8]* @.str, i32 0, i32 0 ; <i8*> [#uses=1]
%tmp6 = load i32* %iftmp.0, align 4 ; <i32> [#uses=1]
%tmp7 = call i32 (i8*, ...)* @printf( i8* noalias %tmp5, i32 %tmp6 ) nounwind ; <i32> [#uses=0]
br label %return
return: ; preds = %cond_next
store i32 0, i32* %retval, align 4
%retval8 = load i32* %retval ; <i32> [#uses=1]
ret i32 %retval8
}
declare i32 @printf(i8* noalias , ...) nounwind

View File

@ -1,8 +0,0 @@
; RUN: %lli -use-mcjit -force-interpreter=true %s
define i32 @main() {
%a = add i32 0, undef
%b = fadd float 0.0, undef
%c = fadd double 0.0, undef
ret i32 0
}

View File

@ -1,20 +0,0 @@
; RUN: %lli -use-mcjit -force-interpreter=true %s | grep 40091eb8
;
define i32 @test(double %x) {
entry:
%x46.i = bitcast double %x to i64
%tmp343.i = lshr i64 %x46.i, 32
%tmp344.i = trunc i64 %tmp343.i to i32
ret i32 %tmp344.i
}
define i32 @main()
{
%res = call i32 @test(double 3.14)
%ptr = getelementptr [4 x i8]* @format, i32 0, i32 0
call i32 (i8*,...)* @printf(i8* %ptr, i32 %res)
ret i32 0
}
declare i32 @printf(i8*, ...)
@format = internal constant [4 x i8] c"%x\0A\00"

View File

@ -1,11 +0,0 @@
; RUN: %lli -use-mcjit %s > /dev/null
@.LC0 = internal global [12 x i8] c"Hello World\00" ; <[12 x i8]*> [#uses=1]
declare i32 @puts(i8*)
define i32 @main() {
%reg210 = call i32 @puts( i8* getelementptr ([12 x i8]* @.LC0, i64 0, i64 0) ) ; <i32> [#uses=0]
ret i32 0
}

View File

@ -1,17 +0,0 @@
; RUN: %lli -use-mcjit %s > /dev/null
@X = global i32 7 ; <i32*> [#uses=0]
@msg = internal global [13 x i8] c"Hello World\0A\00" ; <[13 x i8]*> [#uses=1]
declare void @printf([13 x i8]*, ...)
define void @bar() {
call void ([13 x i8]*, ...)* @printf( [13 x i8]* @msg )
ret void
}
define i32 @main() {
call void @bar( )
ret i32 0
}

View File

@ -1,17 +0,0 @@
config.suffixes = ['.ll', '.c', '.cpp']
def getRoot(config):
if not config.parent:
return config
return getRoot(config.parent)
root = getRoot(config)
targets = set(root.targets_to_build.split())
if ('X86' in targets) | ('ARM' in targets):
config.unsupported = False
else:
config.unsupported = True
if root.host_os in ['Win32', 'Cygwin', 'MingW']:
config.unsupported = True

View File

@ -1,6 +0,0 @@
; RUN: %lli -use-mcjit %s > /dev/null
define i32 @main() {
ret i32 0
}

View File

@ -1,11 +0,0 @@
; RUN: %lli -use-mcjit %s > /dev/null
define i32 @bar() {
ret i32 0
}
define i32 @main() {
%r = call i32 @bar( ) ; <i32> [#uses=1]
ret i32 %r
}

View File

@ -1,34 +0,0 @@
; RUN: %lli -use-mcjit %s > /dev/null
define i32 @main() {
%A = add i8 0, 12 ; <i8> [#uses=1]
%B = sub i8 %A, 1 ; <i8> [#uses=2]
%C = mul i8 %B, %B ; <i8> [#uses=2]
%D = sdiv i8 %C, %C ; <i8> [#uses=2]
%E = srem i8 %D, %D ; <i8> [#uses=0]
%F = udiv i8 5, 6 ; <i8> [#uses=0]
%G = urem i8 6, 5 ; <i8> [#uses=0]
%A.upgrd.1 = add i16 0, 12 ; <i16> [#uses=1]
%B.upgrd.2 = sub i16 %A.upgrd.1, 1 ; <i16> [#uses=2]
%C.upgrd.3 = mul i16 %B.upgrd.2, %B.upgrd.2 ; <i16> [#uses=2]
%D.upgrd.4 = sdiv i16 %C.upgrd.3, %C.upgrd.3 ; <i16> [#uses=2]
%E.upgrd.5 = srem i16 %D.upgrd.4, %D.upgrd.4 ; <i16> [#uses=0]
%F.upgrd.6 = udiv i16 5, 6 ; <i16> [#uses=0]
%G.upgrd.7 = urem i32 6, 5 ; <i32> [#uses=0]
%A.upgrd.8 = add i32 0, 12 ; <i32> [#uses=1]
%B.upgrd.9 = sub i32 %A.upgrd.8, 1 ; <i32> [#uses=2]
%C.upgrd.10 = mul i32 %B.upgrd.9, %B.upgrd.9 ; <i32> [#uses=2]
%D.upgrd.11 = sdiv i32 %C.upgrd.10, %C.upgrd.10 ; <i32> [#uses=2]
%E.upgrd.12 = srem i32 %D.upgrd.11, %D.upgrd.11 ; <i32> [#uses=0]
%F.upgrd.13 = udiv i32 5, 6 ; <i32> [#uses=0]
%G1 = urem i32 6, 5 ; <i32> [#uses=0]
%A.upgrd.14 = add i64 0, 12 ; <i64> [#uses=1]
%B.upgrd.15 = sub i64 %A.upgrd.14, 1 ; <i64> [#uses=2]
%C.upgrd.16 = mul i64 %B.upgrd.15, %B.upgrd.15 ; <i64> [#uses=2]
%D.upgrd.17 = sdiv i64 %C.upgrd.16, %C.upgrd.16 ; <i64> [#uses=2]
%E.upgrd.18 = srem i64 %D.upgrd.17, %D.upgrd.17 ; <i64> [#uses=0]
%F.upgrd.19 = udiv i64 5, 6 ; <i64> [#uses=0]
%G.upgrd.20 = urem i64 6, 5 ; <i64> [#uses=0]
ret i32 0
}

View File

@ -1,12 +0,0 @@
; RUN: %lli -use-mcjit %s > /dev/null
; test unconditional branch
define i32 @main() {
br label %Test
Test: ; preds = %Test, %0
%X = icmp eq i32 0, 4 ; <i1> [#uses=1]
br i1 %X, label %Test, label %Label
Label: ; preds = %Test
ret i32 0
}

View File

@ -1,14 +0,0 @@
; RUN: %lli -use-mcjit %s > /dev/null
define i32 @_Z14func_exit_codev() nounwind uwtable {
entry:
ret i32 0
}
define i32 @main() nounwind uwtable {
entry:
%retval = alloca i32, align 4
store i32 0, i32* %retval
%call = call i32 @_Z14func_exit_codev()
ret i32 %call
}

View File

@ -1,21 +0,0 @@
; RUN: %lli -use-mcjit %s > /dev/null
declare void @exit(i32)
define i32 @test(i8 %C, i16 %S) {
%X = trunc i16 %S to i8 ; <i8> [#uses=1]
%Y = zext i8 %X to i32 ; <i32> [#uses=1]
ret i32 %Y
}
define void @FP(void (i32)* %F) {
%X = call i32 @test( i8 123, i16 1024 ) ; <i32> [#uses=1]
call void %F( i32 %X )
ret void
}
define i32 @main() {
call void @FP( void (i32)* @exit )
ret i32 1
}

View File

@ -1,109 +0,0 @@
; RUN: %lli -use-mcjit %s > /dev/null
define i32 @foo() {
ret i32 0
}
define i32 @main() {
icmp ne i1 true, false ; <i1>:1 [#uses=0]
zext i1 true to i8 ; <i8>:2 [#uses=0]
zext i1 true to i8 ; <i8>:3 [#uses=0]
zext i1 true to i16 ; <i16>:4 [#uses=0]
zext i1 true to i16 ; <i16>:5 [#uses=0]
zext i1 true to i32 ; <i32>:6 [#uses=0]
zext i1 true to i32 ; <i32>:7 [#uses=0]
zext i1 true to i64 ; <i64>:8 [#uses=0]
zext i1 true to i64 ; <i64>:9 [#uses=0]
uitofp i1 true to float ; <float>:10 [#uses=0]
uitofp i1 true to double ; <double>:11 [#uses=0]
icmp ne i8 0, 0 ; <i1>:12 [#uses=0]
icmp ne i8 1, 0 ; <i1>:13 [#uses=0]
bitcast i8 0 to i8 ; <i8>:14 [#uses=0]
bitcast i8 -1 to i8 ; <i8>:15 [#uses=0]
sext i8 4 to i16 ; <i16>:16 [#uses=0]
sext i8 4 to i16 ; <i16>:17 [#uses=0]
sext i8 4 to i64 ; <i64>:18 [#uses=0]
sext i8 4 to i64 ; <i64>:19 [#uses=0]
sitofp i8 4 to float ; <float>:20 [#uses=0]
sitofp i8 4 to double ; <double>:21 [#uses=0]
icmp ne i8 0, 0 ; <i1>:22 [#uses=0]
icmp ne i8 1, 0 ; <i1>:23 [#uses=0]
bitcast i8 0 to i8 ; <i8>:24 [#uses=0]
bitcast i8 1 to i8 ; <i8>:25 [#uses=0]
zext i8 4 to i16 ; <i16>:26 [#uses=0]
zext i8 4 to i16 ; <i16>:27 [#uses=0]
zext i8 4 to i64 ; <i64>:28 [#uses=0]
zext i8 4 to i64 ; <i64>:29 [#uses=0]
uitofp i8 0 to float ; <float>:30 [#uses=0]
uitofp i8 0 to double ; <double>:31 [#uses=0]
icmp ne i16 1, 0 ; <i1>:32 [#uses=0]
trunc i16 -1 to i8 ; <i8>:33 [#uses=0]
trunc i16 255 to i8 ; <i8>:34 [#uses=0]
bitcast i16 0 to i16 ; <i16>:35 [#uses=0]
bitcast i16 0 to i16 ; <i16>:36 [#uses=0]
sext i16 0 to i64 ; <i64>:37 [#uses=0]
sext i16 0 to i64 ; <i64>:38 [#uses=0]
sitofp i16 0 to float ; <float>:39 [#uses=0]
sitofp i16 0 to double ; <double>:40 [#uses=0]
icmp ne i16 1, 0 ; <i1>:41 [#uses=0]
trunc i16 1 to i8 ; <i8>:42 [#uses=0]
trunc i16 255 to i8 ; <i8>:43 [#uses=0]
bitcast i16 0 to i16 ; <i16>:44 [#uses=0]
bitcast i16 0 to i16 ; <i16>:45 [#uses=0]
zext i16 0 to i64 ; <i64>:46 [#uses=0]
zext i16 0 to i64 ; <i64>:47 [#uses=0]
uitofp i16 0 to float ; <float>:48 [#uses=0]
uitofp i16 0 to double ; <double>:49 [#uses=0]
icmp ne i32 6, 0 ; <i1>:50 [#uses=0]
trunc i32 -6 to i8 ; <i8>:51 [#uses=0]
trunc i32 6 to i8 ; <i8>:52 [#uses=0]
trunc i32 6 to i16 ; <i16>:53 [#uses=0]
bitcast i32 0 to i32 ; <i32>:54 [#uses=0]
sext i32 0 to i64 ; <i64>:55 [#uses=0]
sext i32 0 to i64 ; <i64>:56 [#uses=0]
sitofp i32 0 to float ; <float>:57 [#uses=0]
sitofp i32 0 to double ; <double>:58 [#uses=0]
icmp ne i32 6, 0 ; <i1>:59 [#uses=0]
trunc i32 7 to i8 ; <i8>:60 [#uses=0]
trunc i32 8 to i8 ; <i8>:61 [#uses=0]
trunc i32 9 to i16 ; <i16>:62 [#uses=0]
bitcast i32 10 to i32 ; <i32>:63 [#uses=0]
zext i32 0 to i64 ; <i64>:64 [#uses=0]
zext i32 0 to i64 ; <i64>:65 [#uses=0]
uitofp i32 0 to float ; <float>:66 [#uses=0]
uitofp i32 0 to double ; <double>:67 [#uses=0]
icmp ne i64 0, 0 ; <i1>:68 [#uses=0]
trunc i64 0 to i8 ; <i8>:69 [#uses=0]
trunc i64 0 to i8 ; <i8>:70 [#uses=0]
trunc i64 0 to i16 ; <i16>:71 [#uses=0]
trunc i64 0 to i16 ; <i16>:72 [#uses=0]
trunc i64 0 to i32 ; <i32>:73 [#uses=0]
trunc i64 0 to i32 ; <i32>:74 [#uses=0]
bitcast i64 0 to i64 ; <i64>:75 [#uses=0]
bitcast i64 0 to i64 ; <i64>:76 [#uses=0]
sitofp i64 0 to float ; <float>:77 [#uses=0]
sitofp i64 0 to double ; <double>:78 [#uses=0]
icmp ne i64 1, 0 ; <i1>:79 [#uses=0]
trunc i64 1 to i8 ; <i8>:80 [#uses=0]
trunc i64 1 to i8 ; <i8>:81 [#uses=0]
trunc i64 1 to i16 ; <i16>:82 [#uses=0]
trunc i64 1 to i16 ; <i16>:83 [#uses=0]
trunc i64 1 to i32 ; <i32>:84 [#uses=0]
trunc i64 1 to i32 ; <i32>:85 [#uses=0]
bitcast i64 1 to i64 ; <i64>:86 [#uses=0]
bitcast i64 1 to i64 ; <i64>:87 [#uses=0]
uitofp i64 1 to float ; <float>:88 [#uses=0]
uitofp i64 0 to double ; <double>:89 [#uses=0]
bitcast float 0.000000e+00 to float ; <float>:90 [#uses=0]
fpext float 0.000000e+00 to double ; <double>:91 [#uses=0]
fptosi double 0.000000e+00 to i8 ; <i8>:92 [#uses=0]
fptoui double 0.000000e+00 to i8 ; <i8>:93 [#uses=0]
fptosi double 0.000000e+00 to i16 ; <i16>:94 [#uses=0]
fptoui double 0.000000e+00 to i16 ; <i16>:95 [#uses=0]
fptosi double 0.000000e+00 to i32 ; <i32>:96 [#uses=0]
fptoui double 0.000000e+00 to i32 ; <i32>:97 [#uses=0]
fptosi double 0.000000e+00 to i64 ; <i64>:98 [#uses=0]
fptrunc double 0.000000e+00 to float ; <float>:99 [#uses=0]
bitcast double 0.000000e+00 to double ; <double>:100 [#uses=0]
ret i32 0
}

View File

@ -1,12 +0,0 @@
; RUN: %lli -use-mcjit %s > /dev/null
; This tests to make sure that we can evaluate weird constant expressions
@A = global i32 5 ; <i32*> [#uses=1]
@B = global i32 6 ; <i32*> [#uses=1]
define i32 @main() {
%A = or i1 false, icmp slt (i32* @A, i32* @B) ; <i1> [#uses=0]
ret i32 0
}

View File

@ -1,21 +0,0 @@
; RUN: %lli -use-mcjit %s > /dev/null
define double @test(double* %DP, double %Arg) {
%D = load double* %DP ; <double> [#uses=1]
%V = fadd double %D, 1.000000e+00 ; <double> [#uses=2]
%W = fsub double %V, %V ; <double> [#uses=3]
%X = fmul double %W, %W ; <double> [#uses=2]
%Y = fdiv double %X, %X ; <double> [#uses=2]
%Q = fadd double %Y, %Arg ; <double> [#uses=1]
%R = bitcast double %Q to double ; <double> [#uses=1]
store double %Q, double* %DP
ret double %Y
}
define i32 @main() {
%X = alloca double ; <double*> [#uses=2]
store double 0.000000e+00, double* %X
call double @test( double* %X, double 2.000000e+00 ) ; <double>:1 [#uses=0]
ret i32 0
}

View File

@ -1,23 +0,0 @@
; RUN: %lli -use-mcjit %s > /dev/null
define double @test(double* %DP, double %Arg) {
%D = load double* %DP ; <double> [#uses=1]
%V = fadd double %D, 1.000000e+00 ; <double> [#uses=2]
%W = fsub double %V, %V ; <double> [#uses=3]
%X = fmul double %W, %W ; <double> [#uses=2]
%Y = fdiv double %X, %X ; <double> [#uses=2]
%Z = frem double %Y, %Y ; <double> [#uses=3]
%Z1 = fdiv double %Z, %W ; <double> [#uses=0]
%Q = fadd double %Z, %Arg ; <double> [#uses=1]
%R = bitcast double %Q to double ; <double> [#uses=1]
store double %R, double* %DP
ret double %Z
}
define i32 @main() {
%X = alloca double ; <double*> [#uses=2]
store double 0.000000e+00, double* %X
call double @test( double* %X, double 2.000000e+00 ) ; <double>:1 [#uses=0]
ret i32 0
}

View File

@ -1,34 +0,0 @@
; RUN: %lli -use-mcjit %s > /dev/null
@count = global i32 1, align 4
define i32 @main() nounwind uwtable {
entry:
%retval = alloca i32, align 4
%i = alloca i32, align 4
store i32 0, i32* %retval
store i32 0, i32* %i, align 4
br label %for.cond
for.cond: ; preds = %for.inc, %entry
%0 = load i32* %i, align 4
%cmp = icmp slt i32 %0, 49
br i1 %cmp, label %for.body, label %for.end
for.body: ; preds = %for.cond
%1 = load i32* @count, align 4
%inc = add nsw i32 %1, 1
store i32 %inc, i32* @count, align 4
br label %for.inc
for.inc: ; preds = %for.body
%2 = load i32* %i, align 4
%inc1 = add nsw i32 %2, 1
store i32 %inc1, i32* %i, align 4
br label %for.cond
for.end: ; preds = %for.cond
%3 = load i32* @count, align 4
%sub = sub nsw i32 %3, 50
ret i32 %sub
}

View File

@ -1,31 +0,0 @@
; RUN: %lli -use-mcjit %s > /dev/null
define void @test(i8* %P, i16* %P.upgrd.1, i32* %P.upgrd.2, i64* %P.upgrd.3) {
%V = load i8* %P ; <i8> [#uses=1]
store i8 %V, i8* %P
%V.upgrd.4 = load i16* %P.upgrd.1 ; <i16> [#uses=1]
store i16 %V.upgrd.4, i16* %P.upgrd.1
%V.upgrd.5 = load i32* %P.upgrd.2 ; <i32> [#uses=1]
store i32 %V.upgrd.5, i32* %P.upgrd.2
%V.upgrd.6 = load i64* %P.upgrd.3 ; <i64> [#uses=1]
store i64 %V.upgrd.6, i64* %P.upgrd.3
ret void
}
define i32 @varalloca(i32 %Size) {
;; Variable sized alloca
%X = alloca i32, i32 %Size ; <i32*> [#uses=2]
store i32 %Size, i32* %X
%Y = load i32* %X ; <i32> [#uses=1]
ret i32 %Y
}
define i32 @main() {
%A = alloca i8 ; <i8*> [#uses=1]
%B = alloca i16 ; <i16*> [#uses=1]
%C = alloca i32 ; <i32*> [#uses=1]
%D = alloca i64 ; <i64*> [#uses=1]
call void @test( i8* %A, i16* %B, i32* %C, i64* %D )
call i32 @varalloca( i32 7 ) ; <i32>:1 [#uses=0]
ret i32 0
}

View File

@ -1,34 +0,0 @@
; RUN: %lli -use-mcjit %s > /dev/null
define i32 @main() nounwind uwtable {
entry:
%retval = alloca i32, align 4
%count = alloca i32, align 4
%i = alloca i32, align 4
store i32 0, i32* %retval
store i32 0, i32* %count, align 4
store i32 0, i32* %i, align 4
br label %for.cond
for.cond: ; preds = %for.inc, %entry
%0 = load i32* %i, align 4
%cmp = icmp slt i32 %0, 50
br i1 %cmp, label %for.body, label %for.end
for.body: ; preds = %for.cond
%1 = load i32* %count, align 4
%inc = add nsw i32 %1, 1
store i32 %inc, i32* %count, align 4
br label %for.inc
for.inc: ; preds = %for.body
%2 = load i32* %i, align 4
%inc1 = add nsw i32 %2, 1
store i32 %inc1, i32* %i, align 4
br label %for.cond
for.end: ; preds = %for.cond
%3 = load i32* %count, align 4
%sub = sub nsw i32 %3, 50
ret i32 %sub
}

View File

@ -1,18 +0,0 @@
; RUN: %lli -use-mcjit %s > /dev/null
define i32 @main() {
%A = and i8 4, 8 ; <i8> [#uses=2]
%B = or i8 %A, 7 ; <i8> [#uses=1]
%C = xor i8 %B, %A ; <i8> [#uses=0]
%A.upgrd.1 = and i16 4, 8 ; <i16> [#uses=2]
%B.upgrd.2 = or i16 %A.upgrd.1, 7 ; <i16> [#uses=1]
%C.upgrd.3 = xor i16 %B.upgrd.2, %A.upgrd.1 ; <i16> [#uses=0]
%A.upgrd.4 = and i32 4, 8 ; <i32> [#uses=2]
%B.upgrd.5 = or i32 %A.upgrd.4, 7 ; <i32> [#uses=1]
%C.upgrd.6 = xor i32 %B.upgrd.5, %A.upgrd.4 ; <i32> [#uses=0]
%A.upgrd.7 = and i64 4, 8 ; <i64> [#uses=2]
%B.upgrd.8 = or i64 %A.upgrd.7, 7 ; <i64> [#uses=1]
%C.upgrd.9 = xor i64 %B.upgrd.8, %A.upgrd.7 ; <i64> [#uses=0]
ret i32 0
}

View File

@ -1,14 +0,0 @@
; RUN: %lli -use-mcjit %s > /dev/null
define i32 @main() {
; <label>:0
br label %Loop
Loop: ; preds = %Loop, %0
%I = phi i32 [ 0, %0 ], [ %i2, %Loop ] ; <i32> [#uses=1]
%i2 = add i32 %I, 1 ; <i32> [#uses=2]
%C = icmp eq i32 %i2, 10 ; <i1> [#uses=1]
br i1 %C, label %Out, label %Loop
Out: ; preds = %Loop
ret i32 0
}

View File

@ -1,34 +0,0 @@
; RUN: %lli -use-mcjit %s > /dev/null
; test phi node
@Y = global i32 6 ; <i32*> [#uses=1]
define void @blah(i32* %X) {
; <label>:0
br label %T
T: ; preds = %Dead, %0
phi i32* [ %X, %0 ], [ @Y, %Dead ] ; <i32*>:1 [#uses=0]
ret void
Dead: ; No predecessors!
br label %T
}
define i32 @test(i1 %C) {
; <label>:0
br i1 %C, label %T, label %T
T: ; preds = %0, %0
%X = phi i32 [ 123, %0 ], [ 123, %0 ] ; <i32> [#uses=1]
ret i32 %X
}
define i32 @main() {
; <label>:0
br label %Test
Test: ; preds = %Dead, %0
%X = phi i32 [ 0, %0 ], [ %Y, %Dead ] ; <i32> [#uses=1]
ret i32 %X
Dead: ; No predecessors!
%Y = ashr i32 12, 4 ; <i32> [#uses=1]
br label %Test
}

View File

@ -1,46 +0,0 @@
; RUN: %lli -use-mcjit %s > /dev/null
; test return instructions
define void @test1() {
ret void
}
define i8 @test2() {
ret i8 1
}
define i8 @test3() {
ret i8 1
}
define i16 @test4() {
ret i16 -1
}
define i16 @test5() {
ret i16 -1
}
define i32 @main() {
ret i32 0
}
define i32 @test6() {
ret i32 4
}
define i64 @test7() {
ret i64 0
}
define i64 @test8() {
ret i64 0
}
define float @test9() {
ret float 1.000000e+00
}
define double @test10() {
ret double 2.000000e+00
}

View File

@ -1,8 +0,0 @@
; RUN: %lli -use-mcjit %s > /dev/null
define i32 @main() nounwind uwtable {
entry:
%retval = alloca i32, align 4
store i32 0, i32* %retval
ret i32 0
}

View File

@ -1,24 +0,0 @@
; RUN: %lli -use-mcjit %s > /dev/null
define i32 @main() {
%double1 = fadd double 0.000000e+00, 0.000000e+00 ; <double> [#uses=6]
%double2 = fadd double 0.000000e+00, 0.000000e+00 ; <double> [#uses=6]
%float1 = fadd float 0.000000e+00, 0.000000e+00 ; <float> [#uses=6]
%float2 = fadd float 0.000000e+00, 0.000000e+00 ; <float> [#uses=6]
%test49 = fcmp oeq float %float1, %float2 ; <i1> [#uses=0]
%test50 = fcmp oge float %float1, %float2 ; <i1> [#uses=0]
%test51 = fcmp ogt float %float1, %float2 ; <i1> [#uses=0]
%test52 = fcmp ole float %float1, %float2 ; <i1> [#uses=0]
%test53 = fcmp olt float %float1, %float2 ; <i1> [#uses=0]
%test54 = fcmp une float %float1, %float2 ; <i1> [#uses=0]
%test55 = fcmp oeq double %double1, %double2 ; <i1> [#uses=0]
%test56 = fcmp oge double %double1, %double2 ; <i1> [#uses=0]
%test57 = fcmp ogt double %double1, %double2 ; <i1> [#uses=0]
%test58 = fcmp ole double %double1, %double2 ; <i1> [#uses=0]
%test59 = fcmp olt double %double1, %double2 ; <i1> [#uses=0]
%test60 = fcmp une double %double1, %double2 ; <i1> [#uses=0]
ret i32 0
}

View File

@ -1,69 +0,0 @@
; RUN: %lli -use-mcjit %s > /dev/null
define i32 @main() {
%int1 = add i32 0, 0 ; <i32> [#uses=6]
%int2 = add i32 0, 0 ; <i32> [#uses=6]
%long1 = add i64 0, 0 ; <i64> [#uses=6]
%long2 = add i64 0, 0 ; <i64> [#uses=6]
%sbyte1 = add i8 0, 0 ; <i8> [#uses=6]
%sbyte2 = add i8 0, 0 ; <i8> [#uses=6]
%short1 = add i16 0, 0 ; <i16> [#uses=6]
%short2 = add i16 0, 0 ; <i16> [#uses=6]
%ubyte1 = add i8 0, 0 ; <i8> [#uses=6]
%ubyte2 = add i8 0, 0 ; <i8> [#uses=6]
%uint1 = add i32 0, 0 ; <i32> [#uses=6]
%uint2 = add i32 0, 0 ; <i32> [#uses=6]
%ulong1 = add i64 0, 0 ; <i64> [#uses=6]
%ulong2 = add i64 0, 0 ; <i64> [#uses=6]
%ushort1 = add i16 0, 0 ; <i16> [#uses=6]
%ushort2 = add i16 0, 0 ; <i16> [#uses=6]
%test1 = icmp eq i8 %ubyte1, %ubyte2 ; <i1> [#uses=0]
%test2 = icmp uge i8 %ubyte1, %ubyte2 ; <i1> [#uses=0]
%test3 = icmp ugt i8 %ubyte1, %ubyte2 ; <i1> [#uses=0]
%test4 = icmp ule i8 %ubyte1, %ubyte2 ; <i1> [#uses=0]
%test5 = icmp ult i8 %ubyte1, %ubyte2 ; <i1> [#uses=0]
%test6 = icmp ne i8 %ubyte1, %ubyte2 ; <i1> [#uses=0]
%test7 = icmp eq i16 %ushort1, %ushort2 ; <i1> [#uses=0]
%test8 = icmp uge i16 %ushort1, %ushort2 ; <i1> [#uses=0]
%test9 = icmp ugt i16 %ushort1, %ushort2 ; <i1> [#uses=0]
%test10 = icmp ule i16 %ushort1, %ushort2 ; <i1> [#uses=0]
%test11 = icmp ult i16 %ushort1, %ushort2 ; <i1> [#uses=0]
%test12 = icmp ne i16 %ushort1, %ushort2 ; <i1> [#uses=0]
%test13 = icmp eq i32 %uint1, %uint2 ; <i1> [#uses=0]
%test14 = icmp uge i32 %uint1, %uint2 ; <i1> [#uses=0]
%test15 = icmp ugt i32 %uint1, %uint2 ; <i1> [#uses=0]
%test16 = icmp ule i32 %uint1, %uint2 ; <i1> [#uses=0]
%test17 = icmp ult i32 %uint1, %uint2 ; <i1> [#uses=0]
%test18 = icmp ne i32 %uint1, %uint2 ; <i1> [#uses=0]
%test19 = icmp eq i64 %ulong1, %ulong2 ; <i1> [#uses=0]
%test20 = icmp uge i64 %ulong1, %ulong2 ; <i1> [#uses=0]
%test21 = icmp ugt i64 %ulong1, %ulong2 ; <i1> [#uses=0]
%test22 = icmp ule i64 %ulong1, %ulong2 ; <i1> [#uses=0]
%test23 = icmp ult i64 %ulong1, %ulong2 ; <i1> [#uses=0]
%test24 = icmp ne i64 %ulong1, %ulong2 ; <i1> [#uses=0]
%test25 = icmp eq i8 %sbyte1, %sbyte2 ; <i1> [#uses=0]
%test26 = icmp sge i8 %sbyte1, %sbyte2 ; <i1> [#uses=0]
%test27 = icmp sgt i8 %sbyte1, %sbyte2 ; <i1> [#uses=0]
%test28 = icmp sle i8 %sbyte1, %sbyte2 ; <i1> [#uses=0]
%test29 = icmp slt i8 %sbyte1, %sbyte2 ; <i1> [#uses=0]
%test30 = icmp ne i8 %sbyte1, %sbyte2 ; <i1> [#uses=0]
%test31 = icmp eq i16 %short1, %short2 ; <i1> [#uses=0]
%test32 = icmp sge i16 %short1, %short2 ; <i1> [#uses=0]
%test33 = icmp sgt i16 %short1, %short2 ; <i1> [#uses=0]
%test34 = icmp sle i16 %short1, %short2 ; <i1> [#uses=0]
%test35 = icmp slt i16 %short1, %short2 ; <i1> [#uses=0]
%test36 = icmp ne i16 %short1, %short2 ; <i1> [#uses=0]
%test37 = icmp eq i32 %int1, %int2 ; <i1> [#uses=0]
%test38 = icmp sge i32 %int1, %int2 ; <i1> [#uses=0]
%test39 = icmp sgt i32 %int1, %int2 ; <i1> [#uses=0]
%test40 = icmp sle i32 %int1, %int2 ; <i1> [#uses=0]
%test41 = icmp slt i32 %int1, %int2 ; <i1> [#uses=0]
%test42 = icmp ne i32 %int1, %int2 ; <i1> [#uses=0]
%test43 = icmp eq i64 %long1, %long2 ; <i1> [#uses=0]
%test44 = icmp sge i64 %long1, %long2 ; <i1> [#uses=0]
%test45 = icmp sgt i64 %long1, %long2 ; <i1> [#uses=0]
%test46 = icmp sle i64 %long1, %long2 ; <i1> [#uses=0]
%test47 = icmp slt i64 %long1, %long2 ; <i1> [#uses=0]
%test48 = icmp ne i64 %long1, %long2 ; <i1> [#uses=0]
ret i32 0
}

View File

@ -1,32 +0,0 @@
; RUN: %lli -use-mcjit %s > /dev/null
define i32 @main() {
%shamt = add i8 0, 1 ; <i8> [#uses=8]
%shift.upgrd.1 = zext i8 %shamt to i32 ; <i32> [#uses=1]
%t1.s = shl i32 1, %shift.upgrd.1 ; <i32> [#uses=0]
%t2.s = shl i32 1, 4 ; <i32> [#uses=0]
%shift.upgrd.2 = zext i8 %shamt to i32 ; <i32> [#uses=1]
%t1 = shl i32 1, %shift.upgrd.2 ; <i32> [#uses=0]
%t2 = shl i32 1, 5 ; <i32> [#uses=0]
%t2.s.upgrd.3 = shl i64 1, 4 ; <i64> [#uses=0]
%t2.upgrd.4 = shl i64 1, 5 ; <i64> [#uses=0]
%shift.upgrd.5 = zext i8 %shamt to i32 ; <i32> [#uses=1]
%tr1.s = ashr i32 1, %shift.upgrd.5 ; <i32> [#uses=0]
%tr2.s = ashr i32 1, 4 ; <i32> [#uses=0]
%shift.upgrd.6 = zext i8 %shamt to i32 ; <i32> [#uses=1]
%tr1 = lshr i32 1, %shift.upgrd.6 ; <i32> [#uses=0]
%tr2 = lshr i32 1, 5 ; <i32> [#uses=0]
%tr1.l = ashr i64 1, 4 ; <i64> [#uses=0]
%shift.upgrd.7 = zext i8 %shamt to i64 ; <i64> [#uses=1]
%tr2.l = ashr i64 1, %shift.upgrd.7 ; <i64> [#uses=0]
%tr3.l = shl i64 1, 4 ; <i64> [#uses=0]
%shift.upgrd.8 = zext i8 %shamt to i64 ; <i64> [#uses=1]
%tr4.l = shl i64 1, %shift.upgrd.8 ; <i64> [#uses=0]
%tr1.u = lshr i64 1, 5 ; <i64> [#uses=0]
%shift.upgrd.9 = zext i8 %shamt to i64 ; <i64> [#uses=1]
%tr2.u = lshr i64 1, %shift.upgrd.9 ; <i64> [#uses=0]
%tr3.u = shl i64 1, 5 ; <i64> [#uses=0]
%shift.upgrd.10 = zext i8 %shamt to i64 ; <i64> [#uses=1]
%tr4.u = shl i64 1, %shift.upgrd.10 ; <i64> [#uses=0]
ret i32 0
}

View File

@ -171,7 +171,6 @@ lit.site.cfg: site.exp
@$(ECHOPATH) s=@ENABLE_ASSERTIONS@=$(ENABLE_ASSERTIONS)=g >> lit.tmp
@$(ECHOPATH) s=@TARGETS_TO_BUILD@=$(TARGETS_TO_BUILD)=g >> lit.tmp
@$(ECHOPATH) s=@LLVM_BINDINGS@=$(BINDINGS_TO_BUILD)=g >> lit.tmp
@$(ECHOPATH) s=@HOST_OS@=$(HOST_OS)=g >> lit.tmp
@sed -f lit.tmp $(PROJ_SRC_DIR)/lit.site.cfg.in > $@
@-rm -f lit.tmp
@ -185,6 +184,5 @@ Unit/lit.site.cfg: $(PROJ_OBJ_DIR)/Unit/.dir FORCE
@$(ECHOPATH) s=@ENABLE_SHARED@=$(ENABLE_SHARED)=g >> unit.tmp
@$(ECHOPATH) s=@SHLIBDIR@=$(SharedLibDir)=g >> unit.tmp
@$(ECHOPATH) s=@SHLIBPATH_VAR@=$(SHLIBPATH_VAR)=g >> unit.tmp
@$(ECHOPATH) s=@HOST_OS@=$(HOST_OS)=g >> unit.tmp
@sed -f unit.tmp $(PROJ_SRC_DIR)/Unit/lit.site.cfg.in > $@
@-rm -f unit.tmp

View File

@ -9,7 +9,6 @@ config.enable_shared = @ENABLE_SHARED@
config.enable_assertions = @ENABLE_ASSERTIONS@
config.targets_to_build = "@TARGETS_TO_BUILD@"
config.llvm_bindings = "@LLVM_BINDINGS@"
config.host_os = "@HOST_OS@"
# Support substitution of the tools_dir with user parameters. This is
# used when we can't determine the tool dir at configuration time.

View File

@ -58,11 +58,9 @@ public:
uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment,
unsigned SectionID);
virtual void *getPointerToNamedFunction(const std::string &Name,
bool AbortOnFailure = true) {
return 0;
}
uint8_t *startFunctionBody(const char *Name, uintptr_t &Size);
void endFunctionBody(const char *Name, uint8_t *FunctionStart,
uint8_t *FunctionEnd);
};
uint8_t *TrivialMemoryManager::allocateCodeSection(uintptr_t Size,
@ -77,6 +75,18 @@ uint8_t *TrivialMemoryManager::allocateDataSection(uintptr_t Size,
return (uint8_t*)sys::Memory::AllocateRWX(Size, 0, 0).base();
}
uint8_t *TrivialMemoryManager::startFunctionBody(const char *Name,
uintptr_t &Size) {
return (uint8_t*)sys::Memory::AllocateRWX(Size, 0, 0).base();
}
void TrivialMemoryManager::endFunctionBody(const char *Name,
uint8_t *FunctionStart,
uint8_t *FunctionEnd) {
uintptr_t Size = FunctionEnd - FunctionStart + 1;
FunctionMemory.push_back(sys::MemoryBlock(FunctionStart, Size));
}
static const char *ProgramName;
static void Message(const char *Type, const Twine &Msg) {

View File

@ -64,10 +64,6 @@ public:
: Base(JITMemoryManager::CreateDefaultMemManager()) {
stubsAllocated = 0;
}
virtual void *getPointerToNamedFunction(const std::string &Name,
bool AbortOnFailure = true) {
return Base->getPointerToNamedFunction(Name, AbortOnFailure);
}
virtual void setMemoryWritable() { Base->setMemoryWritable(); }
virtual void setMemoryExecutable() { Base->setMemoryExecutable(); }