forked from llvm-mirror/llvm
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Adding a basic ELF dynamic loader and MC-JIT for ELF. Functionality i…
…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
Showing
46 changed files
with
463 additions
and
64 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,5 @@ | ||
add_llvm_library(LLVMRuntimeDyld | ||
RuntimeDyld.cpp | ||
RuntimeDyldMachO.cpp | ||
RuntimeDyldELF.cpp | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
Oops, something went wrong.