From 6a9746127a168306a670eaff11925605dbea9d4f Mon Sep 17 00:00:00 2001 From: Andrew Lenharth Date: Thu, 28 Jul 2005 12:44:13 +0000 Subject: 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 --- lib/ExecutionEngine/JIT/JIT.cpp | 3 +- lib/ExecutionEngine/JIT/JITEmitter.cpp | 89 +++++++++++++++++++++++++++++----- 2 files changed, 78 insertions(+), 14 deletions(-) (limited to 'lib/ExecutionEngine') diff --git a/lib/ExecutionEngine/JIT/JIT.cpp b/lib/ExecutionEngine/JIT/JIT.cpp index 3907511750..1e879a9166 100644 --- a/lib/ExecutionEngine/JIT/JIT.cpp +++ b/lib/ExecutionEngine/JIT/JIT.cpp @@ -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); diff --git a/lib/ExecutionEngine/JIT/JITEmitter.cpp b/lib/ExecutionEngine/JIT/JITEmitter.cpp index 172084a334..0d47a97e2f 100644 --- a/lib/ExecutionEngine/JIT/JITEmitter.cpp +++ b/lib/ExecutionEngine/JIT/JITEmitter.cpp @@ -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 ExternalFnToStubMap; + + //map addresses to indexes in the GOT + std::map 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 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. // -- cgit v1.2.3