From 67868b57912b4624ed4c1b0ad5673917800b1301 Mon Sep 17 00:00:00 2001 From: Lang Hames Date: Thu, 11 Sep 2014 19:21:14 +0000 Subject: [PATCH] [MCJIT] Add support for ARM HALF_DIFF relocations to MCJIT. Fixes . git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@217620 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../RuntimeDyld/RuntimeDyldMachO.cpp | 58 +++++++++ .../RuntimeDyld/RuntimeDyldMachO.h | 10 ++ .../RuntimeDyld/Targets/RuntimeDyldMachOARM.h | 116 +++++++++++++++++- .../Targets/RuntimeDyldMachOI386.h | 57 +-------- .../ARM/MachO_ARM_PIC_relocations.s | 34 ++--- 5 files changed, 202 insertions(+), 73 deletions(-) diff --git a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.cpp b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.cpp index 8e78317669a..c57f7763156 100644 --- a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.cpp +++ b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.cpp @@ -108,6 +108,64 @@ void RuntimeDyldMachO::dumpRelocationToResolve(const RelocationEntry &RE, << " Size: " << (1 << RE.Size) << "\n"; } +section_iterator +RuntimeDyldMachO::getSectionByAddress(const MachOObjectFile &Obj, + uint64_t Addr) { + section_iterator SI = Obj.section_begin(); + section_iterator SE = Obj.section_end(); + + for (; SI != SE; ++SI) { + uint64_t SAddr, SSize; + SI->getAddress(SAddr); + SI->getSize(SSize); + if ((Addr >= SAddr) && (Addr < SAddr + SSize)) + return SI; + } + + return SE; +} + + +// Populate __pointers section. +void RuntimeDyldMachO::populateIndirectSymbolPointersSection( + MachOObjectFile &Obj, + const SectionRef &PTSection, + unsigned PTSectionID) { + assert(!Obj.is64Bit() && + "Pointer table section not supported in 64-bit MachO."); + + MachO::dysymtab_command DySymTabCmd = Obj.getDysymtabLoadCommand(); + MachO::section Sec32 = Obj.getSection(PTSection.getRawDataRefImpl()); + uint32_t PTSectionSize = Sec32.size; + unsigned FirstIndirectSymbol = Sec32.reserved1; + const unsigned PTEntrySize = 4; + unsigned NumPTEntries = PTSectionSize / PTEntrySize; + unsigned PTEntryOffset = 0; + + assert((PTSectionSize % PTEntrySize) == 0 && + "Pointers section does not contain a whole number of stubs?"); + + DEBUG(dbgs() << "Populating pointer table section " + << Sections[PTSectionID].Name + << ", Section ID " << PTSectionID << ", " + << NumPTEntries << " entries, " << PTEntrySize + << " bytes each:\n"); + + for (unsigned i = 0; i < NumPTEntries; ++i) { + unsigned SymbolIndex = + Obj.getIndirectSymbolTableEntry(DySymTabCmd, FirstIndirectSymbol + i); + symbol_iterator SI = Obj.getSymbolByIndex(SymbolIndex); + StringRef IndirectSymbolName; + SI->getName(IndirectSymbolName); + DEBUG(dbgs() << " " << IndirectSymbolName << ": index " << SymbolIndex + << ", PT offset: " << PTEntryOffset << "\n"); + RelocationEntry RE(PTSectionID, PTEntryOffset, + MachO::GENERIC_RELOC_VANILLA, 0, false, 2); + addRelocationForSymbol(RE, IndirectSymbolName); + PTEntryOffset += PTEntrySize; + } +} + bool RuntimeDyldMachO::isCompatibleFormat(const ObjectBuffer *InputBuffer) const { if (InputBuffer->getBufferSize() < 4) diff --git a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.h b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.h index 3b5faab6381..7583474757d 100644 --- a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.h +++ b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.h @@ -101,6 +101,16 @@ protected: /// Dump information about the relocation entry (RE) and resolved value. void dumpRelocationToResolve(const RelocationEntry &RE, uint64_t Value) const; + // Return a section iterator for the section containing the given address. + static section_iterator getSectionByAddress(const MachOObjectFile &Obj, + uint64_t Addr); + + + // Populate __pointers section. + void populateIndirectSymbolPointersSection(MachOObjectFile &Obj, + const SectionRef &PTSection, + unsigned PTSectionID); + public: /// Create an ObjectImage from the given ObjectBuffer. static std::unique_ptr diff --git a/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOARM.h b/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOARM.h index dc8acfef5b7..150b14bfdb4 100644 --- a/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOARM.h +++ b/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOARM.h @@ -56,9 +56,15 @@ public: static_cast(*ObjImg.getObjectFile()); MachO::any_relocation_info RelInfo = Obj.getRelocation(RelI->getRawDataRefImpl()); + uint32_t RelType = Obj.getAnyRelocationType(RelInfo); - if (Obj.isRelocationScattered(RelInfo)) - return ++++RelI; + if (Obj.isRelocationScattered(RelInfo)) { + if (RelType == MachO::ARM_RELOC_HALF_SECTDIFF) + return processHALFSECTDIFFRelocation(SectionID, RelI, ObjImg, + ObjSectionToID); + else + return ++++RelI; + } RelocationEntry RE(getRelocationEntry(SectionID, ObjImg, RelI)); RE.Addend = decodeAddend(RE); @@ -120,10 +126,26 @@ public: *p = (*p & ~0xffffff) | FinalValue; break; } + case MachO::ARM_RELOC_HALF_SECTDIFF: { + uint64_t SectionABase = Sections[RE.Sections.SectionA].LoadAddress; + uint64_t SectionBBase = Sections[RE.Sections.SectionB].LoadAddress; + assert((Value == SectionABase || Value == SectionBBase) && + "Unexpected HALFSECTDIFF relocation value."); + Value = SectionABase - SectionBBase + RE.Addend; + if (RE.Size & 0x1) // :upper16: + Value = (Value >> 16); + Value &= 0xffff; + + uint32_t Insn; + memcpy(&Insn, LocalAddress, 4); + Insn = (Insn & 0xfff0f000) | ((Value & 0xf000) << 4) | (Value & 0x0fff); + memcpy(LocalAddress, &Insn, 4); + break; + } + case MachO::ARM_THUMB_RELOC_BR22: case MachO::ARM_THUMB_32BIT_BRANCH: case MachO::ARM_RELOC_HALF: - case MachO::ARM_RELOC_HALF_SECTDIFF: case MachO::ARM_RELOC_PAIR: case MachO::ARM_RELOC_SECTDIFF: case MachO::ARM_RELOC_LOCAL_SECTDIFF: @@ -134,9 +156,18 @@ public: } void finalizeSection(ObjectImage &ObjImg, unsigned SectionID, - const SectionRef &Section) {} + const SectionRef &Section) { + StringRef Name; + Section.getName(Name); + + if (Name == "__nl_symbol_ptr") + populateIndirectSymbolPointersSection( + cast(*ObjImg.getObjectFile()), + Section, SectionID); + } private: + void processBranchRelocation(const RelocationEntry &RE, const RelocationValueRef &Value, StubMap &Stubs) { @@ -166,6 +197,83 @@ private: RE.IsPCRel, RE.Size); resolveRelocation(TargetRE, (uint64_t)Addr); } + + relocation_iterator + processHALFSECTDIFFRelocation(unsigned SectionID, relocation_iterator RelI, + ObjectImage &Obj, + ObjSectionToIDMap &ObjSectionToID) { + const MachOObjectFile *MachO = + static_cast(Obj.getObjectFile()); + MachO::any_relocation_info RE = + MachO->getRelocation(RelI->getRawDataRefImpl()); + + + // For a half-diff relocation the length bits actually record whether this + // is a movw/movt, and whether this is arm or thumb. + // Bit 0 indicates movw (b0 == 0) or movt (b0 == 1). + // Bit 1 indicates arm (b1 == 0) or thumb (b1 == 1). + unsigned HalfDiffKindBits = MachO->getAnyRelocationLength(RE); + if (HalfDiffKindBits & 0x2) + llvm_unreachable("Thumb not yet supported."); + + SectionEntry &Section = Sections[SectionID]; + uint32_t RelocType = MachO->getAnyRelocationType(RE); + bool IsPCRel = MachO->getAnyRelocationPCRel(RE); + uint64_t Offset; + RelI->getOffset(Offset); + uint8_t *LocalAddress = Section.Address + Offset; + int64_t Immediate = 0; + memcpy(&Immediate, LocalAddress, 4); // Copy the whole instruction out. + Immediate = ((Immediate >> 4) & 0xf000) | (Immediate & 0xfff); + + ++RelI; + MachO::any_relocation_info RE2 = + MachO->getRelocation(RelI->getRawDataRefImpl()); + uint32_t AddrA = MachO->getScatteredRelocationValue(RE); + section_iterator SAI = getSectionByAddress(*MachO, AddrA); + assert(SAI != MachO->section_end() && "Can't find section for address A"); + uint64_t SectionABase; + SAI->getAddress(SectionABase); + uint64_t SectionAOffset = AddrA - SectionABase; + SectionRef SectionA = *SAI; + bool IsCode; + SectionA.isText(IsCode); + uint32_t SectionAID = + findOrEmitSection(Obj, SectionA, IsCode, ObjSectionToID); + + uint32_t AddrB = MachO->getScatteredRelocationValue(RE2); + section_iterator SBI = getSectionByAddress(*MachO, AddrB); + assert(SBI != MachO->section_end() && "Can't find section for address B"); + uint64_t SectionBBase; + SBI->getAddress(SectionBBase); + uint64_t SectionBOffset = AddrB - SectionBBase; + SectionRef SectionB = *SBI; + uint32_t SectionBID = + findOrEmitSection(Obj, SectionB, IsCode, ObjSectionToID); + + uint32_t OtherHalf = MachO->getAnyRelocationAddress(RE2) & 0xffff; + unsigned Shift = (HalfDiffKindBits & 0x1) ? 16 : 0; + uint32_t FullImmVal = (Immediate << Shift) | (OtherHalf << (16 - Shift)); + int64_t Addend = FullImmVal - (AddrA - AddrB); + + // addend = Encoded - Expected + // = Encoded - (AddrA - AddrB) + + DEBUG(dbgs() << "Found SECTDIFF: AddrA: " << AddrA << ", AddrB: " << AddrB + << ", Addend: " << Addend << ", SectionA ID: " << SectionAID + << ", SectionAOffset: " << SectionAOffset + << ", SectionB ID: " << SectionBID + << ", SectionBOffset: " << SectionBOffset << "\n"); + RelocationEntry R(SectionID, Offset, RelocType, Addend, SectionAID, + SectionAOffset, SectionBID, SectionBOffset, IsPCRel, + HalfDiffKindBits); + + addRelocationForSection(R, SectionAID); + addRelocationForSection(R, SectionBID); + + return ++RelI; + } + }; } diff --git a/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOI386.h b/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOI386.h index 2c111c82596..977128737dd 100644 --- a/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOI386.h +++ b/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOI386.h @@ -119,8 +119,9 @@ public: populateJumpTable(cast(*ObjImg.getObjectFile()), Section, SectionID); else if (Name == "__pointers") - populatePointersSection(cast(*ObjImg.getObjectFile()), - Section, SectionID); + populateIndirectSymbolPointersSection( + cast(*ObjImg.getObjectFile()), + Section, SectionID); } private: @@ -259,58 +260,6 @@ private: } } - // Populate __pointers section. - void populatePointersSection(MachOObjectFile &Obj, - const SectionRef &PTSection, - unsigned PTSectionID) { - assert(!Obj.is64Bit() && - "__pointers section not supported in 64-bit MachO."); - - MachO::dysymtab_command DySymTabCmd = Obj.getDysymtabLoadCommand(); - MachO::section Sec32 = Obj.getSection(PTSection.getRawDataRefImpl()); - uint32_t PTSectionSize = Sec32.size; - unsigned FirstIndirectSymbol = Sec32.reserved1; - const unsigned PTEntrySize = 4; - unsigned NumPTEntries = PTSectionSize / PTEntrySize; - unsigned PTEntryOffset = 0; - - assert((PTSectionSize % PTEntrySize) == 0 && - "Pointers section does not contain a whole number of stubs?"); - - DEBUG(dbgs() << "Populating __pointers, Section ID " << PTSectionID << ", " - << NumPTEntries << " entries, " << PTEntrySize - << " bytes each:\n"); - - for (unsigned i = 0; i < NumPTEntries; ++i) { - unsigned SymbolIndex = - Obj.getIndirectSymbolTableEntry(DySymTabCmd, FirstIndirectSymbol + i); - symbol_iterator SI = Obj.getSymbolByIndex(SymbolIndex); - StringRef IndirectSymbolName; - SI->getName(IndirectSymbolName); - DEBUG(dbgs() << " " << IndirectSymbolName << ": index " << SymbolIndex - << ", PT offset: " << PTEntryOffset << "\n"); - RelocationEntry RE(PTSectionID, PTEntryOffset, - MachO::GENERIC_RELOC_VANILLA, 0, false, 2); - addRelocationForSymbol(RE, IndirectSymbolName); - PTEntryOffset += PTEntrySize; - } - } - - static section_iterator getSectionByAddress(const MachOObjectFile &Obj, - uint64_t Addr) { - section_iterator SI = Obj.section_begin(); - section_iterator SE = Obj.section_end(); - - for (; SI != SE; ++SI) { - uint64_t SAddr, SSize; - SI->getAddress(SAddr); - SI->getSize(SSize); - if ((Addr >= SAddr) && (Addr < SAddr + SSize)) - return SI; - } - - return SE; - } }; } diff --git a/test/ExecutionEngine/RuntimeDyld/ARM/MachO_ARM_PIC_relocations.s b/test/ExecutionEngine/RuntimeDyld/ARM/MachO_ARM_PIC_relocations.s index 2dc776cd447..6cad361ab23 100644 --- a/test/ExecutionEngine/RuntimeDyld/ARM/MachO_ARM_PIC_relocations.s +++ b/test/ExecutionEngine/RuntimeDyld/ARM/MachO_ARM_PIC_relocations.s @@ -1,21 +1,21 @@ # RUN: llvm-mc -triple=armv7s-apple-ios7.0.0 -relocation-model=pic -filetype=obj -o %T/foo.o %s # RUN: llvm-rtdyld -triple=armv7s-apple-ios7.0.0 -verify -check=%s %/T/foo.o - .syntax unified - .section __TEXT,__text,regular,pure_instructions - .globl bar - .align 2 + .syntax unified + .section __TEXT,__text,regular,pure_instructions + .globl bar + .align 2 bar: # Check lower 16-bits of section difference relocation -# rtdyld-check: decode_operand(insn1, 1) = (foo-(nextPC+8))[15:0] +# rtdyld-check: decode_operand(insn1, 1) = (foo$non_lazy_ptr-(nextPC+8))[15:0] insn1: - movw r0, :lower16:(foo-(nextPC+8)) + movw r0, :lower16:(foo$non_lazy_ptr-(nextPC+8)) # Check upper 16-bits of section difference relocation -# rtdyld-check: decode_operand(insn2, 2) = (foo-(nextPC+8))[31:16] +# rtdyld-check: decode_operand(insn2, 2) = (foo$non_lazy_ptr-(nextPC+8))[31:16] insn2: - movt r0, :upper16:(foo-(nextPC+8)) + movt r0, :upper16:(foo$non_lazy_ptr-(nextPC+8)) nextPC: - add r0, pc, r0 + add r1, r0, r0 # Check stub generation by referencing a common symbol, 'baz'. Check both the # Content of the stub, and the reference to the stub. @@ -27,16 +27,20 @@ nextPC: # rtdyld-check: decode_operand(insn3, 0) = stub_addr(foo.o, __text, baz) - (insn3 + 8) insn3: bl baz - bx lr - - .globl foo - .align 2 -foo: - bx lr + bx lr # Add 'aaa' to the common symbols to make sure 'baz' isn't at the start of the # section. This ensures that we test VANILLA relocation addends correctly. .comm aaa, 4, 2 .comm baz, 4, 2 + .comm foo, 4, 2 + +# Check that the symbol pointer section entries are fixed up properly: +# rtdyld-check: *{4}foo$non_lazy_ptr = foo + .section __DATA,__nl_symbol_ptr,non_lazy_symbol_pointers + .align 2 +foo$non_lazy_ptr: + .indirect_symbol foo + .long 0 .subsections_via_symbols -- 2.34.1