//===-- RuntimeDyldELF.cpp - Run-time dynamic linker for MC-JIT -*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // Implementation of ELF support for the MC-JIT runtime dynamic linker. // //===----------------------------------------------------------------------===// #define DEBUG_TYPE "dyld" #include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/IntervalMap.h" #include "RuntimeDyldELF.h" #include "llvm/Object/ObjectFile.h" #include "llvm/Support/ELF.h" #include "llvm/ADT/Triple.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); 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(SectionContents.data()) + AddrInSection; } } bool RuntimeDyldELF::loadObject(MemoryBuffer *InputBuffer) { if (!isCompatibleFormat(InputBuffer)) return true; 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; } } // 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::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::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()); } } 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 assert(0 && ("Non-function relocation not implemented yet!")); } switch (RE.Type) { default: assert(0 && ("Relocation type not implemented yet!")); break; case ELF::R_X86_64_64: { uint8_t **Target = reinterpret_cast(TargetAddr); *Target = Addr + RE.Addend; break; } case ELF::R_X86_64_32: case ELF::R_X86_64_32S: { uint64_t Value = reinterpret_cast(Addr) + RE.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 && (Value & 0xFFFFFFFF00000000ULL) == 0xFFFFFFFF00000000ULL)); uint32_t TruncatedAddr = (Value & 0xFFFFFFFF); uint32_t *Target = reinterpret_cast(TargetAddr); *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); *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 assert(0 && ("Non-function relocation not implemented yet!")); } switch (RE.Type) { case ELF::R_386_32: { uint8_t **Target = reinterpret_cast(TargetAddr); *Target = Addr + RE.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); *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!")); break; } } void RuntimeDyldELF::resolveArmRelocation(StringRef Name, uint8_t *Addr, const RelocationEntry &RE) { } void RuntimeDyldELF::resolveRelocation(StringRef Name, uint8_t *Addr, const RelocationEntry &RE) { switch (Arch) { case Triple::x86_64: resolveX86_64Relocation(Name, Addr, RE); break; case Triple::x86: resolveX86Relocation(Name, Addr, RE); break; case Triple::arm: resolveArmRelocation(Name, Addr, RE); break; default: assert(0 && "Unsupported CPU type!"); break; } } 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); } } // 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); } bool RuntimeDyldELF::isCompatibleFormat(const MemoryBuffer *InputBuffer) const { StringRef Magic = InputBuffer->getBuffer().slice(0, ELF::EI_NIDENT); return (memcmp(Magic.data(), ELF::ElfMagic, strlen(ELF::ElfMagic))) == 0; } } // namespace llvm