X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=lib%2FExecutionEngine%2FRuntimeDyld%2FRuntimeDyldELF.cpp;h=e2ebc342adbbbd715a6c5abe621135f459bcfd3c;hb=689ff9c00f4f3dcf3491778bcdbda79e19e2285d;hp=c0845fbbb205401c415c299931278098038c6098;hpb=408a25c583f3d3e7e9b6ef90a56ce435022591df;p=oota-llvm.git diff --git a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp index c0845fbbb20..e2ebc342adb 100644 --- a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp +++ b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp @@ -20,290 +20,404 @@ #include "llvm/Object/ObjectFile.h" #include "llvm/Support/ELF.h" #include "llvm/ADT/Triple.h" +#include "llvm/Object/ELF.h" +#include "JITRegistrar.h" using namespace llvm; 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); +template +class DyldELFObject : public ELFObjectFile { + LLVM_ELF_IMPORT_TYPES(target_endianness, is64Bits) - uint64_t AddrInSection; - Err = Sym->getAddress(AddrInSection); + typedef Elf_Shdr_Impl Elf_Shdr; + typedef Elf_Sym_Impl Elf_Sym; + typedef Elf_Rel_Impl Elf_Rel; + typedef Elf_Rel_Impl Elf_Rela; - SectionRef empty_section; - section_iterator Section(empty_section); - Err = Sym->getSection(Section); + typedef typename ELFObjectFile:: + Elf_Ehdr Elf_Ehdr; - StringRef SectionContents; - Section->getContents(SectionContents); + typedef typename ELFDataTypeTypedefHelper< + target_endianness, is64Bits>::value_type addr_type; - Addr = reinterpret_cast(SectionContents.data()) + AddrInSection; -} +protected: + // This duplicates the 'Data' member in the 'Binary' base class + // but it is necessary to workaround a bug in gcc 4.2 + MemoryBuffer *InputData; -} +public: + DyldELFObject(MemoryBuffer *Object, error_code &ec); + + void updateSectionAddress(const SectionRef &Sec, uint64_t Addr); + void updateSymbolAddress(const SymbolRef &Sym, uint64_t Addr); + + const MemoryBuffer& getBuffer() const { return *InputData; } -bool RuntimeDyldELF::loadObject(MemoryBuffer *InputBuffer) { - if (!isCompatibleFormat(InputBuffer)) + // Methods for type inquiry through isa, cast, and dyn_cast + static inline bool classof(const Binary *v) { + return (isa >(v) + && classof(cast >(v))); + } + static inline bool classof( + const ELFObjectFile *v) { + return v->isDyldType(); + } + static inline bool classof(const DyldELFObject *v) { return true; + } +}; + +template +class ELFObjectImage : public ObjectImage { + protected: + DyldELFObject *DyldObj; + bool Registered; + + public: + ELFObjectImage(DyldELFObject *Obj) + : ObjectImage(Obj), + DyldObj(Obj), + Registered(false) {} + + virtual ~ELFObjectImage() { + if (Registered) + deregisterWithDebugger(); + } - OwningPtr Obj(ObjectFile::createELFObjectFile(InputBuffer)); - - Arch = Obj->getArch(); - - // Map address in the Object file image to function names - IntervalMap::Allocator A; - IntervalMap 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 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(Addr); - End = reinterpret_cast(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; + // Subclasses can override these methods to update the image with loaded + // addresses for sections and common symbols + virtual void updateSectionAddress(const SectionRef &Sec, uint64_t Addr) + { + DyldObj->updateSectionAddress(Sec, 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; + virtual void updateSymbolAddress(const SymbolRef &Sym, uint64_t Addr) + { + DyldObj->updateSymbolAddress(Sym, Addr); } - 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::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)); - } + + virtual void registerWithDebugger() + { + JITRegistrar::getGDBRegistrar().registerObject(DyldObj->getBuffer()); + Registered = true; } - } - return false; + virtual void deregisterWithDebugger() + { + JITRegistrar::getGDBRegistrar().deregisterObject(DyldObj->getBuffer()); + } +}; + +template +DyldELFObject::DyldELFObject(MemoryBuffer *Object, + error_code &ec) + : ELFObjectFile(Object, ec), + InputData(Object) { + this->isDyldELFObject = true; } -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::iterator i = SymbolTable.begin(); - StringMap::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()); - } +template +void DyldELFObject::updateSectionAddress( + const SectionRef &Sec, + uint64_t Addr) { + DataRefImpl ShdrRef = Sec.getRawDataRefImpl(); + Elf_Shdr *shdr = const_cast( + reinterpret_cast(ShdrRef.p)); + + // This assumes the address passed in matches the target address bitness + // The template-based type cast handles everything else. + shdr->sh_addr = static_cast(Addr); } -void RuntimeDyldELF::resolveX86_64Relocation(StringRef Name, - uint8_t *Addr, - const RelocationEntry &RE) { - uint8_t *TargetAddr; - if (RE.IsFunctionRelative) { - StringMap::const_iterator Loc = SymbolTable.find(RE.Target); - assert(Loc != SymbolTable.end() && "Function for relocation not found"); - TargetAddr = - reinterpret_cast(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!"); +template +void DyldELFObject::updateSymbolAddress( + const SymbolRef &SymRef, + uint64_t Addr) { + + Elf_Sym *sym = const_cast( + ELFObjectFile:: + getSymbol(SymRef.getRawDataRefImpl())); + + // This assumes the address passed in matches the target address bitness + // The template-based type cast handles everything else. + sym->st_value = static_cast(Addr); +} + +} // namespace + + +namespace llvm { + +ObjectImage *RuntimeDyldELF::createObjectImage( + const MemoryBuffer *ConstInputBuffer) { + MemoryBuffer *InputBuffer = const_cast(ConstInputBuffer); + std::pair Ident = getElfArchType(InputBuffer); + error_code ec; + + if (Ident.first == ELF::ELFCLASS32 && Ident.second == ELF::ELFDATA2LSB) { + DyldELFObject *Obj = + new DyldELFObject(InputBuffer, ec); + return new ELFObjectImage(Obj); + } + else if (Ident.first == ELF::ELFCLASS32 && Ident.second == ELF::ELFDATA2MSB) { + DyldELFObject *Obj = + new DyldELFObject(InputBuffer, ec); + return new ELFObjectImage(Obj); } + else if (Ident.first == ELF::ELFCLASS64 && Ident.second == ELF::ELFDATA2MSB) { + DyldELFObject *Obj = + new DyldELFObject(InputBuffer, ec); + return new ELFObjectImage(Obj); + } + else if (Ident.first == ELF::ELFCLASS64 && Ident.second == ELF::ELFDATA2LSB) { + DyldELFObject *Obj = + new DyldELFObject(InputBuffer, ec); + return new ELFObjectImage(Obj); + } + else + llvm_unreachable("Unexpected ELF format"); +} + +void RuntimeDyldELF::handleObjectLoaded(ObjectImage *Obj) +{ + Obj->registerWithDebugger(); + // Save the loaded object. It will deregister itself when deleted + LoadedObject = Obj; +} + +RuntimeDyldELF::~RuntimeDyldELF() { + if (LoadedObject) + delete LoadedObject; +} - switch (RE.Type) { +void RuntimeDyldELF::resolveX86_64Relocation(uint8_t *LocalAddress, + uint64_t FinalAddress, + uint64_t Value, + uint32_t Type, + int64_t Addend) { + switch (Type) { default: - assert(0 && ("Relocation type not implemented yet!")); + llvm_unreachable("Relocation type not implemented yet!"); break; case ELF::R_X86_64_64: { - uint8_t **Target = reinterpret_cast(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(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(TargetAddr); + uint32_t *Target = reinterpret_cast(LocalAddress); *Target = TruncatedAddr; break; } case ELF::R_X86_64_PC32: { - uint32_t *Placeholder = reinterpret_cast(TargetAddr); - uint64_t RealOffset = *Placeholder + - reinterpret_cast(Addr) + - RE.Addend - reinterpret_cast(TargetAddr); - assert((RealOffset & 0xFFFFFFFF) == RealOffset); - uint32_t TruncOffset = (RealOffset & 0xFFFFFFFF); + uint32_t *Placeholder = reinterpret_cast(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::const_iterator Loc = SymbolTable.find(RE.Target); - assert(Loc != SymbolTable.end() && "Function for relocation not found"); - TargetAddr = - reinterpret_cast(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(TargetAddr); - *Target = Addr + RE.Addend; + uint32_t *Target = (uint32_t*)(LocalAddress); + uint32_t Placeholder = *Target; + *Target = Placeholder + Value + Addend; break; } case ELF::R_386_PC32: { - uint32_t *Placeholder = reinterpret_cast(TargetAddr); - uint32_t RealOffset = *Placeholder + reinterpret_cast(Addr) + - RE.Addend - reinterpret_cast(TargetAddr); + uint32_t *Placeholder = reinterpret_cast(LocalAddress); + uint32_t RealOffset = *Placeholder + Value + Addend - FinalAddress; *Placeholder = RealOffset; break; } default: // There are other relocation types, but it appears these are the // only ones currently used by the LLVM ELF object writer - assert(0 && ("Relocation type not implemented yet!")); + 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(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); - break; - case Triple::arm: - resolveArmRelocation(Name, Addr, RE); + resolveX86Relocation(LocalAddress, (uint32_t)(FinalAddress & 0xffffffffL), + (uint32_t)(Value & 0xffffffffL), Type, + (uint32_t)(Addend & 0xffffffffL)); break; - default: - assert(0 && "Unsupported CPU type!"); + 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, + ObjectImage &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::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(Obj, (*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 {