Like constants, globals on some platforms are GOT relative. This means they have to be allocated

near the GOT, which new doesn't do.  So break out the allocate into a new function.

Also move GOT index handling into JITResolver.  This lets it update the mapping when a Lazy
function is JITed.  It doesn't managed the table, just the mapping.  Note that this is
still non-ideal, as any function that takes a function address should also take a GOT
index, but that is a lot of changes.  The relocation resolve process updates any GOT entry
it sees is out of date.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@22537 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Andrew Lenharth 2005-07-28 12:44:13 +00:00
parent 988b1dd608
commit 6a9746127a
3 changed files with 84 additions and 14 deletions

View File

@ -94,6 +94,12 @@ public:
//
virtual uint64_t getConstantPoolEntryAddress(unsigned Index) = 0;
// allocateGlobal - Allocate some space for a global variable. This is
// used by the JIT to allocate space in the global variable region.
virtual unsigned char* allocateGlobal(unsigned size, unsigned alignment) {
return new unsigned char[(size_t)size];
}
/// createDebugEmitter - Return a dynamically allocated machine
/// code emitter, which just prints the opcodes and fields out the cout. This
/// can be used for debugging users of the MachineCodeEmitter interface.

View File

@ -294,7 +294,8 @@ void *JIT::getOrEmitGlobalVariable(const GlobalVariable *GV) {
// actually initialize the global after current function has finished
// compilation.
uint64_t S = getTargetData().getTypeSize(GV->getType()->getElementType());
Ptr = new char[(size_t)S];
unsigned char A = getTargetData().getTypeAlignment(GV->getType()->getElementType());
Ptr = MCE->allocateGlobal(S, A);
state.getPendingGlobals(locked).push_back(GV);
}
addGlobalMapping(GV, Ptr);

View File

@ -60,6 +60,8 @@ namespace {
inline unsigned char *allocateStub(unsigned StubSize);
inline unsigned char *allocateConstant(unsigned ConstantSize,
unsigned Alignment);
inline unsigned char* allocateGlobal(unsigned Size,
unsigned Alignment);
inline unsigned char *startFunctionBody();
inline void endFunctionBody(unsigned char *FunctionEnd);
inline unsigned char* getGOTBase() const;
@ -115,6 +117,21 @@ unsigned char *JITMemoryManager::allocateConstant(unsigned ConstantSize,
return CurConstantPtr;
}
unsigned char *JITMemoryManager::allocateGlobal(unsigned Size,
unsigned Alignment) {
// For now, intersperse them with Constants
// Reserve space and align pointer.
CurConstantPtr -= Size;
CurConstantPtr =
(unsigned char *)((intptr_t)CurConstantPtr & ~((intptr_t)Alignment - 1));
if (CurConstantPtr < ConstantPool) {
std::cerr << "JIT ran out of memory for Globals!\n";
abort();
}
return CurConstantPtr;
}
unsigned char *JITMemoryManager::startFunctionBody() {
// Round up to an even multiple of 8 bytes, this should eventually be target
// specific.
@ -175,8 +192,13 @@ namespace {
/// ExternalFnToStubMap - This is the equivalent of FunctionToStubMap for
/// external functions.
std::map<void*, void*> ExternalFnToStubMap;
//map addresses to indexes in the GOT
std::map<void*, unsigned> revGOTMap;
unsigned nextGOTIndex;
public:
JITResolver(MachineCodeEmitter &mce) : MCE(mce) {
JITResolver(MachineCodeEmitter &mce) : MCE(mce), nextGOTIndex(0) {
LazyResolverFn =
TheJIT->getJITInfo().getLazyResolverFunction(JITCompilerFn);
}
@ -199,6 +221,11 @@ namespace {
return (void*)LazyResolverFn;
}
/// getGOTIndexForAddress - Return a new or existing index in the GOT for
/// and address. This function only manages slots, it does not manage the
/// contents of the slots or the memory associated with the GOT.
unsigned getGOTIndexForAddr(void* addr);
/// JITCompilerFn - This function is called to resolve a stub to a compiled
/// address. If the LLVM Function corresponding to the stub has not yet
/// been compiled, this function compiles it first.
@ -261,6 +288,17 @@ void *JITResolver::getExternalFunctionStub(void *FnAddr) {
return Stub;
}
unsigned JITResolver::getGOTIndexForAddr(void* addr) {
unsigned idx = revGOTMap[addr];
if (!idx) {
idx = ++nextGOTIndex;
revGOTMap[addr] = idx;
DEBUG(std::cerr << "Adding GOT entry " << idx
<< " for addr " << addr << "\n");
// ((void**)MemMgr.getGOTBase())[idx] = addr;
}
return idx;
}
/// JITCompilerFn - This function is called when a lazy compilation stub has
/// been entered. It looks up which function this stub corresponds to, compiles
@ -294,6 +332,15 @@ void *JITResolver::JITCompilerFn(void *Stub) {
JR.state.getFunctionToStubMap(locked).erase(F);
// FIXME: We could rewrite all references to this stub if we knew them.
// What we will do is set the compiled function address to map to the
// same GOT entry as the stub so that later clients may update the GOT
// if they see it still using the stub address.
// Note: this is done so the Resolver doesn't have to manage GOT memory
// Do this without allocating map space if the target isn't using a GOT
if(JR.revGOTMap.find(Stub) != JR.revGOTMap.end())
JR.revGOTMap[Result] = JR.revGOTMap[Stub];
return Result;
}
@ -340,8 +387,7 @@ namespace {
public:
JITEmitter(JIT &jit)
:MemMgr(jit.getJITInfo().needsGOT()),
nextGOTIndex(0)
:MemMgr(jit.getJITInfo().needsGOT())
{
TheJIT = &jit;
DEBUG(std::cerr <<
@ -365,11 +411,10 @@ namespace {
virtual uint64_t getCurrentPCValue();
virtual uint64_t getCurrentPCOffset();
virtual uint64_t getConstantPoolEntryAddress(unsigned Entry);
virtual unsigned char* allocateGlobal(unsigned size, unsigned alignment);
private:
void *getPointerToGlobal(GlobalValue *GV, void *Reference, bool NoNeedStub);
unsigned nextGOTIndex;
std::map<void*, unsigned> revGOTMap;
};
}
@ -441,14 +486,17 @@ void JITEmitter::finishFunction(MachineFunction &F) {
MR.setResultPointer(ResultPtr);
// if we are managing the got, check to see if this pointer has all ready
// been allocated a GOT entry. If not, give it the next one.
if (MemMgr.isManagingGOT()) {
if (!revGOTMap[ResultPtr])
revGOTMap[ResultPtr] = ++nextGOTIndex;
((void**)MemMgr.getGOTBase())[revGOTMap[ResultPtr]] = ResultPtr;
if(MR.isGOTRelative())
MR.setGOTIndex(revGOTMap[ResultPtr]);
// if we are managing the GOT and the relocation wants an index,
// give it one
if (MemMgr.isManagingGOT() && !MR.isConstantPoolIndex() &&
MR.isGOTRelative()) {
unsigned idx = getJITResolver(this).getGOTIndexForAddr(ResultPtr);
MR.setGOTIndex(idx);
if (((void**)MemMgr.getGOTBase())[idx] != ResultPtr) {
DEBUG(std::cerr << "GOT was out of date for " << ResultPtr
<< " pointing at " << ((void**)MemMgr.getGOTBase())[idx] << "\n");
((void**)MemMgr.getGOTBase())[idx] = ResultPtr;
}
}
}
@ -456,6 +504,16 @@ void JITEmitter::finishFunction(MachineFunction &F) {
Relocations.size(), MemMgr.getGOTBase());
}
//Update the GOT entry for F to point to the new code.
if(MemMgr.isManagingGOT()) {
unsigned idx = getJITResolver(this).getGOTIndexForAddr((void*)CurBlock);
if (((void**)MemMgr.getGOTBase())[idx] != (void*)CurBlock) {
DEBUG(std::cerr << "GOT was out of date for " << (void*)CurBlock
<< " pointing at " << ((void**)MemMgr.getGOTBase())[idx] << "\n");
((void**)MemMgr.getGOTBase())[idx] = (void*)CurBlock;
}
}
DEBUG(std::cerr << "JIT: Finished CodeGen of [" << (void*)CurBlock
<< "] Function: " << F.getFunction()->getName()
<< ": " << CurByte-CurBlock << " bytes of text, "
@ -516,6 +574,11 @@ uint64_t JITEmitter::getConstantPoolEntryAddress(unsigned ConstantNum) {
return (intptr_t)ConstantPoolAddresses[ConstantNum];
}
unsigned char* JITEmitter::allocateGlobal(unsigned size, unsigned alignment)
{
return MemMgr.allocateGlobal(size, alignment);
}
// getCurrentPCValue - This returns the address that the next emitted byte
// will be output to.
//