diff options
author | Danil Malyshev <dmalyshev@accesssoftek.com> | 2012-03-29 21:46:18 +0000 |
---|---|---|
committer | Danil Malyshev <dmalyshev@accesssoftek.com> | 2012-03-29 21:46:18 +0000 |
commit | 4b0b8ef1b0edc2c343145f6b029c43b00a6f5c13 (patch) | |
tree | 3129fed4802e6e32ce38ca8dc4295d7b0ceffb09 /lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp | |
parent | 6c31ee2b10827583a0fbcb39623fdfb440c917ef (diff) | |
download | llvm-4b0b8ef1b0edc2c343145f6b029c43b00a6f5c13.tar.gz llvm-4b0b8ef1b0edc2c343145f6b029c43b00a6f5c13.tar.bz2 llvm-4b0b8ef1b0edc2c343145f6b029c43b00a6f5c13.tar.xz |
Re-factored RuntimeDyld.
Added ExecutionEngine/MCJIT tests.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@153694 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp')
-rw-r--r-- | lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp | 409 |
1 files changed, 181 insertions, 228 deletions
diff --git a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp index e15b200c5e..9d46b21f59 100644 --- a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp +++ b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp @@ -25,222 +25,58 @@ using namespace llvm::object; namespace llvm { -namespace { -// 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!"); +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; case ELF::R_X86_64_64: { - uint8_t **Target = reinterpret_cast<uint8_t**>(TargetAddr); - *Target = Addr + RE.Addend; + uint64_t *Target = (uint64_t*)(LocalAddress); + *Target = Value + Addend; break; } case ELF::R_X86_64_32: case ELF::R_X86_64_32S: { - uint64_t Value = reinterpret_cast<uint64_t>(Addr) + RE.Addend; + Value += Addend; // FIXME: Handle the possibility of this assertion failing - assert((RE.Type == ELF::R_X86_64_32 && !(Value & 0xFFFFFFFF00000000ULL)) || - (RE.Type == ELF::R_X86_64_32S && + assert((Type == ELF::R_X86_64_32 && !(Value & 0xFFFFFFFF00000000ULL)) || + (Type == ELF::R_X86_64_32S && (Value & 0xFFFFFFFF00000000ULL) == 0xFFFFFFFF00000000ULL)); uint32_t TruncatedAddr = (Value & 0xFFFFFFFF); - uint32_t *Target = reinterpret_cast<uint32_t*>(TargetAddr); + uint32_t *Target = reinterpret_cast<uint32_t*>(LocalAddress); *Target = TruncatedAddr; break; } case ELF::R_X86_64_PC32: { - 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); + 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); *Placeholder = TruncOffset; break; } } } -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) { +void RuntimeDyldELF::resolveX86Relocation(uint8_t *LocalAddress, + uint32_t FinalAddress, + uint32_t Value, + uint32_t Type, + int32_t Addend) { + switch (Type) { case ELF::R_386_32: { - uint8_t **Target = reinterpret_cast<uint8_t**>(TargetAddr); - *Target = Addr + RE.Addend; + uint32_t *Target = (uint32_t*)(LocalAddress); + *Target = Value + Addend; break; } case ELF::R_386_PC32: { - uint32_t *Placeholder = reinterpret_cast<uint32_t*>(TargetAddr); - uint32_t RealOffset = *Placeholder + reinterpret_cast<uintptr_t>(Addr) + - RE.Addend - reinterpret_cast<uintptr_t>(TargetAddr); + uint32_t *Placeholder = reinterpret_cast<uint32_t*>(LocalAddress); + uint32_t RealOffset = *Placeholder + Value + Addend - FinalAddress; *Placeholder = RealOffset; break; } @@ -248,57 +84,174 @@ void RuntimeDyldELF::resolveX86Relocation(StringRef Name, // 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(StringRef Name, - uint8_t *Addr, - const RelocationEntry &RE) { +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::resolveRelocation(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) { switch (Arch) { case Triple::x86_64: - resolveX86_64Relocation(Name, Addr, RE); + resolveX86_64Relocation(LocalAddress, FinalAddress, Value, Type, Addend); break; case Triple::x86: - resolveX86Relocation(Name, Addr, RE); + resolveX86Relocation(LocalAddress, (uint32_t)(FinalAddress & 0xffffffffL), + (uint32_t)(Value & 0xffffffffL), Type, + (uint32_t)(Addend & 0xffffffffL)); break; - case Triple::arm: - resolveArmRelocation(Name, Addr, RE); + case Triple::arm: // Fall through. + case Triple::thumb: + resolveARMRelocation(LocalAddress, (uint32_t)(FinalAddress & 0xffffffffL), + (uint32_t)(Value & 0xffffffffL), Type, + (uint32_t)(Addend & 0xffffffffL)); break; default: llvm_unreachable("Unsupported CPU type!"); } } -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!"); - - RelocationList &Relocs = Relocations[Name]; - for (unsigned i = 0, e = Relocs.size(); i != e; ++i) { - RelocationEntry &RE = Relocs[i]; - resolveRelocation(Name, Addr, RE); +void RuntimeDyldELF::processRelocationRef(const ObjRelocationInfo &Rel, + const ObjectFile &Obj, + ObjSectionToIDMap &ObjSectionToID, + LocalSymbolMap &Symbols, + StubMap &Stubs) { + + 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 lsi = Symbols.find(TargetName.data()); + if (lsi != Symbols.end()) { + Value.SectionID = lsi->second.first; + Value.Addend = lsi->second.second; + } else { + // Second look the symbol in global symbol table. + StringMap<SymbolLoc>::iterator gsi = SymbolTable.find(TargetName.data()); + if (gsi != SymbolTable.end()) { + Value.SectionID = gsi->second.first; + Value.Addend = gsi->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 si = Obj.end_sections(); + Symbol.getSection(si); + if (si == Obj.end_sections()) + llvm_unreachable("Symbol section not found, bad object file format!"); + DEBUG(dbgs() << "\t\tThis is section symbol\n"); + Value.SectionID = findOrEmitSection((*si), 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; + } + } } -} - -// 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); + 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 i = Stubs.find(Value); + if (i != Stubs.end()) { + resolveRelocation(Target, Section.LoadAddress, (uint64_t)Section.Address + + i->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); } bool RuntimeDyldELF::isCompatibleFormat(const MemoryBuffer *InputBuffer) const { |