Kaylor, Andrew
2015-Jan-26 21:59 UTC
[LLVMdev] [llvm] r188726 - Adding PIC support for ELF on x86_64 platforms
Hi Lang, Yeah, I remember this case. Basically what’s happening is that there are relocations for ELF on x86 that use a value that is present in the object image as part of the calculation for the final value that goes in the same location. If you ever find yourself applying relocations for a second time (for instance, because the loaded object location is remapped for out-of-proc execution) the original value is no longer in the loaded object. You could probably figure out a way to combine the placeholder value with the addend field, either while the relocation records are being built (though I’m not sure if the relevant sections have been loaded yet at that point) or the first time the relocation is applied (though it might be a bit cumbersome to know whether or not any given application was the first). -Andy From: Lang Hames [mailto:lhames at gmail.com] Sent: Monday, January 26, 2015 1:14 PM To: Kaylor, Andrew Cc: Commit Messages and Patches for LLVM Subject: Re: [llvm] r188726 - Adding PIC support for ELF on x86_64 platforms Hi Andy, In the following snippet, do you recall what made it necessary to read the value from the object file via Placeholder, rather than from the copied section? + // Get the placeholder value from the generated object since + // a previous relocation attempt may have overwritten the loaded version + uint64_t *Placeholder = reinterpret_cast<uint64_t*>(Section.ObjAddress + + Offset); + uint64_t *Target = reinterpret_cast<uint64_t*>(Section.Address + Offset); + uint64_t FinalAddress = Section.LoadAddress + Offset; + *Target = *Placeholder + Value + Addend - FinalAddress; + break; I''d like to make my new JIT APIs more aggressive about freeing the ObjectFile instances (ideally we'd be able to free immediately after a call to loadObject), but at the moment I have to hold it at least until resolveRelocations is called. I had a quick chat with Tim Northover about this and our guess was that it had something to do with relocations being applied more than once? Cheers, Lang. On Mon, Aug 19, 2013 at 4:27 PM, Andrew Kaylor <andrew.kaylor at intel.com<mailto:andrew.kaylor at intel.com>> wrote: Author: akaylor Date: Mon Aug 19 18:27:43 2013 New Revision: 188726 URL: http://llvm.org/viewvc/llvm-project?rev=188726&view=rev Log: Adding PIC support for ELF on x86_64 platforms Modified: llvm/trunk/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp llvm/trunk/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp llvm/trunk/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h llvm/trunk/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h Modified: llvm/trunk/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp?rev=188726&r1=188725&r2=188726&view=diff =============================================================================--- llvm/trunk/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp (original) +++ llvm/trunk/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp Mon Aug 19 18:27:43 2013 @@ -169,6 +169,9 @@ ObjectImage *RuntimeDyldImpl::loadObject } } + // Give the subclasses a chance to tie-up any loose ends. + finalizeLoad(); + return obj.take(); } @@ -424,6 +427,10 @@ uint8_t *RuntimeDyldImpl::createStubFunc writeInt16BE(Addr+6, 0x07F1); // brc 15,%r1 // 8-byte address stored at Addr + 8 return Addr; + } else if (Arch == Triple::x86_64) { + *Addr = 0xFF; // jmp + *(Addr+1) = 0x25; // rip + // 32-bit PC-relative address of the GOT entry will be stored at Addr+2 } return Addr; } @@ -473,6 +480,7 @@ void RuntimeDyldImpl::resolveExternalSym // MemoryManager. uint8_t *Addr = (uint8_t*) MemMgr->getPointerToNamedFunction(Name.data(), true); + updateGOTEntries(Name, (uint64_t)Addr); DEBUG(dbgs() << "Resolving relocations Name: " << Name << "\t" << format("%p", Addr) << "\n"); Modified: llvm/trunk/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp?rev=188726&r1=188725&r2=188726&view=diff =============================================================================--- llvm/trunk/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp (original) +++ llvm/trunk/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp Mon Aug 19 18:27:43 2013 @@ -202,7 +202,8 @@ void RuntimeDyldELF::resolveX86_64Reloca uint64_t Offset, uint64_t Value, uint32_t Type, - int64_t Addend) { + int64_t Addend, + uint64_t SymOffset) { switch (Type) { default: llvm_unreachable("Relocation type not implemented yet!"); @@ -227,6 +228,21 @@ void RuntimeDyldELF::resolveX86_64Reloca << " at " << format("%p\n",Target)); break; } + case ELF::R_X86_64_GOTPCREL: { + // findGOTEntry returns the 'G + GOT' part of the relocation calculation + // based on the load/target address of the GOT (not the current/local addr). + uint64_t GOTAddr = findGOTEntry(Value, SymOffset); + uint32_t *Target = reinterpret_cast<uint32_t*>(Section.Address + Offset); + uint64_t FinalAddress = Section.LoadAddress + Offset; + // The processRelocationRef method combines the symbol offset and the addend + // and in most cases that's what we want. For this relocation type, we need + // the raw addend, so we subtract the symbol offset to get it. + int64_t RealOffset = GOTAddr + Addend - SymOffset - FinalAddress; + assert(RealOffset <= INT32_MAX && RealOffset >= INT32_MIN); + int32_t TruncOffset = (RealOffset & 0xFFFFFFFF); + *Target = TruncOffset; + break; + } case ELF::R_X86_64_PC32: { // Get the placeholder value from the generated object since // a previous relocation attempt may have overwritten the loaded version @@ -240,6 +256,16 @@ void RuntimeDyldELF::resolveX86_64Reloca *Target = TruncOffset; break; } + case ELF::R_X86_64_PC64: { + // Get the placeholder value from the generated object since + // a previous relocation attempt may have overwritten the loaded version + uint64_t *Placeholder = reinterpret_cast<uint64_t*>(Section.ObjAddress + + Offset); + uint64_t *Target = reinterpret_cast<uint64_t*>(Section.Address + Offset); + uint64_t FinalAddress = Section.LoadAddress + Offset; + *Target = *Placeholder + Value + Addend - FinalAddress; + break; + } } } @@ -584,7 +610,7 @@ void RuntimeDyldELF::findOPDEntrySection // 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) + if (Rel.Addend != (int64_t)TargetSymbolOffset) continue; section_iterator tsi(Obj.end_sections()); @@ -757,17 +783,19 @@ void RuntimeDyldELF::resolveSystemZReloc void RuntimeDyldELF::resolveRelocation(const RelocationEntry &RE, uint64_t Value) { const SectionEntry &Section = Sections[RE.SectionID]; - return resolveRelocation(Section, RE.Offset, Value, RE.RelType, RE.Addend); + return resolveRelocation(Section, RE.Offset, Value, RE.RelType, RE.Addend, + RE.SymOffset); } void RuntimeDyldELF::resolveRelocation(const SectionEntry &Section, uint64_t Offset, uint64_t Value, uint32_t Type, - int64_t Addend) { + int64_t Addend, + uint64_t SymOffset) { switch (Arch) { case Triple::x86_64: - resolveX86_64Relocation(Section, Offset, Value, Type, Addend); + resolveX86_64Relocation(Section, Offset, Value, Type, Addend, SymOffset); break; case Triple::x86: resolveX86Relocation(Section, Offset, @@ -830,6 +858,7 @@ void RuntimeDyldELF::processRelocationRe } if (lsi != Symbols.end()) { Value.SectionID = lsi->second.first; + Value.Offset = lsi->second.second; Value.Addend = lsi->second.second + Addend; } else { // Search for the symbol in the global symbol table @@ -838,6 +867,7 @@ void RuntimeDyldELF::processRelocationRe gsi = GlobalSymbolTable.find(TargetName.data()); if (gsi != GlobalSymbolTable.end()) { Value.SectionID = gsi->second.first; + Value.Offset = gsi->second.second; Value.Addend = gsi->second.second + Addend; } else { switch (SymType) { @@ -860,6 +890,7 @@ void RuntimeDyldELF::processRelocationRe Value.Addend = Addend; break; } + case SymbolRef::ST_Data: case SymbolRef::ST_Unknown: { Value.SymbolName = TargetName.data(); Value.Addend = Addend; @@ -1150,8 +1181,67 @@ void RuntimeDyldELF::processRelocationRe ELF::R_390_PC32DBL, Addend); else resolveRelocation(Section, Offset, StubAddress, RelType, Addend); + } else if (Arch == Triple::x86_64 && RelType == ELF::R_X86_64_PLT32) { + // The way the PLT relocations normally work is that the linker allocates the + // PLT and this relocation makes a PC-relative call into the PLT. The PLT + // entry will then jump to an address provided by the GOT. On first call, the + // GOT address will point back into PLT code that resolves the symbol. After + // the first call, the GOT entry points to the actual function. + // + // For local functions we're ignoring all of that here and just replacing + // the PLT32 relocation type with PC32, which will translate the relocation + // into a PC-relative call directly to the function. For external symbols we + // can't be sure the function will be within 2^32 bytes of the call site, so + // we need to create a stub, which calls into the GOT. This case is + // equivalent to the usual PLT implementation except that we use the stub + // mechanism in RuntimeDyld (which puts stubs at the end of the section) + // rather than allocating a PLT section. + if (Value.SymbolName) { + // This is a call to an external function. + // Look for an existing stub. + SectionEntry &Section = Sections[SectionID]; + StubMap::const_iterator i = Stubs.find(Value); + uintptr_t StubAddress; + if (i != Stubs.end()) { + StubAddress = uintptr_t(Section.Address) + i->second; + DEBUG(dbgs() << " Stub function found\n"); + } else { + // Create a new stub function (equivalent to a PLT entry). + DEBUG(dbgs() << " Create a new stub function\n"); + + uintptr_t BaseAddress = uintptr_t(Section.Address); + uintptr_t StubAlignment = getStubAlignment(); + StubAddress = (BaseAddress + Section.StubOffset + + StubAlignment - 1) & -StubAlignment; + unsigned StubOffset = StubAddress - BaseAddress; + Stubs[Value] = StubOffset; + createStubFunction((uint8_t *)StubAddress); + + // Create a GOT entry for the external function. + GOTEntries.push_back(Value); + + // Make our stub function a relative call to the GOT entry. + RelocationEntry RE(SectionID, StubOffset + 2, + ELF::R_X86_64_GOTPCREL, -4); + addRelocationForSymbol(RE, Value.SymbolName); + + // Bump our stub offset counter + Section.StubOffset = StubOffset + getMaxStubSize(); + } + + // Make the target call a call into the stub table. + resolveRelocation(Section, Offset, StubAddress, + ELF::R_X86_64_PC32, Addend); + } else { + RelocationEntry RE(SectionID, Offset, ELF::R_X86_64_PC32, Value.Addend, + Value.Offset); + addRelocationForSection(RE, Value.SectionID); + } } else { - RelocationEntry RE(SectionID, Offset, RelType, Value.Addend); + if (Arch == Triple::x86_64 && RelType == ELF::R_X86_64_GOTPCREL) { + GOTEntries.push_back(Value); + } + RelocationEntry RE(SectionID, Offset, RelType, Value.Addend, Value.Offset); if (Value.SymbolName) addRelocationForSymbol(RE, Value.SymbolName); else @@ -1159,6 +1249,106 @@ void RuntimeDyldELF::processRelocationRe } } +void RuntimeDyldELF::updateGOTEntries(StringRef Name, uint64_t Addr) { + for (int i = 0, e = GOTEntries.size(); i != e; ++i) { + if (GOTEntries[i].SymbolName != 0 && GOTEntries[i].SymbolName == Name) { + GOTEntries[i].Offset = Addr; + } + } +} + +size_t RuntimeDyldELF::getGOTEntrySize() { + // We don't use the GOT in all of these cases, but it's essentially free + // to put them all here. + size_t Result = 0; + switch (Arch) { + case Triple::x86_64: + case Triple::aarch64: + case Triple::ppc64: + case Triple::ppc64le: + case Triple::systemz: + Result = sizeof(uint64_t); + break; + case Triple::x86: + case Triple::arm: + case Triple::thumb: + case Triple::mips: + case Triple::mipsel: + Result = sizeof(uint32_t); + break; + default: llvm_unreachable("Unsupported CPU type!"); + } + return Result; +} + +uint64_t RuntimeDyldELF::findGOTEntry(uint64_t LoadAddress, + uint64_t Offset) { + assert(GOTSectionID != 0 + && "Attempting to lookup GOT entry but the GOT was never allocated."); + if (GOTSectionID == 0) { + return 0; + } + + size_t GOTEntrySize = getGOTEntrySize(); + + // Find the matching entry in our vector. + int GOTIndex = -1; + uint64_t SymbolOffset = 0; + for (int i = 0, e = GOTEntries.size(); i != e; ++i) { + if (GOTEntries[i].SymbolName == 0) { + if (getSectionLoadAddress(GOTEntries[i].SectionID) == LoadAddress && + GOTEntries[i].Offset == Offset) { + GOTIndex = i; + SymbolOffset = GOTEntries[i].Offset; + break; + } + } else { + // GOT entries for external symbols use the addend as the address when + // the external symbol has been resolved. + if (GOTEntries[i].Offset == LoadAddress) { + GOTIndex = i; + // Don't use the Addend here. The relocation handler will use it. + break; + } + } + } + assert(GOTIndex != -1 && "Unable to find requested GOT entry."); + if (GOTIndex == -1) + return 0; + + if (GOTEntrySize == sizeof(uint64_t)) { + uint64_t *LocalGOTAddr = (uint64_t*)getSectionAddress(GOTSectionID); + // Fill in this entry with the address of the symbol being referenced. + LocalGOTAddr[GOTIndex] = LoadAddress + SymbolOffset; + } else { + uint32_t *LocalGOTAddr = (uint32_t*)getSectionAddress(GOTSectionID); + // Fill in this entry with the address of the symbol being referenced. + LocalGOTAddr[GOTIndex] = (uint32_t)(LoadAddress + SymbolOffset); + } + + // Calculate the load address of this entry + return getSectionLoadAddress(GOTSectionID) + (GOTIndex * GOTEntrySize); +} + +void RuntimeDyldELF::finalizeLoad() { + // Allocate the GOT if necessary + size_t numGOTEntries = GOTEntries.size(); + if (numGOTEntries != 0) { + // Allocate memory for the section + unsigned SectionID = Sections.size(); + size_t TotalSize = numGOTEntries * getGOTEntrySize(); + uint8_t *Addr = MemMgr->allocateDataSection(TotalSize, getGOTEntrySize(), + SectionID, false); + if (!Addr) + report_fatal_error("Unable to allocate memory for GOT!"); + Sections.push_back(SectionEntry(".got", Addr, TotalSize, 0)); + // For now, initialize all GOT entries to zero. We'll fill them in as + // needed when GOT-based relocations are applied. + memset(Addr, 0, TotalSize); + GOTSectionID = SectionID; + } +} + bool RuntimeDyldELF::isCompatibleFormat(const ObjectBuffer *Buffer) const { if (Buffer->getBufferSize() < strlen(ELF::ElfMagic)) return false; Modified: llvm/trunk/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h?rev=188726&r1=188725&r2=188726&view=diff =============================================================================--- llvm/trunk/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h (original) +++ llvm/trunk/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h Mon Aug 19 18:27:43 2013 @@ -35,13 +35,15 @@ class RuntimeDyldELF : public RuntimeDyl uint64_t Offset, uint64_t Value, uint32_t Type, - int64_t Addend); + int64_t Addend, + uint64_t SymOffset=0); void resolveX86_64Relocation(const SectionEntry &Section, uint64_t Offset, uint64_t Value, uint32_t Type, - int64_t Addend); + int64_t Addend, + uint64_t SymOffset); void resolveX86Relocation(const SectionEntry &Section, uint64_t Offset, @@ -84,8 +86,18 @@ class RuntimeDyldELF : public RuntimeDyl ObjSectionToIDMap &LocalSections, RelocationValueRef &Rel); + uint64_t findGOTEntry(uint64_t LoadAddr, uint64_t Offset); + size_t getGOTEntrySize(); + + virtual void updateGOTEntries(StringRef Name, uint64_t Addr); + + SmallVector<RelocationValueRef, 2> GOTEntries; + unsigned GOTSectionID; + public: - RuntimeDyldELF(RTDyldMemoryManager *mm) : RuntimeDyldImpl(mm) {} + RuntimeDyldELF(RTDyldMemoryManager *mm) : RuntimeDyldImpl(mm), + GOTSectionID(0) + {} virtual void resolveRelocation(const RelocationEntry &RE, uint64_t Value); virtual void processRelocationRef(unsigned SectionID, @@ -97,6 +109,7 @@ public: virtual bool isCompatibleFormat(const ObjectBuffer *Buffer) const; virtual ObjectImage *createObjectImage(ObjectBuffer *InputBuffer); virtual StringRef getEHFrameSection(); + virtual void finalizeLoad(); virtual ~RuntimeDyldELF(); }; Modified: llvm/trunk/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h?rev=188726&r1=188725&r2=188726&view=diff =============================================================================--- llvm/trunk/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h (original) +++ llvm/trunk/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h Mon Aug 19 18:27:43 2013 @@ -80,14 +80,18 @@ public: unsigned SectionID; /// Offset - offset into the section. - uintptr_t Offset; + uint64_t Offset; /// RelType - relocation type. uint32_t RelType; /// Addend - the relocation addend encoded in the instruction itself. Also /// used to make a relocation section relative instead of symbol relative. - intptr_t Addend; + int64_t Addend; + + /// SymOffset - Section offset of the relocation entry's symbol (used for GOT + /// lookup). + uint64_t SymOffset; /// True if this is a PCRel relocation (MachO specific). bool IsPCRel; @@ -97,20 +101,26 @@ public: RelocationEntry(unsigned id, uint64_t offset, uint32_t type, int64_t addend) : SectionID(id), Offset(offset), RelType(type), Addend(addend), - IsPCRel(false), Size(0) {} + SymOffset(0), IsPCRel(false), Size(0) {} + + RelocationEntry(unsigned id, uint64_t offset, uint32_t type, int64_t addend, + uint64_t symoffset) + : SectionID(id), Offset(offset), RelType(type), Addend(addend), + SymOffset(symoffset), IsPCRel(false), Size(0) {} RelocationEntry(unsigned id, uint64_t offset, uint32_t type, int64_t addend, bool IsPCRel, unsigned Size) : SectionID(id), Offset(offset), RelType(type), Addend(addend), - IsPCRel(IsPCRel), Size(Size) {} + SymOffset(0), IsPCRel(IsPCRel), Size(Size) {} }; class RelocationValueRef { public: unsigned SectionID; - intptr_t Addend; + uint64_t Offset; + int64_t Addend; const char *SymbolName; - RelocationValueRef(): SectionID(0), Addend(0), SymbolName(0) {} + RelocationValueRef(): SectionID(0), Offset(0), Addend(0), SymbolName(0) {} inline bool operator==(const RelocationValueRef &Other) const { return std::memcmp(this, &Other, sizeof(RelocationValueRef)) == 0; @@ -175,7 +185,7 @@ protected: else if (Arch == Triple::ppc64 || Arch == Triple::ppc64le) return 44; else if (Arch == Triple::x86_64) - return 8; // GOT + return 6; // 2-byte jmp instruction + 32-bit relative address else if (Arch == Triple::systemz) return 16; else @@ -292,6 +302,11 @@ protected: /// \brief Resolve relocations to external symbols. void resolveExternalSymbols(); + + /// \brief Update GOT entries for external symbols. + // The base class does nothing. ELF overrides this. + virtual void updateGOTEntries(StringRef Name, uint64_t Addr) {} + virtual ObjectImage *createObjectImage(ObjectBuffer *InputBuffer); public: RuntimeDyldImpl(RTDyldMemoryManager *mm) : MemMgr(mm), HasError(false) {} @@ -336,6 +351,8 @@ public: virtual bool isCompatibleFormat(const ObjectBuffer *Buffer) const = 0; virtual StringRef getEHFrameSection(); + + virtual void finalizeLoad() {} }; } // end namespace llvm _______________________________________________ llvm-commits mailing list llvm-commits at cs.uiuc.edu<mailto:llvm-commits at cs.uiuc.edu> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20150126/ee11bc95/attachment.html>
Lang Hames
2015-Jan-27 05:07 UTC
[LLVMdev] [llvm] r188726 - Adding PIC support for ELF on x86_64 platforms
Hi Andy, Thanks very much for the insight. I'll see if I can come up with a scheme to support reapplication without having the object file present. Cheers, Lang. On Mon, Jan 26, 2015 at 1:59 PM, Kaylor, Andrew <andrew.kaylor at intel.com> wrote:> Hi Lang, > > > > Yeah, I remember this case. Basically what’s happening is that there are > relocations for ELF on x86 that use a value that is present in the object > image as part of the calculation for the final value that goes in the same > location. If you ever find yourself applying relocations for a second time > (for instance, because the loaded object location is remapped for > out-of-proc execution) the original value is no longer in the loaded object. > > > > You could probably figure out a way to combine the placeholder value with > the addend field, either while the relocation records are being built > (though I’m not sure if the relevant sections have been loaded yet at that > point) or the first time the relocation is applied (though it might be a > bit cumbersome to know whether or not any given application was the first). > > > > -Andy > > > > > > *From:* Lang Hames [mailto:lhames at gmail.com] > *Sent:* Monday, January 26, 2015 1:14 PM > *To:* Kaylor, Andrew > *Cc:* Commit Messages and Patches for LLVM > *Subject:* Re: [llvm] r188726 - Adding PIC support for ELF on x86_64 > platforms > > > > Hi Andy, > > > > In the following snippet, do you recall what made it necessary to read the > value from the object file via Placeholder, rather than from the copied > section? > > > > + // Get the placeholder value from the generated object since > + // a previous relocation attempt may have overwritten the loaded > version > + uint64_t *Placeholder = reinterpret_cast<uint64_t*>(Section.ObjAddress > + + > Offset); > + uint64_t *Target = reinterpret_cast<uint64_t*>(Section.Address + > Offset); > + uint64_t FinalAddress = Section.LoadAddress + Offset; > + *Target = *Placeholder + Value + Addend - FinalAddress; > + break; > > > > I''d like to make my new JIT APIs more aggressive about freeing the > ObjectFile instances (ideally we'd be able to free immediately after a call > to loadObject), but at the moment I have to hold it at least until > resolveRelocations is called. > > > > I had a quick chat with Tim Northover about this and our guess was that it > had something to do with relocations being applied more than once? > > > > Cheers, > > Lang. > > > > > > On Mon, Aug 19, 2013 at 4:27 PM, Andrew Kaylor <andrew.kaylor at intel.com> > wrote: > > Author: akaylor > Date: Mon Aug 19 18:27:43 2013 > New Revision: 188726 > > URL: http://llvm.org/viewvc/llvm-project?rev=188726&view=rev > Log: > Adding PIC support for ELF on x86_64 platforms > > Modified: > llvm/trunk/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp > llvm/trunk/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp > llvm/trunk/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h > llvm/trunk/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h > > Modified: llvm/trunk/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp > URL: > http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp?rev=188726&r1=188725&r2=188726&view=diff > > =============================================================================> --- llvm/trunk/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp (original) > +++ llvm/trunk/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp Mon Aug 19 > 18:27:43 2013 > @@ -169,6 +169,9 @@ ObjectImage *RuntimeDyldImpl::loadObject > } > } > > + // Give the subclasses a chance to tie-up any loose ends. > + finalizeLoad(); > + > return obj.take(); > } > > @@ -424,6 +427,10 @@ uint8_t *RuntimeDyldImpl::createStubFunc > writeInt16BE(Addr+6, 0x07F1); // brc 15,%r1 > // 8-byte address stored at Addr + 8 > return Addr; > + } else if (Arch == Triple::x86_64) { > + *Addr = 0xFF; // jmp > + *(Addr+1) = 0x25; // rip > + // 32-bit PC-relative address of the GOT entry will be stored at > Addr+2 > } > return Addr; > } > @@ -473,6 +480,7 @@ void RuntimeDyldImpl::resolveExternalSym > // MemoryManager. > uint8_t *Addr = (uint8_t*) > MemMgr->getPointerToNamedFunction(Name.data(), > true); > + updateGOTEntries(Name, (uint64_t)Addr); > DEBUG(dbgs() << "Resolving relocations Name: " << Name > << "\t" << format("%p", Addr) > << "\n"); > > Modified: llvm/trunk/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp > URL: > http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp?rev=188726&r1=188725&r2=188726&view=diff > > =============================================================================> --- llvm/trunk/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp > (original) > +++ llvm/trunk/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp Mon Aug > 19 18:27:43 2013 > @@ -202,7 +202,8 @@ void RuntimeDyldELF::resolveX86_64Reloca > uint64_t Offset, > uint64_t Value, > uint32_t Type, > - int64_t Addend) { > + int64_t Addend, > + uint64_t SymOffset) { > switch (Type) { > default: > llvm_unreachable("Relocation type not implemented yet!"); > @@ -227,6 +228,21 @@ void RuntimeDyldELF::resolveX86_64Reloca > << " at " << format("%p\n",Target)); > break; > } > + case ELF::R_X86_64_GOTPCREL: { > + // findGOTEntry returns the 'G + GOT' part of the relocation > calculation > + // based on the load/target address of the GOT (not the current/local > addr). > + uint64_t GOTAddr = findGOTEntry(Value, SymOffset); > + uint32_t *Target = reinterpret_cast<uint32_t*>(Section.Address + > Offset); > + uint64_t FinalAddress = Section.LoadAddress + Offset; > + // The processRelocationRef method combines the symbol offset and the > addend > + // and in most cases that's what we want. For this relocation type, > we need > + // the raw addend, so we subtract the symbol offset to get it. > + int64_t RealOffset = GOTAddr + Addend - SymOffset - FinalAddress; > + assert(RealOffset <= INT32_MAX && RealOffset >= INT32_MIN); > + int32_t TruncOffset = (RealOffset & 0xFFFFFFFF); > + *Target = TruncOffset; > + break; > + } > case ELF::R_X86_64_PC32: { > // Get the placeholder value from the generated object since > // a previous relocation attempt may have overwritten the loaded > version > @@ -240,6 +256,16 @@ void RuntimeDyldELF::resolveX86_64Reloca > *Target = TruncOffset; > break; > } > + case ELF::R_X86_64_PC64: { > + // Get the placeholder value from the generated object since > + // a previous relocation attempt may have overwritten the loaded > version > + uint64_t *Placeholder = reinterpret_cast<uint64_t*>(Section.ObjAddress > + + > Offset); > + uint64_t *Target = reinterpret_cast<uint64_t*>(Section.Address + > Offset); > + uint64_t FinalAddress = Section.LoadAddress + Offset; > + *Target = *Placeholder + Value + Addend - FinalAddress; > + break; > + } > } > } > > @@ -584,7 +610,7 @@ void RuntimeDyldELF::findOPDEntrySection > // 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) > + if (Rel.Addend != (int64_t)TargetSymbolOffset) > continue; > > section_iterator tsi(Obj.end_sections()); > @@ -757,17 +783,19 @@ void RuntimeDyldELF::resolveSystemZReloc > void RuntimeDyldELF::resolveRelocation(const RelocationEntry &RE, > uint64_t Value) { > const SectionEntry &Section = Sections[RE.SectionID]; > - return resolveRelocation(Section, RE.Offset, Value, RE.RelType, > RE.Addend); > + return resolveRelocation(Section, RE.Offset, Value, RE.RelType, > RE.Addend, > + RE.SymOffset); > } > > void RuntimeDyldELF::resolveRelocation(const SectionEntry &Section, > uint64_t Offset, > uint64_t Value, > uint32_t Type, > - int64_t Addend) { > + int64_t Addend, > + uint64_t SymOffset) { > switch (Arch) { > case Triple::x86_64: > - resolveX86_64Relocation(Section, Offset, Value, Type, Addend); > + resolveX86_64Relocation(Section, Offset, Value, Type, Addend, > SymOffset); > break; > case Triple::x86: > resolveX86Relocation(Section, Offset, > @@ -830,6 +858,7 @@ void RuntimeDyldELF::processRelocationRe > } > if (lsi != Symbols.end()) { > Value.SectionID = lsi->second.first; > + Value.Offset = lsi->second.second; > Value.Addend = lsi->second.second + Addend; > } else { > // Search for the symbol in the global symbol table > @@ -838,6 +867,7 @@ void RuntimeDyldELF::processRelocationRe > gsi = GlobalSymbolTable.find(TargetName.data()); > if (gsi != GlobalSymbolTable.end()) { > Value.SectionID = gsi->second.first; > + Value.Offset = gsi->second.second; > Value.Addend = gsi->second.second + Addend; > } else { > switch (SymType) { > @@ -860,6 +890,7 @@ void RuntimeDyldELF::processRelocationRe > Value.Addend = Addend; > break; > } > + case SymbolRef::ST_Data: > case SymbolRef::ST_Unknown: { > Value.SymbolName = TargetName.data(); > Value.Addend = Addend; > @@ -1150,8 +1181,67 @@ void RuntimeDyldELF::processRelocationRe > ELF::R_390_PC32DBL, Addend); > else > resolveRelocation(Section, Offset, StubAddress, RelType, Addend); > + } else if (Arch == Triple::x86_64 && RelType == ELF::R_X86_64_PLT32) { > + // The way the PLT relocations normally work is that the linker > allocates the > + // PLT and this relocation makes a PC-relative call into the PLT. > The PLT > + // entry will then jump to an address provided by the GOT. On first > call, the > + // GOT address will point back into PLT code that resolves the > symbol. After > + // the first call, the GOT entry points to the actual function. > + // > + // For local functions we're ignoring all of that here and just > replacing > + // the PLT32 relocation type with PC32, which will translate the > relocation > + // into a PC-relative call directly to the function. For external > symbols we > + // can't be sure the function will be within 2^32 bytes of the call > site, so > + // we need to create a stub, which calls into the GOT. This case is > + // equivalent to the usual PLT implementation except that we use the > stub > + // mechanism in RuntimeDyld (which puts stubs at the end of the > section) > + // rather than allocating a PLT section. > + if (Value.SymbolName) { > + // This is a call to an external function. > + // Look for an existing stub. > + SectionEntry &Section = Sections[SectionID]; > + StubMap::const_iterator i = Stubs.find(Value); > + uintptr_t StubAddress; > + if (i != Stubs.end()) { > + StubAddress = uintptr_t(Section.Address) + i->second; > + DEBUG(dbgs() << " Stub function found\n"); > + } else { > + // Create a new stub function (equivalent to a PLT entry). > + DEBUG(dbgs() << " Create a new stub function\n"); > + > + uintptr_t BaseAddress = uintptr_t(Section.Address); > + uintptr_t StubAlignment = getStubAlignment(); > + StubAddress = (BaseAddress + Section.StubOffset + > + StubAlignment - 1) & -StubAlignment; > + unsigned StubOffset = StubAddress - BaseAddress; > + Stubs[Value] = StubOffset; > + createStubFunction((uint8_t *)StubAddress); > + > + // Create a GOT entry for the external function. > + GOTEntries.push_back(Value); > + > + // Make our stub function a relative call to the GOT entry. > + RelocationEntry RE(SectionID, StubOffset + 2, > + ELF::R_X86_64_GOTPCREL, -4); > + addRelocationForSymbol(RE, Value.SymbolName); > + > + // Bump our stub offset counter > + Section.StubOffset = StubOffset + getMaxStubSize(); > + } > + > + // Make the target call a call into the stub table. > + resolveRelocation(Section, Offset, StubAddress, > + ELF::R_X86_64_PC32, Addend); > + } else { > + RelocationEntry RE(SectionID, Offset, ELF::R_X86_64_PC32, > Value.Addend, > + Value.Offset); > + addRelocationForSection(RE, Value.SectionID); > + } > } else { > - RelocationEntry RE(SectionID, Offset, RelType, Value.Addend); > + if (Arch == Triple::x86_64 && RelType == ELF::R_X86_64_GOTPCREL) { > + GOTEntries.push_back(Value); > + } > + RelocationEntry RE(SectionID, Offset, RelType, Value.Addend, > Value.Offset); > if (Value.SymbolName) > addRelocationForSymbol(RE, Value.SymbolName); > else > @@ -1159,6 +1249,106 @@ void RuntimeDyldELF::processRelocationRe > } > } > > +void RuntimeDyldELF::updateGOTEntries(StringRef Name, uint64_t Addr) { > + for (int i = 0, e = GOTEntries.size(); i != e; ++i) { > + if (GOTEntries[i].SymbolName != 0 && GOTEntries[i].SymbolName => Name) { > + GOTEntries[i].Offset = Addr; > + } > + } > +} > + > +size_t RuntimeDyldELF::getGOTEntrySize() { > + // We don't use the GOT in all of these cases, but it's essentially free > + // to put them all here. > + size_t Result = 0; > + switch (Arch) { > + case Triple::x86_64: > + case Triple::aarch64: > + case Triple::ppc64: > + case Triple::ppc64le: > + case Triple::systemz: > + Result = sizeof(uint64_t); > + break; > + case Triple::x86: > + case Triple::arm: > + case Triple::thumb: > + case Triple::mips: > + case Triple::mipsel: > + Result = sizeof(uint32_t); > + break; > + default: llvm_unreachable("Unsupported CPU type!"); > + } > + return Result; > +} > + > +uint64_t RuntimeDyldELF::findGOTEntry(uint64_t LoadAddress, > + uint64_t Offset) { > + assert(GOTSectionID != 0 > + && "Attempting to lookup GOT entry but the GOT was never > allocated."); > + if (GOTSectionID == 0) { > + return 0; > + } > + > + size_t GOTEntrySize = getGOTEntrySize(); > + > + // Find the matching entry in our vector. > + int GOTIndex = -1; > + uint64_t SymbolOffset = 0; > + for (int i = 0, e = GOTEntries.size(); i != e; ++i) { > + if (GOTEntries[i].SymbolName == 0) { > + if (getSectionLoadAddress(GOTEntries[i].SectionID) == LoadAddress && > + GOTEntries[i].Offset == Offset) { > + GOTIndex = i; > + SymbolOffset = GOTEntries[i].Offset; > + break; > + } > + } else { > + // GOT entries for external symbols use the addend as the address > when > + // the external symbol has been resolved. > + if (GOTEntries[i].Offset == LoadAddress) { > + GOTIndex = i; > + // Don't use the Addend here. The relocation handler will use it. > + break; > + } > + } > + } > + assert(GOTIndex != -1 && "Unable to find requested GOT entry."); > + if (GOTIndex == -1) > + return 0; > + > + if (GOTEntrySize == sizeof(uint64_t)) { > + uint64_t *LocalGOTAddr = (uint64_t*)getSectionAddress(GOTSectionID); > + // Fill in this entry with the address of the symbol being referenced. > + LocalGOTAddr[GOTIndex] = LoadAddress + SymbolOffset; > + } else { > + uint32_t *LocalGOTAddr = (uint32_t*)getSectionAddress(GOTSectionID); > + // Fill in this entry with the address of the symbol being referenced. > + LocalGOTAddr[GOTIndex] = (uint32_t)(LoadAddress + SymbolOffset); > + } > + > + // Calculate the load address of this entry > + return getSectionLoadAddress(GOTSectionID) + (GOTIndex * GOTEntrySize); > +} > + > +void RuntimeDyldELF::finalizeLoad() { > + // Allocate the GOT if necessary > + size_t numGOTEntries = GOTEntries.size(); > + if (numGOTEntries != 0) { > + // Allocate memory for the section > + unsigned SectionID = Sections.size(); > + size_t TotalSize = numGOTEntries * getGOTEntrySize(); > + uint8_t *Addr = MemMgr->allocateDataSection(TotalSize, > getGOTEntrySize(), > + SectionID, false); > + if (!Addr) > + report_fatal_error("Unable to allocate memory for GOT!"); > + Sections.push_back(SectionEntry(".got", Addr, TotalSize, 0)); > + // For now, initialize all GOT entries to zero. We'll fill them in as > + // needed when GOT-based relocations are applied. > + memset(Addr, 0, TotalSize); > + GOTSectionID = SectionID; > + } > +} > + > bool RuntimeDyldELF::isCompatibleFormat(const ObjectBuffer *Buffer) const > { > if (Buffer->getBufferSize() < strlen(ELF::ElfMagic)) > return false; > > Modified: llvm/trunk/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h > URL: > http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h?rev=188726&r1=188725&r2=188726&view=diff > > =============================================================================> --- llvm/trunk/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h (original) > +++ llvm/trunk/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h Mon Aug 19 > 18:27:43 2013 > @@ -35,13 +35,15 @@ class RuntimeDyldELF : public RuntimeDyl > uint64_t Offset, > uint64_t Value, > uint32_t Type, > - int64_t Addend); > + int64_t Addend, > + uint64_t SymOffset=0); > > void resolveX86_64Relocation(const SectionEntry &Section, > uint64_t Offset, > uint64_t Value, > uint32_t Type, > - int64_t Addend); > + int64_t Addend, > + uint64_t SymOffset); > > void resolveX86Relocation(const SectionEntry &Section, > uint64_t Offset, > @@ -84,8 +86,18 @@ class RuntimeDyldELF : public RuntimeDyl > ObjSectionToIDMap &LocalSections, > RelocationValueRef &Rel); > > + uint64_t findGOTEntry(uint64_t LoadAddr, uint64_t Offset); > + size_t getGOTEntrySize(); > + > + virtual void updateGOTEntries(StringRef Name, uint64_t Addr); > + > + SmallVector<RelocationValueRef, 2> GOTEntries; > + unsigned GOTSectionID; > + > public: > - RuntimeDyldELF(RTDyldMemoryManager *mm) : RuntimeDyldImpl(mm) {} > + RuntimeDyldELF(RTDyldMemoryManager *mm) : RuntimeDyldImpl(mm), > + GOTSectionID(0) > + {} > > virtual void resolveRelocation(const RelocationEntry &RE, uint64_t > Value); > virtual void processRelocationRef(unsigned SectionID, > @@ -97,6 +109,7 @@ public: > virtual bool isCompatibleFormat(const ObjectBuffer *Buffer) const; > virtual ObjectImage *createObjectImage(ObjectBuffer *InputBuffer); > virtual StringRef getEHFrameSection(); > + virtual void finalizeLoad(); > virtual ~RuntimeDyldELF(); > }; > > > Modified: llvm/trunk/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h > URL: > http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h?rev=188726&r1=188725&r2=188726&view=diff > > =============================================================================> --- llvm/trunk/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h (original) > +++ llvm/trunk/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h Mon Aug > 19 18:27:43 2013 > @@ -80,14 +80,18 @@ public: > unsigned SectionID; > > /// Offset - offset into the section. > - uintptr_t Offset; > + uint64_t Offset; > > /// RelType - relocation type. > uint32_t RelType; > > /// Addend - the relocation addend encoded in the instruction itself. > Also > /// used to make a relocation section relative instead of symbol > relative. > - intptr_t Addend; > + int64_t Addend; > + > + /// SymOffset - Section offset of the relocation entry's symbol (used > for GOT > + /// lookup). > + uint64_t SymOffset; > > /// True if this is a PCRel relocation (MachO specific). > bool IsPCRel; > @@ -97,20 +101,26 @@ public: > > RelocationEntry(unsigned id, uint64_t offset, uint32_t type, int64_t > addend) > : SectionID(id), Offset(offset), RelType(type), Addend(addend), > - IsPCRel(false), Size(0) {} > + SymOffset(0), IsPCRel(false), Size(0) {} > + > + RelocationEntry(unsigned id, uint64_t offset, uint32_t type, int64_t > addend, > + uint64_t symoffset) > + : SectionID(id), Offset(offset), RelType(type), Addend(addend), > + SymOffset(symoffset), IsPCRel(false), Size(0) {} > > RelocationEntry(unsigned id, uint64_t offset, uint32_t type, int64_t > addend, > bool IsPCRel, unsigned Size) > : SectionID(id), Offset(offset), RelType(type), Addend(addend), > - IsPCRel(IsPCRel), Size(Size) {} > + SymOffset(0), IsPCRel(IsPCRel), Size(Size) {} > }; > > class RelocationValueRef { > public: > unsigned SectionID; > - intptr_t Addend; > + uint64_t Offset; > + int64_t Addend; > const char *SymbolName; > - RelocationValueRef(): SectionID(0), Addend(0), SymbolName(0) {} > + RelocationValueRef(): SectionID(0), Offset(0), Addend(0), SymbolName(0) > {} > > inline bool operator==(const RelocationValueRef &Other) const { > return std::memcmp(this, &Other, sizeof(RelocationValueRef)) == 0; > @@ -175,7 +185,7 @@ protected: > else if (Arch == Triple::ppc64 || Arch == Triple::ppc64le) > return 44; > else if (Arch == Triple::x86_64) > - return 8; // GOT > + return 6; // 2-byte jmp instruction + 32-bit relative address > else if (Arch == Triple::systemz) > return 16; > else > @@ -292,6 +302,11 @@ protected: > > /// \brief Resolve relocations to external symbols. > void resolveExternalSymbols(); > + > + /// \brief Update GOT entries for external symbols. > + // The base class does nothing. ELF overrides this. > + virtual void updateGOTEntries(StringRef Name, uint64_t Addr) {} > + > virtual ObjectImage *createObjectImage(ObjectBuffer *InputBuffer); > public: > RuntimeDyldImpl(RTDyldMemoryManager *mm) : MemMgr(mm), HasError(false) > {} > @@ -336,6 +351,8 @@ public: > virtual bool isCompatibleFormat(const ObjectBuffer *Buffer) const = 0; > > virtual StringRef getEHFrameSection(); > + > + virtual void finalizeLoad() {} > }; > > } // end namespace llvm > > > _______________________________________________ > llvm-commits mailing list > llvm-commits at cs.uiuc.edu > http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits > > >-------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20150126/b0e4a683/attachment.html>
Keno Fischer
2015-Feb-02 06:06 UTC
[LLVMdev] [llvm] r188726 - Adding PIC support for ELF on x86_64 platforms
Hi Lang, Did you ever make any progress on this? I ran into the same problem when rewriting the GOT support (though for a different reason). If not, I can take a crack at it, but I wanted to avoid duplicating effort. Thanks, Keno On Tue, Jan 27, 2015 at 12:07 AM, Lang Hames <lhames at gmail.com> wrote:> Hi Andy, > > Thanks very much for the insight. I'll see if I can come up with a scheme > to support reapplication without having the object file present. > > Cheers, > Lang. > > On Mon, Jan 26, 2015 at 1:59 PM, Kaylor, Andrew <andrew.kaylor at intel.com> > wrote: > >> Hi Lang, >> >> >> >> Yeah, I remember this case. Basically what’s happening is that there are >> relocations for ELF on x86 that use a value that is present in the object >> image as part of the calculation for the final value that goes in the same >> location. If you ever find yourself applying relocations for a second time >> (for instance, because the loaded object location is remapped for >> out-of-proc execution) the original value is no longer in the loaded object. >> >> >> >> You could probably figure out a way to combine the placeholder value with >> the addend field, either while the relocation records are being built >> (though I’m not sure if the relevant sections have been loaded yet at that >> point) or the first time the relocation is applied (though it might be a >> bit cumbersome to know whether or not any given application was the first). >> >> >> >> -Andy >> >> >> >> >> >> *From:* Lang Hames [mailto:lhames at gmail.com] >> *Sent:* Monday, January 26, 2015 1:14 PM >> *To:* Kaylor, Andrew >> *Cc:* Commit Messages and Patches for LLVM >> *Subject:* Re: [llvm] r188726 - Adding PIC support for ELF on x86_64 >> platforms >> >> >> >> Hi Andy, >> >> >> >> In the following snippet, do you recall what made it necessary to read >> the value from the object file via Placeholder, rather than from the copied >> section? >> >> >> >> + // Get the placeholder value from the generated object since >> + // a previous relocation attempt may have overwritten the loaded >> version >> + uint64_t *Placeholder >> reinterpret_cast<uint64_t*>(Section.ObjAddress >> + + >> Offset); >> + uint64_t *Target = reinterpret_cast<uint64_t*>(Section.Address + >> Offset); >> + uint64_t FinalAddress = Section.LoadAddress + Offset; >> + *Target = *Placeholder + Value + Addend - FinalAddress; >> + break; >> >> >> >> I''d like to make my new JIT APIs more aggressive about freeing the >> ObjectFile instances (ideally we'd be able to free immediately after a call >> to loadObject), but at the moment I have to hold it at least until >> resolveRelocations is called. >> >> >> >> I had a quick chat with Tim Northover about this and our guess was that >> it had something to do with relocations being applied more than once? >> >> >> >> Cheers, >> >> Lang. >> >> >> >> >> >> On Mon, Aug 19, 2013 at 4:27 PM, Andrew Kaylor <andrew.kaylor at intel.com> >> wrote: >> >> Author: akaylor >> Date: Mon Aug 19 18:27:43 2013 >> New Revision: 188726 >> >> URL: http://llvm.org/viewvc/llvm-project?rev=188726&view=rev >> Log: >> Adding PIC support for ELF on x86_64 platforms >> >> Modified: >> llvm/trunk/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp >> llvm/trunk/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp >> llvm/trunk/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h >> llvm/trunk/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h >> >> Modified: llvm/trunk/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp >> URL: >> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp?rev=188726&r1=188725&r2=188726&view=diff >> >> =============================================================================>> --- llvm/trunk/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp (original) >> +++ llvm/trunk/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp Mon Aug 19 >> 18:27:43 2013 >> @@ -169,6 +169,9 @@ ObjectImage *RuntimeDyldImpl::loadObject >> } >> } >> >> + // Give the subclasses a chance to tie-up any loose ends. >> + finalizeLoad(); >> + >> return obj.take(); >> } >> >> @@ -424,6 +427,10 @@ uint8_t *RuntimeDyldImpl::createStubFunc >> writeInt16BE(Addr+6, 0x07F1); // brc 15,%r1 >> // 8-byte address stored at Addr + 8 >> return Addr; >> + } else if (Arch == Triple::x86_64) { >> + *Addr = 0xFF; // jmp >> + *(Addr+1) = 0x25; // rip >> + // 32-bit PC-relative address of the GOT entry will be stored at >> Addr+2 >> } >> return Addr; >> } >> @@ -473,6 +480,7 @@ void RuntimeDyldImpl::resolveExternalSym >> // MemoryManager. >> uint8_t *Addr = (uint8_t*) >> MemMgr->getPointerToNamedFunction(Name.data(), >> true); >> + updateGOTEntries(Name, (uint64_t)Addr); >> DEBUG(dbgs() << "Resolving relocations Name: " << Name >> << "\t" << format("%p", Addr) >> << "\n"); >> >> Modified: llvm/trunk/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp >> URL: >> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp?rev=188726&r1=188725&r2=188726&view=diff >> >> =============================================================================>> --- llvm/trunk/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp >> (original) >> +++ llvm/trunk/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp Mon Aug >> 19 18:27:43 2013 >> @@ -202,7 +202,8 @@ void RuntimeDyldELF::resolveX86_64Reloca >> uint64_t Offset, >> uint64_t Value, >> uint32_t Type, >> - int64_t Addend) { >> + int64_t Addend, >> + uint64_t SymOffset) { >> switch (Type) { >> default: >> llvm_unreachable("Relocation type not implemented yet!"); >> @@ -227,6 +228,21 @@ void RuntimeDyldELF::resolveX86_64Reloca >> << " at " << format("%p\n",Target)); >> break; >> } >> + case ELF::R_X86_64_GOTPCREL: { >> + // findGOTEntry returns the 'G + GOT' part of the relocation >> calculation >> + // based on the load/target address of the GOT (not the >> current/local addr). >> + uint64_t GOTAddr = findGOTEntry(Value, SymOffset); >> + uint32_t *Target = reinterpret_cast<uint32_t*>(Section.Address + >> Offset); >> + uint64_t FinalAddress = Section.LoadAddress + Offset; >> + // The processRelocationRef method combines the symbol offset and >> the addend >> + // and in most cases that's what we want. For this relocation type, >> we need >> + // the raw addend, so we subtract the symbol offset to get it. >> + int64_t RealOffset = GOTAddr + Addend - SymOffset - FinalAddress; >> + assert(RealOffset <= INT32_MAX && RealOffset >= INT32_MIN); >> + int32_t TruncOffset = (RealOffset & 0xFFFFFFFF); >> + *Target = TruncOffset; >> + break; >> + } >> case ELF::R_X86_64_PC32: { >> // Get the placeholder value from the generated object since >> // a previous relocation attempt may have overwritten the loaded >> version >> @@ -240,6 +256,16 @@ void RuntimeDyldELF::resolveX86_64Reloca >> *Target = TruncOffset; >> break; >> } >> + case ELF::R_X86_64_PC64: { >> + // Get the placeholder value from the generated object since >> + // a previous relocation attempt may have overwritten the loaded >> version >> + uint64_t *Placeholder >> reinterpret_cast<uint64_t*>(Section.ObjAddress >> + + >> Offset); >> + uint64_t *Target = reinterpret_cast<uint64_t*>(Section.Address + >> Offset); >> + uint64_t FinalAddress = Section.LoadAddress + Offset; >> + *Target = *Placeholder + Value + Addend - FinalAddress; >> + break; >> + } >> } >> } >> >> @@ -584,7 +610,7 @@ void RuntimeDyldELF::findOPDEntrySection >> // 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) >> + if (Rel.Addend != (int64_t)TargetSymbolOffset) >> continue; >> >> section_iterator tsi(Obj.end_sections()); >> @@ -757,17 +783,19 @@ void RuntimeDyldELF::resolveSystemZReloc >> void RuntimeDyldELF::resolveRelocation(const RelocationEntry &RE, >> uint64_t Value) { >> const SectionEntry &Section = Sections[RE.SectionID]; >> - return resolveRelocation(Section, RE.Offset, Value, RE.RelType, >> RE.Addend); >> + return resolveRelocation(Section, RE.Offset, Value, RE.RelType, >> RE.Addend, >> + RE.SymOffset); >> } >> >> void RuntimeDyldELF::resolveRelocation(const SectionEntry &Section, >> uint64_t Offset, >> uint64_t Value, >> uint32_t Type, >> - int64_t Addend) { >> + int64_t Addend, >> + uint64_t SymOffset) { >> switch (Arch) { >> case Triple::x86_64: >> - resolveX86_64Relocation(Section, Offset, Value, Type, Addend); >> + resolveX86_64Relocation(Section, Offset, Value, Type, Addend, >> SymOffset); >> break; >> case Triple::x86: >> resolveX86Relocation(Section, Offset, >> @@ -830,6 +858,7 @@ void RuntimeDyldELF::processRelocationRe >> } >> if (lsi != Symbols.end()) { >> Value.SectionID = lsi->second.first; >> + Value.Offset = lsi->second.second; >> Value.Addend = lsi->second.second + Addend; >> } else { >> // Search for the symbol in the global symbol table >> @@ -838,6 +867,7 @@ void RuntimeDyldELF::processRelocationRe >> gsi = GlobalSymbolTable.find(TargetName.data()); >> if (gsi != GlobalSymbolTable.end()) { >> Value.SectionID = gsi->second.first; >> + Value.Offset = gsi->second.second; >> Value.Addend = gsi->second.second + Addend; >> } else { >> switch (SymType) { >> @@ -860,6 +890,7 @@ void RuntimeDyldELF::processRelocationRe >> Value.Addend = Addend; >> break; >> } >> + case SymbolRef::ST_Data: >> case SymbolRef::ST_Unknown: { >> Value.SymbolName = TargetName.data(); >> Value.Addend = Addend; >> @@ -1150,8 +1181,67 @@ void RuntimeDyldELF::processRelocationRe >> ELF::R_390_PC32DBL, Addend); >> else >> resolveRelocation(Section, Offset, StubAddress, RelType, Addend); >> + } else if (Arch == Triple::x86_64 && RelType == ELF::R_X86_64_PLT32) { >> + // The way the PLT relocations normally work is that the linker >> allocates the >> + // PLT and this relocation makes a PC-relative call into the PLT. >> The PLT >> + // entry will then jump to an address provided by the GOT. On first >> call, the >> + // GOT address will point back into PLT code that resolves the >> symbol. After >> + // the first call, the GOT entry points to the actual function. >> + // >> + // For local functions we're ignoring all of that here and just >> replacing >> + // the PLT32 relocation type with PC32, which will translate the >> relocation >> + // into a PC-relative call directly to the function. For external >> symbols we >> + // can't be sure the function will be within 2^32 bytes of the call >> site, so >> + // we need to create a stub, which calls into the GOT. This case is >> + // equivalent to the usual PLT implementation except that we use the >> stub >> + // mechanism in RuntimeDyld (which puts stubs at the end of the >> section) >> + // rather than allocating a PLT section. >> + if (Value.SymbolName) { >> + // This is a call to an external function. >> + // Look for an existing stub. >> + SectionEntry &Section = Sections[SectionID]; >> + StubMap::const_iterator i = Stubs.find(Value); >> + uintptr_t StubAddress; >> + if (i != Stubs.end()) { >> + StubAddress = uintptr_t(Section.Address) + i->second; >> + DEBUG(dbgs() << " Stub function found\n"); >> + } else { >> + // Create a new stub function (equivalent to a PLT entry). >> + DEBUG(dbgs() << " Create a new stub function\n"); >> + >> + uintptr_t BaseAddress = uintptr_t(Section.Address); >> + uintptr_t StubAlignment = getStubAlignment(); >> + StubAddress = (BaseAddress + Section.StubOffset + >> + StubAlignment - 1) & -StubAlignment; >> + unsigned StubOffset = StubAddress - BaseAddress; >> + Stubs[Value] = StubOffset; >> + createStubFunction((uint8_t *)StubAddress); >> + >> + // Create a GOT entry for the external function. >> + GOTEntries.push_back(Value); >> + >> + // Make our stub function a relative call to the GOT entry. >> + RelocationEntry RE(SectionID, StubOffset + 2, >> + ELF::R_X86_64_GOTPCREL, -4); >> + addRelocationForSymbol(RE, Value.SymbolName); >> + >> + // Bump our stub offset counter >> + Section.StubOffset = StubOffset + getMaxStubSize(); >> + } >> + >> + // Make the target call a call into the stub table. >> + resolveRelocation(Section, Offset, StubAddress, >> + ELF::R_X86_64_PC32, Addend); >> + } else { >> + RelocationEntry RE(SectionID, Offset, ELF::R_X86_64_PC32, >> Value.Addend, >> + Value.Offset); >> + addRelocationForSection(RE, Value.SectionID); >> + } >> } else { >> - RelocationEntry RE(SectionID, Offset, RelType, Value.Addend); >> + if (Arch == Triple::x86_64 && RelType == ELF::R_X86_64_GOTPCREL) { >> + GOTEntries.push_back(Value); >> + } >> + RelocationEntry RE(SectionID, Offset, RelType, Value.Addend, >> Value.Offset); >> if (Value.SymbolName) >> addRelocationForSymbol(RE, Value.SymbolName); >> else >> @@ -1159,6 +1249,106 @@ void RuntimeDyldELF::processRelocationRe >> } >> } >> >> +void RuntimeDyldELF::updateGOTEntries(StringRef Name, uint64_t Addr) { >> + for (int i = 0, e = GOTEntries.size(); i != e; ++i) { >> + if (GOTEntries[i].SymbolName != 0 && GOTEntries[i].SymbolName =>> Name) { >> + GOTEntries[i].Offset = Addr; >> + } >> + } >> +} >> + >> +size_t RuntimeDyldELF::getGOTEntrySize() { >> + // We don't use the GOT in all of these cases, but it's essentially >> free >> + // to put them all here. >> + size_t Result = 0; >> + switch (Arch) { >> + case Triple::x86_64: >> + case Triple::aarch64: >> + case Triple::ppc64: >> + case Triple::ppc64le: >> + case Triple::systemz: >> + Result = sizeof(uint64_t); >> + break; >> + case Triple::x86: >> + case Triple::arm: >> + case Triple::thumb: >> + case Triple::mips: >> + case Triple::mipsel: >> + Result = sizeof(uint32_t); >> + break; >> + default: llvm_unreachable("Unsupported CPU type!"); >> + } >> + return Result; >> +} >> + >> +uint64_t RuntimeDyldELF::findGOTEntry(uint64_t LoadAddress, >> + uint64_t Offset) { >> + assert(GOTSectionID != 0 >> + && "Attempting to lookup GOT entry but the GOT was never >> allocated."); >> + if (GOTSectionID == 0) { >> + return 0; >> + } >> + >> + size_t GOTEntrySize = getGOTEntrySize(); >> + >> + // Find the matching entry in our vector. >> + int GOTIndex = -1; >> + uint64_t SymbolOffset = 0; >> + for (int i = 0, e = GOTEntries.size(); i != e; ++i) { >> + if (GOTEntries[i].SymbolName == 0) { >> + if (getSectionLoadAddress(GOTEntries[i].SectionID) == LoadAddress >> && >> + GOTEntries[i].Offset == Offset) { >> + GOTIndex = i; >> + SymbolOffset = GOTEntries[i].Offset; >> + break; >> + } >> + } else { >> + // GOT entries for external symbols use the addend as the address >> when >> + // the external symbol has been resolved. >> + if (GOTEntries[i].Offset == LoadAddress) { >> + GOTIndex = i; >> + // Don't use the Addend here. The relocation handler will use >> it. >> + break; >> + } >> + } >> + } >> + assert(GOTIndex != -1 && "Unable to find requested GOT entry."); >> + if (GOTIndex == -1) >> + return 0; >> + >> + if (GOTEntrySize == sizeof(uint64_t)) { >> + uint64_t *LocalGOTAddr = (uint64_t*)getSectionAddress(GOTSectionID); >> + // Fill in this entry with the address of the symbol being >> referenced. >> + LocalGOTAddr[GOTIndex] = LoadAddress + SymbolOffset; >> + } else { >> + uint32_t *LocalGOTAddr = (uint32_t*)getSectionAddress(GOTSectionID); >> + // Fill in this entry with the address of the symbol being >> referenced. >> + LocalGOTAddr[GOTIndex] = (uint32_t)(LoadAddress + SymbolOffset); >> + } >> + >> + // Calculate the load address of this entry >> + return getSectionLoadAddress(GOTSectionID) + (GOTIndex * GOTEntrySize); >> +} >> + >> +void RuntimeDyldELF::finalizeLoad() { >> + // Allocate the GOT if necessary >> + size_t numGOTEntries = GOTEntries.size(); >> + if (numGOTEntries != 0) { >> + // Allocate memory for the section >> + unsigned SectionID = Sections.size(); >> + size_t TotalSize = numGOTEntries * getGOTEntrySize(); >> + uint8_t *Addr = MemMgr->allocateDataSection(TotalSize, >> getGOTEntrySize(), >> + SectionID, false); >> + if (!Addr) >> + report_fatal_error("Unable to allocate memory for GOT!"); >> + Sections.push_back(SectionEntry(".got", Addr, TotalSize, 0)); >> + // For now, initialize all GOT entries to zero. We'll fill them in >> as >> + // needed when GOT-based relocations are applied. >> + memset(Addr, 0, TotalSize); >> + GOTSectionID = SectionID; >> + } >> +} >> + >> bool RuntimeDyldELF::isCompatibleFormat(const ObjectBuffer *Buffer) >> const { >> if (Buffer->getBufferSize() < strlen(ELF::ElfMagic)) >> return false; >> >> Modified: llvm/trunk/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h >> URL: >> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h?rev=188726&r1=188725&r2=188726&view=diff >> >> =============================================================================>> --- llvm/trunk/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h (original) >> +++ llvm/trunk/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.h Mon Aug >> 19 18:27:43 2013 >> @@ -35,13 +35,15 @@ class RuntimeDyldELF : public RuntimeDyl >> uint64_t Offset, >> uint64_t Value, >> uint32_t Type, >> - int64_t Addend); >> + int64_t Addend, >> + uint64_t SymOffset=0); >> >> void resolveX86_64Relocation(const SectionEntry &Section, >> uint64_t Offset, >> uint64_t Value, >> uint32_t Type, >> - int64_t Addend); >> + int64_t Addend, >> + uint64_t SymOffset); >> >> void resolveX86Relocation(const SectionEntry &Section, >> uint64_t Offset, >> @@ -84,8 +86,18 @@ class RuntimeDyldELF : public RuntimeDyl >> ObjSectionToIDMap &LocalSections, >> RelocationValueRef &Rel); >> >> + uint64_t findGOTEntry(uint64_t LoadAddr, uint64_t Offset); >> + size_t getGOTEntrySize(); >> + >> + virtual void updateGOTEntries(StringRef Name, uint64_t Addr); >> + >> + SmallVector<RelocationValueRef, 2> GOTEntries; >> + unsigned GOTSectionID; >> + >> public: >> - RuntimeDyldELF(RTDyldMemoryManager *mm) : RuntimeDyldImpl(mm) {} >> + RuntimeDyldELF(RTDyldMemoryManager *mm) : RuntimeDyldImpl(mm), >> + GOTSectionID(0) >> + {} >> >> virtual void resolveRelocation(const RelocationEntry &RE, uint64_t >> Value); >> virtual void processRelocationRef(unsigned SectionID, >> @@ -97,6 +109,7 @@ public: >> virtual bool isCompatibleFormat(const ObjectBuffer *Buffer) const; >> virtual ObjectImage *createObjectImage(ObjectBuffer *InputBuffer); >> virtual StringRef getEHFrameSection(); >> + virtual void finalizeLoad(); >> virtual ~RuntimeDyldELF(); >> }; >> >> >> Modified: llvm/trunk/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h >> URL: >> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h?rev=188726&r1=188725&r2=188726&view=diff >> >> =============================================================================>> --- llvm/trunk/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h >> (original) >> +++ llvm/trunk/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h Mon Aug >> 19 18:27:43 2013 >> @@ -80,14 +80,18 @@ public: >> unsigned SectionID; >> >> /// Offset - offset into the section. >> - uintptr_t Offset; >> + uint64_t Offset; >> >> /// RelType - relocation type. >> uint32_t RelType; >> >> /// Addend - the relocation addend encoded in the instruction itself. >> Also >> /// used to make a relocation section relative instead of symbol >> relative. >> - intptr_t Addend; >> + int64_t Addend; >> + >> + /// SymOffset - Section offset of the relocation entry's symbol (used >> for GOT >> + /// lookup). >> + uint64_t SymOffset; >> >> /// True if this is a PCRel relocation (MachO specific). >> bool IsPCRel; >> @@ -97,20 +101,26 @@ public: >> >> RelocationEntry(unsigned id, uint64_t offset, uint32_t type, int64_t >> addend) >> : SectionID(id), Offset(offset), RelType(type), Addend(addend), >> - IsPCRel(false), Size(0) {} >> + SymOffset(0), IsPCRel(false), Size(0) {} >> + >> + RelocationEntry(unsigned id, uint64_t offset, uint32_t type, int64_t >> addend, >> + uint64_t symoffset) >> + : SectionID(id), Offset(offset), RelType(type), Addend(addend), >> + SymOffset(symoffset), IsPCRel(false), Size(0) {} >> >> RelocationEntry(unsigned id, uint64_t offset, uint32_t type, int64_t >> addend, >> bool IsPCRel, unsigned Size) >> : SectionID(id), Offset(offset), RelType(type), Addend(addend), >> - IsPCRel(IsPCRel), Size(Size) {} >> + SymOffset(0), IsPCRel(IsPCRel), Size(Size) {} >> }; >> >> class RelocationValueRef { >> public: >> unsigned SectionID; >> - intptr_t Addend; >> + uint64_t Offset; >> + int64_t Addend; >> const char *SymbolName; >> - RelocationValueRef(): SectionID(0), Addend(0), SymbolName(0) {} >> + RelocationValueRef(): SectionID(0), Offset(0), Addend(0), >> SymbolName(0) {} >> >> inline bool operator==(const RelocationValueRef &Other) const { >> return std::memcmp(this, &Other, sizeof(RelocationValueRef)) == 0; >> @@ -175,7 +185,7 @@ protected: >> else if (Arch == Triple::ppc64 || Arch == Triple::ppc64le) >> return 44; >> else if (Arch == Triple::x86_64) >> - return 8; // GOT >> + return 6; // 2-byte jmp instruction + 32-bit relative address >> else if (Arch == Triple::systemz) >> return 16; >> else >> @@ -292,6 +302,11 @@ protected: >> >> /// \brief Resolve relocations to external symbols. >> void resolveExternalSymbols(); >> + >> + /// \brief Update GOT entries for external symbols. >> + // The base class does nothing. ELF overrides this. >> + virtual void updateGOTEntries(StringRef Name, uint64_t Addr) {} >> + >> virtual ObjectImage *createObjectImage(ObjectBuffer *InputBuffer); >> public: >> RuntimeDyldImpl(RTDyldMemoryManager *mm) : MemMgr(mm), HasError(false) >> {} >> @@ -336,6 +351,8 @@ public: >> virtual bool isCompatibleFormat(const ObjectBuffer *Buffer) const = 0; >> >> virtual StringRef getEHFrameSection(); >> + >> + virtual void finalizeLoad() {} >> }; >> >> } // end namespace llvm >> >> >> _______________________________________________ >> llvm-commits mailing list >> llvm-commits at cs.uiuc.edu >> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits >> >> >> > > > _______________________________________________ > LLVM Developers mailing list > LLVMdev at cs.uiuc.edu http://llvm.cs.uiuc.edu > http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev > >-------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20150202/1f9acfad/attachment.html>