diff options
Diffstat (limited to 'contrib/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp')
| -rw-r--r-- | contrib/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp | 313 |
1 files changed, 212 insertions, 101 deletions
diff --git a/contrib/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp b/contrib/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp index 05615d3cc6cf..9ce3974529bb 100644 --- a/contrib/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp +++ b/contrib/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldELF.cpp @@ -221,22 +221,10 @@ void RuntimeDyldELF::registerEHFrames() { uint64_t EHFrameLoadAddr = Sections[EHFrameSID].getLoadAddress(); size_t EHFrameSize = Sections[EHFrameSID].getSize(); MemMgr.registerEHFrames(EHFrameAddr, EHFrameLoadAddr, EHFrameSize); - RegisteredEHFrameSections.push_back(EHFrameSID); } UnregisteredEHFrameSections.clear(); } -void RuntimeDyldELF::deregisterEHFrames() { - for (int i = 0, e = RegisteredEHFrameSections.size(); i != e; ++i) { - SID EHFrameSID = RegisteredEHFrameSections[i]; - uint8_t *EHFrameAddr = Sections[EHFrameSID].getAddress(); - uint64_t EHFrameLoadAddr = Sections[EHFrameSID].getLoadAddress(); - size_t EHFrameSize = Sections[EHFrameSID].getSize(); - MemMgr.deregisterEHFrames(EHFrameAddr, EHFrameLoadAddr, EHFrameSize); - } - RegisteredEHFrameSections.clear(); -} - std::unique_ptr<RuntimeDyldELF> llvm::RuntimeDyldELF::create(Triple::ArchType Arch, RuntimeDyld::MemoryManager &MemMgr, @@ -272,6 +260,8 @@ void RuntimeDyldELF::resolveX86_64Relocation(const SectionEntry &Section, default: llvm_unreachable("Relocation type not implemented yet!"); break; + case ELF::R_X86_64_NONE: + break; case ELF::R_X86_64_64: { support::ulittle64_t::ref(Section.getAddressWithOffset(Offset)) = Value + Addend; @@ -419,6 +409,18 @@ void RuntimeDyldELF::resolveAArch64Relocation(const SectionEntry &Section, // from bits 11:0 of X or32AArch64Imm(TargetPtr, Value + Addend); break; + case ELF::R_AARCH64_LDST8_ABS_LO12_NC: + // Operation: S + A + // Immediate goes in bits 21:10 of LD/ST instruction, taken + // from bits 11:0 of X + or32AArch64Imm(TargetPtr, getBits(Value + Addend, 0, 11)); + break; + case ELF::R_AARCH64_LDST16_ABS_LO12_NC: + // Operation: S + A + // Immediate goes in bits 21:10 of LD/ST instruction, taken + // from bits 11:1 of X + or32AArch64Imm(TargetPtr, getBits(Value + Addend, 1, 11)); + break; case ELF::R_AARCH64_LDST32_ABS_LO12_NC: // Operation: S + A // Immediate goes in bits 21:10 of LD/ST instruction, taken @@ -431,6 +433,12 @@ void RuntimeDyldELF::resolveAArch64Relocation(const SectionEntry &Section, // from bits 11:3 of X or32AArch64Imm(TargetPtr, getBits(Value + Addend, 3, 11)); break; + case ELF::R_AARCH64_LDST128_ABS_LO12_NC: + // Operation: S + A + // Immediate goes in bits 21:10 of LD/ST instruction, taken + // from bits 11:4 of X + or32AArch64Imm(TargetPtr, getBits(Value + Addend, 4, 11)); + break; } } @@ -729,23 +737,23 @@ void RuntimeDyldELF::resolvePPC64Relocation(const SectionEntry &Section, writeInt16BE(LocalAddress, applyPPCha(Delta)); } break; case ELF::R_PPC64_ADDR32: { - int32_t Result = static_cast<int32_t>(Value + Addend); - if (SignExtend32<32>(Result) != Result) + int64_t Result = static_cast<int64_t>(Value + Addend); + if (SignExtend64<32>(Result) != Result) llvm_unreachable("Relocation R_PPC64_ADDR32 overflow"); writeInt32BE(LocalAddress, Result); } break; case ELF::R_PPC64_REL24: { uint64_t FinalAddress = Section.getLoadAddressWithOffset(Offset); - int32_t delta = static_cast<int32_t>(Value - FinalAddress + Addend); - if (SignExtend32<26>(delta) != delta) + int64_t delta = static_cast<int64_t>(Value - FinalAddress + Addend); + if (SignExtend64<26>(delta) != delta) llvm_unreachable("Relocation R_PPC64_REL24 overflow"); // Generates a 'bl <address>' instruction writeInt32BE(LocalAddress, 0x48000001 | (delta & 0x03FFFFFC)); } break; case ELF::R_PPC64_REL32: { uint64_t FinalAddress = Section.getLoadAddressWithOffset(Offset); - int32_t delta = static_cast<int32_t>(Value - FinalAddress + Addend); - if (SignExtend32<32>(delta) != delta) + int64_t delta = static_cast<int64_t>(Value - FinalAddress + Addend); + if (SignExtend64<32>(delta) != delta) llvm_unreachable("Relocation R_PPC64_REL32 overflow"); writeInt32BE(LocalAddress, delta); } break; @@ -782,20 +790,63 @@ void RuntimeDyldELF::resolveSystemZRelocation(const SectionEntry &Section, writeInt32BE(LocalAddress, Delta / 2); break; } + case ELF::R_390_PC16: { + int64_t Delta = (Value + Addend) - Section.getLoadAddressWithOffset(Offset); + assert(int16_t(Delta) == Delta && "R_390_PC16 overflow"); + writeInt16BE(LocalAddress, Delta); + break; + } case ELF::R_390_PC32: { int64_t Delta = (Value + Addend) - Section.getLoadAddressWithOffset(Offset); assert(int32_t(Delta) == Delta && "R_390_PC32 overflow"); writeInt32BE(LocalAddress, Delta); break; } - case ELF::R_390_64: - writeInt64BE(LocalAddress, Value + Addend); - break; case ELF::R_390_PC64: { int64_t Delta = (Value + Addend) - Section.getLoadAddressWithOffset(Offset); writeInt64BE(LocalAddress, Delta); break; } + case ELF::R_390_8: + *LocalAddress = (uint8_t)(Value + Addend); + break; + case ELF::R_390_16: + writeInt16BE(LocalAddress, Value + Addend); + break; + case ELF::R_390_32: + writeInt32BE(LocalAddress, Value + Addend); + break; + case ELF::R_390_64: + writeInt64BE(LocalAddress, Value + Addend); + break; + } +} + +void RuntimeDyldELF::resolveBPFRelocation(const SectionEntry &Section, + uint64_t Offset, uint64_t Value, + uint32_t Type, int64_t Addend) { + bool isBE = Arch == Triple::bpfeb; + + switch (Type) { + default: + llvm_unreachable("Relocation type not implemented yet!"); + break; + case ELF::R_BPF_NONE: + break; + case ELF::R_BPF_64_64: { + write(isBE, Section.getAddressWithOffset(Offset), Value + Addend); + DEBUG(dbgs() << "Writing " << format("%p", (Value + Addend)) << " at " + << format("%p\n", Section.getAddressWithOffset(Offset))); + break; + } + case ELF::R_BPF_64_32: { + Value += Addend; + assert(Value <= UINT32_MAX); + write(isBE, Section.getAddressWithOffset(Offset), static_cast<uint32_t>(Value)); + DEBUG(dbgs() << "Writing " << format("%p", Value) << " at " + << format("%p\n", Section.getAddressWithOffset(Offset))); + break; + } } } @@ -859,6 +910,10 @@ void RuntimeDyldELF::resolveRelocation(const SectionEntry &Section, case Triple::systemz: resolveSystemZRelocation(Section, Offset, Value, Type, Addend); break; + case Triple::bpfel: + case Triple::bpfeb: + resolveBPFRelocation(Section, Offset, Value, Type, Addend); + break; default: llvm_unreachable("Unsupported CPU type!"); } @@ -900,7 +955,7 @@ uint32_t RuntimeDyldELF::getMatchingLoRelocation(uint32_t RelType, } // Sometimes we don't need to create thunk for a branch. -// This typically happens when branch target is located +// This typically happens when branch target is located // in the same object file. In such case target is either // a weak symbol or symbol in a different executable section. // This function checks if branch target is located in the @@ -941,6 +996,61 @@ bool RuntimeDyldELF::resolveAArch64ShortBranch( return true; } +void RuntimeDyldELF::resolveAArch64Branch(unsigned SectionID, + const RelocationValueRef &Value, + relocation_iterator RelI, + StubMap &Stubs) { + + DEBUG(dbgs() << "\t\tThis is an AArch64 branch relocation."); + SectionEntry &Section = Sections[SectionID]; + + uint64_t Offset = RelI->getOffset(); + unsigned RelType = RelI->getType(); + // Look for an existing stub. + StubMap::const_iterator i = Stubs.find(Value); + if (i != Stubs.end()) { + resolveRelocation(Section, Offset, + (uint64_t)Section.getAddressWithOffset(i->second), + RelType, 0); + DEBUG(dbgs() << " Stub function found\n"); + } else if (!resolveAArch64ShortBranch(SectionID, RelI, Value)) { + // Create a new stub function. + DEBUG(dbgs() << " Create a new stub function\n"); + Stubs[Value] = Section.getStubOffset(); + uint8_t *StubTargetAddr = createStubFunction( + Section.getAddressWithOffset(Section.getStubOffset())); + + RelocationEntry REmovz_g3(SectionID, StubTargetAddr - Section.getAddress(), + ELF::R_AARCH64_MOVW_UABS_G3, Value.Addend); + RelocationEntry REmovk_g2(SectionID, + StubTargetAddr - Section.getAddress() + 4, + ELF::R_AARCH64_MOVW_UABS_G2_NC, Value.Addend); + RelocationEntry REmovk_g1(SectionID, + StubTargetAddr - Section.getAddress() + 8, + ELF::R_AARCH64_MOVW_UABS_G1_NC, Value.Addend); + RelocationEntry REmovk_g0(SectionID, + StubTargetAddr - Section.getAddress() + 12, + ELF::R_AARCH64_MOVW_UABS_G0_NC, Value.Addend); + + if (Value.SymbolName) { + addRelocationForSymbol(REmovz_g3, Value.SymbolName); + addRelocationForSymbol(REmovk_g2, Value.SymbolName); + addRelocationForSymbol(REmovk_g1, Value.SymbolName); + addRelocationForSymbol(REmovk_g0, Value.SymbolName); + } else { + addRelocationForSection(REmovz_g3, Value.SectionID); + addRelocationForSection(REmovk_g2, Value.SectionID); + addRelocationForSection(REmovk_g1, Value.SectionID); + addRelocationForSection(REmovk_g0, Value.SectionID); + } + resolveRelocation(Section, Offset, + reinterpret_cast<uint64_t>(Section.getAddressWithOffset( + Section.getStubOffset())), + RelType, 0); + Section.advanceStubOffset(getMaxStubSize()); + } +} + Expected<relocation_iterator> RuntimeDyldELF::processRelocationRef( unsigned SectionID, relocation_iterator RelI, const ObjectFile &O, @@ -1035,55 +1145,22 @@ RuntimeDyldELF::processRelocationRef( DEBUG(dbgs() << "\t\tSectionID: " << SectionID << " Offset: " << Offset << "\n"); - if ((Arch == Triple::aarch64 || Arch == Triple::aarch64_be) && - (RelType == ELF::R_AARCH64_CALL26 || RelType == ELF::R_AARCH64_JUMP26)) { - // This is an AArch64 branch relocation, need to use a stub function. - DEBUG(dbgs() << "\t\tThis is an AArch64 branch relocation."); - SectionEntry &Section = Sections[SectionID]; - - // Look for an existing stub. - StubMap::const_iterator i = Stubs.find(Value); - if (i != Stubs.end()) { - resolveRelocation(Section, Offset, - (uint64_t)Section.getAddressWithOffset(i->second), - RelType, 0); - DEBUG(dbgs() << " Stub function found\n"); - } else if (!resolveAArch64ShortBranch(SectionID, RelI, Value)) { - // Create a new stub function. - DEBUG(dbgs() << " Create a new stub function\n"); - Stubs[Value] = Section.getStubOffset(); - uint8_t *StubTargetAddr = createStubFunction( - Section.getAddressWithOffset(Section.getStubOffset())); - - RelocationEntry REmovz_g3(SectionID, - StubTargetAddr - Section.getAddress(), - ELF::R_AARCH64_MOVW_UABS_G3, Value.Addend); - RelocationEntry REmovk_g2(SectionID, StubTargetAddr - - Section.getAddress() + 4, - ELF::R_AARCH64_MOVW_UABS_G2_NC, Value.Addend); - RelocationEntry REmovk_g1(SectionID, StubTargetAddr - - Section.getAddress() + 8, - ELF::R_AARCH64_MOVW_UABS_G1_NC, Value.Addend); - RelocationEntry REmovk_g0(SectionID, StubTargetAddr - - Section.getAddress() + 12, - ELF::R_AARCH64_MOVW_UABS_G0_NC, Value.Addend); - - if (Value.SymbolName) { - addRelocationForSymbol(REmovz_g3, Value.SymbolName); - addRelocationForSymbol(REmovk_g2, Value.SymbolName); - addRelocationForSymbol(REmovk_g1, Value.SymbolName); - addRelocationForSymbol(REmovk_g0, Value.SymbolName); - } else { - addRelocationForSection(REmovz_g3, Value.SectionID); - addRelocationForSection(REmovk_g2, Value.SectionID); - addRelocationForSection(REmovk_g1, Value.SectionID); - addRelocationForSection(REmovk_g0, Value.SectionID); - } - resolveRelocation(Section, Offset, - reinterpret_cast<uint64_t>(Section.getAddressWithOffset( - Section.getStubOffset())), - RelType, 0); - Section.advanceStubOffset(getMaxStubSize()); + if ((Arch == Triple::aarch64 || Arch == Triple::aarch64_be)) { + if (RelType == ELF::R_AARCH64_CALL26 || RelType == ELF::R_AARCH64_JUMP26) { + resolveAArch64Branch(SectionID, Value, RelI, Stubs); + } else if (RelType == ELF::R_AARCH64_ADR_GOT_PAGE) { + // Craete new GOT entry or find existing one. If GOT entry is + // to be created, then we also emit ABS64 relocation for it. + uint64_t GOTOffset = findOrAllocGOTEntry(Value, ELF::R_AARCH64_ABS64); + resolveGOTOffsetRelocation(SectionID, Offset, GOTOffset + Addend, + ELF::R_AARCH64_ADR_PREL_PG_HI21); + + } else if (RelType == ELF::R_AARCH64_LD64_GOT_LO12_NC) { + uint64_t GOTOffset = findOrAllocGOTEntry(Value, ELF::R_AARCH64_ABS64); + resolveGOTOffsetRelocation(SectionID, Offset, GOTOffset + Addend, + ELF::R_AARCH64_LDST64_ABS_LO12_NC); + } else { + processSimpleRelocation(SectionID, Offset, RelType, Value); } } else if (Arch == Triple::arm) { if (RelType == ELF::R_ARM_PC24 || RelType == ELF::R_ARM_CALL || @@ -1232,7 +1309,7 @@ RuntimeDyldELF::processRelocationRef( if (i != GOTSymbolOffsets.end()) RE.SymOffset = i->second; else { - RE.SymOffset = allocateGOTEntries(SectionID, 1); + RE.SymOffset = allocateGOTEntries(1); GOTSymbolOffsets[TargetName] = RE.SymOffset; } } @@ -1247,12 +1324,13 @@ RuntimeDyldELF::processRelocationRef( Obj.getPlatformFlags(AbiVariant); AbiVariant &= ELF::EF_PPC64_ABI; // 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. + // an external symbol (either Value.SymbolName is set, or SymType is + // Symbol::ST_Unknown) or if the target address is not within the + // signed 24-bits branch address. SectionEntry &Section = Sections[SectionID]; uint8_t *Target = Section.getAddressWithOffset(Offset); bool RangeOverflow = false; - if (SymType != SymbolRef::ST_Unknown) { + if (!Value.SymbolName && SymType != SymbolRef::ST_Unknown) { if (AbiVariant != 2) { // In the ELFv1 ABI, a function call may point to the .opd entry, // so the final symbol value is calculated based on the relocation @@ -1267,21 +1345,19 @@ RuntimeDyldELF::processRelocationRef( } uint8_t *RelocTarget = Sections[Value.SectionID].getAddressWithOffset(Value.Addend); - int32_t delta = static_cast<int32_t>(Target - RelocTarget); + int64_t delta = static_cast<int64_t>(Target - RelocTarget); // If it is within 26-bits branch range, just set the branch target - if (SignExtend32<26>(delta) == delta) { + if (SignExtend64<26>(delta) == delta) { RelocationEntry RE(SectionID, Offset, RelType, Value.Addend); - if (Value.SymbolName) - addRelocationForSymbol(RE, Value.SymbolName); - else - addRelocationForSection(RE, Value.SectionID); + addRelocationForSection(RE, Value.SectionID); } else { RangeOverflow = true; } } - if (SymType == SymbolRef::ST_Unknown || RangeOverflow) { - // It is an external symbol (SymbolRef::ST_Unknown) or within a range - // larger than 24-bits. + if (Value.SymbolName || SymType == SymbolRef::ST_Unknown || + RangeOverflow) { + // It is an external symbol (either Value.SymbolName is set, or + // SymType is SymbolRef::ST_Unknown) or out of range. StubMap::const_iterator i = Stubs.find(Value); if (i != Stubs.end()) { // Symbol function stub already created, just relocate to it @@ -1335,7 +1411,7 @@ RuntimeDyldELF::processRelocationRef( RelType, 0); Section.advanceStubOffset(getMaxStubSize()); } - if (SymType == SymbolRef::ST_Unknown) { + if (Value.SymbolName || SymType == SymbolRef::ST_Unknown) { // Restore the TOC for external calls if (AbiVariant == 2) writeInt32BE(Target + 4, 0xE8410018); // ld r2,28(r1) @@ -1489,14 +1565,15 @@ RuntimeDyldELF::processRelocationRef( Section.advanceStubOffset(getMaxStubSize()); // Allocate a GOT Entry - uint64_t GOTOffset = allocateGOTEntries(SectionID, 1); + uint64_t GOTOffset = allocateGOTEntries(1); // The load of the GOT address has an addend of -4 - resolveGOTOffsetRelocation(SectionID, StubOffset + 2, GOTOffset - 4); + resolveGOTOffsetRelocation(SectionID, StubOffset + 2, GOTOffset - 4, + ELF::R_X86_64_PC32); // Fill in the value of the symbol we're targeting into the GOT addRelocationForSymbol( - computeGOTOffsetRE(SectionID, GOTOffset, 0, ELF::R_X86_64_64), + computeGOTOffsetRE(GOTOffset, 0, ELF::R_X86_64_64), Value.SymbolName); } @@ -1511,11 +1588,13 @@ RuntimeDyldELF::processRelocationRef( } else if (RelType == ELF::R_X86_64_GOTPCREL || RelType == ELF::R_X86_64_GOTPCRELX || RelType == ELF::R_X86_64_REX_GOTPCRELX) { - uint64_t GOTOffset = allocateGOTEntries(SectionID, 1); - resolveGOTOffsetRelocation(SectionID, Offset, GOTOffset + Addend); + uint64_t GOTOffset = allocateGOTEntries(1); + resolveGOTOffsetRelocation(SectionID, Offset, GOTOffset + Addend, + ELF::R_X86_64_PC32); // Fill in the value of the symbol we're targeting into the GOT - RelocationEntry RE = computeGOTOffsetRE(SectionID, GOTOffset, Value.Offset, ELF::R_X86_64_64); + RelocationEntry RE = + computeGOTOffsetRE(GOTOffset, Value.Offset, ELF::R_X86_64_64); if (Value.SymbolName) addRelocationForSymbol(RE, Value.SymbolName); else @@ -1573,9 +1652,7 @@ size_t RuntimeDyldELF::getGOTEntrySize() { return Result; } -uint64_t RuntimeDyldELF::allocateGOTEntries(unsigned SectionID, unsigned no) -{ - (void)SectionID; // The GOT Section is the same for all section in the object file +uint64_t RuntimeDyldELF::allocateGOTEntries(unsigned no) { if (GOTSectionID == 0) { GOTSectionID = Sections.size(); // Reserve a section id. We'll allocate the section later @@ -1587,17 +1664,38 @@ uint64_t RuntimeDyldELF::allocateGOTEntries(unsigned SectionID, unsigned no) return StartOffset; } -void RuntimeDyldELF::resolveGOTOffsetRelocation(unsigned SectionID, uint64_t Offset, uint64_t GOTOffset) -{ +uint64_t RuntimeDyldELF::findOrAllocGOTEntry(const RelocationValueRef &Value, + unsigned GOTRelType) { + auto E = GOTOffsetMap.insert({Value, 0}); + if (E.second) { + uint64_t GOTOffset = allocateGOTEntries(1); + + // Create relocation for newly created GOT entry + RelocationEntry RE = + computeGOTOffsetRE(GOTOffset, Value.Offset, GOTRelType); + if (Value.SymbolName) + addRelocationForSymbol(RE, Value.SymbolName); + else + addRelocationForSection(RE, Value.SectionID); + + E.first->second = GOTOffset; + } + + return E.first->second; +} + +void RuntimeDyldELF::resolveGOTOffsetRelocation(unsigned SectionID, + uint64_t Offset, + uint64_t GOTOffset, + uint32_t Type) { // Fill in the relative address of the GOT Entry into the stub - RelocationEntry GOTRE(SectionID, Offset, ELF::R_X86_64_PC32, GOTOffset); + RelocationEntry GOTRE(SectionID, Offset, Type, GOTOffset); addRelocationForSection(GOTRE, GOTSectionID); } -RelocationEntry RuntimeDyldELF::computeGOTOffsetRE(unsigned SectionID, uint64_t GOTOffset, uint64_t SymbolOffset, - uint32_t Type) -{ - (void)SectionID; // The GOT Section is the same for all section in the object file +RelocationEntry RuntimeDyldELF::computeGOTOffsetRE(uint64_t GOTOffset, + uint64_t SymbolOffset, + uint32_t Type) { return RelocationEntry(GOTSectionID, GOTOffset, Type, SymbolOffset); } @@ -1663,6 +1761,19 @@ bool RuntimeDyldELF::isCompatibleFile(const object::ObjectFile &Obj) const { return Obj.isELF(); } +bool RuntimeDyldELF::relocationNeedsGot(const RelocationRef &R) const { + unsigned RelTy = R.getType(); + if (Arch == Triple::aarch64 || Arch == Triple::aarch64_be) + return RelTy == ELF::R_AARCH64_ADR_GOT_PAGE || + RelTy == ELF::R_AARCH64_LD64_GOT_LO12_NC; + + if (Arch == Triple::x86_64) + return RelTy == ELF::R_X86_64_GOTPCREL || + RelTy == ELF::R_X86_64_GOTPCRELX || + RelTy == ELF::R_X86_64_REX_GOTPCRELX; + return false; +} + bool RuntimeDyldELF::relocationNeedsStub(const RelocationRef &R) const { if (Arch != Triple::x86_64) return true; // Conservative answer |
