diff options
Diffstat (limited to 'contrib/llvm/lib/ExecutionEngine/RuntimeDyld')
-rw-r--r-- | contrib/llvm/lib/ExecutionEngine/RuntimeDyld/GDBRegistrar.cpp | 8 | ||||
-rw-r--r-- | contrib/llvm/lib/ExecutionEngine/RuntimeDyld/JITRegistrar.h | 6 | ||||
-rw-r--r-- | contrib/llvm/lib/ExecutionEngine/RuntimeDyld/ObjectImageCommon.h (renamed from contrib/llvm/lib/ExecutionEngine/RuntimeDyld/ObjectImage.h) | 135 | ||||
-rw-r--r-- | contrib/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp | 145 | ||||
-rw-r--r-- | contrib/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp | 555 | ||||
-rw-r--r-- | contrib/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h | 56 | ||||
-rw-r--r-- | contrib/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h | 96 | ||||
-rw-r--r-- | contrib/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.cpp | 28 | ||||
-rw-r--r-- | contrib/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.h | 6 |
9 files changed, 789 insertions, 246 deletions
diff --git a/contrib/llvm/lib/ExecutionEngine/RuntimeDyld/GDBRegistrar.cpp b/contrib/llvm/lib/ExecutionEngine/RuntimeDyld/GDBRegistrar.cpp index 8b50101..50cd072 100644 --- a/contrib/llvm/lib/ExecutionEngine/RuntimeDyld/GDBRegistrar.cpp +++ b/contrib/llvm/lib/ExecutionEngine/RuntimeDyld/GDBRegistrar.cpp @@ -78,12 +78,12 @@ public: /// Creates an entry in the JIT registry for the buffer @p Object, /// which must contain an object file in executable memory with any /// debug information for the debugger. - void registerObject(const MemoryBuffer &Object); + void registerObject(const ObjectBuffer &Object); /// Removes the internal registration of @p Object, and /// frees associated resources. /// Returns true if @p Object was found in ObjectBufferMap. - bool deregisterObject(const MemoryBuffer &Object); + bool deregisterObject(const ObjectBuffer &Object); private: /// Deregister the debug info for the given object file from the debugger @@ -124,7 +124,7 @@ GDBJITRegistrar::~GDBJITRegistrar() { ObjectBufferMap.clear(); } -void GDBJITRegistrar::registerObject(const MemoryBuffer &Object) { +void GDBJITRegistrar::registerObject(const ObjectBuffer &Object) { const char *Buffer = Object.getBufferStart(); size_t Size = Object.getBufferSize(); @@ -147,7 +147,7 @@ void GDBJITRegistrar::registerObject(const MemoryBuffer &Object) { } } -bool GDBJITRegistrar::deregisterObject(const MemoryBuffer& Object) { +bool GDBJITRegistrar::deregisterObject(const ObjectBuffer& Object) { const char *Buffer = Object.getBufferStart(); RegisteredObjectBufferMap::iterator I = ObjectBufferMap.find(Buffer); diff --git a/contrib/llvm/lib/ExecutionEngine/RuntimeDyld/JITRegistrar.h b/contrib/llvm/lib/ExecutionEngine/RuntimeDyld/JITRegistrar.h index f964bc6..69e9dbe 100644 --- a/contrib/llvm/lib/ExecutionEngine/RuntimeDyld/JITRegistrar.h +++ b/contrib/llvm/lib/ExecutionEngine/RuntimeDyld/JITRegistrar.h @@ -10,7 +10,7 @@ #ifndef LLVM_EXECUTION_ENGINE_JIT_REGISTRAR_H #define LLVM_EXECUTION_ENGINE_JIT_REGISTRAR_H -#include "llvm/Support/MemoryBuffer.h" +#include "llvm/ExecutionEngine/ObjectBuffer.h" namespace llvm { @@ -27,12 +27,12 @@ public: /// Creates an entry in the JIT registry for the buffer @p Object, /// which must contain an object file in executable memory with any /// debug information for the debugger. - virtual void registerObject(const MemoryBuffer &Object) = 0; + virtual void registerObject(const ObjectBuffer &Object) = 0; /// Removes the internal registration of @p Object, and /// frees associated resources. /// Returns true if @p Object was previously registered. - virtual bool deregisterObject(const MemoryBuffer &Object) = 0; + virtual bool deregisterObject(const ObjectBuffer &Object) = 0; /// Returns a reference to a GDB JIT registrar singleton static JITRegistrar& getGDBRegistrar(); diff --git a/contrib/llvm/lib/ExecutionEngine/RuntimeDyld/ObjectImage.h b/contrib/llvm/lib/ExecutionEngine/RuntimeDyld/ObjectImageCommon.h index c3e3572..17f3a21 100644 --- a/contrib/llvm/lib/ExecutionEngine/RuntimeDyld/ObjectImage.h +++ b/contrib/llvm/lib/ExecutionEngine/RuntimeDyld/ObjectImageCommon.h @@ -1,59 +1,76 @@ -//===---- ObjectImage.h - Format independent executuable object image -----===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file declares a file format independent ObjectImage class. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_RUNTIMEDYLD_OBJECT_IMAGE_H -#define LLVM_RUNTIMEDYLD_OBJECT_IMAGE_H - -#include "llvm/Object/ObjectFile.h" - -namespace llvm { - -class ObjectImage { - ObjectImage(); // = delete - ObjectImage(const ObjectImage &other); // = delete -protected: - object::ObjectFile *ObjFile; - -public: - ObjectImage(object::ObjectFile *Obj) { ObjFile = Obj; } - virtual ~ObjectImage() {} - - virtual object::symbol_iterator begin_symbols() const - { return ObjFile->begin_symbols(); } - virtual object::symbol_iterator end_symbols() const - { return ObjFile->end_symbols(); } - - virtual object::section_iterator begin_sections() const - { return ObjFile->begin_sections(); } - virtual object::section_iterator end_sections() const - { return ObjFile->end_sections(); } - - virtual /* Triple::ArchType */ unsigned getArch() const - { return ObjFile->getArch(); } - - // Subclasses can override these methods to update the image with loaded - // addresses for sections and common symbols - virtual void updateSectionAddress(const object::SectionRef &Sec, - uint64_t Addr) {} - virtual void updateSymbolAddress(const object::SymbolRef &Sym, uint64_t Addr) - {} - - // Subclasses can override these methods to provide JIT debugging support - virtual void registerWithDebugger() {} - virtual void deregisterWithDebugger() {} -}; - -} // end namespace llvm - -#endif // LLVM_RUNTIMEDYLD_OBJECT_IMAGE_H - +//===-- ObjectImageCommon.h - Format independent executuable object image -===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file declares a file format independent ObjectImage class.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_RUNTIMEDYLD_OBJECTIMAGECOMMON_H
+#define LLVM_RUNTIMEDYLD_OBJECTIMAGECOMMON_H
+
+#include "llvm/Object/ObjectFile.h"
+#include "llvm/ExecutionEngine/ObjectImage.h"
+#include "llvm/ExecutionEngine/ObjectBuffer.h"
+
+namespace llvm {
+
+class ObjectImageCommon : public ObjectImage {
+ ObjectImageCommon(); // = delete
+ ObjectImageCommon(const ObjectImageCommon &other); // = delete
+
+protected:
+ object::ObjectFile *ObjFile;
+
+ // This form of the constructor allows subclasses to use
+ // format-specific subclasses of ObjectFile directly
+ ObjectImageCommon(ObjectBuffer *Input, object::ObjectFile *Obj)
+ : ObjectImage(Input), // saves Input as Buffer and takes ownership
+ ObjFile(Obj)
+ {
+ }
+
+public:
+ ObjectImageCommon(ObjectBuffer* Input)
+ : ObjectImage(Input) // saves Input as Buffer and takes ownership
+ {
+ ObjFile = object::ObjectFile::createObjectFile(Buffer->getMemBuffer());
+ }
+ virtual ~ObjectImageCommon() { delete ObjFile; }
+
+ virtual object::symbol_iterator begin_symbols() const
+ { return ObjFile->begin_symbols(); }
+ virtual object::symbol_iterator end_symbols() const
+ { return ObjFile->end_symbols(); }
+
+ virtual object::section_iterator begin_sections() const
+ { return ObjFile->begin_sections(); }
+ virtual object::section_iterator end_sections() const
+ { return ObjFile->end_sections(); }
+
+ virtual /* Triple::ArchType */ unsigned getArch() const
+ { return ObjFile->getArch(); }
+
+ virtual StringRef getData() const { return ObjFile->getData(); }
+
+ // Subclasses can override these methods to update the image with loaded
+ // addresses for sections and common symbols
+ virtual void updateSectionAddress(const object::SectionRef &Sec,
+ uint64_t Addr) {}
+ virtual void updateSymbolAddress(const object::SymbolRef &Sym, uint64_t Addr)
+ {}
+
+ // Subclasses can override these methods to provide JIT debugging support
+ virtual void registerWithDebugger() {}
+ virtual void deregisterWithDebugger() {}
+};
+
+} // end namespace llvm
+
+#endif // LLVM_RUNTIMEDYLD_OBJECT_IMAGE_H
+
diff --git a/contrib/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp b/contrib/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp index b464040..f6dccb1 100644 --- a/contrib/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp +++ b/contrib/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp @@ -12,10 +12,12 @@ //===----------------------------------------------------------------------===// #define DEBUG_TYPE "dyld" +#include "ObjectImageCommon.h" #include "RuntimeDyldImpl.h" #include "RuntimeDyldELF.h" #include "RuntimeDyldMachO.h" #include "llvm/Support/Path.h" +#include "llvm/Support/MathExtras.h" using namespace llvm; using namespace llvm::object; @@ -26,16 +28,6 @@ RuntimeDyldImpl::~RuntimeDyldImpl() {} namespace llvm { -namespace { - // Helper for extensive error checking in debug builds. - error_code Check(error_code Err) { - if (Err) { - report_fatal_error(Err.message()); - } - return Err; - } -} // end anonymous namespace - // Resolve the relocations for all symbols we currently know about. void RuntimeDyldImpl::resolveRelocations() { // First, resolve relocations associated with external symbols. @@ -44,11 +36,15 @@ void RuntimeDyldImpl::resolveRelocations() { // Just iterate over the sections we have and resolve all the relocations // in them. Gross overkill, but it gets the job done. for (int i = 0, e = Sections.size(); i != e; ++i) { - reassignSectionAddress(i, Sections[i].LoadAddress); + uint64_t Addr = Sections[i].LoadAddress; + DEBUG(dbgs() << "Resolving relocations Section #" << i + << "\t" << format("%p", (uint8_t *)Addr) + << "\n"); + resolveRelocationList(Relocations[i], Addr); } } -void RuntimeDyldImpl::mapSectionAddress(void *LocalAddress, +void RuntimeDyldImpl::mapSectionAddress(const void *LocalAddress, uint64_t TargetAddress) { for (unsigned i = 0, e = Sections.size(); i != e; ++i) { if (Sections[i].Address == LocalAddress) { @@ -61,14 +57,11 @@ void RuntimeDyldImpl::mapSectionAddress(void *LocalAddress, // Subclasses can implement this method to create specialized image instances. // The caller owns the pointer that is returned. -ObjectImage *RuntimeDyldImpl::createObjectImage(const MemoryBuffer *InputBuffer) { - ObjectFile *ObjFile = ObjectFile::createObjectFile(const_cast<MemoryBuffer*> - (InputBuffer)); - ObjectImage *Obj = new ObjectImage(ObjFile); - return Obj; +ObjectImage *RuntimeDyldImpl::createObjectImage(ObjectBuffer *InputBuffer) { + return new ObjectImageCommon(InputBuffer); } -bool RuntimeDyldImpl::loadObject(const MemoryBuffer *InputBuffer) { +ObjectImage *RuntimeDyldImpl::loadObject(ObjectBuffer *InputBuffer) { OwningPtr<ObjectImage> obj(createObjectImage(InputBuffer)); if (!obj) report_fatal_error("Unable to create object image from memory buffer!"); @@ -80,9 +73,9 @@ bool RuntimeDyldImpl::loadObject(const MemoryBuffer *InputBuffer) { // Used sections from the object file ObjSectionToIDMap LocalSections; - // Common symbols requiring allocation, and the total size required to - // allocate all common symbols. + // Common symbols requiring allocation, with their sizes and alignments CommonSymbolMap CommonSymbols; + // Maximum required total memory to allocate all common symbols uint64_t CommonSize = 0; error_code err; @@ -102,13 +95,15 @@ bool RuntimeDyldImpl::loadObject(const MemoryBuffer *InputBuffer) { bool isCommon = flags & SymbolRef::SF_Common; if (isCommon) { // Add the common symbols to a list. We'll allocate them all below. + uint64_t Align = getCommonSymbolAlignment(*i); uint64_t Size = 0; Check(i->getSize(Size)); - CommonSize += Size; - CommonSymbols[*i] = Size; + CommonSize += Size + Align; + CommonSymbols[*i] = CommonSymbolInfo(Size, Align); } else { if (SymType == object::SymbolRef::ST_Function || - SymType == object::SymbolRef::ST_Data) { + SymType == object::SymbolRef::ST_Data || + SymType == object::SymbolRef::ST_Unknown) { uint64_t FileOffset; StringRef SectionData; section_iterator si = obj->end_sections(); @@ -177,9 +172,7 @@ bool RuntimeDyldImpl::loadObject(const MemoryBuffer *InputBuffer) { } } - handleObjectLoaded(obj.take()); - - return false; + return obj.take(); } void RuntimeDyldImpl::emitCommonSymbols(ObjectImage &Obj, @@ -193,7 +186,7 @@ void RuntimeDyldImpl::emitCommonSymbols(ObjectImage &Obj, if (!Addr) report_fatal_error("Unable to allocate memory for common symbols!"); uint64_t Offset = 0; - Sections.push_back(SectionEntry(Addr, TotalSize, TotalSize, 0)); + Sections.push_back(SectionEntry(StringRef(), Addr, TotalSize, TotalSize, 0)); memset(Addr, 0, TotalSize); DEBUG(dbgs() << "emitCommonSection SectionID: " << SectionID @@ -204,11 +197,20 @@ void RuntimeDyldImpl::emitCommonSymbols(ObjectImage &Obj, // Assign the address of each symbol for (CommonSymbolMap::const_iterator it = CommonSymbols.begin(), itEnd = CommonSymbols.end(); it != itEnd; it++) { + uint64_t Size = it->second.first; + uint64_t Align = it->second.second; StringRef Name; it->first.getName(Name); + if (Align) { + // This symbol has an alignment requirement. + uint64_t AlignOffset = OffsetToAlignment((uint64_t)Addr, Align); + Addr += AlignOffset; + Offset += AlignOffset; + DEBUG(dbgs() << "Allocating common symbol " << Name << " address " << + format("%p\n", Addr)); + } Obj.updateSymbolAddress(it->first, (uint64_t)Addr); SymbolTable[Name.data()] = SymbolLoc(SectionID, Offset); - uint64_t Size = it->second; Offset += Size; Addr += Size; } @@ -236,10 +238,12 @@ unsigned RuntimeDyldImpl::emitSection(ObjectImage &Obj, bool IsVirtual; bool IsZeroInit; uint64_t DataSize; + StringRef Name; Check(Section.isRequiredForExecution(IsRequired)); Check(Section.isVirtual(IsVirtual)); Check(Section.isZeroInit(IsZeroInit)); Check(Section.getSize(DataSize)); + Check(Section.getName(Name)); unsigned Allocate; unsigned SectionID = Sections.size(); @@ -267,6 +271,7 @@ unsigned RuntimeDyldImpl::emitSection(ObjectImage &Obj, memcpy(Addr, pData, DataSize); DEBUG(dbgs() << "emitSection SectionID: " << SectionID + << " Name: " << Name << " obj addr: " << format("%p", pData) << " new addr: " << format("%p", Addr) << " DataSize: " << DataSize @@ -282,6 +287,7 @@ unsigned RuntimeDyldImpl::emitSection(ObjectImage &Obj, Allocate = 0; Addr = 0; DEBUG(dbgs() << "emitSection SectionID: " << SectionID + << " Name: " << Name << " obj addr: " << format("%p", data.data()) << " new addr: 0" << " DataSize: " << DataSize @@ -290,7 +296,8 @@ unsigned RuntimeDyldImpl::emitSection(ObjectImage &Obj, << "\n"); } - Sections.push_back(SectionEntry(Addr, Allocate, DataSize,(uintptr_t)pData)); + Sections.push_back(SectionEntry(Name, Addr, Allocate, DataSize, + (uintptr_t)pData)); return SectionID; } @@ -333,15 +340,49 @@ void RuntimeDyldImpl::addRelocationForSymbol(const RelocationEntry &RE, } uint8_t *RuntimeDyldImpl::createStubFunction(uint8_t *Addr) { - // TODO: There is only ARM far stub now. We should add the Thumb stub, - // and stubs for branches Thumb - ARM and ARM - Thumb. if (Arch == Triple::arm) { + // TODO: There is only ARM far stub now. We should add the Thumb stub, + // and stubs for branches Thumb - ARM and ARM - Thumb. uint32_t *StubAddr = (uint32_t*)Addr; *StubAddr = 0xe51ff004; // ldr pc,<label> return (uint8_t*)++StubAddr; - } - else + } else if (Arch == Triple::mipsel) { + uint32_t *StubAddr = (uint32_t*)Addr; + // 0: 3c190000 lui t9,%hi(addr). + // 4: 27390000 addiu t9,t9,%lo(addr). + // 8: 03200008 jr t9. + // c: 00000000 nop. + const unsigned LuiT9Instr = 0x3c190000, AdduiT9Instr = 0x27390000; + const unsigned JrT9Instr = 0x03200008, NopInstr = 0x0; + + *StubAddr = LuiT9Instr; + StubAddr++; + *StubAddr = AdduiT9Instr; + StubAddr++; + *StubAddr = JrT9Instr; + StubAddr++; + *StubAddr = NopInstr; return Addr; + } else if (Arch == Triple::ppc64) { + // PowerPC64 stub: the address points to a function descriptor + // instead of the function itself. Load the function address + // on r11 and sets it to control register. Also loads the function + // TOC in r2 and environment pointer to r11. + writeInt32BE(Addr, 0x3D800000); // lis r12, highest(addr) + writeInt32BE(Addr+4, 0x618C0000); // ori r12, higher(addr) + writeInt32BE(Addr+8, 0x798C07C6); // sldi r12, r12, 32 + writeInt32BE(Addr+12, 0x658C0000); // oris r12, r12, h(addr) + writeInt32BE(Addr+16, 0x618C0000); // ori r12, r12, l(addr) + writeInt32BE(Addr+20, 0xF8410028); // std r2, 40(r1) + writeInt32BE(Addr+24, 0xE96C0000); // ld r11, 0(r12) + writeInt32BE(Addr+28, 0xE84C0008); // ld r2, 0(r12) + writeInt32BE(Addr+32, 0x7D6903A6); // mtctr r11 + writeInt32BE(Addr+36, 0xE96C0010); // ld r11, 16(r2) + writeInt32BE(Addr+40, 0x4E800420); // bctr + + return Addr; + } + return Addr; } // Assign an address to a symbol name and resolve all the relocations @@ -350,32 +391,30 @@ void RuntimeDyldImpl::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. + // a remote execution environment of some sort. Relocations can't + // be applied until all the sections have been moved. The client must + // trigger this with a call to MCJIT::finalize() or + // RuntimeDyld::resolveRelocations(). // // 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. Sections[SectionID].LoadAddress = Addr; - DEBUG(dbgs() << "Resolving relocations Section #" << SectionID - << "\t" << format("%p", (uint8_t *)Addr) - << "\n"); - resolveRelocationList(Relocations[SectionID], Addr); } void RuntimeDyldImpl::resolveRelocationEntry(const RelocationEntry &RE, uint64_t Value) { - // Ignore relocations for sections that were not loaded - if (Sections[RE.SectionID].Address != 0) { - uint8_t *Target = Sections[RE.SectionID].Address + RE.Offset; - DEBUG(dbgs() << "\tSectionID: " << RE.SectionID - << " + " << RE.Offset << " (" << format("%p", Target) << ")" - << " RelType: " << RE.RelType - << " Addend: " << RE.Addend - << "\n"); + // Ignore relocations for sections that were not loaded + if (Sections[RE.SectionID].Address != 0) { + DEBUG(dbgs() << "\tSectionID: " << RE.SectionID + << " + " << RE.Offset << " (" + << format("%p", Sections[RE.SectionID].Address + RE.Offset) << ")" + << " RelType: " << RE.RelType + << " Addend: " << RE.Addend + << "\n"); - resolveRelocation(Target, Sections[RE.SectionID].LoadAddress + RE.Offset, - Value, RE.RelType, RE.Addend); + resolveRelocation(Sections[RE.SectionID], RE.Offset, + Value, RE.RelType, RE.Addend); } } @@ -420,7 +459,7 @@ RuntimeDyld::~RuntimeDyld() { delete Dyld; } -bool RuntimeDyld::loadObject(MemoryBuffer *InputBuffer) { +ObjectImage *RuntimeDyld::loadObject(ObjectBuffer *InputBuffer) { if (!Dyld) { sys::LLVMFileType type = sys::IdentifyFileType( InputBuffer->getBufferStart(), @@ -462,6 +501,10 @@ void *RuntimeDyld::getSymbolAddress(StringRef Name) { return Dyld->getSymbolAddress(Name); } +uint64_t RuntimeDyld::getSymbolLoadAddress(StringRef Name) { + return Dyld->getSymbolLoadAddress(Name); +} + void RuntimeDyld::resolveRelocations() { Dyld->resolveRelocations(); } @@ -471,7 +514,7 @@ void RuntimeDyld::reassignSectionAddress(unsigned SectionID, Dyld->reassignSectionAddress(SectionID, Addr); } -void RuntimeDyld::mapSectionAddress(void *LocalAddress, +void RuntimeDyld::mapSectionAddress(const void *LocalAddress, uint64_t TargetAddress) { Dyld->mapSectionAddress(LocalAddress, TargetAddress); } diff --git a/contrib/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp b/contrib/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp index 75bb586..1ebcaf7 100644 --- a/contrib/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp +++ b/contrib/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp @@ -12,21 +12,32 @@ //===----------------------------------------------------------------------===// #define DEBUG_TYPE "dyld" +#include "RuntimeDyldELF.h" +#include "JITRegistrar.h" +#include "ObjectImageCommon.h" #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/ExecutionEngine/ObjectImage.h" +#include "llvm/ExecutionEngine/ObjectBuffer.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 { +static inline +error_code check(error_code Err) { + if (Err) { + report_fatal_error(Err.message()); + } + return Err; +} + template<support::endianness target_endianness, bool is64Bits> class DyldELFObject : public ELFObjectFile<target_endianness, is64Bits> { LLVM_ELF_IMPORT_TYPES(target_endianness, is64Bits) @@ -36,25 +47,17 @@ class DyldELFObject : public ELFObjectFile<target_endianness, is64Bits> { typedef Elf_Rel_Impl<target_endianness, is64Bits, false> Elf_Rel; typedef Elf_Rel_Impl<target_endianness, is64Bits, true> Elf_Rela; - typedef typename ELFObjectFile<target_endianness, is64Bits>:: - Elf_Ehdr Elf_Ehdr; + typedef Elf_Ehdr_Impl<target_endianness, is64Bits> Elf_Ehdr; typedef typename ELFDataTypeTypedefHelper< target_endianness, is64Bits>::value_type addr_type; -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); + DyldELFObject(MemoryBuffer *Wrapper, 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; } - // Methods for type inquiry through isa, cast and dyn_cast static inline bool classof(const Binary *v) { return (isa<ELFObjectFile<target_endianness, is64Bits> >(v) @@ -64,20 +67,18 @@ public: const ELFObjectFile<target_endianness, is64Bits> *v) { return v->isDyldType(); } - static inline bool classof(const DyldELFObject *v) { - return true; - } }; template<support::endianness target_endianness, bool is64Bits> -class ELFObjectImage : public ObjectImage { +class ELFObjectImage : public ObjectImageCommon { protected: DyldELFObject<target_endianness, is64Bits> *DyldObj; bool Registered; public: - ELFObjectImage(DyldELFObject<target_endianness, is64Bits> *Obj) - : ObjectImage(Obj), + ELFObjectImage(ObjectBuffer *Input, + DyldELFObject<target_endianness, is64Bits> *Obj) + : ObjectImageCommon(Input, Obj), DyldObj(Obj), Registered(false) {} @@ -100,20 +101,22 @@ class ELFObjectImage : public ObjectImage { virtual void registerWithDebugger() { - JITRegistrar::getGDBRegistrar().registerObject(DyldObj->getBuffer()); + JITRegistrar::getGDBRegistrar().registerObject(*Buffer); Registered = true; } virtual void deregisterWithDebugger() { - JITRegistrar::getGDBRegistrar().deregisterObject(DyldObj->getBuffer()); + JITRegistrar::getGDBRegistrar().deregisterObject(*Buffer); } }; +// The MemoryBuffer passed into this constructor is just a wrapper around the +// actual memory. Ultimately, the Binary parent class will take ownership of +// this MemoryBuffer object but not the underlying memory. template<support::endianness target_endianness, bool is64Bits> -DyldELFObject<target_endianness, is64Bits>::DyldELFObject(MemoryBuffer *Object, +DyldELFObject<target_endianness, is64Bits>::DyldELFObject(MemoryBuffer *Wrapper, error_code &ec) - : ELFObjectFile<target_endianness, is64Bits>(Object, ec), - InputData(Object) { + : ELFObjectFile<target_endianness, is64Bits>(Wrapper, ec) { this->isDyldELFObject = true; } @@ -149,50 +152,43 @@ void DyldELFObject<target_endianness, is64Bits>::updateSymbolAddress( namespace llvm { -ObjectImage *RuntimeDyldELF::createObjectImage( - const MemoryBuffer *ConstInputBuffer) { - MemoryBuffer *InputBuffer = const_cast<MemoryBuffer*>(ConstInputBuffer); - std::pair<unsigned char, unsigned char> Ident = getElfArchType(InputBuffer); +ObjectImage *RuntimeDyldELF::createObjectImage(ObjectBuffer *Buffer) { + if (Buffer->getBufferSize() < ELF::EI_NIDENT) + llvm_unreachable("Unexpected ELF object size"); + std::pair<unsigned char, unsigned char> Ident = std::make_pair( + (uint8_t)Buffer->getBufferStart()[ELF::EI_CLASS], + (uint8_t)Buffer->getBufferStart()[ELF::EI_DATA]); error_code ec; if (Ident.first == ELF::ELFCLASS32 && Ident.second == ELF::ELFDATA2LSB) { DyldELFObject<support::little, false> *Obj = - new DyldELFObject<support::little, false>(InputBuffer, ec); - return new ELFObjectImage<support::little, false>(Obj); + new DyldELFObject<support::little, false>(Buffer->getMemBuffer(), ec); + return new ELFObjectImage<support::little, false>(Buffer, Obj); } else if (Ident.first == ELF::ELFCLASS32 && Ident.second == ELF::ELFDATA2MSB) { DyldELFObject<support::big, false> *Obj = - new DyldELFObject<support::big, false>(InputBuffer, ec); - return new ELFObjectImage<support::big, false>(Obj); + new DyldELFObject<support::big, false>(Buffer->getMemBuffer(), ec); + return new ELFObjectImage<support::big, false>(Buffer, Obj); } else if (Ident.first == ELF::ELFCLASS64 && Ident.second == ELF::ELFDATA2MSB) { DyldELFObject<support::big, true> *Obj = - new DyldELFObject<support::big, true>(InputBuffer, ec); - return new ELFObjectImage<support::big, true>(Obj); + new DyldELFObject<support::big, true>(Buffer->getMemBuffer(), ec); + return new ELFObjectImage<support::big, true>(Buffer, Obj); } else if (Ident.first == ELF::ELFCLASS64 && Ident.second == ELF::ELFDATA2LSB) { DyldELFObject<support::little, true> *Obj = - new DyldELFObject<support::little, true>(InputBuffer, ec); - return new ELFObjectImage<support::little, true>(Obj); + new DyldELFObject<support::little, true>(Buffer->getMemBuffer(), ec); + return new ELFObjectImage<support::little, true>(Buffer, 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; } -void RuntimeDyldELF::resolveX86_64Relocation(uint8_t *LocalAddress, - uint64_t FinalAddress, +void RuntimeDyldELF::resolveX86_64Relocation(const SectionEntry &Section, + uint64_t Offset, uint64_t Value, uint32_t Type, int64_t Addend) { @@ -201,8 +197,10 @@ void RuntimeDyldELF::resolveX86_64Relocation(uint8_t *LocalAddress, llvm_unreachable("Relocation type not implemented yet!"); break; case ELF::R_X86_64_64: { - uint64_t *Target = (uint64_t*)(LocalAddress); + uint64_t *Target = reinterpret_cast<uint64_t*>(Section.Address + Offset); *Target = Value + Addend; + DEBUG(dbgs() << "Writing " << format("%p", (Value + Addend)) + << " at " << format("%p\n",Target)); break; } case ELF::R_X86_64_32: @@ -212,37 +210,52 @@ void RuntimeDyldELF::resolveX86_64Relocation(uint8_t *LocalAddress, (Type == ELF::R_X86_64_32S && ((int64_t)Value <= INT32_MAX && (int64_t)Value >= INT32_MIN))); uint32_t TruncatedAddr = (Value & 0xFFFFFFFF); - uint32_t *Target = reinterpret_cast<uint32_t*>(LocalAddress); + uint32_t *Target = reinterpret_cast<uint32_t*>(Section.Address + Offset); *Target = TruncatedAddr; + DEBUG(dbgs() << "Writing " << format("%p", TruncatedAddr) + << " at " << format("%p\n",Target)); break; } case ELF::R_X86_64_PC32: { - uint32_t *Placeholder = reinterpret_cast<uint32_t*>(LocalAddress); + // Get the placeholder value from the generated object since + // a previous relocation attempt may have overwritten the loaded version + uint32_t *Placeholder = reinterpret_cast<uint32_t*>(Section.ObjAddress + + Offset); + uint32_t *Target = reinterpret_cast<uint32_t*>(Section.Address + Offset); + uint64_t FinalAddress = Section.LoadAddress + Offset; int64_t RealOffset = *Placeholder + Value + Addend - FinalAddress; assert(RealOffset <= INT32_MAX && RealOffset >= INT32_MIN); int32_t TruncOffset = (RealOffset & 0xFFFFFFFF); - *Placeholder = TruncOffset; + *Target = TruncOffset; break; } } } -void RuntimeDyldELF::resolveX86Relocation(uint8_t *LocalAddress, - uint32_t FinalAddress, +void RuntimeDyldELF::resolveX86Relocation(const SectionEntry &Section, + uint64_t Offset, uint32_t Value, uint32_t Type, int32_t Addend) { switch (Type) { case ELF::R_386_32: { - uint32_t *Target = (uint32_t*)(LocalAddress); - uint32_t Placeholder = *Target; - *Target = Placeholder + Value + Addend; + // Get the placeholder value from the generated object since + // a previous relocation attempt may have overwritten the loaded version + uint32_t *Placeholder = reinterpret_cast<uint32_t*>(Section.ObjAddress + + Offset); + uint32_t *Target = reinterpret_cast<uint32_t*>(Section.Address + Offset); + *Target = *Placeholder + Value + Addend; break; } case ELF::R_386_PC32: { - uint32_t *Placeholder = reinterpret_cast<uint32_t*>(LocalAddress); + // Get the placeholder value from the generated object since + // a previous relocation attempt may have overwritten the loaded version + uint32_t *Placeholder = reinterpret_cast<uint32_t*>(Section.ObjAddress + + Offset); + uint32_t *Target = reinterpret_cast<uint32_t*>(Section.Address + Offset); + uint32_t FinalAddress = ((Section.LoadAddress + Offset) & 0xFFFFFFFF); uint32_t RealOffset = *Placeholder + Value + Addend - FinalAddress; - *Placeholder = RealOffset; + *Target = RealOffset; break; } default: @@ -253,16 +266,18 @@ void RuntimeDyldELF::resolveX86Relocation(uint8_t *LocalAddress, } } -void RuntimeDyldELF::resolveARMRelocation(uint8_t *LocalAddress, - uint32_t FinalAddress, +void RuntimeDyldELF::resolveARMRelocation(const SectionEntry &Section, + uint64_t Offset, uint32_t Value, uint32_t Type, int32_t Addend) { // TODO: Add Thumb relocations. - uint32_t* TargetPtr = (uint32_t*)LocalAddress; + uint32_t* TargetPtr = (uint32_t*)(Section.Address + Offset); + uint32_t FinalAddress = ((Section.LoadAddress + Offset) & 0xFFFFFFFF); Value += Addend; - DEBUG(dbgs() << "resolveARMRelocation, LocalAddress: " << LocalAddress + DEBUG(dbgs() << "resolveARMRelocation, LocalAddress: " + << Section.Address + Offset << " FinalAddress: " << format("%p",FinalAddress) << " Value: " << format("%x",Value) << " Type: " << format("%x",Type) @@ -273,14 +288,19 @@ void RuntimeDyldELF::resolveARMRelocation(uint8_t *LocalAddress, default: llvm_unreachable("Not implemented relocation type!"); - // Just write 32bit value to relocation address + // Write a 32bit value to relocation address, taking into account the + // implicit addend encoded in the target. case ELF::R_ARM_ABS32 : - *TargetPtr = Value; + *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 : + // We are not expecting any other addend in the relocation address. + // Using 0x000F0FFF because MOVW has its 16 bit immediate split into 2 + // non-contiguous fields. + assert((*TargetPtr & 0x000F0FFF) == 0); Value = Value & 0xFFFF; *TargetPtr |= Value & 0xFFF; *TargetPtr |= ((Value >> 12) & 0xF) << 16; @@ -289,6 +309,9 @@ void RuntimeDyldELF::resolveARMRelocation(uint8_t *LocalAddress, // Write last 16 bit of 32 bit value to the mov instruction. // Last 4 bit should be shifted. case ELF::R_ARM_MOVT_ABS : + // We are not expecting any other addend in the relocation address. + // Use 0x000F0FFF for the same reason as R_ARM_MOVW_ABS_NC. + assert((*TargetPtr & 0x000F0FFF) == 0); Value = (Value >> 16) & 0xFFFF; *TargetPtr |= Value & 0xFFF; *TargetPtr |= ((Value >> 12) & 0xF) << 16; @@ -306,26 +329,250 @@ void RuntimeDyldELF::resolveARMRelocation(uint8_t *LocalAddress, } } -void RuntimeDyldELF::resolveRelocation(uint8_t *LocalAddress, - uint64_t FinalAddress, +void RuntimeDyldELF::resolveMIPSRelocation(const SectionEntry &Section, + uint64_t Offset, + uint32_t Value, + uint32_t Type, + int32_t Addend) { + uint32_t* TargetPtr = (uint32_t*)(Section.Address + Offset); + Value += Addend; + + DEBUG(dbgs() << "resolveMipselocation, LocalAddress: " + << Section.Address + Offset + << " FinalAddress: " + << format("%p",Section.LoadAddress + Offset) + << " Value: " << format("%x",Value) + << " Type: " << format("%x",Type) + << " Addend: " << format("%x",Addend) + << "\n"); + + switch(Type) { + default: + llvm_unreachable("Not implemented relocation type!"); + break; + case ELF::R_MIPS_32: + *TargetPtr = Value + (*TargetPtr); + break; + case ELF::R_MIPS_26: + *TargetPtr = ((*TargetPtr) & 0xfc000000) | (( Value & 0x0fffffff) >> 2); + break; + case ELF::R_MIPS_HI16: + // Get the higher 16-bits. Also add 1 if bit 15 is 1. + Value += ((*TargetPtr) & 0x0000ffff) << 16; + *TargetPtr = ((*TargetPtr) & 0xffff0000) | + (((Value + 0x8000) >> 16) & 0xffff); + break; + case ELF::R_MIPS_LO16: + Value += ((*TargetPtr) & 0x0000ffff); + *TargetPtr = ((*TargetPtr) & 0xffff0000) | (Value & 0xffff); + break; + } +} + +// Return the .TOC. section address to R_PPC64_TOC relocations. +uint64_t RuntimeDyldELF::findPPC64TOC() const { + // The TOC consists of sections .got, .toc, .tocbss, .plt in that + // order. The TOC starts where the first of these sections starts. + SectionList::const_iterator it = Sections.begin(); + SectionList::const_iterator ite = Sections.end(); + for (; it != ite; ++it) { + if (it->Name == ".got" || + it->Name == ".toc" || + it->Name == ".tocbss" || + it->Name == ".plt") + break; + } + if (it == ite) { + // This may happen for + // * references to TOC base base (sym@toc, .odp relocation) without + // a .toc directive. + // In this case just use the first section (which is usually + // the .odp) since the code won't reference the .toc base + // directly. + it = Sections.begin(); + } + assert (it != ite); + // Per the ppc64-elf-linux ABI, The TOC base is TOC value plus 0x8000 + // thus permitting a full 64 Kbytes segment. + return it->LoadAddress + 0x8000; +} + +// Returns the sections and offset associated with the ODP entry referenced +// by Symbol. +void RuntimeDyldELF::findOPDEntrySection(ObjectImage &Obj, + ObjSectionToIDMap &LocalSections, + RelocationValueRef &Rel) { + // Get the ELF symbol value (st_value) to compare with Relocation offset in + // .opd entries + + error_code err; + for (section_iterator si = Obj.begin_sections(), + se = Obj.end_sections(); si != se; si.increment(err)) { + StringRef SectionName; + check(si->getName(SectionName)); + if (SectionName != ".opd") + continue; + + for (relocation_iterator i = si->begin_relocations(), + e = si->end_relocations(); i != e;) { + check(err); + + // The R_PPC64_ADDR64 relocation indicates the first field + // of a .opd entry + uint64_t TypeFunc; + check(i->getType(TypeFunc)); + if (TypeFunc != ELF::R_PPC64_ADDR64) { + i.increment(err); + continue; + } + + SymbolRef TargetSymbol; + uint64_t TargetSymbolOffset; + int64_t TargetAdditionalInfo; + check(i->getSymbol(TargetSymbol)); + check(i->getOffset(TargetSymbolOffset)); + check(i->getAdditionalInfo(TargetAdditionalInfo)); + + i = i.increment(err); + if (i == e) + break; + check(err); + + // Just check if following relocation is a R_PPC64_TOC + uint64_t TypeTOC; + check(i->getType(TypeTOC)); + if (TypeTOC != ELF::R_PPC64_TOC) + continue; + + // Finally compares the Symbol value and the target symbol offset + // to check if this .opd entry refers to the symbol the relocation + // points to. + if (Rel.Addend != (intptr_t)TargetSymbolOffset) + continue; + + section_iterator tsi(Obj.end_sections()); + check(TargetSymbol.getSection(tsi)); + Rel.SectionID = findOrEmitSection(Obj, (*tsi), true, LocalSections); + Rel.Addend = (intptr_t)TargetAdditionalInfo; + return; + } + } + llvm_unreachable("Attempting to get address of ODP entry!"); +} + +// Relocation masks following the #lo(value), #hi(value), #higher(value), +// and #highest(value) macros defined in section 4.5.1. Relocation Types +// in PPC-elf64abi document. +// +static inline +uint16_t applyPPClo (uint64_t value) +{ + return value & 0xffff; +} + +static inline +uint16_t applyPPChi (uint64_t value) +{ + return (value >> 16) & 0xffff; +} + +static inline +uint16_t applyPPChigher (uint64_t value) +{ + return (value >> 32) & 0xffff; +} + +static inline +uint16_t applyPPChighest (uint64_t value) +{ + return (value >> 48) & 0xffff; +} + +void RuntimeDyldELF::resolvePPC64Relocation(const SectionEntry &Section, + uint64_t Offset, + uint64_t Value, + uint32_t Type, + int64_t Addend) { + uint8_t* LocalAddress = Section.Address + Offset; + switch (Type) { + default: + llvm_unreachable("Relocation type not implemented yet!"); + break; + case ELF::R_PPC64_ADDR16_LO : + writeInt16BE(LocalAddress, applyPPClo (Value + Addend)); + break; + case ELF::R_PPC64_ADDR16_HI : + writeInt16BE(LocalAddress, applyPPChi (Value + Addend)); + break; + case ELF::R_PPC64_ADDR16_HIGHER : + writeInt16BE(LocalAddress, applyPPChigher (Value + Addend)); + break; + case ELF::R_PPC64_ADDR16_HIGHEST : + writeInt16BE(LocalAddress, applyPPChighest (Value + Addend)); + break; + case ELF::R_PPC64_ADDR14 : { + assert(((Value + Addend) & 3) == 0); + // Preserve the AA/LK bits in the branch instruction + uint8_t aalk = *(LocalAddress+3); + writeInt16BE(LocalAddress + 2, (aalk & 3) | ((Value + Addend) & 0xfffc)); + } break; + case ELF::R_PPC64_REL24 : { + uint64_t FinalAddress = (Section.LoadAddress + Offset); + int32_t delta = static_cast<int32_t>(Value - FinalAddress + Addend); + if (SignExtend32<24>(delta) != delta) + llvm_unreachable("Relocation R_PPC64_REL24 overflow"); + // Generates a 'bl <address>' instruction + writeInt32BE(LocalAddress, 0x48000001 | (delta & 0x03FFFFFC)); + } break; + case ELF::R_PPC64_ADDR64 : + writeInt64BE(LocalAddress, Value + Addend); + break; + case ELF::R_PPC64_TOC : + writeInt64BE(LocalAddress, findPPC64TOC()); + break; + case ELF::R_PPC64_TOC16 : { + uint64_t TOCStart = findPPC64TOC(); + Value = applyPPClo((Value + Addend) - TOCStart); + writeInt16BE(LocalAddress, applyPPClo(Value)); + } break; + case ELF::R_PPC64_TOC16_DS : { + uint64_t TOCStart = findPPC64TOC(); + Value = ((Value + Addend) - TOCStart); + writeInt16BE(LocalAddress, applyPPClo(Value)); + } break; + } +} + + +void RuntimeDyldELF::resolveRelocation(const SectionEntry &Section, + uint64_t Offset, uint64_t Value, uint32_t Type, int64_t Addend) { switch (Arch) { case Triple::x86_64: - resolveX86_64Relocation(LocalAddress, FinalAddress, Value, Type, Addend); + resolveX86_64Relocation(Section, Offset, Value, Type, Addend); break; case Triple::x86: - resolveX86Relocation(LocalAddress, (uint32_t)(FinalAddress & 0xffffffffL), + resolveX86Relocation(Section, Offset, (uint32_t)(Value & 0xffffffffL), Type, (uint32_t)(Addend & 0xffffffffL)); break; case Triple::arm: // Fall through. case Triple::thumb: - resolveARMRelocation(LocalAddress, (uint32_t)(FinalAddress & 0xffffffffL), + resolveARMRelocation(Section, Offset, (uint32_t)(Value & 0xffffffffL), Type, (uint32_t)(Addend & 0xffffffffL)); break; + case Triple::mips: // Fall through. + case Triple::mipsel: + resolveMIPSRelocation(Section, Offset, + (uint32_t)(Value & 0xffffffffL), Type, + (uint32_t)(Addend & 0xffffffffL)); + break; + case Triple::ppc64: + resolvePPC64Relocation(Section, Offset, Value, Type, Addend); + break; default: llvm_unreachable("Unsupported CPU type!"); } } @@ -350,6 +597,8 @@ void RuntimeDyldELF::processRelocationRef(const ObjRelocationInfo &Rel, RelocationValueRef Value; // First search for the symbol in the local symbol table SymbolTableMap::const_iterator lsi = Symbols.find(TargetName.data()); + SymbolRef::Type SymType; + Symbol.getType(SymType); if (lsi != Symbols.end()) { Value.SectionID = lsi->second.first; Value.Addend = lsi->second.second; @@ -361,8 +610,6 @@ void RuntimeDyldELF::processRelocationRef(const ObjRelocationInfo &Rel, 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 @@ -373,7 +620,13 @@ void RuntimeDyldELF::processRelocationRef(const ObjRelocationInfo &Rel, 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); + // Default to 'true' in case isText fails (though it never does). + bool isCode = true; + si->isText(isCode); + Value.SectionID = findOrEmitSection(Obj, + (*si), + isCode, + ObjSectionToID); Value.Addend = Addend; break; } @@ -398,13 +651,12 @@ void RuntimeDyldELF::processRelocationRef(const ObjRelocationInfo &Rel, // 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. + // Look for an existing stub. StubMap::const_iterator i = Stubs.find(Value); if (i != Stubs.end()) { - resolveRelocation(Target, (uint64_t)Target, (uint64_t)Section.Address + - i->second, RelType, 0); + resolveRelocation(Section, Rel.Offset, + (uint64_t)Section.Address + i->second, RelType, 0); DEBUG(dbgs() << " Stub function found\n"); } else { // Create a new stub function. @@ -419,10 +671,145 @@ void RuntimeDyldELF::processRelocationRef(const ObjRelocationInfo &Rel, else addRelocationForSection(RE, Value.SectionID); - resolveRelocation(Target, (uint64_t)Target, (uint64_t)Section.Address + - Section.StubOffset, RelType, 0); + resolveRelocation(Section, Rel.Offset, + (uint64_t)Section.Address + Section.StubOffset, + RelType, 0); Section.StubOffset += getMaxStubSize(); } + } else if (Arch == Triple::mipsel && RelType == ELF::R_MIPS_26) { + // This is an Mips branch relocation, need to use a stub function. + DEBUG(dbgs() << "\t\tThis is a Mips branch relocation."); + SectionEntry &Section = Sections[Rel.SectionID]; + uint8_t *Target = Section.Address + Rel.Offset; + uint32_t *TargetAddress = (uint32_t *)Target; + + // Extract the addend from the instruction. + uint32_t Addend = ((*TargetAddress) & 0x03ffffff) << 2; + + Value.Addend += Addend; + + // Look up for existing stub. + StubMap::const_iterator i = Stubs.find(Value); + if (i != Stubs.end()) { + resolveRelocation(Section, Rel.Offset, + (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); + + // Creating Hi and Lo relocations for the filled stub instructions. + RelocationEntry REHi(Rel.SectionID, + StubTargetAddr - Section.Address, + ELF::R_MIPS_HI16, Value.Addend); + RelocationEntry RELo(Rel.SectionID, + StubTargetAddr - Section.Address + 4, + ELF::R_MIPS_LO16, Value.Addend); + + if (Value.SymbolName) { + addRelocationForSymbol(REHi, Value.SymbolName); + addRelocationForSymbol(RELo, Value.SymbolName); + } else { + addRelocationForSection(REHi, Value.SectionID); + addRelocationForSection(RELo, Value.SectionID); + } + + resolveRelocation(Section, Rel.Offset, + (uint64_t)Section.Address + Section.StubOffset, + RelType, 0); + Section.StubOffset += getMaxStubSize(); + } + } else if (Arch == Triple::ppc64) { + if (RelType == ELF::R_PPC64_REL24) { + // A PPC branch relocation will need a stub function if the target is + // an external symbol (Symbol::ST_Unknown) or if the target address + // is not within the signed 24-bits branch address. + SectionEntry &Section = Sections[Rel.SectionID]; + uint8_t *Target = Section.Address + Rel.Offset; + bool RangeOverflow = false; + if (SymType != SymbolRef::ST_Unknown) { + // A function call may points to the .opd entry, so the final symbol value + // in calculated based in the relocation values in .opd section. + findOPDEntrySection(Obj, ObjSectionToID, Value); + uint8_t *RelocTarget = Sections[Value.SectionID].Address + Value.Addend; + int32_t delta = static_cast<int32_t>(Target - RelocTarget); + // If it is within 24-bits branch range, just set the branch target + if (SignExtend32<24>(delta) == delta) { + RelocationEntry RE(Rel.SectionID, Rel.Offset, RelType, Value.Addend); + if (Value.SymbolName) + addRelocationForSymbol(RE, Value.SymbolName); + else + addRelocationForSection(RE, Value.SectionID); + } else { + RangeOverflow = true; + } + } + if (SymType == SymbolRef::ST_Unknown || RangeOverflow == true) { + // It is an external symbol (SymbolRef::ST_Unknown) or within a range + // larger than 24-bits. + StubMap::const_iterator i = Stubs.find(Value); + if (i != Stubs.end()) { + // Symbol function stub already created, just relocate to it + resolveRelocation(Section, Rel.Offset, + (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); + RelocationEntry RE(Rel.SectionID, StubTargetAddr - Section.Address, + ELF::R_PPC64_ADDR64, Value.Addend); + + // Generates the 64-bits address loads as exemplified in section + // 4.5.1 in PPC64 ELF ABI. + RelocationEntry REhst(Rel.SectionID, + StubTargetAddr - Section.Address + 2, + ELF::R_PPC64_ADDR16_HIGHEST, Value.Addend); + RelocationEntry REhr(Rel.SectionID, + StubTargetAddr - Section.Address + 6, + ELF::R_PPC64_ADDR16_HIGHER, Value.Addend); + RelocationEntry REh(Rel.SectionID, + StubTargetAddr - Section.Address + 14, + ELF::R_PPC64_ADDR16_HI, Value.Addend); + RelocationEntry REl(Rel.SectionID, + StubTargetAddr - Section.Address + 18, + ELF::R_PPC64_ADDR16_LO, Value.Addend); + + if (Value.SymbolName) { + addRelocationForSymbol(REhst, Value.SymbolName); + addRelocationForSymbol(REhr, Value.SymbolName); + addRelocationForSymbol(REh, Value.SymbolName); + addRelocationForSymbol(REl, Value.SymbolName); + } else { + addRelocationForSection(REhst, Value.SectionID); + addRelocationForSection(REhr, Value.SectionID); + addRelocationForSection(REh, Value.SectionID); + addRelocationForSection(REl, Value.SectionID); + } + + resolveRelocation(Section, Rel.Offset, + (uint64_t)Section.Address + Section.StubOffset, + RelType, 0); + if (SymType == SymbolRef::ST_Unknown) + // Restore the TOC for external calls + writeInt32BE(Target+4, 0xE8410028); // ld r2,40(r1) + Section.StubOffset += getMaxStubSize(); + } + } + } else { + RelocationEntry RE(Rel.SectionID, Rel.Offset, RelType, Value.Addend); + // Extra check to avoid relocation againt empty symbols (usually + // the R_PPC64_TOC). + if (Value.SymbolName && !TargetName.empty()) + addRelocationForSymbol(RE, Value.SymbolName); + else + addRelocationForSection(RE, Value.SectionID); + } } else { RelocationEntry RE(Rel.SectionID, Rel.Offset, RelType, Value.Addend); if (Value.SymbolName) @@ -432,8 +819,16 @@ void RuntimeDyldELF::processRelocationRef(const ObjRelocationInfo &Rel, } } -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; +unsigned RuntimeDyldELF::getCommonSymbolAlignment(const SymbolRef &Sym) { + // In ELF, the value of an SHN_COMMON symbol is its alignment requirement. + uint64_t Align; + Check(Sym.getValue(Align)); + return Align; +} + +bool RuntimeDyldELF::isCompatibleFormat(const ObjectBuffer *Buffer) const { + if (Buffer->getBufferSize() < strlen(ELF::ElfMagic)) + return false; + return (memcmp(Buffer->getBufferStart(), ELF::ElfMagic, strlen(ELF::ElfMagic))) == 0; } } // namespace llvm diff --git a/contrib/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h b/contrib/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h index e413f78..07e704b 100644 --- a/contrib/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h +++ b/contrib/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h @@ -18,32 +18,52 @@ using namespace llvm; - namespace llvm { + +namespace { + // Helper for extensive error checking in debug builds. + error_code Check(error_code Err) { + if (Err) { + report_fatal_error(Err.message()); + } + return Err; + } +} // end anonymous namespace + class RuntimeDyldELF : public RuntimeDyldImpl { protected: - ObjectImage *LoadedObject; - - void resolveX86_64Relocation(uint8_t *LocalAddress, - uint64_t FinalAddress, + void resolveX86_64Relocation(const SectionEntry &Section, + uint64_t Offset, uint64_t Value, uint32_t Type, int64_t Addend); - void resolveX86Relocation(uint8_t *LocalAddress, - uint32_t FinalAddress, + void resolveX86Relocation(const SectionEntry &Section, + uint64_t Offset, uint32_t Value, uint32_t Type, int32_t Addend); - void resolveARMRelocation(uint8_t *LocalAddress, - uint32_t FinalAddress, + void resolveARMRelocation(const SectionEntry &Section, + uint64_t Offset, uint32_t Value, uint32_t Type, int32_t Addend); - virtual void resolveRelocation(uint8_t *LocalAddress, - uint64_t FinalAddress, + void resolveMIPSRelocation(const SectionEntry &Section, + uint64_t Offset, + uint32_t Value, + uint32_t Type, + int32_t Addend); + + void resolvePPC64Relocation(const SectionEntry &Section, + uint64_t Offset, + uint64_t Value, + uint32_t Type, + int64_t Addend); + + virtual void resolveRelocation(const SectionEntry &Section, + uint64_t Offset, uint64_t Value, uint32_t Type, int64_t Addend); @@ -54,16 +74,22 @@ protected: const SymbolTableMap &Symbols, StubMap &Stubs); - virtual ObjectImage *createObjectImage(const MemoryBuffer *InputBuffer); - virtual void handleObjectLoaded(ObjectImage *Obj); + unsigned getCommonSymbolAlignment(const SymbolRef &Sym); + + virtual ObjectImage *createObjectImage(ObjectBuffer *InputBuffer); + + uint64_t findPPC64TOC() const; + void findOPDEntrySection(ObjectImage &Obj, + ObjSectionToIDMap &LocalSections, + RelocationValueRef &Rel); public: RuntimeDyldELF(RTDyldMemoryManager *mm) - : RuntimeDyldImpl(mm), LoadedObject(0) {} + : RuntimeDyldImpl(mm) {} virtual ~RuntimeDyldELF(); - bool isCompatibleFormat(const MemoryBuffer *InputBuffer) const; + bool isCompatibleFormat(const ObjectBuffer *Buffer) const; }; } // end namespace llvm diff --git a/contrib/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h b/contrib/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h index c38ca69..829fd6c 100644 --- a/contrib/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h +++ b/contrib/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h @@ -14,8 +14,8 @@ #ifndef LLVM_RUNTIME_DYLD_IMPL_H #define LLVM_RUNTIME_DYLD_IMPL_H -#include "ObjectImage.h" #include "llvm/ExecutionEngine/RuntimeDyld.h" +#include "llvm/ExecutionEngine/ObjectImage.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringMap.h" @@ -24,6 +24,8 @@ #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Format.h" +#include "llvm/Support/Host.h" +#include "llvm/Support/SwapByteOrder.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/system_error.h" #include <map> @@ -33,7 +35,7 @@ using namespace llvm::object; namespace llvm { -class MemoryBuffer; +class ObjectBuffer; class Twine; @@ -41,6 +43,9 @@ class Twine; /// linker. class SectionEntry { public: + /// Name - section name. + StringRef Name; + /// Address - address in the linker's memory where the section resides. uint8_t *Address; @@ -61,9 +66,9 @@ public: /// for calculating relocations in some object formats (like MachO). uintptr_t ObjAddress; - SectionEntry(uint8_t *address, size_t size, uintptr_t stubOffset, - uintptr_t objAddress) - : Address(address), Size(size), LoadAddress((uintptr_t)address), + SectionEntry(StringRef name, uint8_t *address, size_t size, + uintptr_t stubOffset, uintptr_t objAddress) + : Name(name), Address(address), Size(size), LoadAddress((uintptr_t)address), StubOffset(stubOffset), ObjAddress(objAddress) {} }; @@ -135,8 +140,10 @@ protected: typedef StringMap<SymbolLoc> SymbolTableMap; SymbolTableMap GlobalSymbolTable; - // Keep a map of common symbols to their sizes - typedef std::map<SymbolRef, unsigned> CommonSymbolMap; + // Pair representing the size and alignment requirement for a common symbol. + typedef std::pair<unsigned, unsigned> CommonSymbolInfo; + // Keep a map of common symbols to their info pairs + typedef std::map<SymbolRef, CommonSymbolInfo> CommonSymbolMap; // For each symbol, keep a list of relocations based on it. Anytime // its address is reassigned (the JIT re-compiled the function, e.g.), @@ -161,6 +168,10 @@ protected: inline unsigned getMaxStubSize() { if (Arch == Triple::arm || Arch == Triple::thumb) return 8; // 32-bit instruction and 32-bit address + else if (Arch == Triple::mipsel) + return 16; + else if (Arch == Triple::ppc64) + return 44; else return 0; } @@ -175,10 +186,50 @@ protected: return true; } + uint64_t getSectionLoadAddress(unsigned SectionID) { + return Sections[SectionID].LoadAddress; + } + uint8_t *getSectionAddress(unsigned SectionID) { return (uint8_t*)Sections[SectionID].Address; } + // Subclasses can override this method to get the alignment requirement of + // a common symbol. Returns no alignment requirement if not implemented. + virtual unsigned getCommonSymbolAlignment(const SymbolRef &Sym) { + return 0; + } + + + void writeInt16BE(uint8_t *Addr, uint16_t Value) { + if (sys::isLittleEndianHost()) + Value = sys::SwapByteOrder(Value); + *Addr = (Value >> 8) & 0xFF; + *(Addr+1) = Value & 0xFF; + } + + void writeInt32BE(uint8_t *Addr, uint32_t Value) { + if (sys::isLittleEndianHost()) + Value = sys::SwapByteOrder(Value); + *Addr = (Value >> 24) & 0xFF; + *(Addr+1) = (Value >> 16) & 0xFF; + *(Addr+2) = (Value >> 8) & 0xFF; + *(Addr+3) = Value & 0xFF; + } + + void writeInt64BE(uint8_t *Addr, uint64_t Value) { + if (sys::isLittleEndianHost()) + Value = sys::SwapByteOrder(Value); + *Addr = (Value >> 56) & 0xFF; + *(Addr+1) = (Value >> 48) & 0xFF; + *(Addr+2) = (Value >> 40) & 0xFF; + *(Addr+3) = (Value >> 32) & 0xFF; + *(Addr+4) = (Value >> 24) & 0xFF; + *(Addr+5) = (Value >> 16) & 0xFF; + *(Addr+6) = (Value >> 8) & 0xFF; + *(Addr+7) = Value & 0xFF; + } + /// \brief Given the common symbols discovered in the object file, emit a /// new section for them and update the symbol mappings in the object and /// symbol table. @@ -221,13 +272,14 @@ protected: void resolveRelocationEntry(const RelocationEntry &RE, uint64_t Value); /// \brief A object file specific relocation resolver - /// \param Address Address to apply the relocation action + /// \param Section The section where the relocation is being applied + /// \param Offset The offset into the section for this relocation /// \param Value Target symbol address to apply the relocation action /// \param Type object file specific relocation type /// \param Addend A constant addend used to compute the value to be stored /// into the relocatable field - virtual void resolveRelocation(uint8_t *LocalAddress, - uint64_t FinalAddress, + virtual void resolveRelocation(const SectionEntry &Section, + uint64_t Offset, uint64_t Value, uint32_t Type, int64_t Addend) = 0; @@ -242,19 +294,13 @@ protected: /// \brief Resolve relocations to external symbols. void resolveExternalSymbols(); - virtual ObjectImage *createObjectImage(const MemoryBuffer *InputBuffer); - virtual void handleObjectLoaded(ObjectImage *Obj) - { - // Subclasses may choose to retain this image if they have a use for it - delete Obj; - } - + virtual ObjectImage *createObjectImage(ObjectBuffer *InputBuffer); public: RuntimeDyldImpl(RTDyldMemoryManager *mm) : MemMgr(mm), HasError(false) {} virtual ~RuntimeDyldImpl(); - bool loadObject(const MemoryBuffer *InputBuffer); + ObjectImage *loadObject(ObjectBuffer *InputBuffer); void *getSymbolAddress(StringRef Name) { // FIXME: Just look up as a function for now. Overly simple of course. @@ -265,11 +311,20 @@ public: return getSectionAddress(Loc.first) + Loc.second; } + uint64_t getSymbolLoadAddress(StringRef Name) { + // FIXME: Just look up as a function for now. Overly simple of course. + // Work in progress. + if (GlobalSymbolTable.find(Name) == GlobalSymbolTable.end()) + return 0; + SymbolLoc Loc = GlobalSymbolTable.lookup(Name); + return getSectionLoadAddress(Loc.first) + Loc.second; + } + void resolveRelocations(); void reassignSectionAddress(unsigned SectionID, uint64_t Addr); - void mapSectionAddress(void *LocalAddress, uint64_t TargetAddress); + void mapSectionAddress(const void *LocalAddress, uint64_t TargetAddress); // Is the linker in an error state? bool hasError() { return HasError; } @@ -280,8 +335,7 @@ public: // Get the error message. StringRef getErrorString() { return ErrorStr; } - virtual bool isCompatibleFormat(const MemoryBuffer *InputBuffer) const = 0; - + virtual bool isCompatibleFormat(const ObjectBuffer *Buffer) const = 0; }; } // end namespace llvm diff --git a/contrib/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.cpp b/contrib/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.cpp index 0e3a9d4..987c0c3 100644 --- a/contrib/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.cpp +++ b/contrib/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.cpp @@ -21,11 +21,13 @@ using namespace llvm::object; namespace llvm { -void RuntimeDyldMachO::resolveRelocation(uint8_t *LocalAddress, - uint64_t FinalAddress, +void RuntimeDyldMachO::resolveRelocation(const SectionEntry &Section, + uint64_t Offset, uint64_t Value, uint32_t Type, int64_t Addend) { + uint8_t *LocalAddress = Section.Address + Offset; + uint64_t FinalAddress = Section.LoadAddress + Offset; bool isPCRel = (Type >> 24) & 1; unsigned MachoType = (Type >> 28) & 0xf; unsigned Size = 1 << ((Type >> 25) & 3); @@ -57,7 +59,7 @@ void RuntimeDyldMachO::resolveRelocation(uint8_t *LocalAddress, FinalAddress, (uintptr_t)Value, isPCRel, - Type, + MachoType, Size, Addend); break; @@ -211,7 +213,6 @@ void RuntimeDyldMachO::processRelocationRef(const ObjRelocationInfo &Rel, uint32_t RelType = (uint32_t) (Rel.Type & 0xffffffffL); RelocationValueRef Value; SectionEntry &Section = Sections[Rel.SectionID]; - uint8_t *Target = Section.Address + Rel.Offset; bool isExtern = (RelType >> 27) & 1; if (isExtern) { @@ -246,7 +247,12 @@ void RuntimeDyldMachO::processRelocationRef(const ObjRelocationInfo &Rel, } assert(si != se && "No section containing relocation!"); Value.SectionID = findOrEmitSection(Obj, *si, true, ObjSectionToID); - Value.Addend = *(const intptr_t *)Target; + Value.Addend = 0; + // FIXME: The size and type of the relocation determines if we can + // encode an Addend in the target location itself, and if so, how many + // bytes we should read in order to get it. We don't yet support doing + // that, and just assuming it's sizeof(intptr_t) is blatantly wrong. + //Value.Addend = *(const intptr_t *)Target; if (Value.Addend) { // The MachO addend is an offset from the current section. We need it // to be an offset from the destination section @@ -254,13 +260,13 @@ void RuntimeDyldMachO::processRelocationRef(const ObjRelocationInfo &Rel, } } - if (Arch == Triple::arm && RelType == macho::RIT_ARM_Branch24Bit) { + if (Arch == Triple::arm && (RelType & 0xf) == macho::RIT_ARM_Branch24Bit) { // This is an ARM branch relocation, need to use a stub function. // Look up for existing stub. StubMap::const_iterator i = Stubs.find(Value); if (i != Stubs.end()) - resolveRelocation(Target, (uint64_t)Target, + resolveRelocation(Section, Rel.Offset, (uint64_t)Section.Address + i->second, RelType, 0); else { @@ -274,7 +280,7 @@ void RuntimeDyldMachO::processRelocationRef(const ObjRelocationInfo &Rel, addRelocationForSymbol(RE, Value.SymbolName); else addRelocationForSection(RE, Value.SectionID); - resolveRelocation(Target, (uint64_t)Target, + resolveRelocation(Section, Rel.Offset, (uint64_t)Section.Address + Section.StubOffset, RelType, 0); Section.StubOffset += getMaxStubSize(); @@ -290,8 +296,10 @@ void RuntimeDyldMachO::processRelocationRef(const ObjRelocationInfo &Rel, bool RuntimeDyldMachO::isCompatibleFormat( - const MemoryBuffer *InputBuffer) const { - StringRef Magic = InputBuffer->getBuffer().slice(0, 4); + const ObjectBuffer *InputBuffer) const { + if (InputBuffer->getBufferSize() < 4) + return false; + StringRef Magic(InputBuffer->getBufferStart(), 4); if (Magic == "\xFE\xED\xFA\xCE") return true; if (Magic == "\xCE\xFA\xED\xFE") return true; if (Magic == "\xFE\xED\xFA\xCF") return true; diff --git a/contrib/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.h b/contrib/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.h index 707664c..fe3539d 100644 --- a/contrib/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.h +++ b/contrib/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.h @@ -55,15 +55,15 @@ protected: StubMap &Stubs); public: - virtual void resolveRelocation(uint8_t *LocalAddress, - uint64_t FinalAddress, + virtual void resolveRelocation(const SectionEntry &Section, + uint64_t Offset, uint64_t Value, uint32_t Type, int64_t Addend); RuntimeDyldMachO(RTDyldMemoryManager *mm) : RuntimeDyldImpl(mm) {} - bool isCompatibleFormat(const MemoryBuffer *InputBuffer) const; + bool isCompatibleFormat(const ObjectBuffer *Buffer) const; }; } // end namespace llvm |