Skip to content

Commit

Permalink
Adding a basic ELF dynamic loader and MC-JIT for ELF. Functionality i…
Browse files Browse the repository at this point in the history
…s 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
  • Loading branch information
Eli Bendersky committed Jan 16, 2012
1 parent 810d6d3 commit a66a185
Show file tree
Hide file tree
Showing 46 changed files with 463 additions and 64 deletions.
1 change: 1 addition & 0 deletions lib/ExecutionEngine/RuntimeDyld/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
add_llvm_library(LLVMRuntimeDyld
RuntimeDyld.cpp
RuntimeDyldMachO.cpp
RuntimeDyldELF.cpp
)
35 changes: 30 additions & 5 deletions lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

#define DEBUG_TYPE "dyld"
#include "RuntimeDyldImpl.h"
#include "llvm/Support/Path.h"
using namespace llvm;
using namespace llvm::object;

Expand Down Expand Up @@ -64,12 +65,36 @@ RuntimeDyld::~RuntimeDyld() {

bool RuntimeDyld::loadObject(MemoryBuffer *InputBuffer) {
if (!Dyld) {
if (RuntimeDyldMachO::isKnownFormat(InputBuffer))
Dyld = new RuntimeDyldMachO(MM);
else
report_fatal_error("Unknown object format!");
sys::LLVMFileType type = sys::IdentifyFileType(
InputBuffer->getBufferStart(),
static_cast<unsigned>(InputBuffer->getBufferSize()));
switch (type) {
case sys::ELF_Relocatable_FileType:
case sys::ELF_Executable_FileType:
case sys::ELF_SharedObject_FileType:
case sys::ELF_Core_FileType:
Dyld = new RuntimeDyldELF(MM);
break;
case sys::Mach_O_Object_FileType:
case sys::Mach_O_Executable_FileType:
case sys::Mach_O_FixedVirtualMemorySharedLib_FileType:
case sys::Mach_O_Core_FileType:
case sys::Mach_O_PreloadExecutable_FileType:
case sys::Mach_O_DynamicallyLinkedSharedLib_FileType:
case sys::Mach_O_DynamicLinker_FileType:
case sys::Mach_O_Bundle_FileType:
case sys::Mach_O_DynamicallyLinkedSharedLibStub_FileType:
case sys::Mach_O_DSYMCompanion_FileType:
Dyld = new RuntimeDyldMachO(MM);
break;
case sys::Unknown_FileType:
case sys::Bitcode_FileType:
case sys::Archive_FileType:
case sys::COFF_FileType:
report_fatal_error("Incompatible object format!");
}
} else {
if(!Dyld->isCompatibleFormat(InputBuffer))
if (!Dyld->isCompatibleFormat(InputBuffer))
report_fatal_error("Incompatible object format!");
}

Expand Down
282 changes: 282 additions & 0 deletions lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp
Original file line number Diff line number Diff line change
@@ -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
Loading

0 comments on commit a66a185

Please sign in to comment.