From f00677d74f1be5b4c7c73e1681a64c9062f4c7ee Mon Sep 17 00:00:00 2001 From: Tim Northover Date: Mon, 29 Oct 2012 10:47:04 +0000 Subject: [PATCH] Make use of common-symbol alignment info in ELF loader. Patch by Amara Emerson. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@166919 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../RuntimeDyld/RuntimeDyld.cpp | 31 +++++++++--------- .../RuntimeDyld/RuntimeDyldELF.cpp | 7 ++++ .../RuntimeDyld/RuntimeDyldELF.h | 14 +++++++- .../RuntimeDyld/RuntimeDyldImpl.h | 13 ++++++-- .../MCJIT/test-common-symbols-alignment.ll | 32 +++++++++++++++++++ 5 files changed, 79 insertions(+), 18 deletions(-) create mode 100644 test/ExecutionEngine/MCJIT/test-common-symbols-alignment.ll diff --git a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp index ff05c82aecb..fb07cb90218 100644 --- a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp +++ b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp @@ -17,6 +17,7 @@ #include "RuntimeDyldELF.h" #include "RuntimeDyldMachO.h" #include "llvm/Support/Path.h" +#include "llvm/Support/MathExtras.h" using namespace llvm; using namespace llvm::object; @@ -27,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. @@ -78,9 +69,9 @@ ObjectImage *RuntimeDyldImpl::loadObject(ObjectBuffer *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; @@ -100,10 +91,11 @@ ObjectImage *RuntimeDyldImpl::loadObject(ObjectBuffer *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 || @@ -201,11 +193,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("0x%x\n", Addr)); + } Obj.updateSymbolAddress(it->first, (uint64_t)Addr); SymbolTable[Name.data()] = SymbolLoc(SectionID, Offset); - uint64_t Size = it->second; Offset += Size; Addr += Size; } diff --git a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp index 1073c6fc522..b9c5f8b8647 100644 --- a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp +++ b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp @@ -796,6 +796,13 @@ void RuntimeDyldELF::processRelocationRef(const ObjRelocationInfo &Rel, } } +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; diff --git a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h index 6c31f0dc122..cbdc0dbc6b7 100644 --- a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h +++ b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h @@ -18,8 +18,18 @@ 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: void resolveX86_64Relocation(uint8_t *LocalAddress, @@ -64,6 +74,8 @@ protected: const SymbolTableMap &Symbols, StubMap &Stubs); + unsigned getCommonSymbolAlignment(const SymbolRef &Sym); + virtual ObjectImage *createObjectImage(ObjectBuffer *InputBuffer); uint64_t findPPC64TOC() const; diff --git a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h index 45633e735c6..3baec3cf2a1 100644 --- a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h +++ b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h @@ -140,8 +140,10 @@ protected: typedef StringMap SymbolTableMap; SymbolTableMap GlobalSymbolTable; - // Keep a map of common symbols to their sizes - typedef std::map CommonSymbolMap; + // Pair representing the size and alignment requirement for a common symbol. + typedef std::pair CommonSymbolInfo; + // Keep a map of common symbols to their info pairs + typedef std::map 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.), @@ -192,6 +194,13 @@ protected: 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); diff --git a/test/ExecutionEngine/MCJIT/test-common-symbols-alignment.ll b/test/ExecutionEngine/MCJIT/test-common-symbols-alignment.ll new file mode 100644 index 00000000000..d666a2aa4aa --- /dev/null +++ b/test/ExecutionEngine/MCJIT/test-common-symbols-alignment.ll @@ -0,0 +1,32 @@ +; RUN: %lli -mtriple=%mcjit_triple -use-mcjit -O0 %s + +; This test checks that common symbols have been allocated addresses honouring +; the alignment requirement. + +@CS1 = common global i32 0, align 16 +@CS2 = common global i8 0, align 1 +@CS3 = common global i32 0, align 16 + +define i32 @main() nounwind { +entry: + %retval = alloca i32, align 4 + %ptr = alloca i32, align 4 + store i32 0, i32* %retval + store i32 ptrtoint (i32* @CS3 to i32), i32* %ptr, align 4 + %0 = load i32* %ptr, align 4 + %and = and i32 %0, 15 + %tobool = icmp ne i32 %and, 0 + br i1 %tobool, label %if.then, label %if.else + +if.then: ; preds = %entry + store i32 1, i32* %retval + br label %return + +if.else: ; preds = %entry + store i32 0, i32* %retval + br label %return + +return: ; preds = %if.else, %if.then + %1 = load i32* %retval + ret i32 %1 +} -- 2.34.1