summaryrefslogtreecommitdiff
path: root/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp
diff options
context:
space:
mode:
authorEli Bendersky <eli.bendersky@intel.com>2012-01-16 08:56:09 +0000
committerEli Bendersky <eli.bendersky@intel.com>2012-01-16 08:56:09 +0000
commita66a18505e07a4e72d6fa7e85663937a257577f3 (patch)
tree1c14e0bc22014ae756f795ee8c9a3108bbcb8df1 /lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp
parent810d6d3354a31f24125abef831e4afccbbbe973d (diff)
downloadllvm-a66a18505e07a4e72d6fa7e85663937a257577f3.tar.gz
llvm-a66a18505e07a4e72d6fa7e85663937a257577f3.tar.bz2
llvm-a66a18505e07a4e72d6fa7e85663937a257577f3.tar.xz
Adding a basic ELF dynamic loader and MC-JIT for ELF. Functionality is currently basic and will be enhanced with future patches.
Patch developed by Andy Kaylor and Daniel Malea. Reviewed on llvm-commits. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@148231 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp')
-rw-r--r--lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp282
1 files changed, 282 insertions, 0 deletions
diff --git a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp
new file mode 100644
index 0000000000..9ff95ff8b6
--- /dev/null
+++ b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp
@@ -0,0 +1,282 @@
+//===-- 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 "RuntimeDyldImpl.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<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::resolveX86_64Relocation(StringRef Name,
+ uint8_t *Addr,
+ const RelocationEntry &RE) {
+ uint8_t *TargetAddr;
+ if (RE.IsFunctionRelative) {
+ StringMap<sys::MemoryBlock>::iterator ContainingFunc
+ = Functions.find(RE.Target);
+ assert(ContainingFunc != Functions.end()
+ && "Function for relocation not found");
+ TargetAddr = reinterpret_cast<uint8_t*>(ContainingFunc->getValue().base()) +
+ 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<uint8_t**>(TargetAddr);
+ *Target = Addr + RE.Addend;
+ break;
+ }
+ case ELF::R_X86_64_32:
+ case ELF::R_X86_64_32S: {
+ uint64_t Value = reinterpret_cast<uint64_t>(Addr) + RE.Addend;
+ // FIXME: Handle the possibility of this assertion failing
+ assert((RE.Type == ELF::R_X86_64_32 && !(Value & 0xFFFFFFFF00000000)) ||
+ (RE.Type == ELF::R_X86_64_32S &&
+ (Value & 0xFFFFFFFF00000000) == 0xFFFFFFFF00000000));
+ uint32_t TruncatedAddr = (Value & 0xFFFFFFFF);
+ uint32_t *Target = reinterpret_cast<uint32_t*>(TargetAddr);
+ *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);
+ *Placeholder = TruncOffset;
+ break;
+ }
+ }
+}
+
+void RuntimeDyldELF::resolveX86Relocation(StringRef Name,
+ uint8_t *Addr,
+ const RelocationEntry &RE) {
+ uint8_t *TargetAddr;
+ if (RE.IsFunctionRelative) {
+ StringMap<sys::MemoryBlock>::iterator ContainingFunc
+ = Functions.find(RE.Target);
+ assert(ContainingFunc != Functions.end()
+ && "Function for relocation not found");
+ TargetAddr = reinterpret_cast<uint8_t*>(
+ ContainingFunc->getValue().base()) + 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<uint8_t**>(TargetAddr);
+ *Target = Addr + RE.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);
+ *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) {
+ SymbolTable[Name] = Addr;
+
+ RelocationList &Relocs = Relocations[Name];
+ for (unsigned i = 0, e = Relocs.size(); i != e; ++i) {
+ RelocationEntry &RE = Relocs[i];
+ resolveRelocation(Name, Addr, RE);
+ }
+}
+
+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