diff --git a/include/llvm/ExecutionEngine/RuntimeDyld.h b/include/llvm/ExecutionEngine/RuntimeDyld.h index 6e18c7cfca5..416acceee97 100644 --- a/include/llvm/ExecutionEngine/RuntimeDyld.h +++ b/include/llvm/ExecutionEngine/RuntimeDyld.h @@ -38,12 +38,12 @@ public: // 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 uint64_t startFunctionBody(const char *Name, uintptr_t &Size) = 0; + 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, uint64_t FunctionStart, - uint64_t FunctionEnd) = 0; + virtual void endFunctionBody(const char *Name, uint8_t *FunctionStart, + uint8_t *FunctionEnd) = 0; }; class RuntimeDyld { diff --git a/lib/ExecutionEngine/MCJIT/MCJITMemoryManager.h b/lib/ExecutionEngine/MCJIT/MCJITMemoryManager.h index b5251650169..0108ecca84f 100644 --- a/lib/ExecutionEngine/MCJIT/MCJITMemoryManager.h +++ b/lib/ExecutionEngine/MCJIT/MCJITMemoryManager.h @@ -31,23 +31,19 @@ public: // 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. - uint64_t startFunctionBody(const char *Name, uintptr_t &Size) { + uint8_t *startFunctionBody(const char *Name, uintptr_t &Size) { Function *F = M->getFunction(Name); assert(F && "No matching function in JIT IR Module!"); - return (uint64_t)JMM->startFunctionBody(F, Size); + 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, uint64_t FunctionStart, - uint64_t FunctionEnd) { + void endFunctionBody(const char *Name, uint8_t *FunctionStart, + uint8_t *FunctionEnd) { Function *F = M->getFunction(Name); assert(F && "No matching function in JIT IR Module!"); - // The JITMemoryManager interface makes the unfortunate assumption that - // the address space/sizes we're compiling on are the same as what we're - // compiling for, so it uses pointer types for its addresses. Explicit - // casts between them to deal with that. - JMM->endFunctionBody(F, (uint8_t*)FunctionStart, (uint8_t*)FunctionEnd); + JMM->endFunctionBody(F, FunctionStart, FunctionEnd); } }; diff --git a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp index 7e6a1f04f0d..de54f082eb4 100644 --- a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp +++ b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp @@ -16,6 +16,7 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/Twine.h" #include "llvm/ExecutionEngine/RuntimeDyld.h" #include "llvm/Object/MachOObject.h" @@ -40,6 +41,10 @@ class RuntimeDyldImpl { // The MemoryManager to load objects into. RTDyldMemoryManager *MemMgr; + + // For each function, we have a MemoryBlock of it's instruction data. + StringMap Functions; + // Master symbol table. As modules are loaded and external symbols are // resolved, their addresses are stored here. StringMap SymbolTable; @@ -58,6 +63,8 @@ class RuntimeDyldImpl { return true; } + void extractFunction(StringRef Name, uint8_t *StartAddress, + uint8_t *EndAddress); bool resolveRelocation(uint32_t BaseSection, macho::RelocationEntry RE, SmallVectorImpl &SectionBases, SmallVectorImpl &SymbolNames); @@ -79,9 +86,9 @@ public: bool loadObject(MemoryBuffer *InputBuffer); uint64_t getSymbolAddress(StringRef Name) { - // Use lookup() rather than [] because we don't want to add an entry - // if there isn't one already, which the [] operator does. - return SymbolTable.lookup(Name); + // FIXME: Just look up as a function for now. Overly simple of course. + // Work in progress. + return (uint64_t)Functions.lookup(Name).base(); } sys::MemoryBlock getMemoryBlock() { return Data; } @@ -96,7 +103,21 @@ public: StringRef getErrorString() { return ErrorStr; } }; -// FIXME: Relocations for targets other than x86_64. +void RuntimeDyldImpl::extractFunction(StringRef Name, uint8_t *StartAddress, + uint8_t *EndAddress) { + // Allocate memory for the function via the memory manager. + uintptr_t Size = EndAddress - StartAddress + 1; + uint8_t *Mem = MemMgr->startFunctionBody(Name.data(), Size); + 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, EndAddress - StartAddress + 1); + MemMgr->endFunctionBody(Name.data(), Mem, Mem + Size); + // Remember where we put it. + Functions[Name] = sys::MemoryBlock(Mem, Size); + DEBUG(dbgs() << " allocated to " << Mem << "\n"); +} + bool RuntimeDyldImpl:: resolveRelocation(uint32_t BaseSection, macho::RelocationEntry RE, SmallVectorImpl &SectionBases, @@ -273,7 +294,7 @@ loadSegment32(const MachOObject *Obj, for (unsigned i = 0; i != Segment32LC->NumSections; ++i) { InMemoryStruct Sect; Obj->ReadSection(*SegmentLCI, i, Sect); - if (!Sect) + if (!Sect) return Error("unable to load section: '" + Twine(i) + "'"); // Remember any relocations the section has so we can resolve them later. @@ -353,92 +374,72 @@ loadSegment64(const MachOObject *Obj, if (!Segment64LC) return Error("unable to load segment load command"); - // Map the segment into memory. - std::string ErrorStr; - Data = sys::Memory::AllocateRWX(Segment64LC->VMSize, 0, &ErrorStr); - if (!Data.base()) - return Error("unable to allocate memory block: '" + ErrorStr + "'"); - memcpy(Data.base(), Obj->getData(Segment64LC->FileOffset, - Segment64LC->FileSize).data(), - Segment64LC->FileSize); - memset((char*)Data.base() + Segment64LC->FileSize, 0, - Segment64LC->VMSize - Segment64LC->FileSize); - - // Bind the section indices to addresses and record the relocations we - // need to resolve. - typedef std::pair RelocationMap; - SmallVector Relocations; - - SmallVector SectionBases; - for (unsigned i = 0; i != Segment64LC->NumSections; ++i) { + for (unsigned SectNum = 0; SectNum != Segment64LC->NumSections; ++SectNum) { InMemoryStruct Sect; - Obj->ReadSection64(*SegmentLCI, i, Sect); + Obj->ReadSection64(*SegmentLCI, SectNum, Sect); if (!Sect) - return Error("unable to load section: '" + Twine(i) + "'"); - - // Remember any relocations the section has so we can resolve them later. - for (unsigned j = 0; j != Sect->NumRelocationTableEntries; ++j) { - InMemoryStruct RE; - Obj->ReadRelocationEntry(Sect->RelocationTableOffset, j, RE); - Relocations.push_back(RelocationMap(j, *RE)); - } + return Error("unable to load section: '" + Twine(SectNum) + "'"); // FIXME: Improve check. if (Sect->Flags != 0x80000400) return Error("unsupported section type!"); - SectionBases.push_back((char*) Data.base() + Sect->Address); + // Address and names of symbols in the section. + typedef std::pair SymbolEntry; + SmallVector Symbols; + for (unsigned i = 0; i != SymtabLC->NumSymbolTableEntries; ++i) { + InMemoryStruct STE; + Obj->ReadSymbol64TableEntry(SymtabLC->SymbolTableOffset, i, STE); + if (!STE) + return Error("unable to read symbol: '" + Twine(i) + "'"); + if (STE->SectionIndex > Segment64LC->NumSections) + return Error("invalid section index for symbol: '" + Twine() + "'"); + + // Just skip symbols not defined in this section. + if (STE->SectionIndex - 1 != SectNum) + continue; + + // Get the symbol name. + StringRef Name = Obj->getStringAtIndex(STE->StringIndex); + + // FIXME: Check the symbol type and flags. + if (STE->Type != 0xF) // external, defined in this section. + return Error("unexpected symbol type!"); + if (STE->Flags != 0x0) + return Error("unexpected symbol type!"); + + uint64_t BaseAddress = Sect->Address; + uint64_t Address = BaseAddress + STE->Value; + + // Remember the symbol. + Symbols.push_back(SymbolEntry(Address, Name)); + + DEBUG(dbgs() << "Function sym: '" << Name << "' @ " << Address << "\n"); + } + // Sort the symbols by address, just in case they didn't come in that + // way. + array_pod_sort(Symbols.begin(), Symbols.end()); + + // Extract the function data. + uint8_t *Base = (uint8_t*)Obj->getData(Segment64LC->FileOffset, + Segment64LC->FileSize).data(); + for (unsigned i = 0, e = Symbols.size() - 1; i != e; ++i) { + uint64_t StartOffset = Symbols[i].first; + uint64_t EndOffset = Symbols[i + 1].first - 1; + DEBUG(dbgs() << "Extracting function: " << Symbols[i].second + << " from [" << StartOffset << ", " << EndOffset << "]\n"); + extractFunction(Symbols[i].second, Base + StartOffset, Base + EndOffset); + } + // The last symbol we do after since the end address is calculated + // differently because there is no next symbol to reference. + uint64_t StartOffset = Symbols[Symbols.size() - 1].first; + uint64_t EndOffset = Sect->Size - 1; + DEBUG(dbgs() << "Extracting function: " << Symbols[Symbols.size()-1].second + << " from [" << StartOffset << ", " << EndOffset << "]\n"); + extractFunction(Symbols[Symbols.size()-1].second, + Base + StartOffset, Base + EndOffset); } - // Bind all the symbols to address. Keep a record of the names for use - // by relocation resolution. - SmallVector SymbolNames; - for (unsigned i = 0; i != SymtabLC->NumSymbolTableEntries; ++i) { - InMemoryStruct 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); - - // Just skip undefined symbols. They'll be loaded from whatever - // module they come from (or system dylib) when we resolve relocations - // involving them. - if (STE->SectionIndex == 0) - continue; - - unsigned Index = STE->SectionIndex - 1; - if (Index >= Segment64LC->NumSections) - return Error("invalid section index for symbol: '" + Twine() + "'"); - - // Get the section base address. - void *SectionBase = SectionBases[Index]; - - // Get the symbol address. - uint64_t Address = (uint64_t) SectionBase + STE->Value; - - // FIXME: Check the symbol type and flags. - if (STE->Type != 0xF) - return Error("unexpected symbol type!"); - if (STE->Flags != 0x0) - return Error("unexpected symbol type!"); - - DEBUG(dbgs() << "Symbol: '" << Name << "' @ " << Address << "\n"); - SymbolTable[Name] = Address; - } - - // Now resolve any relocations. - for (unsigned i = 0, e = Relocations.size(); i != e; ++i) { - if (resolveRelocation(Relocations[i].first, Relocations[i].second, - SectionBases, SymbolNames)) - return true; - } - - // We've loaded the section; now mark the functions in it as executable. - // FIXME: We really should use the MemoryManager for this. - sys::Memory::setRangeExecutable(Data.base(), Data.size()); - return false; } diff --git a/tools/llvm-rtdyld/llvm-rtdyld.cpp b/tools/llvm-rtdyld/llvm-rtdyld.cpp index e09f14ad784..ddd6683a2f2 100644 --- a/tools/llvm-rtdyld/llvm-rtdyld.cpp +++ b/tools/llvm-rtdyld/llvm-rtdyld.cpp @@ -44,14 +44,14 @@ Action(cl::desc("Action to perform:"), // support library allocation routines directly. class TrivialMemoryManager : public RTDyldMemoryManager { public: - uint64_t startFunctionBody(const char *Name, uintptr_t &Size); - void endFunctionBody(const char *Name, uint64_t FunctionStart, - uint64_t FunctionEnd) {} + uint8_t *startFunctionBody(const char *Name, uintptr_t &Size); + void endFunctionBody(const char *Name, uint8_t *FunctionStart, + uint8_t *FunctionEnd) {} }; -uint64_t TrivialMemoryManager::startFunctionBody(const char *Name, +uint8_t *TrivialMemoryManager::startFunctionBody(const char *Name, uintptr_t &Size) { - return (uint64_t)sys::Memory::AllocateRWX(Size, 0, 0).base(); + return (uint8_t*)sys::Memory::AllocateRWX(Size, 0, 0).base(); } static const char *ProgramName;