+ case ELF::R_ARM_PRIVATE_0:
+ // This relocation is reserved by the ARM ELF ABI for internal use. We
+ // appropriate it here to act as an R_ARM_ABS32 without any addend for use
+ // in the stubs created during JIT (which can't put an addend into the
+ // original object file).
+ *TargetPtr = Value;
+ break;
+ }
+}
+
+void RuntimeDyldELF::resolveMIPSRelocation(const SectionEntry &Section,
+ uint64_t Offset,
+ uint32_t Value,
+ uint32_t Type,
+ int32_t Addend) {
+ uint32_t *Placeholder = reinterpret_cast<uint32_t*>(Section.ObjAddress +
+ Offset);
+ uint32_t* TargetPtr = (uint32_t*)(Section.Address + Offset);
+ Value += Addend;
+
+ DEBUG(dbgs() << "resolveMipselocation, LocalAddress: "
+ << Section.Address + Offset
+ << " FinalAddress: "
+ << format("%p",Section.LoadAddress + Offset)
+ << " Value: " << format("%x",Value)
+ << " Type: " << format("%x",Type)
+ << " Addend: " << format("%x",Addend)
+ << "\n");
+
+ switch(Type) {
+ default:
+ llvm_unreachable("Not implemented relocation type!");
+ break;
+ case ELF::R_MIPS_32:
+ *TargetPtr = Value + (*Placeholder);
+ break;
+ case ELF::R_MIPS_26:
+ *TargetPtr = ((*Placeholder) & 0xfc000000) | (( Value & 0x0fffffff) >> 2);
+ break;
+ case ELF::R_MIPS_HI16:
+ // Get the higher 16-bits. Also add 1 if bit 15 is 1.
+ Value += ((*Placeholder) & 0x0000ffff) << 16;
+ *TargetPtr = ((*Placeholder) & 0xffff0000) |
+ (((Value + 0x8000) >> 16) & 0xffff);
+ break;
+ case ELF::R_MIPS_LO16:
+ Value += ((*Placeholder) & 0x0000ffff);
+ *TargetPtr = ((*Placeholder) & 0xffff0000) | (Value & 0xffff);
+ break;
+ case ELF::R_MIPS_UNUSED1:
+ // Similar to ELF::R_ARM_PRIVATE_0, R_MIPS_UNUSED1 and R_MIPS_UNUSED2
+ // are used for internal JIT purpose. These relocations are similar to
+ // R_MIPS_HI16 and R_MIPS_LO16, but they do not take any addend into
+ // account.
+ *TargetPtr = ((*TargetPtr) & 0xffff0000) |
+ (((Value + 0x8000) >> 16) & 0xffff);
+ break;
+ case ELF::R_MIPS_UNUSED2:
+ *TargetPtr = ((*TargetPtr) & 0xffff0000) | (Value & 0xffff);
+ break;
+ }
+}
+
+// Return the .TOC. section address to R_PPC64_TOC relocations.
+uint64_t RuntimeDyldELF::findPPC64TOC() const {
+ // The TOC consists of sections .got, .toc, .tocbss, .plt in that
+ // order. The TOC starts where the first of these sections starts.
+ SectionList::const_iterator it = Sections.begin();
+ SectionList::const_iterator ite = Sections.end();
+ for (; it != ite; ++it) {
+ if (it->Name == ".got" ||
+ it->Name == ".toc" ||
+ it->Name == ".tocbss" ||
+ it->Name == ".plt")
+ break;
+ }
+ if (it == ite) {
+ // This may happen for
+ // * references to TOC base base (sym@toc, .odp relocation) without
+ // a .toc directive.
+ // In this case just use the first section (which is usually
+ // the .odp) since the code won't reference the .toc base
+ // directly.
+ it = Sections.begin();
+ }
+ assert (it != ite);
+ // Per the ppc64-elf-linux ABI, The TOC base is TOC value plus 0x8000
+ // thus permitting a full 64 Kbytes segment.
+ return it->LoadAddress + 0x8000;
+}
+
+// Returns the sections and offset associated with the ODP entry referenced
+// by Symbol.
+void RuntimeDyldELF::findOPDEntrySection(ObjectImage &Obj,
+ ObjSectionToIDMap &LocalSections,
+ RelocationValueRef &Rel) {
+ // Get the ELF symbol value (st_value) to compare with Relocation offset in
+ // .opd entries
+
+ error_code err;
+ for (section_iterator si = Obj.begin_sections(),
+ se = Obj.end_sections(); si != se; si.increment(err)) {
+ section_iterator RelSecI = si->getRelocatedSection();
+ if (RelSecI == Obj.end_sections())
+ continue;
+
+ StringRef RelSectionName;
+ check(RelSecI->getName(RelSectionName));
+ if (RelSectionName != ".opd")
+ continue;
+
+ for (relocation_iterator i = si->begin_relocations(),
+ e = si->end_relocations(); i != e;) {
+ check(err);
+
+ // The R_PPC64_ADDR64 relocation indicates the first field
+ // of a .opd entry
+ uint64_t TypeFunc;
+ check(i->getType(TypeFunc));
+ if (TypeFunc != ELF::R_PPC64_ADDR64) {
+ i.increment(err);
+ continue;
+ }
+
+ uint64_t TargetSymbolOffset;
+ symbol_iterator TargetSymbol = i->getSymbol();
+ check(i->getOffset(TargetSymbolOffset));
+ int64_t Addend;
+ check(getELFRelocationAddend(*i, Addend));
+
+ i = i.increment(err);
+ if (i == e)
+ break;
+ check(err);
+
+ // Just check if following relocation is a R_PPC64_TOC
+ uint64_t TypeTOC;
+ check(i->getType(TypeTOC));
+ if (TypeTOC != ELF::R_PPC64_TOC)
+ continue;
+
+ // Finally compares the Symbol value and the target symbol offset
+ // to check if this .opd entry refers to the symbol the relocation
+ // points to.
+ if (Rel.Addend != (intptr_t)TargetSymbolOffset)
+ continue;
+
+ section_iterator tsi(Obj.end_sections());
+ check(TargetSymbol->getSection(tsi));
+ Rel.SectionID = findOrEmitSection(Obj, (*tsi), true, LocalSections);
+ Rel.Addend = (intptr_t)Addend;
+ return;
+ }
+ }
+ llvm_unreachable("Attempting to get address of ODP entry!");
+}
+
+// Relocation masks following the #lo(value), #hi(value), #higher(value),
+// and #highest(value) macros defined in section 4.5.1. Relocation Types
+// in PPC-elf64abi document.
+//
+static inline
+uint16_t applyPPClo (uint64_t value)
+{
+ return value & 0xffff;
+}
+
+static inline
+uint16_t applyPPChi (uint64_t value)
+{
+ return (value >> 16) & 0xffff;
+}
+
+static inline
+uint16_t applyPPChigher (uint64_t value)
+{
+ return (value >> 32) & 0xffff;
+}
+
+static inline
+uint16_t applyPPChighest (uint64_t value)
+{
+ return (value >> 48) & 0xffff;
+}
+
+void RuntimeDyldELF::resolvePPC64Relocation(const SectionEntry &Section,
+ uint64_t Offset,
+ uint64_t Value,
+ uint32_t Type,
+ int64_t Addend) {
+ uint8_t* LocalAddress = Section.Address + Offset;
+ switch (Type) {
+ default:
+ llvm_unreachable("Relocation type not implemented yet!");
+ break;
+ case ELF::R_PPC64_ADDR16_LO :
+ writeInt16BE(LocalAddress, applyPPClo (Value + Addend));
+ break;
+ case ELF::R_PPC64_ADDR16_HI :
+ writeInt16BE(LocalAddress, applyPPChi (Value + Addend));
+ break;
+ case ELF::R_PPC64_ADDR16_HIGHER :
+ writeInt16BE(LocalAddress, applyPPChigher (Value + Addend));
+ break;
+ case ELF::R_PPC64_ADDR16_HIGHEST :
+ writeInt16BE(LocalAddress, applyPPChighest (Value + Addend));
+ break;
+ case ELF::R_PPC64_ADDR14 : {
+ assert(((Value + Addend) & 3) == 0);
+ // Preserve the AA/LK bits in the branch instruction
+ uint8_t aalk = *(LocalAddress+3);
+ writeInt16BE(LocalAddress + 2, (aalk & 3) | ((Value + Addend) & 0xfffc));
+ } break;
+ case ELF::R_PPC64_ADDR32 : {
+ int32_t Result = static_cast<int32_t>(Value + Addend);
+ if (SignExtend32<32>(Result) != Result)
+ llvm_unreachable("Relocation R_PPC64_ADDR32 overflow");
+ writeInt32BE(LocalAddress, Result);
+ } break;
+ case ELF::R_PPC64_REL24 : {
+ uint64_t FinalAddress = (Section.LoadAddress + Offset);
+ int32_t delta = static_cast<int32_t>(Value - FinalAddress + Addend);
+ if (SignExtend32<24>(delta) != delta)
+ llvm_unreachable("Relocation R_PPC64_REL24 overflow");
+ // Generates a 'bl <address>' instruction
+ writeInt32BE(LocalAddress, 0x48000001 | (delta & 0x03FFFFFC));
+ } break;
+ case ELF::R_PPC64_REL32 : {
+ uint64_t FinalAddress = (Section.LoadAddress + Offset);
+ int32_t delta = static_cast<int32_t>(Value - FinalAddress + Addend);
+ if (SignExtend32<32>(delta) != delta)
+ llvm_unreachable("Relocation R_PPC64_REL32 overflow");
+ writeInt32BE(LocalAddress, delta);
+ } break;
+ case ELF::R_PPC64_REL64: {
+ uint64_t FinalAddress = (Section.LoadAddress + Offset);
+ uint64_t Delta = Value - FinalAddress + Addend;
+ writeInt64BE(LocalAddress, Delta);
+ } break;
+ case ELF::R_PPC64_ADDR64 :
+ writeInt64BE(LocalAddress, Value + Addend);
+ break;
+ case ELF::R_PPC64_TOC :
+ writeInt64BE(LocalAddress, findPPC64TOC());
+ break;
+ case ELF::R_PPC64_TOC16 : {
+ uint64_t TOCStart = findPPC64TOC();
+ Value = applyPPClo((Value + Addend) - TOCStart);
+ writeInt16BE(LocalAddress, applyPPClo(Value));
+ } break;
+ case ELF::R_PPC64_TOC16_DS : {
+ uint64_t TOCStart = findPPC64TOC();
+ Value = ((Value + Addend) - TOCStart);
+ writeInt16BE(LocalAddress, applyPPClo(Value));
+ } break;
+ }
+}
+
+void RuntimeDyldELF::resolveSystemZRelocation(const SectionEntry &Section,
+ uint64_t Offset,
+ uint64_t Value,
+ uint32_t Type,
+ int64_t Addend) {
+ uint8_t *LocalAddress = Section.Address + Offset;
+ switch (Type) {
+ default:
+ llvm_unreachable("Relocation type not implemented yet!");
+ break;
+ case ELF::R_390_PC16DBL:
+ case ELF::R_390_PLT16DBL: {
+ int64_t Delta = (Value + Addend) - (Section.LoadAddress + Offset);
+ assert(int16_t(Delta / 2) * 2 == Delta && "R_390_PC16DBL overflow");
+ writeInt16BE(LocalAddress, Delta / 2);
+ break;
+ }
+ case ELF::R_390_PC32DBL:
+ case ELF::R_390_PLT32DBL: {
+ int64_t Delta = (Value + Addend) - (Section.LoadAddress + Offset);
+ assert(int32_t(Delta / 2) * 2 == Delta && "R_390_PC32DBL overflow");
+ writeInt32BE(LocalAddress, Delta / 2);
+ break;
+ }
+ case ELF::R_390_PC32: {
+ int64_t Delta = (Value + Addend) - (Section.LoadAddress + Offset);
+ assert(int32_t(Delta) == Delta && "R_390_PC32 overflow");
+ writeInt32BE(LocalAddress, Delta);
+ break;
+ }
+ case ELF::R_390_64:
+ writeInt64BE(LocalAddress, Value + Addend);
+ break;
+ }
+}
+
+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);